diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml
index e7c36c5535..70ebf9b955 100644
--- a/.devcontainer/docker-compose.yml
+++ b/.devcontainer/docker-compose.yml
@@ -20,8 +20,7 @@ services:
environment:
- HOST=0.0.0.0
- MONGO_URI=mongodb://mongodb:27017/LibreChat
- # - CHATGPT_REVERSE_PROXY=http://host.docker.internal:8080/api/conversation # if you are hosting your own chatgpt reverse proxy with docker
- # - OPENAI_REVERSE_PROXY=http://host.docker.internal:8070/v1/chat/completions # if you are hosting your own chatgpt reverse proxy with docker
+ # - OPENAI_REVERSE_PROXY=http://host.docker.internal:8070/v1
- MEILI_HOST=http://meilisearch:7700
# Runs app on the same network as the service container, allows "forwardPorts" in devcontainer.json function.
diff --git a/.env.example b/.env.example
index 90995be72f..e19346c4bf 100644
--- a/.env.example
+++ b/.env.example
@@ -47,6 +47,10 @@ TRUST_PROXY=1
# password policies.
# MIN_PASSWORD_LENGTH=8
+# When enabled, the app will continue running after encountering uncaught exceptions
+# instead of exiting the process. Not recommended for production unless necessary.
+# CONTINUE_ON_UNCAUGHT_EXCEPTION=false
+
#===============#
# JSON Logging #
#===============#
@@ -61,6 +65,9 @@ CONSOLE_JSON=false
DEBUG_LOGGING=true
DEBUG_CONSOLE=false
+# Enable memory diagnostics (logs heap/RSS snapshots every 60s, auto-enabled with --inspect)
+# MEM_DIAG=true
+
#=============#
# Permissions #
#=============#
@@ -68,6 +75,18 @@ DEBUG_CONSOLE=false
# UID=1000
# GID=1000
+#==============#
+# Node Options #
+#==============#
+
+# NOTE: NODE_MAX_OLD_SPACE_SIZE is NOT recognized by Node.js directly.
+# This variable is used as a build argument for Docker or CI/CD workflows,
+# and is NOT used by Node.js to set the heap size at runtime.
+# To configure Node.js memory, use NODE_OPTIONS, e.g.:
+# NODE_OPTIONS="--max-old-space-size=6144"
+# See: https://nodejs.org/api/cli.html#--max-old-space-sizesize-in-mib
+NODE_MAX_OLD_SPACE_SIZE=6144
+
#===============#
# Configuration #
#===============#
@@ -75,6 +94,16 @@ DEBUG_CONSOLE=false
# CONFIG_PATH="/alternative/path/to/librechat.yaml"
+#==================#
+# Langfuse Tracing #
+#==================#
+
+# Get Langfuse API keys for your project from the project settings page: https://cloud.langfuse.com
+
+# LANGFUSE_PUBLIC_KEY=
+# LANGFUSE_SECRET_KEY=
+# LANGFUSE_BASE_URL=
+
#===================================================#
# Endpoints #
#===================================================#
@@ -109,9 +138,13 @@ PROXY=
#============#
ANTHROPIC_API_KEY=user_provided
-# ANTHROPIC_MODELS=claude-opus-4-20250514,claude-sonnet-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022,claude-3-opus-20240229,claude-3-sonnet-20240229,claude-3-haiku-20240307
+# ANTHROPIC_MODELS=claude-sonnet-4-6,claude-opus-4-6,claude-opus-4-20250514,claude-sonnet-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022,claude-3-opus-20240229,claude-3-sonnet-20240229,claude-3-haiku-20240307
# ANTHROPIC_REVERSE_PROXY=
+# Set to true to use Anthropic models through Google Vertex AI instead of direct API
+# ANTHROPIC_USE_VERTEX=
+# ANTHROPIC_VERTEX_REGION=us-east5
+
#============#
# Azure #
#============#
@@ -129,7 +162,6 @@ ANTHROPIC_API_KEY=user_provided
# AZURE_OPENAI_API_VERSION= # Deprecated
# AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME= # Deprecated
# AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME= # Deprecated
-# PLUGINS_USE_AZURE="true" # Deprecated
#=================#
# AWS Bedrock #
@@ -141,7 +173,8 @@ ANTHROPIC_API_KEY=user_provided
# BEDROCK_AWS_SESSION_TOKEN=someSessionToken
# Note: This example list is not meant to be exhaustive. If omitted, all known, supported model IDs will be included for you.
-# BEDROCK_AWS_MODELS=anthropic.claude-3-5-sonnet-20240620-v1:0,meta.llama3-1-8b-instruct-v1:0
+# BEDROCK_AWS_MODELS=anthropic.claude-sonnet-4-6,anthropic.claude-opus-4-6-v1,anthropic.claude-3-5-sonnet-20240620-v1:0,meta.llama3-1-8b-instruct-v1:0
+# Cross-region inference model IDs: us.anthropic.claude-sonnet-4-6,us.anthropic.claude-opus-4-6-v1,global.anthropic.claude-opus-4-6-v1
# See all Bedrock model IDs here: https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html#model-ids-arns
@@ -163,15 +196,23 @@ GOOGLE_KEY=user_provided
# GOOGLE_AUTH_HEADER=true
# Gemini API (AI Studio)
-# GOOGLE_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash,gemini-2.0-flash-lite
+# GOOGLE_MODELS=gemini-3.1-pro-preview,gemini-3.1-pro-preview-customtools,gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash,gemini-2.0-flash-lite
# Vertex AI
-# GOOGLE_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash-001,gemini-2.0-flash-lite-001
+# GOOGLE_MODELS=gemini-3.1-pro-preview,gemini-3.1-pro-preview-customtools,gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash-001,gemini-2.0-flash-lite-001
# GOOGLE_TITLE_MODEL=gemini-2.0-flash-lite-001
+# Google Cloud region for Vertex AI (used by both chat and image generation)
# GOOGLE_LOC=us-central1
+# Alternative region env var for Gemini Image Generation
+# GOOGLE_CLOUD_LOCATION=global
+
+# Vertex AI Service Account Configuration
+# Path to your Google Cloud service account JSON file
+# GOOGLE_SERVICE_KEY_FILE=/path/to/service-account.json
+
# Google Safety Settings
# NOTE: These settings apply to both Vertex AI and Gemini API (AI Studio)
#
@@ -191,6 +232,23 @@ GOOGLE_KEY=user_provided
# GOOGLE_SAFETY_DANGEROUS_CONTENT=BLOCK_ONLY_HIGH
# GOOGLE_SAFETY_CIVIC_INTEGRITY=BLOCK_ONLY_HIGH
+#========================#
+# Gemini Image Generation #
+#========================#
+
+# Gemini Image Generation Tool (for Agents)
+# Supports multiple authentication methods in priority order:
+# 1. User-provided API key (via GUI)
+# 2. GEMINI_API_KEY env var (admin-configured)
+# 3. GOOGLE_KEY env var (shared with Google chat endpoint)
+# 4. Vertex AI service account (via GOOGLE_SERVICE_KEY_FILE)
+
+# Option A: Use dedicated Gemini API key for image generation
+# GEMINI_API_KEY=your-gemini-api-key
+
+# Vertex AI model for image generation (defaults to gemini-2.5-flash-image)
+# GEMINI_IMAGE_MODEL=gemini-2.5-flash-image
+
#============#
# OpenAI #
#============#
@@ -230,14 +288,6 @@ ASSISTANTS_API_KEY=user_provided
# More info, including how to enable use of Assistants with Azure here:
# https://www.librechat.ai/docs/configuration/librechat_yaml/ai_endpoints/azure#using-assistants-with-azure
-#============#
-# Plugins #
-#============#
-
-# PLUGIN_MODELS=gpt-4o,gpt-4o-mini,gpt-4,gpt-4-turbo-preview,gpt-4-0125-preview,gpt-4-1106-preview,gpt-4-0613,gpt-3.5-turbo,gpt-3.5-turbo-0125,gpt-3.5-turbo-1106,gpt-3.5-turbo-0613
-
-DEBUG_PLUGINS=true
-
CREDS_KEY=f34be427ebb29de8d88c107a71546019685ed8b241d8f2ed00c3df97ad2566f0
CREDS_IV=e2341419ec3dd3d19b13a1a87fafcbfb
@@ -257,6 +307,7 @@ AZURE_AI_SEARCH_SEARCH_OPTION_SELECT=
# IMAGE_GEN_OAI_API_KEY= # Create or reuse OpenAI API key for image generation tool
# IMAGE_GEN_OAI_BASEURL= # Custom OpenAI base URL for image generation tool
# IMAGE_GEN_OAI_AZURE_API_VERSION= # Custom Azure OpenAI deployments
+# IMAGE_GEN_OAI_MODEL=gpt-image-1 # OpenAI image model (e.g., gpt-image-1, gpt-image-1.5)
# IMAGE_GEN_OAI_DESCRIPTION=
# IMAGE_GEN_OAI_DESCRIPTION_WITH_FILES=Custom description for image generation tool when files are present
# IMAGE_GEN_OAI_DESCRIPTION_NO_FILES=Custom description for image generation tool when no files are present
@@ -294,10 +345,6 @@ FLUX_API_BASE_URL=https://api.us1.bfl.ai
GOOGLE_SEARCH_API_KEY=
GOOGLE_CSE_ID=
-# YOUTUBE
-#-----------------
-YOUTUBE_API_KEY=
-
# Stable Diffusion
#-----------------
SD_WEBUI_URL=http://host.docker.internal:7860
@@ -466,6 +513,9 @@ OPENID_ADMIN_ROLE_TOKEN_KIND=
OPENID_USERNAME_CLAIM=
# Set to determine which user info property returned from OpenID Provider to store as the User's name
OPENID_NAME_CLAIM=
+# Set to determine which user info claim to use as the email/identifier for user matching (e.g., "upn" for Entra ID)
+# When not set, defaults to: email -> preferred_username -> upn
+OPENID_EMAIL_CLAIM=
# Optional audience parameter for OpenID authorization requests
OPENID_AUDIENCE=
@@ -488,6 +538,8 @@ OPENID_ON_BEHALF_FLOW_FOR_USERINFO_REQUIRED=
OPENID_ON_BEHALF_FLOW_USERINFO_SCOPE="user.read" # example for Scope Needed for Microsoft Graph API
# Set to true to use the OpenID Connect end session endpoint for logout
OPENID_USE_END_SESSION_ENDPOINT=
+# URL to redirect to after OpenID logout (defaults to ${DOMAIN_CLIENT}/login)
+OPENID_POST_LOGOUT_REDIRECT_URI=
#========================#
# SharePoint Integration #
@@ -608,6 +660,9 @@ AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
AWS_BUCKET_NAME=
+# Required for path-style S3-compatible providers (MinIO, Hetzner, Backblaze B2, etc.)
+# that don't support virtual-hosted-style URLs (bucket.endpoint). Not needed for AWS S3.
+# AWS_FORCE_PATH_STYLE=false
#========================#
# Azure Blob Storage #
@@ -665,6 +720,9 @@ HELP_AND_FAQ_URL=https://librechat.ai
# Enable Redis for caching and session storage
# USE_REDIS=true
+# Enable Redis for resumable LLM streams (defaults to USE_REDIS value if not set)
+# Set to false to use in-memory storage for streams while keeping Redis for other caches
+# USE_REDIS_STREAMS=true
# Single Redis instance
# REDIS_URI=redis://127.0.0.1:6379
@@ -699,8 +757,10 @@ HELP_AND_FAQ_URL=https://librechat.ai
# REDIS_PING_INTERVAL=300
# Force specific cache namespaces to use in-memory storage even when Redis is enabled
-# Comma-separated list of CacheKeys (e.g., ROLES,MESSAGES)
-# FORCED_IN_MEMORY_CACHE_NAMESPACES=ROLES,MESSAGES
+# Comma-separated list of CacheKeys
+# Defaults to CONFIG_STORE,APP_CONFIG so YAML-derived config stays per-container (safe for blue/green deployments)
+# Set to empty string to force all namespaces through Redis: FORCED_IN_MEMORY_CACHE_NAMESPACES=
+# FORCED_IN_MEMORY_CACHE_NAMESPACES=CONFIG_STORE,APP_CONFIG
# Leader Election Configuration (for multi-instance deployments with Redis)
# Duration in seconds that the leader lease is valid before it expires (default: 25)
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index ad0a75ab9b..ae9e6d8e4b 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -26,18 +26,14 @@ Project maintainers have the right and responsibility to remove, edit, or reject
## 1. Development Setup
-1. Use Node.JS 20.x.
-2. Install typescript globally: `npm i -g typescript`.
-3. Run `npm ci` to install dependencies.
-4. Build the data provider: `npm run build:data-provider`.
-5. Build data schemas: `npm run build:data-schemas`.
-6. Build API methods: `npm run build:api`.
-7. Setup and run unit tests:
+1. Use Node.js v20.19.0+ or ^22.12.0 or >= 23.0.0.
+2. Run `npm run smart-reinstall` to install dependencies (uses Turborepo). Use `npm run reinstall` for a clean install, or `npm ci` for a fresh lockfile-based install.
+3. Build all compiled code: `npm run build`.
+4. Setup and run unit tests:
- Copy `.env.test`: `cp api/test/.env.test.example api/test/.env.test`.
- Run backend unit tests: `npm run test:api`.
- Run frontend unit tests: `npm run test:client`.
-8. Setup and run integration tests:
- - Build client: `cd client && npm run build`.
+5. Setup and run integration tests:
- Create `.env`: `cp .env.example .env`.
- Install [MongoDB Community Edition](https://www.mongodb.com/docs/manual/administration/install-community/), ensure that `mongosh` connects to your local instance.
- Run: `npx install playwright`, then `npx playwright install`.
@@ -48,11 +44,11 @@ Project maintainers have the right and responsibility to remove, edit, or reject
## 2. Development Notes
1. Before starting work, make sure your main branch has the latest commits with `npm run update`.
-3. Run linting command to find errors: `npm run lint`. Alternatively, ensure husky pre-commit checks are functioning.
+2. Run linting command to find errors: `npm run lint`. Alternatively, ensure husky pre-commit checks are functioning.
3. After your changes, reinstall packages in your current branch using `npm run reinstall` and ensure everything still works.
- Restart the ESLint server ("ESLint: Restart ESLint Server" in VS Code command bar) and your IDE after reinstalling or updating.
4. Clear web app localStorage and cookies before and after changes.
-5. For frontend changes, compile typescript before and after changes to check for introduced errors: `cd client && npm run build`.
+5. To check for introduced errors, build all compiled code: `npm run build`.
6. Run backend unit tests: `npm run test:api`.
7. Run frontend unit tests: `npm run test:client`.
8. Run integration tests: `npm run e2e`.
@@ -118,50 +114,45 @@ Apply the following naming conventions to branches, labels, and other Git-relate
- **JS/TS:** Directories and file names: Descriptive and camelCase. First letter uppercased for React files (e.g., `helperFunction.ts, ReactComponent.tsx`).
- **Docs:** Directories and file names: Descriptive and snake_case (e.g., `config_files.md`).
-## 7. TypeScript Conversion
+## 7. Coding Standards
+
+For detailed coding conventions, workspace boundaries, and architecture guidance, refer to the [`AGENTS.md`](../AGENTS.md) file at the project root. It covers code style, type safety, import ordering, iteration/performance expectations, frontend rules, testing, and development commands.
+
+## 8. TypeScript Conversion
1. **Original State**: The project was initially developed entirely in JavaScript (JS).
-2. **Frontend Transition**:
- - We are in the process of transitioning the frontend from JS to TypeScript (TS).
- - The transition is nearing completion.
- - This conversion is feasible due to React's capability to intermix JS and TS prior to code compilation. It's standard practice to compile/bundle the code in such scenarios.
+2. **Frontend**: Fully transitioned to TypeScript.
-3. **Backend Considerations**:
- - Transitioning the backend to TypeScript would be a more intricate process, especially for an established Express.js server.
-
- - **Options for Transition**:
- - **Single Phase Overhaul**: This involves converting the entire backend to TypeScript in one go. It's the most straightforward approach but can be disruptive, especially for larger codebases.
-
- - **Incremental Transition**: Convert parts of the backend progressively. This can be done by:
- - Maintaining a separate directory for TypeScript files.
- - Gradually migrating and testing individual modules or routes.
- - Using a build tool like `tsc` to compile TypeScript files independently until the entire transition is complete.
-
- - **Compilation Considerations**:
- - Introducing a compilation step for the server is an option. This would involve using tools like `ts-node` for development and `tsc` for production builds.
- - However, this is not a conventional approach for Express.js servers and could introduce added complexity, especially in terms of build and deployment processes.
-
- - **Current Stance**: At present, this backend transition is of lower priority and might not be pursued.
+3. **Backend**:
+ - The legacy Express.js server remains in `/api` as JavaScript.
+ - All new backend code is written in TypeScript under `/packages/api`, which is compiled and consumed by `/api`.
+ - Shared database logic lives in `/packages/data-schemas` (TypeScript).
+ - Shared frontend/backend API types and services live in `/packages/data-provider` (TypeScript).
+ - Minimize direct changes to `/api`; prefer adding TypeScript code to `/packages/api` and importing it.
-## 8. Module Import Conventions
+## 9. Module Import Conventions
-- `npm` packages first,
- - from longest line (top) to shortest (bottom)
+Imports are organized into three sections (in order):
-- Followed by typescript types (pertains to data-provider and client workspaces)
- - longest line (top) to shortest (bottom)
- - types from package come first
+1. **Package imports** — sorted from shortest to longest line length.
+ - `react` is always the first import.
+ - Multi-line (stacked) imports count their total character length across all lines for sorting.
-- Lastly, local imports
- - longest line (top) to shortest (bottom)
- - imports with alias `~` treated the same as relative import with respect to line length
+2. **`import type` imports** — sorted from longest to shortest line length.
+ - Package type imports come first, then local type imports.
+ - Line length sorting resets between the package and local sub-groups.
+
+3. **Local/project imports** — sorted from longest to shortest line length.
+ - Multi-line (stacked) imports count their total character length across all lines for sorting.
+ - Imports with alias `~` are treated the same as relative imports with respect to line length.
+
+- Consolidate value imports from the same module as much as possible.
+- Always use standalone `import type { ... }` for type imports; never use inline `type` keyword inside value imports (e.g., `import { Foo, type Bar }` is wrong).
**Note:** ESLint will automatically enforce these import conventions when you run `npm run lint --fix` or through pre-commit hooks.
----
-
-Please ensure that you adapt this summary to fit the specific context and nuances of your project.
+For the full set of coding standards, see [`AGENTS.md`](../AGENTS.md).
---
diff --git a/.github/workflows/backend-review.yml b/.github/workflows/backend-review.yml
index 4f6fab329b..e151087790 100644
--- a/.github/workflows/backend-review.yml
+++ b/.github/workflows/backend-review.yml
@@ -4,6 +4,7 @@ on:
branches:
- main
- dev
+ - dev-staging
- release/*
paths:
- 'api/**'
@@ -23,6 +24,7 @@ jobs:
BAN_DURATION: ${{ secrets.BAN_DURATION }}
BAN_INTERVAL: ${{ secrets.BAN_INTERVAL }}
NODE_ENV: CI
+ NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.x
@@ -40,8 +42,14 @@ jobs:
- name: Install Data Schemas Package
run: npm run build:data-schemas
- - name: Install API Package
- run: npm run build:api
+ - name: Build API Package & Detect Circular Dependencies
+ run: |
+ output=$(npm run build:api 2>&1)
+ echo "$output"
+ if echo "$output" | grep -q "Circular depend"; then
+ echo "Error: Circular dependency detected in @librechat/api!"
+ exit 1
+ fi
- name: Create empty auth.json file
run: |
@@ -71,4 +79,4 @@ jobs:
run: cd packages/data-schemas && npm run test:ci
- name: Run @librechat/api unit tests
- run: cd packages/api && npm run test:ci
\ No newline at end of file
+ run: cd packages/api && npm run test:ci
diff --git a/.github/workflows/cache-integration-tests.yml b/.github/workflows/cache-integration-tests.yml
index 1f056dd791..caebbfc445 100644
--- a/.github/workflows/cache-integration-tests.yml
+++ b/.github/workflows/cache-integration-tests.yml
@@ -5,11 +5,13 @@ on:
branches:
- main
- dev
+ - dev-staging
- release/*
paths:
- 'packages/api/src/cache/**'
- 'packages/api/src/cluster/**'
- 'packages/api/src/mcp/**'
+ - 'packages/api/src/stream/**'
- 'redis-config/**'
- '.github/workflows/cache-integration-tests.yml'
@@ -86,4 +88,4 @@ jobs:
- name: Stop Single Redis Instance
if: always()
- run: redis-cli -p 6379 shutdown || true
\ No newline at end of file
+ run: redis-cli -p 6379 shutdown || true
diff --git a/.github/workflows/eslint-ci.yml b/.github/workflows/eslint-ci.yml
index 9383dd939e..8203da4e8b 100644
--- a/.github/workflows/eslint-ci.yml
+++ b/.github/workflows/eslint-ci.yml
@@ -5,6 +5,7 @@ on:
branches:
- main
- dev
+ - dev-staging
- release/*
paths:
- 'api/**'
@@ -56,4 +57,4 @@ jobs:
# Run ESLint
npx eslint --no-error-on-unmatched-pattern \
--config eslint.config.mjs \
- $CHANGED_FILES
\ No newline at end of file
+ $CHANGED_FILES
diff --git a/.github/workflows/frontend-review.yml b/.github/workflows/frontend-review.yml
index 7064c18c13..989e2e4abe 100644
--- a/.github/workflows/frontend-review.yml
+++ b/.github/workflows/frontend-review.yml
@@ -5,6 +5,7 @@ on:
branches:
- main
- dev
+ - dev-staging
- release/*
paths:
- 'client/**'
@@ -15,6 +16,8 @@ jobs:
name: Run frontend unit tests on Ubuntu
timeout-minutes: 60
runs-on: ubuntu-latest
+ env:
+ NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.x
@@ -37,6 +40,8 @@ jobs:
name: Run frontend unit tests on Windows
timeout-minutes: 60
runs-on: windows-latest
+ env:
+ NODE_OPTIONS: '--max-old-space-size=${{ secrets.NODE_MAX_OLD_SPACE_SIZE || 6144 }}'
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.x
diff --git a/.github/workflows/unused-packages.yml b/.github/workflows/unused-packages.yml
index 442925b69b..f67c1d23be 100644
--- a/.github/workflows/unused-packages.yml
+++ b/.github/workflows/unused-packages.yml
@@ -8,6 +8,7 @@ on:
- 'client/**'
- 'api/**'
- 'packages/client/**'
+ - 'packages/api/**'
jobs:
detect-unused-packages:
@@ -63,35 +64,45 @@ jobs:
extract_deps_from_code() {
local folder=$1
local output_file=$2
+
+ # Initialize empty output file
+ > "$output_file"
+
if [[ -d "$folder" ]]; then
- # Extract require() statements
- grep -rEho "require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)" "$folder" --include=\*.{js,ts,tsx,jsx,mjs,cjs} | \
- sed -E "s/require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)/\1/" > "$output_file"
+ # Extract require() statements (use explicit includes for portability)
+ grep -rEho "require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)" "$folder" \
+ --include='*.js' --include='*.ts' --include='*.tsx' --include='*.jsx' --include='*.mjs' --include='*.cjs' 2>/dev/null | \
+ sed -E "s/require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)/\1/" >> "$output_file" || true
- # Extract ES6 imports - various patterns
- # import x from 'module'
- grep -rEho "import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" --include=\*.{js,ts,tsx,jsx,mjs,cjs} | \
- sed -E "s/import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file"
+ # Extract ES6 imports - import x from 'module'
+ grep -rEho "import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" \
+ --include='*.js' --include='*.ts' --include='*.tsx' --include='*.jsx' --include='*.mjs' --include='*.cjs' 2>/dev/null | \
+ sed -E "s/import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" || true
# import 'module' (side-effect imports)
- grep -rEho "import ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" --include=\*.{js,ts,tsx,jsx,mjs,cjs} | \
- sed -E "s/import ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file"
+ grep -rEho "import ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" \
+ --include='*.js' --include='*.ts' --include='*.tsx' --include='*.jsx' --include='*.mjs' --include='*.cjs' 2>/dev/null | \
+ sed -E "s/import ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" || true
# export { x } from 'module' or export * from 'module'
- grep -rEho "export .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" --include=\*.{js,ts,tsx,jsx,mjs,cjs} | \
- sed -E "s/export .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file"
+ grep -rEho "export .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" \
+ --include='*.js' --include='*.ts' --include='*.tsx' --include='*.jsx' --include='*.mjs' --include='*.cjs' 2>/dev/null | \
+ sed -E "s/export .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" || true
# import type { x } from 'module' (TypeScript)
- grep -rEho "import type .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" --include=\*.{ts,tsx} | \
- sed -E "s/import type .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file"
+ grep -rEho "import type .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" \
+ --include='*.ts' --include='*.tsx' 2>/dev/null | \
+ sed -E "s/import type .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" || true
# Remove subpath imports but keep the base package
- # e.g., '@tanstack/react-query/devtools' becomes '@tanstack/react-query'
- sed -i -E 's|^(@?[a-zA-Z0-9-]+(/[a-zA-Z0-9-]+)?)/.*|\1|' "$output_file"
+ # For scoped packages: '@scope/pkg/subpath' -> '@scope/pkg'
+ # For regular packages: 'pkg/subpath' -> 'pkg'
+ # Scoped packages (must keep @scope/package, strip anything after)
+ sed -i -E 's|^(@[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+)/.*|\1|' "$output_file" 2>/dev/null || true
+ # Non-scoped packages (keep package name, strip subpath)
+ sed -i -E 's|^([a-zA-Z0-9_-]+)/.*|\1|' "$output_file" 2>/dev/null || true
sort -u "$output_file" -o "$output_file"
- else
- touch "$output_file"
fi
}
@@ -99,8 +110,10 @@ jobs:
extract_deps_from_code "client" client_used_code.txt
extract_deps_from_code "api" api_used_code.txt
- # Extract dependencies used by @librechat/client package
+ # Extract dependencies used by workspace packages
+ # These packages are used in the workspace but dependencies are provided by parent package.json
extract_deps_from_code "packages/client" packages_client_used_code.txt
+ extract_deps_from_code "packages/api" packages_api_used_code.txt
- name: Get @librechat/client dependencies
id: get-librechat-client-deps
@@ -126,6 +139,30 @@ jobs:
touch librechat_client_deps.txt
fi
+ - name: Get @librechat/api dependencies
+ id: get-librechat-api-deps
+ run: |
+ if [[ -f "packages/api/package.json" ]]; then
+ # Get all dependencies from @librechat/api (dependencies, devDependencies, and peerDependencies)
+ DEPS=$(jq -r '.dependencies // {} | keys[]' packages/api/package.json 2>/dev/null || echo "")
+ DEV_DEPS=$(jq -r '.devDependencies // {} | keys[]' packages/api/package.json 2>/dev/null || echo "")
+ PEER_DEPS=$(jq -r '.peerDependencies // {} | keys[]' packages/api/package.json 2>/dev/null || echo "")
+
+ # Combine all dependencies
+ echo "$DEPS" > librechat_api_deps.txt
+ echo "$DEV_DEPS" >> librechat_api_deps.txt
+ echo "$PEER_DEPS" >> librechat_api_deps.txt
+
+ # Also include dependencies that are imported in packages/api
+ cat packages_api_used_code.txt >> librechat_api_deps.txt
+
+ # Remove empty lines and sort
+ grep -v '^$' librechat_api_deps.txt | sort -u > temp_deps.txt
+ mv temp_deps.txt librechat_api_deps.txt
+ else
+ touch librechat_api_deps.txt
+ fi
+
- name: Extract Workspace Dependencies
id: extract-workspace-deps
run: |
@@ -184,8 +221,8 @@ jobs:
chmod -R 755 client
cd client
UNUSED=$(depcheck --json | jq -r '.dependencies | join("\n")' || echo "")
- # Exclude dependencies used in scripts, code, and workspace packages
- UNUSED=$(comm -23 <(echo "$UNUSED" | sort) <(cat ../client_used_deps.txt ../client_used_code.txt ../client_workspace_deps.txt | sort) || echo "")
+ # Exclude dependencies used in scripts, code, workspace packages, and @librechat/client imports
+ UNUSED=$(comm -23 <(echo "$UNUSED" | sort) <(cat ../client_used_deps.txt ../client_used_code.txt ../client_workspace_deps.txt ../packages_client_used_code.txt ../librechat_client_deps.txt 2>/dev/null | sort -u) || echo "")
# Filter out false positives
UNUSED=$(echo "$UNUSED" | grep -v "^micromark-extension-llm-math$" || echo "")
echo "CLIENT_UNUSED<> $GITHUB_ENV
@@ -201,8 +238,8 @@ jobs:
chmod -R 755 api
cd api
UNUSED=$(depcheck --json | jq -r '.dependencies | join("\n")' || echo "")
- # Exclude dependencies used in scripts, code, and workspace packages
- UNUSED=$(comm -23 <(echo "$UNUSED" | sort) <(cat ../api_used_deps.txt ../api_used_code.txt ../api_workspace_deps.txt | sort) || echo "")
+ # Exclude dependencies used in scripts, code, workspace packages, and @librechat/api imports
+ UNUSED=$(comm -23 <(echo "$UNUSED" | sort) <(cat ../api_used_deps.txt ../api_used_code.txt ../api_workspace_deps.txt ../packages_api_used_code.txt ../librechat_api_deps.txt 2>/dev/null | sort -u) || echo "")
echo "API_UNUSED<> $GITHUB_ENV
echo "$UNUSED" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
@@ -241,4 +278,4 @@ jobs:
- name: Fail workflow if unused dependencies found
if: env.ROOT_UNUSED != '' || env.CLIENT_UNUSED != '' || env.API_UNUSED != ''
- run: exit 1
\ No newline at end of file
+ run: exit 1
diff --git a/.gitignore b/.gitignore
index d173d26b60..86d4a3ddae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@ pids
# CI/CD data
test-image*
+dump.rdb
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
@@ -29,6 +30,9 @@ coverage
config/translations/stores/*
client/src/localization/languages/*_missing_keys.json
+# Turborepo
+.turbo
+
# Compiled Dirs (http://nodejs.org/api/addons.html)
build/
dist/
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000000..23b5fc0fbb
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,158 @@
+# LibreChat
+
+## Project Overview
+
+LibreChat is a monorepo with the following key workspaces:
+
+| Workspace | Language | Side | Dependency | Purpose |
+|---|---|---|---|---|
+| `/api` | JS (legacy) | Backend | `packages/api`, `packages/data-schemas`, `packages/data-provider`, `@librechat/agents` | Express server — minimize changes here |
+| `/packages/api` | **TypeScript** | Backend | `packages/data-schemas`, `packages/data-provider` | New backend code lives here (TS only, consumed by `/api`) |
+| `/packages/data-schemas` | TypeScript | Backend | `packages/data-provider` | Database models/schemas, shareable across backend projects |
+| `/packages/data-provider` | TypeScript | Shared | — | Shared API types, endpoints, data-service — used by both frontend and backend |
+| `/client` | TypeScript/React | Frontend | `packages/data-provider`, `packages/client` | Frontend SPA |
+| `/packages/client` | TypeScript | Frontend | `packages/data-provider` | Shared frontend utilities |
+
+The source code for `@librechat/agents` (major backend dependency, same team) is at `/home/danny/agentus`.
+
+---
+
+## Workspace Boundaries
+
+- **All new backend code must be TypeScript** in `/packages/api`.
+- Keep `/api` changes to the absolute minimum (thin JS wrappers calling into `/packages/api`).
+- Database-specific shared logic goes in `/packages/data-schemas`.
+- Frontend/backend shared API logic (endpoints, types, data-service) goes in `/packages/data-provider`.
+- Build data-provider from project root: `npm run build:data-provider`.
+
+---
+
+## Code Style
+
+### Structure and Clarity
+
+- **Never-nesting**: early returns, flat code, minimal indentation. Break complex operations into well-named helpers.
+- **Functional first**: pure functions, immutable data, `map`/`filter`/`reduce` over imperative loops. Only reach for OOP when it clearly improves domain modeling or state encapsulation.
+- **No dynamic imports** unless absolutely necessary.
+
+### DRY
+
+- Extract repeated logic into utility functions.
+- Reusable hooks / higher-order components for UI patterns.
+- Parameterized helpers instead of near-duplicate functions.
+- Constants for repeated values; configuration objects over duplicated init code.
+- Shared validators, centralized error handling, single source of truth for business rules.
+- Shared typing system with interfaces/types extending common base definitions.
+- Abstraction layers for external API interactions.
+
+### Iteration and Performance
+
+- **Minimize looping** — especially over shared data structures like message arrays, which are iterated frequently throughout the codebase. Every additional pass adds up at scale.
+- Consolidate sequential O(n) operations into a single pass whenever possible; never loop over the same collection twice if the work can be combined.
+- Choose data structures that reduce the need to iterate (e.g., `Map`/`Set` for lookups instead of `Array.find`/`Array.includes`).
+- Avoid unnecessary object creation; consider space-time tradeoffs.
+- Prevent memory leaks: careful with closures, dispose resources/event listeners, no circular references.
+
+### Type Safety
+
+- **Never use `any`**. Explicit types for all parameters, return values, and variables.
+- **Limit `unknown`** — avoid `unknown`, `Record`, and `as unknown as T` assertions. A `Record` almost always signals a missing explicit type definition.
+- **Don't duplicate types** — before defining a new type, check whether it already exists in the project (especially `packages/data-provider`). Reuse and extend existing types rather than creating redundant definitions.
+- Use union types, generics, and interfaces appropriately.
+- All TypeScript and ESLint warnings/errors must be addressed — do not leave unresolved diagnostics.
+
+### Comments and Documentation
+
+- Write self-documenting code; no inline comments narrating what code does.
+- JSDoc only for complex/non-obvious logic or intellisense on public APIs.
+- Single-line JSDoc for brief docs, multi-line for complex cases.
+- Avoid standalone `//` comments unless absolutely necessary.
+
+### Import Order
+
+Imports are organized into three sections:
+
+1. **Package imports** — sorted shortest to longest line length (`react` always first).
+2. **`import type` imports** — sorted longest to shortest (package types first, then local types; length resets between sub-groups).
+3. **Local/project imports** — sorted longest to shortest.
+
+Multi-line imports count total character length across all lines. Consolidate value imports from the same module. Always use standalone `import type { ... }` — never inline `type` inside value imports.
+
+### JS/TS Loop Preferences
+
+- **Limit looping as much as possible.** Prefer single-pass transformations and avoid re-iterating the same data.
+- `for (let i = 0; ...)` for performance-critical or index-dependent operations.
+- `for...of` for simple array iteration.
+- `for...in` only for object property enumeration.
+
+---
+
+## Frontend Rules (`client/src/**/*`)
+
+### Localization
+
+- All user-facing text must use `useLocalize()`.
+- Only update English keys in `client/src/locales/en/translation.json` (other languages are automated externally).
+- Semantic key prefixes: `com_ui_`, `com_assistants_`, etc.
+
+### Components
+
+- TypeScript for all React components with proper type imports.
+- Semantic HTML with ARIA labels (`role`, `aria-label`) for accessibility.
+- Group related components in feature directories (e.g., `SidePanel/Memories/`).
+- Use index files for clean exports.
+
+### Data Management
+
+- Feature hooks: `client/src/data-provider/[Feature]/queries.ts` → `[Feature]/index.ts` → `client/src/data-provider/index.ts`.
+- React Query (`@tanstack/react-query`) for all API interactions; proper query invalidation on mutations.
+- QueryKeys and MutationKeys in `packages/data-provider/src/keys.ts`.
+
+### Data-Provider Integration
+
+- Endpoints: `packages/data-provider/src/api-endpoints.ts`
+- Data service: `packages/data-provider/src/data-service.ts`
+- Types: `packages/data-provider/src/types/queries.ts`
+- Use `encodeURIComponent` for dynamic URL parameters.
+
+### Performance
+
+- Prioritize memory and speed efficiency at scale.
+- Cursor pagination for large datasets.
+- Proper dependency arrays to avoid unnecessary re-renders.
+- Leverage React Query caching and background refetching.
+
+---
+
+## Development Commands
+
+| Command | Purpose |
+|---|---|
+| `npm run smart-reinstall` | Install deps (if lockfile changed) + build via Turborepo |
+| `npm run reinstall` | Clean install — wipe `node_modules` and reinstall from scratch |
+| `npm run backend` | Start the backend server |
+| `npm run backend:dev` | Start backend with file watching (development) |
+| `npm run build` | Build all compiled code via Turborepo (parallel, cached) |
+| `npm run frontend` | Build all compiled code sequentially (legacy fallback) |
+| `npm run frontend:dev` | Start frontend dev server with HMR (port 3090, requires backend running) |
+| `npm run build:data-provider` | Rebuild `packages/data-provider` after changes |
+
+- Node.js: v20.19.0+ or ^22.12.0 or >= 23.0.0
+- Database: MongoDB
+- Backend runs on `http://localhost:3080/`; frontend dev server on `http://localhost:3090/`
+
+---
+
+## Testing
+
+- Framework: **Jest**, run per-workspace.
+- Run tests from their workspace directory: `cd api && npx jest `, `cd packages/api && npx jest `, etc.
+- Frontend tests: `__tests__` directories alongside components; use `test/layout-test-utils` for rendering.
+- Cover loading, success, and error states for UI/data flows.
+- Mock data-provider hooks and external dependencies.
+
+---
+
+## Formatting
+
+Fix all formatting lint errors (trailing spaces, tabs, newlines, indentation) using auto-fix when available. All TypeScript/ESLint warnings and errors **must** be resolved.
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 120000
index 0000000000..47dc3e3d86
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1 @@
+AGENTS.md
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 7cda70178b..d45844c4a6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-# v0.8.1
+# v0.8.3-rc1
# Base node image
FROM node:20-alpine AS node
@@ -11,9 +11,12 @@ RUN apk add --no-cache python3 py3-pip uv
ENV LD_PRELOAD=/usr/lib/libjemalloc.so.2
# Add `uv` for extended MCP support
-COPY --from=ghcr.io/astral-sh/uv:0.6.13 /uv /uvx /bin/
+COPY --from=ghcr.io/astral-sh/uv:0.9.5-python3.12-alpine /usr/local/bin/uv /usr/local/bin/uvx /bin/
RUN uv --version
+# Set configurable max-old-space-size with default
+ARG NODE_MAX_OLD_SPACE_SIZE=6144
+
RUN mkdir -p /app && chown node:node /app
WORKDIR /app
@@ -30,7 +33,7 @@ RUN \
# Allow mounting of these files, which have no default
touch .env ; \
# Create directories for the volumes to inherit the correct permissions
- mkdir -p /app/client/public/images /app/api/logs /app/uploads ; \
+ mkdir -p /app/client/public/images /app/logs /app/uploads ; \
npm config set fetch-retry-maxtimeout 600000 ; \
npm config set fetch-retries 5 ; \
npm config set fetch-retry-mintimeout 15000 ; \
@@ -39,8 +42,8 @@ RUN \
COPY --chown=node:node . .
RUN \
- # React client build
- NODE_OPTIONS="--max-old-space-size=2048" npm run frontend; \
+ # React client build with configurable memory
+ NODE_OPTIONS="--max-old-space-size=${NODE_MAX_OLD_SPACE_SIZE}" npm run frontend; \
npm prune --production; \
npm cache clean --force
diff --git a/Dockerfile.multi b/Dockerfile.multi
index c106b5e5fa..5a610725d5 100644
--- a/Dockerfile.multi
+++ b/Dockerfile.multi
@@ -1,5 +1,8 @@
# Dockerfile.multi
-# v0.8.1
+# v0.8.3-rc1
+
+# Set configurable max-old-space-size with default
+ARG NODE_MAX_OLD_SPACE_SIZE=6144
# Base for all builds
FROM node:20-alpine AS base-min
@@ -7,6 +10,7 @@ FROM node:20-alpine AS base-min
RUN apk add --no-cache jemalloc
# Set environment variable to use jemalloc
ENV LD_PRELOAD=/usr/lib/libjemalloc.so.2
+
WORKDIR /app
RUN apk --no-cache add curl
RUN npm config set fetch-retry-maxtimeout 600000 && \
@@ -59,7 +63,8 @@ COPY client ./
COPY --from=data-provider-build /app/packages/data-provider/dist /app/packages/data-provider/dist
COPY --from=client-package-build /app/packages/client/dist /app/packages/client/dist
COPY --from=client-package-build /app/packages/client/src /app/packages/client/src
-ENV NODE_OPTIONS="--max-old-space-size=2048"
+ARG NODE_MAX_OLD_SPACE_SIZE
+ENV NODE_OPTIONS="--max-old-space-size=${NODE_MAX_OLD_SPACE_SIZE}"
RUN npm run build
# API setup (including client dist)
@@ -79,4 +84,4 @@ COPY --from=client-build /app/client/dist ./client/dist
WORKDIR /app/api
EXPOSE 3080
ENV HOST=0.0.0.0
-CMD ["node", "server/index.js"]
\ No newline at end of file
+CMD ["node", "server/index.js"]
diff --git a/README.md b/README.md
index a96e47f70f..e82b3ebc2c 100644
--- a/README.md
+++ b/README.md
@@ -27,8 +27,8 @@
-
-
+
+
@@ -109,6 +109,11 @@
- 🎨 **Customizable Interface**:
- Customizable Dropdown & Interface that adapts to both power users and newcomers
+- 🌊 **[Resumable Streams](https://www.librechat.ai/docs/features/resumable_streams)**:
+ - Never lose a response: AI responses automatically reconnect and resume if your connection drops
+ - Multi-Tab & Multi-Device Sync: Open the same chat in multiple tabs or pick up on another device
+ - Production-Ready: Works from single-server setups to horizontally scaled deployments with Redis
+
- 🗣️ **Speech & Audio**:
- Chat hands-free with Speech-to-Text and Text-to-Speech
- Automatically send and play Audio
@@ -137,13 +142,11 @@
## 🪶 All-In-One AI Conversations with LibreChat
-LibreChat brings together the future of assistant AIs with the revolutionary technology of OpenAI's ChatGPT. Celebrating the original styling, LibreChat gives you the ability to integrate multiple AI models. It also integrates and enhances original client features such as conversation and message search, prompt templates and plugins.
+LibreChat is a self-hosted AI chat platform that unifies all major AI providers in a single, privacy-focused interface.
-With LibreChat, you no longer need to opt for ChatGPT Plus and can instead use free or pay-per-call APIs. We welcome contributions, cloning, and forking to enhance the capabilities of this advanced chatbot platform.
+Beyond chat, LibreChat provides AI Agents, Model Context Protocol (MCP) support, Artifacts, Code Interpreter, custom actions, conversation search, and enterprise-ready multi-user authentication.
-[](https://www.youtube.com/watch?v=ilfwGQtJNlI)
-
-Click on the thumbnail to open the video☝️
+Open source, actively developed, and built for anyone who values control over their AI infrastructure.
---
diff --git a/api/app/clients/AnthropicClient.js b/api/app/clients/AnthropicClient.js
deleted file mode 100644
index 16a79278f1..0000000000
--- a/api/app/clients/AnthropicClient.js
+++ /dev/null
@@ -1,991 +0,0 @@
-const Anthropic = require('@anthropic-ai/sdk');
-const { logger } = require('@librechat/data-schemas');
-const { HttpsProxyAgent } = require('https-proxy-agent');
-const {
- Constants,
- ErrorTypes,
- EModelEndpoint,
- parseTextParts,
- anthropicSettings,
- getResponseSender,
- validateVisionModel,
-} = require('librechat-data-provider');
-const { sleep, SplitStreamHandler: _Handler, addCacheControl } = require('@librechat/agents');
-const {
- Tokenizer,
- createFetch,
- matchModelName,
- getClaudeHeaders,
- getModelMaxTokens,
- configureReasoning,
- checkPromptCacheSupport,
- getModelMaxOutputTokens,
- createStreamEventHandlers,
-} = require('@librechat/api');
-const {
- truncateText,
- formatMessage,
- titleFunctionPrompt,
- parseParamFromPrompt,
- createContextHandlers,
-} = require('./prompts');
-const { spendTokens, spendStructuredTokens } = require('~/models/spendTokens');
-const { encodeAndFormat } = require('~/server/services/Files/images/encode');
-const BaseClient = require('./BaseClient');
-
-const HUMAN_PROMPT = '\n\nHuman:';
-const AI_PROMPT = '\n\nAssistant:';
-
-class SplitStreamHandler extends _Handler {
- getDeltaContent(chunk) {
- return (chunk?.delta?.text ?? chunk?.completion) || '';
- }
- getReasoningDelta(chunk) {
- return chunk?.delta?.thinking || '';
- }
-}
-
-/** Helper function to introduce a delay before retrying */
-function delayBeforeRetry(attempts, baseDelay = 1000) {
- return new Promise((resolve) => setTimeout(resolve, baseDelay * attempts));
-}
-
-const tokenEventTypes = new Set(['message_start', 'message_delta']);
-const { legacy } = anthropicSettings;
-
-class AnthropicClient extends BaseClient {
- constructor(apiKey, options = {}) {
- super(apiKey, options);
- this.apiKey = apiKey || process.env.ANTHROPIC_API_KEY;
- this.userLabel = HUMAN_PROMPT;
- this.assistantLabel = AI_PROMPT;
- this.contextStrategy = options.contextStrategy
- ? options.contextStrategy.toLowerCase()
- : 'discard';
- this.setOptions(options);
- /** @type {string | undefined} */
- this.systemMessage;
- /** @type {AnthropicMessageStartEvent| undefined} */
- this.message_start;
- /** @type {AnthropicMessageDeltaEvent| undefined} */
- this.message_delta;
- /** Whether the model is part of the Claude 3 Family
- * @type {boolean} */
- this.isClaudeLatest;
- /** Whether to use Messages API or Completions API
- * @type {boolean} */
- this.useMessages;
- /** Whether or not the model supports Prompt Caching
- * @type {boolean} */
- this.supportsCacheControl;
- /** The key for the usage object's input tokens
- * @type {string} */
- this.inputTokensKey = 'input_tokens';
- /** The key for the usage object's output tokens
- * @type {string} */
- this.outputTokensKey = 'output_tokens';
- /** @type {SplitStreamHandler | undefined} */
- this.streamHandler;
- }
-
- setOptions(options) {
- if (this.options && !this.options.replaceOptions) {
- // nested options aren't spread properly, so we need to do this manually
- this.options.modelOptions = {
- ...this.options.modelOptions,
- ...options.modelOptions,
- };
- delete options.modelOptions;
- // now we can merge options
- this.options = {
- ...this.options,
- ...options,
- };
- } else {
- this.options = options;
- }
-
- this.modelOptions = Object.assign(
- {
- model: anthropicSettings.model.default,
- },
- this.modelOptions,
- this.options.modelOptions,
- );
-
- const modelMatch = matchModelName(this.modelOptions.model, EModelEndpoint.anthropic);
- this.isClaudeLatest =
- /claude-[3-9]/.test(modelMatch) || /claude-(?:sonnet|opus|haiku)-[4-9]/.test(modelMatch);
- const isLegacyOutput = !(
- /claude-3[-.]5-sonnet/.test(modelMatch) ||
- /claude-3[-.]7/.test(modelMatch) ||
- /claude-(?:sonnet|opus|haiku)-[4-9]/.test(modelMatch) ||
- /claude-[4-9]/.test(modelMatch)
- );
- this.supportsCacheControl = this.options.promptCache && checkPromptCacheSupport(modelMatch);
-
- if (
- isLegacyOutput &&
- this.modelOptions.maxOutputTokens &&
- this.modelOptions.maxOutputTokens > legacy.maxOutputTokens.default
- ) {
- this.modelOptions.maxOutputTokens = legacy.maxOutputTokens.default;
- }
-
- this.useMessages = this.isClaudeLatest || !!this.options.attachments;
-
- this.defaultVisionModel = this.options.visionModel ?? 'claude-3-sonnet-20240229';
- this.options.attachments?.then((attachments) => this.checkVisionRequest(attachments));
-
- this.maxContextTokens =
- this.options.maxContextTokens ??
- getModelMaxTokens(this.modelOptions.model, EModelEndpoint.anthropic) ??
- 100000;
- this.maxResponseTokens =
- this.modelOptions.maxOutputTokens ??
- getModelMaxOutputTokens(
- this.modelOptions.model,
- this.options.endpointType ?? this.options.endpoint,
- this.options.endpointTokenConfig,
- ) ??
- anthropicSettings.maxOutputTokens.reset(this.modelOptions.model);
- this.maxPromptTokens =
- this.options.maxPromptTokens || this.maxContextTokens - this.maxResponseTokens;
-
- const reservedTokens = this.maxPromptTokens + this.maxResponseTokens;
- if (reservedTokens > this.maxContextTokens) {
- const info = `Total Possible Tokens + Max Output Tokens must be less than or equal to Max Context Tokens: ${this.maxPromptTokens} (total possible output) + ${this.maxResponseTokens} (max output) = ${reservedTokens}/${this.maxContextTokens} (max context)`;
- const errorMessage = `{ "type": "${ErrorTypes.INPUT_LENGTH}", "info": "${info}" }`;
- logger.warn(info);
- throw new Error(errorMessage);
- } else if (this.maxResponseTokens === this.maxContextTokens) {
- const info = `Max Output Tokens must be less than Max Context Tokens: ${this.maxResponseTokens} (max output) = ${this.maxContextTokens} (max context)`;
- const errorMessage = `{ "type": "${ErrorTypes.INPUT_LENGTH}", "info": "${info}" }`;
- logger.warn(info);
- throw new Error(errorMessage);
- }
-
- this.sender =
- this.options.sender ??
- getResponseSender({
- model: this.modelOptions.model,
- endpoint: EModelEndpoint.anthropic,
- modelLabel: this.options.modelLabel,
- });
-
- this.startToken = '||>';
- this.endToken = '';
-
- return this;
- }
-
- /**
- * Get the initialized Anthropic client.
- * @param {Partial} requestOptions - The options for the client.
- * @returns {Anthropic} The Anthropic client instance.
- */
- getClient(requestOptions) {
- /** @type {Anthropic.ClientOptions} */
- const options = {
- fetch: createFetch({
- directEndpoint: this.options.directEndpoint,
- reverseProxyUrl: this.options.reverseProxyUrl,
- }),
- apiKey: this.apiKey,
- fetchOptions: {},
- };
-
- if (this.options.proxy) {
- options.fetchOptions.agent = new HttpsProxyAgent(this.options.proxy);
- }
-
- if (this.options.reverseProxyUrl) {
- options.baseURL = this.options.reverseProxyUrl;
- }
-
- const headers = getClaudeHeaders(requestOptions?.model, this.supportsCacheControl);
- if (headers) {
- options.defaultHeaders = headers;
- }
-
- return new Anthropic(options);
- }
-
- /**
- * Get stream usage as returned by this client's API response.
- * @returns {AnthropicStreamUsage} The stream usage object.
- */
- getStreamUsage() {
- const inputUsage = this.message_start?.message?.usage ?? {};
- const outputUsage = this.message_delta?.usage ?? {};
- return Object.assign({}, inputUsage, outputUsage);
- }
-
- /**
- * Calculates the correct token count for the current user message based on the token count map and API usage.
- * Edge case: If the calculation results in a negative value, it returns the original estimate.
- * If revisiting a conversation with a chat history entirely composed of token estimates,
- * the cumulative token count going forward should become more accurate as the conversation progresses.
- * @param {Object} params - The parameters for the calculation.
- * @param {Record} params.tokenCountMap - A map of message IDs to their token counts.
- * @param {string} params.currentMessageId - The ID of the current message to calculate.
- * @param {AnthropicStreamUsage} params.usage - The usage object returned by the API.
- * @returns {number} The correct token count for the current user message.
- */
- calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage }) {
- const originalEstimate = tokenCountMap[currentMessageId] || 0;
-
- if (!usage || typeof usage.input_tokens !== 'number') {
- return originalEstimate;
- }
-
- tokenCountMap[currentMessageId] = 0;
- const totalTokensFromMap = Object.values(tokenCountMap).reduce((sum, count) => {
- const numCount = Number(count);
- return sum + (isNaN(numCount) ? 0 : numCount);
- }, 0);
- const totalInputTokens =
- (usage.input_tokens ?? 0) +
- (usage.cache_creation_input_tokens ?? 0) +
- (usage.cache_read_input_tokens ?? 0);
-
- const currentMessageTokens = totalInputTokens - totalTokensFromMap;
- return currentMessageTokens > 0 ? currentMessageTokens : originalEstimate;
- }
-
- /**
- * Get Token Count for LibreChat Message
- * @param {TMessage} responseMessage
- * @returns {number}
- */
- getTokenCountForResponse(responseMessage) {
- return this.getTokenCountForMessage({
- role: 'assistant',
- content: responseMessage.text,
- });
- }
-
- /**
- *
- * Checks if the model is a vision model based on request attachments and sets the appropriate options:
- * - Sets `this.modelOptions.model` to `gpt-4-vision-preview` if the request is a vision request.
- * - Sets `this.isVisionModel` to `true` if vision request.
- * - Deletes `this.modelOptions.stop` if vision request.
- * @param {MongoFile[]} attachments
- */
- checkVisionRequest(attachments) {
- const availableModels = this.options.modelsConfig?.[EModelEndpoint.anthropic];
- this.isVisionModel = validateVisionModel({ model: this.modelOptions.model, availableModels });
-
- const visionModelAvailable = availableModels?.includes(this.defaultVisionModel);
- if (
- attachments &&
- attachments.some((file) => file?.type && file?.type?.includes('image')) &&
- visionModelAvailable &&
- !this.isVisionModel
- ) {
- this.modelOptions.model = this.defaultVisionModel;
- this.isVisionModel = true;
- }
- }
-
- /**
- * Calculate the token cost in tokens for an image based on its dimensions and detail level.
- *
- * For reference, see: https://docs.anthropic.com/claude/docs/vision#image-costs
- *
- * @param {Object} image - The image object.
- * @param {number} image.width - The width of the image.
- * @param {number} image.height - The height of the image.
- * @returns {number} The calculated token cost measured by tokens.
- *
- */
- calculateImageTokenCost({ width, height }) {
- return Math.ceil((width * height) / 750);
- }
-
- async addImageURLs(message, attachments) {
- const { files, image_urls } = await encodeAndFormat(this.options.req, attachments, {
- endpoint: EModelEndpoint.anthropic,
- });
- message.image_urls = image_urls.length ? image_urls : undefined;
- return files;
- }
-
- /**
- * @param {object} params
- * @param {number} params.promptTokens
- * @param {number} params.completionTokens
- * @param {AnthropicStreamUsage} [params.usage]
- * @param {string} [params.model]
- * @param {string} [params.context='message']
- * @returns {Promise}
- */
- async recordTokenUsage({ promptTokens, completionTokens, usage, model, context = 'message' }) {
- if (usage != null && usage?.input_tokens != null) {
- const input = usage.input_tokens ?? 0;
- const write = usage.cache_creation_input_tokens ?? 0;
- const read = usage.cache_read_input_tokens ?? 0;
-
- await spendStructuredTokens(
- {
- context,
- user: this.user,
- conversationId: this.conversationId,
- model: model ?? this.modelOptions.model,
- endpointTokenConfig: this.options.endpointTokenConfig,
- },
- {
- promptTokens: { input, write, read },
- completionTokens,
- },
- );
-
- return;
- }
-
- await spendTokens(
- {
- context,
- user: this.user,
- conversationId: this.conversationId,
- model: model ?? this.modelOptions.model,
- endpointTokenConfig: this.options.endpointTokenConfig,
- },
- { promptTokens, completionTokens },
- );
- }
-
- async buildMessages(messages, parentMessageId) {
- const orderedMessages = this.constructor.getMessagesForConversation({
- messages,
- parentMessageId,
- });
-
- logger.debug('[AnthropicClient] orderedMessages', { orderedMessages, parentMessageId });
-
- if (this.options.attachments) {
- const attachments = await this.options.attachments;
- const images = attachments.filter((file) => file.type.includes('image'));
-
- if (images.length && !this.isVisionModel) {
- throw new Error('Images are only supported with the Claude 3 family of models');
- }
-
- const latestMessage = orderedMessages[orderedMessages.length - 1];
-
- if (this.message_file_map) {
- this.message_file_map[latestMessage.messageId] = attachments;
- } else {
- this.message_file_map = {
- [latestMessage.messageId]: attachments,
- };
- }
-
- const files = await this.addImageURLs(latestMessage, attachments);
-
- this.options.attachments = files;
- }
-
- if (this.message_file_map) {
- this.contextHandlers = createContextHandlers(
- this.options.req,
- orderedMessages[orderedMessages.length - 1].text,
- );
- }
-
- const formattedMessages = orderedMessages.map((message, i) => {
- const formattedMessage = this.useMessages
- ? formatMessage({
- message,
- endpoint: EModelEndpoint.anthropic,
- })
- : {
- author: message.isCreatedByUser ? this.userLabel : this.assistantLabel,
- content: message?.content ?? message.text,
- };
-
- const needsTokenCount = this.contextStrategy && !orderedMessages[i].tokenCount;
- /* If tokens were never counted, or, is a Vision request and the message has files, count again */
- if (needsTokenCount || (this.isVisionModel && (message.image_urls || message.files))) {
- orderedMessages[i].tokenCount = this.getTokenCountForMessage(formattedMessage);
- }
-
- /* If message has files, calculate image token cost */
- if (this.message_file_map && this.message_file_map[message.messageId]) {
- const attachments = this.message_file_map[message.messageId];
- for (const file of attachments) {
- if (file.embedded) {
- this.contextHandlers?.processFile(file);
- continue;
- }
- if (file.metadata?.fileIdentifier) {
- continue;
- }
-
- orderedMessages[i].tokenCount += this.calculateImageTokenCost({
- width: file.width,
- height: file.height,
- });
- }
- }
-
- formattedMessage.tokenCount = orderedMessages[i].tokenCount;
- return formattedMessage;
- });
-
- if (this.contextHandlers) {
- this.augmentedPrompt = await this.contextHandlers.createContext();
- this.options.promptPrefix = this.augmentedPrompt + (this.options.promptPrefix ?? '');
- }
-
- let { context: messagesInWindow, remainingContextTokens } =
- await this.getMessagesWithinTokenLimit({ messages: formattedMessages });
-
- const tokenCountMap = orderedMessages
- .slice(orderedMessages.length - messagesInWindow.length)
- .reduce((map, message, index) => {
- const { messageId } = message;
- if (!messageId) {
- return map;
- }
-
- map[messageId] = orderedMessages[index].tokenCount;
- return map;
- }, {});
-
- logger.debug('[AnthropicClient]', {
- messagesInWindow: messagesInWindow.length,
- remainingContextTokens,
- });
-
- let lastAuthor = '';
- let groupedMessages = [];
-
- for (let i = 0; i < messagesInWindow.length; i++) {
- const message = messagesInWindow[i];
- const author = message.role ?? message.author;
- // If last author is not same as current author, add to new group
- if (lastAuthor !== author) {
- const newMessage = {
- content: [message.content],
- };
-
- if (message.role) {
- newMessage.role = message.role;
- } else {
- newMessage.author = message.author;
- }
-
- groupedMessages.push(newMessage);
- lastAuthor = author;
- // If same author, append content to the last group
- } else {
- groupedMessages[groupedMessages.length - 1].content.push(message.content);
- }
- }
-
- groupedMessages = groupedMessages.map((msg, i) => {
- const isLast = i === groupedMessages.length - 1;
- if (msg.content.length === 1) {
- const content = msg.content[0];
- return {
- ...msg,
- // reason: final assistant content cannot end with trailing whitespace
- content:
- isLast && this.useMessages && msg.role === 'assistant' && typeof content === 'string'
- ? content?.trim()
- : content,
- };
- }
-
- if (!this.useMessages && msg.tokenCount) {
- delete msg.tokenCount;
- }
-
- return msg;
- });
-
- let identityPrefix = '';
- if (this.options.userLabel) {
- identityPrefix = `\nHuman's name: ${this.options.userLabel}`;
- }
-
- if (this.options.modelLabel) {
- identityPrefix = `${identityPrefix}\nYou are ${this.options.modelLabel}`;
- }
-
- let promptPrefix = (this.options.promptPrefix ?? '').trim();
- if (typeof this.options.artifactsPrompt === 'string' && this.options.artifactsPrompt) {
- promptPrefix = `${promptPrefix ?? ''}\n${this.options.artifactsPrompt}`.trim();
- }
- if (promptPrefix) {
- // If the prompt prefix doesn't end with the end token, add it.
- if (!promptPrefix.endsWith(`${this.endToken}`)) {
- promptPrefix = `${promptPrefix.trim()}${this.endToken}\n\n`;
- }
- promptPrefix = `\nContext:\n${promptPrefix}`;
- }
-
- if (identityPrefix) {
- promptPrefix = `${identityPrefix}${promptPrefix}`;
- }
-
- // Prompt AI to respond, empty if last message was from AI
- let isEdited = lastAuthor === this.assistantLabel;
- const promptSuffix = isEdited ? '' : `${promptPrefix}${this.assistantLabel}\n`;
- let currentTokenCount =
- isEdited || this.useMessages
- ? this.getTokenCount(promptPrefix)
- : this.getTokenCount(promptSuffix);
-
- let promptBody = '';
- const maxTokenCount = this.maxPromptTokens;
-
- const context = [];
-
- // Iterate backwards through the messages, adding them to the prompt until we reach the max token count.
- // Do this within a recursive async function so that it doesn't block the event loop for too long.
- // Also, remove the next message when the message that puts us over the token limit is created by the user.
- // Otherwise, remove only the exceeding message. This is due to Anthropic's strict payload rule to start with "Human:".
- const nextMessage = {
- remove: false,
- tokenCount: 0,
- messageString: '',
- };
-
- const buildPromptBody = async () => {
- if (currentTokenCount < maxTokenCount && groupedMessages.length > 0) {
- const message = groupedMessages.pop();
- const isCreatedByUser = message.author === this.userLabel;
- // Use promptPrefix if message is edited assistant'
- const messagePrefix =
- isCreatedByUser || !isEdited ? message.author : `${promptPrefix}${message.author}`;
- const messageString = `${messagePrefix}\n${message.content}${this.endToken}\n`;
- let newPromptBody = `${messageString}${promptBody}`;
-
- context.unshift(message);
-
- const tokenCountForMessage = this.getTokenCount(messageString);
- const newTokenCount = currentTokenCount + tokenCountForMessage;
-
- if (!isCreatedByUser) {
- nextMessage.messageString = messageString;
- nextMessage.tokenCount = tokenCountForMessage;
- }
-
- if (newTokenCount > maxTokenCount) {
- if (!promptBody) {
- // This is the first message, so we can't add it. Just throw an error.
- throw new Error(
- `Prompt is too long. Max token count is ${maxTokenCount}, but prompt is ${newTokenCount} tokens long.`,
- );
- }
-
- // Otherwise, ths message would put us over the token limit, so don't add it.
- // if created by user, remove next message, otherwise remove only this message
- if (isCreatedByUser) {
- nextMessage.remove = true;
- }
-
- return false;
- }
- promptBody = newPromptBody;
- currentTokenCount = newTokenCount;
-
- // Switch off isEdited after using it for the first time
- if (isEdited) {
- isEdited = false;
- }
-
- // wait for next tick to avoid blocking the event loop
- await new Promise((resolve) => setImmediate(resolve));
- return buildPromptBody();
- }
- return true;
- };
-
- const messagesPayload = [];
- const buildMessagesPayload = async () => {
- let canContinue = true;
-
- if (promptPrefix) {
- this.systemMessage = promptPrefix;
- }
-
- while (currentTokenCount < maxTokenCount && groupedMessages.length > 0 && canContinue) {
- const message = groupedMessages.pop();
-
- let tokenCountForMessage = message.tokenCount ?? this.getTokenCountForMessage(message);
-
- const newTokenCount = currentTokenCount + tokenCountForMessage;
- const exceededMaxCount = newTokenCount > maxTokenCount;
-
- if (exceededMaxCount && messagesPayload.length === 0) {
- throw new Error(
- `Prompt is too long. Max token count is ${maxTokenCount}, but prompt is ${newTokenCount} tokens long.`,
- );
- } else if (exceededMaxCount) {
- canContinue = false;
- break;
- }
-
- delete message.tokenCount;
- messagesPayload.unshift(message);
- currentTokenCount = newTokenCount;
-
- // Switch off isEdited after using it once
- if (isEdited && message.role === 'assistant') {
- isEdited = false;
- }
-
- // Wait for next tick to avoid blocking the event loop
- await new Promise((resolve) => setImmediate(resolve));
- }
- };
-
- const processTokens = () => {
- // Add 2 tokens for metadata after all messages have been counted.
- currentTokenCount += 2;
-
- // Use up to `this.maxContextTokens` tokens (prompt + response), but try to leave `this.maxTokens` tokens for the response.
- this.modelOptions.maxOutputTokens = Math.min(
- this.maxContextTokens - currentTokenCount,
- this.maxResponseTokens,
- );
- };
-
- if (
- /claude-[3-9]/.test(this.modelOptions.model) ||
- /claude-(?:sonnet|opus|haiku)-[4-9]/.test(this.modelOptions.model)
- ) {
- await buildMessagesPayload();
- processTokens();
- return {
- prompt: messagesPayload,
- context: messagesInWindow,
- promptTokens: currentTokenCount,
- tokenCountMap,
- };
- } else {
- await buildPromptBody();
- processTokens();
- }
-
- if (nextMessage.remove) {
- promptBody = promptBody.replace(nextMessage.messageString, '');
- currentTokenCount -= nextMessage.tokenCount;
- context.shift();
- }
-
- let prompt = `${promptBody}${promptSuffix}`;
-
- return { prompt, context, promptTokens: currentTokenCount, tokenCountMap };
- }
-
- getCompletion() {
- logger.debug("AnthropicClient doesn't use getCompletion (all handled in sendCompletion)");
- }
-
- /**
- * Creates a message or completion response using the Anthropic client.
- * @param {Anthropic} client - The Anthropic client instance.
- * @param {Anthropic.default.MessageCreateParams | Anthropic.default.CompletionCreateParams} options - The options for the message or completion.
- * @param {boolean} useMessages - Whether to use messages or completions. Defaults to `this.useMessages`.
- * @returns {Promise} The response from the Anthropic client.
- */
- async createResponse(client, options, useMessages) {
- return (useMessages ?? this.useMessages)
- ? await client.messages.create(options)
- : await client.completions.create(options);
- }
-
- getMessageMapMethod() {
- /**
- * @param {TMessage} msg
- */
- return (msg) => {
- if (msg.text != null && msg.text && msg.text.startsWith(':::thinking')) {
- msg.text = msg.text.replace(/:::thinking.*?:::/gs, '').trim();
- } else if (msg.content != null) {
- msg.text = parseTextParts(msg.content, true);
- delete msg.content;
- }
-
- return msg;
- };
- }
-
- /**
- * @param {string[]} [intermediateReply]
- * @returns {string}
- */
- getStreamText(intermediateReply) {
- if (!this.streamHandler) {
- return intermediateReply?.join('') ?? '';
- }
-
- const reasoningText = this.streamHandler.reasoningTokens.join('');
-
- const reasoningBlock = reasoningText.length > 0 ? `:::thinking\n${reasoningText}\n:::\n` : '';
-
- return `${reasoningBlock}${this.streamHandler.tokens.join('')}`;
- }
-
- async sendCompletion(payload, { onProgress, abortController }) {
- if (!abortController) {
- abortController = new AbortController();
- }
-
- const { signal } = abortController;
-
- const modelOptions = { ...this.modelOptions };
- if (typeof onProgress === 'function') {
- modelOptions.stream = true;
- }
-
- logger.debug('modelOptions', { modelOptions });
- const metadata = {
- user_id: this.user,
- };
-
- const {
- stream,
- model,
- temperature,
- maxOutputTokens,
- stop: stop_sequences,
- topP: top_p,
- topK: top_k,
- } = this.modelOptions;
-
- let requestOptions = {
- model,
- stream: stream || true,
- stop_sequences,
- temperature,
- metadata,
- };
-
- if (this.useMessages) {
- requestOptions.messages = payload;
- requestOptions.max_tokens =
- maxOutputTokens || anthropicSettings.maxOutputTokens.reset(requestOptions.model);
- } else {
- requestOptions.prompt = payload;
- requestOptions.max_tokens_to_sample = maxOutputTokens || legacy.maxOutputTokens.default;
- }
-
- requestOptions = configureReasoning(requestOptions, {
- thinking: this.options.thinking,
- thinkingBudget: this.options.thinkingBudget,
- });
-
- if (!/claude-3[-.]7/.test(model)) {
- requestOptions.top_p = top_p;
- requestOptions.top_k = top_k;
- } else if (requestOptions.thinking == null) {
- requestOptions.topP = top_p;
- requestOptions.topK = top_k;
- }
-
- if (this.systemMessage && this.supportsCacheControl === true) {
- requestOptions.system = [
- {
- type: 'text',
- text: this.systemMessage,
- cache_control: { type: 'ephemeral' },
- },
- ];
- } else if (this.systemMessage) {
- requestOptions.system = this.systemMessage;
- }
-
- if (this.supportsCacheControl === true && this.useMessages) {
- requestOptions.messages = addCacheControl(requestOptions.messages);
- }
-
- logger.debug('[AnthropicClient]', { ...requestOptions });
- const handlers = createStreamEventHandlers(this.options.res);
- this.streamHandler = new SplitStreamHandler({
- accumulate: true,
- runId: this.responseMessageId,
- handlers,
- });
-
- let intermediateReply = this.streamHandler.tokens;
-
- const maxRetries = 3;
- const streamRate = this.options.streamRate ?? Constants.DEFAULT_STREAM_RATE;
- async function processResponse() {
- let attempts = 0;
-
- while (attempts < maxRetries) {
- let response;
- try {
- const client = this.getClient(requestOptions);
- response = await this.createResponse(client, requestOptions);
-
- signal.addEventListener('abort', () => {
- logger.debug('[AnthropicClient] message aborted!');
- if (response.controller?.abort) {
- response.controller.abort();
- }
- });
-
- for await (const completion of response) {
- const type = completion?.type ?? '';
- if (tokenEventTypes.has(type)) {
- logger.debug(`[AnthropicClient] ${type}`, completion);
- this[type] = completion;
- }
- this.streamHandler.handle(completion);
- await sleep(streamRate);
- }
-
- break;
- } catch (error) {
- attempts += 1;
- logger.warn(
- `User: ${this.user} | Anthropic Request ${attempts} failed: ${error.message}`,
- );
-
- if (attempts < maxRetries) {
- await delayBeforeRetry(attempts, 350);
- } else if (this.streamHandler && this.streamHandler.reasoningTokens.length) {
- return this.getStreamText();
- } else if (intermediateReply.length > 0) {
- return this.getStreamText(intermediateReply);
- } else {
- throw new Error(`Operation failed after ${maxRetries} attempts: ${error.message}`);
- }
- } finally {
- signal.removeEventListener('abort', () => {
- logger.debug('[AnthropicClient] message aborted!');
- if (response.controller?.abort) {
- response.controller.abort();
- }
- });
- }
- }
- }
-
- await processResponse.bind(this)();
- return this.getStreamText(intermediateReply);
- }
-
- getSaveOptions() {
- return {
- maxContextTokens: this.options.maxContextTokens,
- artifacts: this.options.artifacts,
- promptPrefix: this.options.promptPrefix,
- modelLabel: this.options.modelLabel,
- promptCache: this.options.promptCache,
- thinking: this.options.thinking,
- thinkingBudget: this.options.thinkingBudget,
- resendFiles: this.options.resendFiles,
- iconURL: this.options.iconURL,
- greeting: this.options.greeting,
- spec: this.options.spec,
- ...this.modelOptions,
- };
- }
-
- getBuildMessagesOptions() {
- logger.debug("AnthropicClient doesn't use getBuildMessagesOptions");
- }
-
- getEncoding() {
- return 'cl100k_base';
- }
-
- /**
- * Returns the token count of a given text. It also checks and resets the tokenizers if necessary.
- * @param {string} text - The text to get the token count for.
- * @returns {number} The token count of the given text.
- */
- getTokenCount(text) {
- const encoding = this.getEncoding();
- return Tokenizer.getTokenCount(text, encoding);
- }
-
- /**
- * Generates a concise title for a conversation based on the user's input text and response.
- * Involves sending a chat completion request with specific instructions for title generation.
- *
- * This function capitlizes on [Anthropic's function calling training](https://docs.anthropic.com/claude/docs/functions-external-tools).
- *
- * @param {Object} params - The parameters for the conversation title generation.
- * @param {string} params.text - The user's input.
- * @param {string} [params.responseText=''] - The AI's immediate response to the user.
- *
- * @returns {Promise} A promise that resolves to the generated conversation title.
- * In case of failure, it will return the default title, "New Chat".
- */
- async titleConvo({ text, responseText = '' }) {
- let title = 'New Chat';
- this.message_delta = undefined;
- this.message_start = undefined;
- const convo = `
- ${truncateText(text)}
-
-
- ${JSON.stringify(truncateText(responseText))}
- `;
-
- const { ANTHROPIC_TITLE_MODEL } = process.env ?? {};
- const model = this.options.titleModel ?? ANTHROPIC_TITLE_MODEL ?? 'claude-3-haiku-20240307';
- const system = titleFunctionPrompt;
-
- const titleChatCompletion = async () => {
- const content = `
- ${convo}
-
-
- Please generate a title for this conversation.`;
-
- const titleMessage = { role: 'user', content };
- const requestOptions = {
- model,
- temperature: 0.3,
- max_tokens: 1024,
- system,
- stop_sequences: ['\n\nHuman:', '\n\nAssistant', ''],
- messages: [titleMessage],
- };
-
- try {
- const response = await this.createResponse(
- this.getClient(requestOptions),
- requestOptions,
- true,
- );
- let promptTokens = response?.usage?.input_tokens;
- let completionTokens = response?.usage?.output_tokens;
- if (!promptTokens) {
- promptTokens = this.getTokenCountForMessage(titleMessage);
- promptTokens += this.getTokenCountForMessage({ role: 'system', content: system });
- }
- if (!completionTokens) {
- completionTokens = this.getTokenCountForMessage(response.content[0]);
- }
- await this.recordTokenUsage({
- model,
- promptTokens,
- completionTokens,
- context: 'title',
- });
- const text = response.content[0].text;
- title = parseParamFromPrompt(text, 'title');
- } catch (e) {
- logger.error('[AnthropicClient] There was an issue generating the title', e);
- }
- };
-
- await titleChatCompletion();
- logger.debug('[AnthropicClient] Convo Title: ' + title);
- return title;
- }
-}
-
-module.exports = AnthropicClient;
diff --git a/api/app/clients/BaseClient.js b/api/app/clients/BaseClient.js
index f4a69be229..e5771aac55 100644
--- a/api/app/clients/BaseClient.js
+++ b/api/app/clients/BaseClient.js
@@ -4,6 +4,7 @@ const { logger } = require('@librechat/data-schemas');
const {
countTokens,
getBalanceConfig,
+ buildMessageFiles,
extractFileContext,
encodeAndFormatAudios,
encodeAndFormatVideos,
@@ -18,13 +19,21 @@ const {
EModelEndpoint,
isParamEndpoint,
isAgentsEndpoint,
+ isEphemeralAgentId,
supportsBalanceCheck,
+ isBedrockDocumentType,
} = require('librechat-data-provider');
-const { getMessages, saveMessage, updateMessage, saveConvo, getConvo } = require('~/models');
+const {
+ updateMessage,
+ getMessages,
+ saveMessage,
+ saveConvo,
+ getConvo,
+ getFiles,
+} = require('~/models');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
const { checkBalance } = require('~/models/balanceMethods');
const { truncateToolCallOutputs } = require('./prompts');
-const { getFiles } = require('~/models/File');
const TextStream = require('./TextStream');
class BaseClient {
@@ -662,6 +671,14 @@ class BaseClient {
}
if (!isEdited && !this.skipSaveUserMessage) {
+ const reqFiles = this.options.req?.body?.files;
+ if (reqFiles && Array.isArray(this.options.attachments)) {
+ const files = buildMessageFiles(reqFiles, this.options.attachments);
+ if (files.length > 0) {
+ userMessage.files = files;
+ }
+ delete userMessage.image_urls;
+ }
userMessagePromise = this.saveMessageToDatabase(userMessage, saveOptions, user);
this.savedMessageIds.add(userMessage.messageId);
if (typeof opts?.getReqData === 'function') {
@@ -708,7 +725,7 @@ class BaseClient {
iconURL: this.options.iconURL,
endpoint: this.options.endpoint,
...(this.metadata ?? {}),
- metadata,
+ metadata: Object.keys(metadata ?? {}).length > 0 ? metadata : undefined,
};
if (typeof completion === 'string') {
@@ -931,6 +948,7 @@ class BaseClient {
throw new Error('User mismatch.');
}
+ const hasAddedConvo = this.options?.req?.body?.addedConvo != null;
const savedMessage = await saveMessage(
this.options?.req,
{
@@ -938,6 +956,7 @@ class BaseClient {
endpoint: this.options.endpoint,
unfinished: false,
user,
+ ...(hasAddedConvo && { addedConvo: true }),
},
{ context: 'api/app/clients/BaseClient.js - saveMessageToDatabase #saveMessage' },
);
@@ -960,6 +979,13 @@ class BaseClient {
const unsetFields = {};
const exceptions = new Set(['spec', 'iconURL']);
+ const hasNonEphemeralAgent =
+ isAgentsEndpoint(this.options.endpoint) &&
+ endpointOptions?.agent_id &&
+ !isEphemeralAgentId(endpointOptions.agent_id);
+ if (hasNonEphemeralAgent) {
+ exceptions.add('model');
+ }
if (existingConvo != null) {
this.fetchedConvo = true;
for (const key in existingConvo) {
@@ -1011,7 +1037,8 @@ class BaseClient {
* @param {Object} options - The options for the function.
* @param {TMessage[]} options.messages - An array of message objects. Each object should have either an 'id' or 'messageId' property, and may have a 'parentMessageId' property.
* @param {string} options.parentMessageId - The ID of the parent message to start the traversal from.
- * @param {Function} [options.mapMethod] - An optional function to map over the ordered messages. If provided, it will be applied to each message in the resulting array.
+ * @param {Function} [options.mapMethod] - An optional function to map over the ordered messages. Applied conditionally based on mapCondition.
+ * @param {(message: TMessage) => boolean} [options.mapCondition] - An optional function to determine whether mapMethod should be applied to a given message. If not provided and mapMethod is set, mapMethod applies to all messages.
* @param {boolean} [options.summary=false] - If set to true, the traversal modifies messages with 'summary' and 'summaryTokenCount' properties and stops at the message with a 'summary' property.
* @returns {TMessage[]} An array containing the messages in the order they should be displayed, starting with the most recent message with a 'summary' property if the 'summary' option is true, and ending with the message identified by 'parentMessageId'.
*/
@@ -1019,6 +1046,7 @@ class BaseClient {
messages,
parentMessageId,
mapMethod = null,
+ mapCondition = null,
summary = false,
}) {
if (!messages || messages.length === 0) {
@@ -1053,7 +1081,9 @@ class BaseClient {
message.tokenCount = message.summaryTokenCount;
}
- orderedMessages.push(message);
+ const shouldMap = mapMethod != null && (mapCondition != null ? mapCondition(message) : true);
+ const processedMessage = shouldMap ? mapMethod(message) : message;
+ orderedMessages.push(processedMessage);
if (summary && message.summary) {
break;
@@ -1064,11 +1094,6 @@ class BaseClient {
}
orderedMessages.reverse();
-
- if (mapMethod) {
- return orderedMessages.map(mapMethod);
- }
-
return orderedMessages;
}
@@ -1285,6 +1310,9 @@ class BaseClient {
const allFiles = [];
+ const provider = this.options.agent?.provider ?? this.options.endpoint;
+ const isBedrock = provider === EModelEndpoint.bedrock;
+
for (const file of attachments) {
/** @type {FileSources} */
const source = file.source ?? FileSources.local;
@@ -1302,6 +1330,9 @@ class BaseClient {
} else if (file.type === 'application/pdf') {
categorizedAttachments.documents.push(file);
allFiles.push(file);
+ } else if (isBedrock && isBedrockDocumentType(file.type)) {
+ categorizedAttachments.documents.push(file);
+ allFiles.push(file);
} else if (file.type.startsWith('video/')) {
categorizedAttachments.videos.push(file);
allFiles.push(file);
diff --git a/api/app/clients/GoogleClient.js b/api/app/clients/GoogleClient.js
deleted file mode 100644
index 760889df8c..0000000000
--- a/api/app/clients/GoogleClient.js
+++ /dev/null
@@ -1,994 +0,0 @@
-const { google } = require('googleapis');
-const { sleep } = require('@librechat/agents');
-const { logger } = require('@librechat/data-schemas');
-const { getModelMaxTokens } = require('@librechat/api');
-const { concat } = require('@langchain/core/utils/stream');
-const { ChatVertexAI } = require('@langchain/google-vertexai');
-const { Tokenizer, getSafetySettings } = require('@librechat/api');
-const { ChatGoogleGenerativeAI } = require('@langchain/google-genai');
-const { GoogleGenerativeAI: GenAI } = require('@google/generative-ai');
-const { HumanMessage, SystemMessage } = require('@langchain/core/messages');
-const {
- googleGenConfigSchema,
- validateVisionModel,
- getResponseSender,
- endpointSettings,
- parseTextParts,
- EModelEndpoint,
- googleSettings,
- ContentTypes,
- VisionModes,
- ErrorTypes,
- Constants,
- AuthKeys,
-} = require('librechat-data-provider');
-const { encodeAndFormat } = require('~/server/services/Files/images');
-const { spendTokens } = require('~/models/spendTokens');
-const {
- formatMessage,
- createContextHandlers,
- titleInstruction,
- truncateText,
-} = require('./prompts');
-const BaseClient = require('./BaseClient');
-
-const loc = process.env.GOOGLE_LOC || 'us-central1';
-const publisher = 'google';
-const endpointPrefix =
- loc === 'global' ? 'aiplatform.googleapis.com' : `${loc}-aiplatform.googleapis.com`;
-
-const settings = endpointSettings[EModelEndpoint.google];
-const EXCLUDED_GENAI_MODELS = /gemini-(?:1\.0|1-0|pro)/;
-
-class GoogleClient extends BaseClient {
- constructor(credentials, options = {}) {
- super('apiKey', options);
- let creds = {};
-
- if (typeof credentials === 'string') {
- creds = JSON.parse(credentials);
- } else if (credentials) {
- creds = credentials;
- }
-
- const serviceKey = creds[AuthKeys.GOOGLE_SERVICE_KEY] ?? {};
- this.serviceKey =
- serviceKey && typeof serviceKey === 'string' ? JSON.parse(serviceKey) : (serviceKey ?? {});
- /** @type {string | null | undefined} */
- this.project_id = this.serviceKey.project_id;
- this.client_email = this.serviceKey.client_email;
- this.private_key = this.serviceKey.private_key;
- this.access_token = null;
-
- this.apiKey = creds[AuthKeys.GOOGLE_API_KEY];
-
- this.reverseProxyUrl = options.reverseProxyUrl;
-
- this.authHeader = options.authHeader;
-
- /** @type {UsageMetadata | undefined} */
- this.usage;
- /** The key for the usage object's input tokens
- * @type {string} */
- this.inputTokensKey = 'input_tokens';
- /** The key for the usage object's output tokens
- * @type {string} */
- this.outputTokensKey = 'output_tokens';
- this.visionMode = VisionModes.generative;
- /** @type {string} */
- this.systemMessage;
- if (options.skipSetOptions) {
- return;
- }
- this.setOptions(options);
- }
-
- /* Google specific methods */
- constructUrl() {
- return `https://${endpointPrefix}/v1/projects/${this.project_id}/locations/${loc}/publishers/${publisher}/models/${this.modelOptions.model}:serverStreamingPredict`;
- }
-
- async getClient() {
- const scopes = ['https://www.googleapis.com/auth/cloud-platform'];
- const jwtClient = new google.auth.JWT(this.client_email, null, this.private_key, scopes);
-
- jwtClient.authorize((err) => {
- if (err) {
- logger.error('jwtClient failed to authorize', err);
- throw err;
- }
- });
-
- return jwtClient;
- }
-
- async getAccessToken() {
- const scopes = ['https://www.googleapis.com/auth/cloud-platform'];
- const jwtClient = new google.auth.JWT(this.client_email, null, this.private_key, scopes);
-
- return new Promise((resolve, reject) => {
- jwtClient.authorize((err, tokens) => {
- if (err) {
- logger.error('jwtClient failed to authorize', err);
- reject(err);
- } else {
- resolve(tokens.access_token);
- }
- });
- });
- }
-
- /* Required Client methods */
- setOptions(options) {
- if (this.options && !this.options.replaceOptions) {
- // nested options aren't spread properly, so we need to do this manually
- this.options.modelOptions = {
- ...this.options.modelOptions,
- ...options.modelOptions,
- };
- delete options.modelOptions;
- // now we can merge options
- this.options = {
- ...this.options,
- ...options,
- };
- } else {
- this.options = options;
- }
-
- this.modelOptions = this.options.modelOptions || {};
-
- this.options.attachments?.then((attachments) => this.checkVisionRequest(attachments));
-
- /** @type {boolean} Whether using a "GenerativeAI" Model */
- this.isGenerativeModel = /gemini|learnlm|gemma/.test(this.modelOptions.model);
-
- this.maxContextTokens =
- this.options.maxContextTokens ??
- getModelMaxTokens(this.modelOptions.model, EModelEndpoint.google);
-
- // The max prompt tokens is determined by the max context tokens minus the max response tokens.
- // Earlier messages will be dropped until the prompt is within the limit.
- this.maxResponseTokens = this.modelOptions.maxOutputTokens || settings.maxOutputTokens.default;
-
- if (this.maxContextTokens > 32000) {
- this.maxContextTokens = this.maxContextTokens - this.maxResponseTokens;
- }
-
- this.maxPromptTokens =
- this.options.maxPromptTokens || this.maxContextTokens - this.maxResponseTokens;
-
- if (this.maxPromptTokens + this.maxResponseTokens > this.maxContextTokens) {
- throw new Error(
- `maxPromptTokens + maxOutputTokens (${this.maxPromptTokens} + ${this.maxResponseTokens} = ${
- this.maxPromptTokens + this.maxResponseTokens
- }) must be less than or equal to maxContextTokens (${this.maxContextTokens})`,
- );
- }
-
- // Add thinking configuration
- this.modelOptions.thinkingConfig = {
- thinkingBudget:
- (this.modelOptions.thinking ?? googleSettings.thinking.default)
- ? this.modelOptions.thinkingBudget
- : 0,
- };
- delete this.modelOptions.thinking;
- delete this.modelOptions.thinkingBudget;
-
- this.sender =
- this.options.sender ??
- getResponseSender({
- model: this.modelOptions.model,
- endpoint: EModelEndpoint.google,
- modelLabel: this.options.modelLabel,
- });
-
- this.userLabel = this.options.userLabel || 'User';
- this.modelLabel = this.options.modelLabel || 'Assistant';
-
- if (this.options.reverseProxyUrl) {
- this.completionsUrl = this.options.reverseProxyUrl;
- } else {
- this.completionsUrl = this.constructUrl();
- }
-
- let promptPrefix = (this.options.promptPrefix ?? '').trim();
- if (typeof this.options.artifactsPrompt === 'string' && this.options.artifactsPrompt) {
- promptPrefix = `${promptPrefix ?? ''}\n${this.options.artifactsPrompt}`.trim();
- }
- this.systemMessage = promptPrefix;
- this.initializeClient();
- return this;
- }
-
- /**
- *
- * Checks if the model is a vision model based on request attachments and sets the appropriate options:
- * @param {MongoFile[]} attachments
- */
- checkVisionRequest(attachments) {
- /* Validation vision request */
- this.defaultVisionModel =
- this.options.visionModel ??
- (!EXCLUDED_GENAI_MODELS.test(this.modelOptions.model)
- ? this.modelOptions.model
- : 'gemini-pro-vision');
- const availableModels = this.options.modelsConfig?.[EModelEndpoint.google];
- this.isVisionModel = validateVisionModel({ model: this.modelOptions.model, availableModels });
-
- if (
- attachments &&
- attachments.some((file) => file?.type && file?.type?.includes('image')) &&
- availableModels?.includes(this.defaultVisionModel) &&
- !this.isVisionModel
- ) {
- this.modelOptions.model = this.defaultVisionModel;
- this.isVisionModel = true;
- }
-
- if (this.isVisionModel && !attachments && this.modelOptions.model.includes('gemini-pro')) {
- this.modelOptions.model = 'gemini-pro';
- this.isVisionModel = false;
- }
- }
-
- formatMessages() {
- return ((message) => {
- const msg = {
- author: message?.author ?? (message.isCreatedByUser ? this.userLabel : this.modelLabel),
- content: message?.content ?? message.text,
- };
-
- if (!message.image_urls?.length) {
- return msg;
- }
-
- msg.content = (
- !Array.isArray(msg.content)
- ? [
- {
- type: ContentTypes.TEXT,
- [ContentTypes.TEXT]: msg.content,
- },
- ]
- : msg.content
- ).concat(message.image_urls);
-
- return msg;
- }).bind(this);
- }
-
- /**
- * Formats messages for generative AI
- * @param {TMessage[]} messages
- * @returns
- */
- async formatGenerativeMessages(messages) {
- const formattedMessages = [];
- const attachments = await this.options.attachments;
- const latestMessage = { ...messages[messages.length - 1] };
- const files = await this.addImageURLs(latestMessage, attachments, VisionModes.generative);
- this.options.attachments = files;
- messages[messages.length - 1] = latestMessage;
-
- for (const _message of messages) {
- const role = _message.isCreatedByUser ? this.userLabel : this.modelLabel;
- const parts = [];
- parts.push({ text: _message.text });
- if (!_message.image_urls?.length) {
- formattedMessages.push({ role, parts });
- continue;
- }
-
- for (const images of _message.image_urls) {
- if (images.inlineData) {
- parts.push({ inlineData: images.inlineData });
- }
- }
-
- formattedMessages.push({ role, parts });
- }
-
- return formattedMessages;
- }
-
- /**
- *
- * Adds image URLs to the message object and returns the files
- *
- * @param {TMessage[]} messages
- * @param {MongoFile[]} files
- * @returns {Promise}
- */
- async addImageURLs(message, attachments, mode = '') {
- const { files, image_urls } = await encodeAndFormat(
- this.options.req,
- attachments,
- {
- endpoint: EModelEndpoint.google,
- },
- mode,
- );
- message.image_urls = image_urls.length ? image_urls : undefined;
- return files;
- }
-
- /**
- * Builds the augmented prompt for attachments
- * TODO: Add File API Support
- * @param {TMessage[]} messages
- */
- async buildAugmentedPrompt(messages = []) {
- const attachments = await this.options.attachments;
- const latestMessage = { ...messages[messages.length - 1] };
- this.contextHandlers = createContextHandlers(this.options.req, latestMessage.text);
-
- if (this.contextHandlers) {
- for (const file of attachments) {
- if (file.embedded) {
- this.contextHandlers?.processFile(file);
- continue;
- }
- if (file.metadata?.fileIdentifier) {
- continue;
- }
- }
-
- this.augmentedPrompt = await this.contextHandlers.createContext();
- this.systemMessage = this.augmentedPrompt + this.systemMessage;
- }
- }
-
- async buildVisionMessages(messages = [], parentMessageId) {
- const attachments = await this.options.attachments;
- const latestMessage = { ...messages[messages.length - 1] };
- await this.buildAugmentedPrompt(messages);
-
- const { prompt } = await this.buildMessagesPrompt(messages, parentMessageId);
-
- const files = await this.addImageURLs(latestMessage, attachments);
-
- this.options.attachments = files;
-
- latestMessage.text = prompt;
-
- const payload = {
- instances: [
- {
- messages: [new HumanMessage(formatMessage({ message: latestMessage }))],
- },
- ],
- };
- return { prompt: payload };
- }
-
- /** @param {TMessage[]} [messages=[]] */
- async buildGenerativeMessages(messages = []) {
- this.userLabel = 'user';
- this.modelLabel = 'model';
- const promises = [];
- promises.push(await this.formatGenerativeMessages(messages));
- promises.push(this.buildAugmentedPrompt(messages));
- const [formattedMessages] = await Promise.all(promises);
- return { prompt: formattedMessages };
- }
-
- /**
- * @param {TMessage[]} [messages=[]]
- * @param {string} [parentMessageId]
- */
- async buildMessages(_messages = [], parentMessageId) {
- if (!this.isGenerativeModel && !this.project_id) {
- throw new Error('[GoogleClient] PaLM 2 and Codey models are no longer supported.');
- }
-
- if (this.systemMessage) {
- const instructionsTokenCount = this.getTokenCount(this.systemMessage);
-
- this.maxContextTokens = this.maxContextTokens - instructionsTokenCount;
- if (this.maxContextTokens < 0) {
- const info = `${instructionsTokenCount} / ${this.maxContextTokens}`;
- const errorMessage = `{ "type": "${ErrorTypes.INPUT_LENGTH}", "info": "${info}" }`;
- logger.warn(`Instructions token count exceeds max context (${info}).`);
- throw new Error(errorMessage);
- }
- }
-
- for (let i = 0; i < _messages.length; i++) {
- const message = _messages[i];
- if (!message.tokenCount) {
- _messages[i].tokenCount = this.getTokenCountForMessage({
- role: message.isCreatedByUser ? 'user' : 'assistant',
- content: message.content ?? message.text,
- });
- }
- }
-
- const {
- payload: messages,
- tokenCountMap,
- promptTokens,
- } = await this.handleContextStrategy({
- orderedMessages: _messages,
- formattedMessages: _messages,
- });
-
- if (!this.project_id && !EXCLUDED_GENAI_MODELS.test(this.modelOptions.model)) {
- const result = await this.buildGenerativeMessages(messages);
- result.tokenCountMap = tokenCountMap;
- result.promptTokens = promptTokens;
- return result;
- }
-
- if (this.options.attachments && this.isGenerativeModel) {
- const result = this.buildVisionMessages(messages, parentMessageId);
- result.tokenCountMap = tokenCountMap;
- result.promptTokens = promptTokens;
- return result;
- }
-
- let payload = {
- instances: [
- {
- messages: messages
- .map(this.formatMessages())
- .map((msg) => ({ ...msg, role: msg.author === 'User' ? 'user' : 'assistant' }))
- .map((message) => formatMessage({ message, langChain: true })),
- },
- ],
- };
-
- if (this.systemMessage) {
- payload.instances[0].context = this.systemMessage;
- }
-
- logger.debug('[GoogleClient] buildMessages', payload);
- return { prompt: payload, tokenCountMap, promptTokens };
- }
-
- async buildMessagesPrompt(messages, parentMessageId) {
- const orderedMessages = this.constructor.getMessagesForConversation({
- messages,
- parentMessageId,
- });
-
- logger.debug('[GoogleClient]', {
- orderedMessages,
- parentMessageId,
- });
-
- const formattedMessages = orderedMessages.map(this.formatMessages());
-
- let lastAuthor = '';
- let groupedMessages = [];
-
- for (let message of formattedMessages) {
- // If last author is not same as current author, add to new group
- if (lastAuthor !== message.author) {
- groupedMessages.push({
- author: message.author,
- content: [message.content],
- });
- lastAuthor = message.author;
- // If same author, append content to the last group
- } else {
- groupedMessages[groupedMessages.length - 1].content.push(message.content);
- }
- }
-
- let identityPrefix = '';
- if (this.options.userLabel) {
- identityPrefix = `\nHuman's name: ${this.options.userLabel}`;
- }
-
- if (this.options.modelLabel) {
- identityPrefix = `${identityPrefix}\nYou are ${this.options.modelLabel}`;
- }
-
- let promptPrefix = (this.systemMessage ?? '').trim();
-
- if (identityPrefix) {
- promptPrefix = `${identityPrefix}${promptPrefix}`;
- }
-
- // Prompt AI to respond, empty if last message was from AI
- let isEdited = lastAuthor === this.modelLabel;
- const promptSuffix = isEdited ? '' : `${promptPrefix}\n\n${this.modelLabel}:\n`;
- let currentTokenCount = isEdited
- ? this.getTokenCount(promptPrefix)
- : this.getTokenCount(promptSuffix);
-
- let promptBody = '';
- const maxTokenCount = this.maxPromptTokens;
-
- const context = [];
-
- // Iterate backwards through the messages, adding them to the prompt until we reach the max token count.
- // Do this within a recursive async function so that it doesn't block the event loop for too long.
- // Also, remove the next message when the message that puts us over the token limit is created by the user.
- // Otherwise, remove only the exceeding message. This is due to Anthropic's strict payload rule to start with "Human:".
- const nextMessage = {
- remove: false,
- tokenCount: 0,
- messageString: '',
- };
-
- const buildPromptBody = async () => {
- if (currentTokenCount < maxTokenCount && groupedMessages.length > 0) {
- const message = groupedMessages.pop();
- const isCreatedByUser = message.author === this.userLabel;
- // Use promptPrefix if message is edited assistant'
- const messagePrefix =
- isCreatedByUser || !isEdited
- ? `\n\n${message.author}:`
- : `${promptPrefix}\n\n${message.author}:`;
- const messageString = `${messagePrefix}\n${message.content}\n`;
- let newPromptBody = `${messageString}${promptBody}`;
-
- context.unshift(message);
-
- const tokenCountForMessage = this.getTokenCount(messageString);
- const newTokenCount = currentTokenCount + tokenCountForMessage;
-
- if (!isCreatedByUser) {
- nextMessage.messageString = messageString;
- nextMessage.tokenCount = tokenCountForMessage;
- }
-
- if (newTokenCount > maxTokenCount) {
- if (!promptBody) {
- // This is the first message, so we can't add it. Just throw an error.
- throw new Error(
- `Prompt is too long. Max token count is ${maxTokenCount}, but prompt is ${newTokenCount} tokens long.`,
- );
- }
-
- // Otherwise, ths message would put us over the token limit, so don't add it.
- // if created by user, remove next message, otherwise remove only this message
- if (isCreatedByUser) {
- nextMessage.remove = true;
- }
-
- return false;
- }
- promptBody = newPromptBody;
- currentTokenCount = newTokenCount;
-
- // Switch off isEdited after using it for the first time
- if (isEdited) {
- isEdited = false;
- }
-
- // wait for next tick to avoid blocking the event loop
- await new Promise((resolve) => setImmediate(resolve));
- return buildPromptBody();
- }
- return true;
- };
-
- await buildPromptBody();
-
- if (nextMessage.remove) {
- promptBody = promptBody.replace(nextMessage.messageString, '');
- currentTokenCount -= nextMessage.tokenCount;
- context.shift();
- }
-
- let prompt = `${promptBody}${promptSuffix}`.trim();
-
- // Add 2 tokens for metadata after all messages have been counted.
- currentTokenCount += 2;
-
- // Use up to `this.maxContextTokens` tokens (prompt + response), but try to leave `this.maxTokens` tokens for the response.
- this.modelOptions.maxOutputTokens = Math.min(
- this.maxContextTokens - currentTokenCount,
- this.maxResponseTokens,
- );
-
- return { prompt, context };
- }
-
- createLLM(clientOptions) {
- const model = clientOptions.modelName ?? clientOptions.model;
- clientOptions.location = loc;
- clientOptions.endpoint = endpointPrefix;
-
- let requestOptions = null;
- if (this.reverseProxyUrl) {
- requestOptions = {
- baseUrl: this.reverseProxyUrl,
- };
-
- if (this.authHeader) {
- requestOptions.customHeaders = {
- Authorization: `Bearer ${this.apiKey}`,
- };
- }
- }
-
- if (this.project_id != null) {
- logger.debug('Creating VertexAI client');
- this.visionMode = undefined;
- clientOptions.streaming = true;
- const client = new ChatVertexAI(clientOptions);
- client.temperature = clientOptions.temperature;
- client.topP = clientOptions.topP;
- client.topK = clientOptions.topK;
- client.topLogprobs = clientOptions.topLogprobs;
- client.frequencyPenalty = clientOptions.frequencyPenalty;
- client.presencePenalty = clientOptions.presencePenalty;
- client.maxOutputTokens = clientOptions.maxOutputTokens;
- return client;
- } else if (!EXCLUDED_GENAI_MODELS.test(model)) {
- logger.debug('Creating GenAI client');
- return new GenAI(this.apiKey).getGenerativeModel({ model }, requestOptions);
- }
-
- logger.debug('Creating Chat Google Generative AI client');
- return new ChatGoogleGenerativeAI({ ...clientOptions, apiKey: this.apiKey });
- }
-
- initializeClient() {
- let clientOptions = { ...this.modelOptions };
-
- if (this.project_id) {
- clientOptions['authOptions'] = {
- credentials: {
- ...this.serviceKey,
- },
- projectId: this.project_id,
- };
- }
-
- if (this.isGenerativeModel && !this.project_id) {
- clientOptions.modelName = clientOptions.model;
- delete clientOptions.model;
- }
-
- this.client = this.createLLM(clientOptions);
- return this.client;
- }
-
- async getCompletion(_payload, options = {}) {
- const { onProgress, abortController } = options;
- const safetySettings = getSafetySettings(this.modelOptions.model);
- const streamRate = this.options.streamRate ?? Constants.DEFAULT_STREAM_RATE;
- const modelName = this.modelOptions.modelName ?? this.modelOptions.model ?? '';
-
- let reply = '';
- /** @type {Error} */
- let error;
- try {
- if (!EXCLUDED_GENAI_MODELS.test(modelName) && !this.project_id) {
- /** @type {GenerativeModel} */
- const client = this.client;
- /** @type {GenerateContentRequest} */
- const requestOptions = {
- safetySettings,
- contents: _payload,
- generationConfig: googleGenConfigSchema.parse(this.modelOptions),
- };
-
- const promptPrefix = (this.systemMessage ?? '').trim();
- if (promptPrefix.length) {
- requestOptions.systemInstruction = {
- parts: [
- {
- text: promptPrefix,
- },
- ],
- };
- }
-
- const delay = modelName.includes('flash') ? 8 : 15;
- /** @type {GenAIUsageMetadata} */
- let usageMetadata;
-
- abortController.signal.addEventListener(
- 'abort',
- () => {
- logger.warn('[GoogleClient] Request was aborted', abortController.signal.reason);
- },
- { once: true },
- );
-
- const result = await client.generateContentStream(requestOptions, {
- signal: abortController.signal,
- });
- for await (const chunk of result.stream) {
- usageMetadata = !usageMetadata
- ? chunk?.usageMetadata
- : Object.assign(usageMetadata, chunk?.usageMetadata);
- const chunkText = chunk.text();
- await this.generateTextStream(chunkText, onProgress, {
- delay,
- });
- reply += chunkText;
- await sleep(streamRate);
- }
-
- if (usageMetadata) {
- this.usage = {
- input_tokens: usageMetadata.promptTokenCount,
- output_tokens: usageMetadata.candidatesTokenCount,
- };
- }
-
- return reply;
- }
-
- const { instances } = _payload;
- const { messages: messages, context } = instances?.[0] ?? {};
-
- if (!this.isVisionModel && context && messages?.length > 0) {
- messages.unshift(new SystemMessage(context));
- }
-
- /** @type {import('@langchain/core/messages').AIMessageChunk['usage_metadata']} */
- let usageMetadata;
- /** @type {ChatVertexAI} */
- const client = this.client;
- const stream = await client.stream(messages, {
- signal: abortController.signal,
- streamUsage: true,
- safetySettings,
- });
-
- let delay = this.options.streamRate || 8;
-
- if (!this.options.streamRate) {
- if (this.isGenerativeModel) {
- delay = 15;
- }
- if (modelName.includes('flash')) {
- delay = 5;
- }
- }
-
- for await (const chunk of stream) {
- if (chunk?.usage_metadata) {
- const metadata = chunk.usage_metadata;
- for (const key in metadata) {
- if (Number.isNaN(metadata[key])) {
- delete metadata[key];
- }
- }
-
- usageMetadata = !usageMetadata ? metadata : concat(usageMetadata, metadata);
- }
-
- const chunkText = chunk?.content ?? '';
- await this.generateTextStream(chunkText, onProgress, {
- delay,
- });
- reply += chunkText;
- }
-
- if (usageMetadata) {
- this.usage = usageMetadata;
- }
- } catch (e) {
- error = e;
- logger.error('[GoogleClient] There was an issue generating the completion', e);
- }
-
- if (error != null && reply === '') {
- const errorMessage = `{ "type": "${ErrorTypes.GoogleError}", "info": "${
- error.message ?? 'The Google provider failed to generate content, please contact the Admin.'
- }" }`;
- throw new Error(errorMessage);
- }
- return reply;
- }
-
- /**
- * Get stream usage as returned by this client's API response.
- * @returns {UsageMetadata} The stream usage object.
- */
- getStreamUsage() {
- return this.usage;
- }
-
- getMessageMapMethod() {
- /**
- * @param {TMessage} msg
- */
- return (msg) => {
- if (msg.text != null && msg.text && msg.text.startsWith(':::thinking')) {
- msg.text = msg.text.replace(/:::thinking.*?:::/gs, '').trim();
- } else if (msg.content != null) {
- msg.text = parseTextParts(msg.content, true);
- delete msg.content;
- }
-
- return msg;
- };
- }
-
- /**
- * Calculates the correct token count for the current user message based on the token count map and API usage.
- * Edge case: If the calculation results in a negative value, it returns the original estimate.
- * If revisiting a conversation with a chat history entirely composed of token estimates,
- * the cumulative token count going forward should become more accurate as the conversation progresses.
- * @param {Object} params - The parameters for the calculation.
- * @param {Record} params.tokenCountMap - A map of message IDs to their token counts.
- * @param {string} params.currentMessageId - The ID of the current message to calculate.
- * @param {UsageMetadata} params.usage - The usage object returned by the API.
- * @returns {number} The correct token count for the current user message.
- */
- calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage }) {
- const originalEstimate = tokenCountMap[currentMessageId] || 0;
-
- if (!usage || typeof usage.input_tokens !== 'number') {
- return originalEstimate;
- }
-
- tokenCountMap[currentMessageId] = 0;
- const totalTokensFromMap = Object.values(tokenCountMap).reduce((sum, count) => {
- const numCount = Number(count);
- return sum + (isNaN(numCount) ? 0 : numCount);
- }, 0);
- const totalInputTokens = usage.input_tokens ?? 0;
- const currentMessageTokens = totalInputTokens - totalTokensFromMap;
- return currentMessageTokens > 0 ? currentMessageTokens : originalEstimate;
- }
-
- /**
- * @param {object} params
- * @param {number} params.promptTokens
- * @param {number} params.completionTokens
- * @param {UsageMetadata} [params.usage]
- * @param {string} [params.model]
- * @param {string} [params.context='message']
- * @returns {Promise}
- */
- async recordTokenUsage({ promptTokens, completionTokens, model, context = 'message' }) {
- await spendTokens(
- {
- context,
- user: this.user ?? this.options.req?.user?.id,
- conversationId: this.conversationId,
- model: model ?? this.modelOptions.model,
- endpointTokenConfig: this.options.endpointTokenConfig,
- },
- { promptTokens, completionTokens },
- );
- }
-
- /**
- * Stripped-down logic for generating a title. This uses the non-streaming APIs, since the user does not see titles streaming
- */
- async titleChatCompletion(_payload, options = {}) {
- let reply = '';
- const { abortController } = options;
-
- const model =
- this.options.titleModel ?? this.modelOptions.modelName ?? this.modelOptions.model ?? '';
- const safetySettings = getSafetySettings(model);
- if (!EXCLUDED_GENAI_MODELS.test(model) && !this.project_id) {
- logger.debug('Identified titling model as GenAI version');
- /** @type {GenerativeModel} */
- const client = this.client;
- const requestOptions = {
- contents: _payload,
- safetySettings,
- generationConfig: {
- temperature: 0.5,
- },
- };
-
- const result = await client.generateContent(requestOptions);
- reply = result.response?.text();
- return reply;
- } else {
- const { instances } = _payload;
- const { messages } = instances?.[0] ?? {};
- const titleResponse = await this.client.invoke(messages, {
- signal: abortController.signal,
- timeout: 7000,
- safetySettings,
- });
-
- if (titleResponse.usage_metadata) {
- await this.recordTokenUsage({
- model,
- promptTokens: titleResponse.usage_metadata.input_tokens,
- completionTokens: titleResponse.usage_metadata.output_tokens,
- context: 'title',
- });
- }
-
- reply = titleResponse.content;
- return reply;
- }
- }
-
- async titleConvo({ text, responseText = '' }) {
- let title = 'New Chat';
- const convo = `||>User:
-"${truncateText(text)}"
-||>Response:
-"${JSON.stringify(truncateText(responseText))}"`;
-
- let { prompt: payload } = await this.buildMessages([
- {
- text: `Please generate ${titleInstruction}
-
- ${convo}
-
- ||>Title:`,
- isCreatedByUser: true,
- author: this.userLabel,
- },
- ]);
-
- try {
- this.initializeClient();
- title = await this.titleChatCompletion(payload, {
- abortController: new AbortController(),
- onProgress: () => {},
- });
- } catch (e) {
- logger.error('[GoogleClient] There was an issue generating the title', e);
- }
- logger.debug(`Title response: ${title}`);
- return title;
- }
-
- getSaveOptions() {
- return {
- endpointType: null,
- artifacts: this.options.artifacts,
- promptPrefix: this.options.promptPrefix,
- maxContextTokens: this.options.maxContextTokens,
- modelLabel: this.options.modelLabel,
- iconURL: this.options.iconURL,
- greeting: this.options.greeting,
- spec: this.options.spec,
- ...this.modelOptions,
- };
- }
-
- getBuildMessagesOptions() {
- // logger.debug('GoogleClient doesn\'t use getBuildMessagesOptions');
- }
-
- async sendCompletion(payload, opts = {}) {
- let reply = '';
- reply = await this.getCompletion(payload, opts);
- return reply.trim();
- }
-
- getEncoding() {
- return 'cl100k_base';
- }
-
- async getVertexTokenCount(text) {
- /** @type {ChatVertexAI} */
- const client = this.client ?? this.initializeClient();
- const connection = client.connection;
- const gAuthClient = connection.client;
- const tokenEndpoint = `https://${connection._endpoint}/${connection.apiVersion}/projects/${this.project_id}/locations/${connection._location}/publishers/google/models/${connection.model}/:countTokens`;
- const result = await gAuthClient.request({
- url: tokenEndpoint,
- method: 'POST',
- data: {
- contents: [{ role: 'user', parts: [{ text }] }],
- },
- });
- return result;
- }
-
- /**
- * Returns the token count of a given text. It also checks and resets the tokenizers if necessary.
- * @param {string} text - The text to get the token count for.
- * @returns {number} The token count of the given text.
- */
- getTokenCount(text) {
- const encoding = this.getEncoding();
- return Tokenizer.getTokenCount(text, encoding);
- }
-}
-
-module.exports = GoogleClient;
diff --git a/api/app/clients/OllamaClient.js b/api/app/clients/OllamaClient.js
index b8bdacf13e..d0dda519fe 100644
--- a/api/app/clients/OllamaClient.js
+++ b/api/app/clients/OllamaClient.js
@@ -2,10 +2,9 @@ const { z } = require('zod');
const axios = require('axios');
const { Ollama } = require('ollama');
const { sleep } = require('@librechat/agents');
-const { resolveHeaders } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { Constants } = require('librechat-data-provider');
-const { deriveBaseURL } = require('~/utils');
+const { resolveHeaders, deriveBaseURL } = require('@librechat/api');
const ollamaPayloadSchema = z.object({
mirostat: z.number().optional(),
diff --git a/api/app/clients/OpenAIClient.js b/api/app/clients/OpenAIClient.js
deleted file mode 100644
index f4c42351e3..0000000000
--- a/api/app/clients/OpenAIClient.js
+++ /dev/null
@@ -1,1207 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { HttpsProxyAgent } = require('https-proxy-agent');
-const { sleep, SplitStreamHandler, CustomOpenAIClient: OpenAI } = require('@librechat/agents');
-const {
- isEnabled,
- Tokenizer,
- createFetch,
- resolveHeaders,
- constructAzureURL,
- getModelMaxTokens,
- genAzureChatCompletion,
- getModelMaxOutputTokens,
- createStreamEventHandlers,
-} = require('@librechat/api');
-const {
- Constants,
- ImageDetail,
- ContentTypes,
- parseTextParts,
- EModelEndpoint,
- KnownEndpoints,
- openAISettings,
- ImageDetailCost,
- getResponseSender,
- validateVisionModel,
- mapModelToAzureConfig,
-} = require('librechat-data-provider');
-const { encodeAndFormat } = require('~/server/services/Files/images/encode');
-const { formatMessage, createContextHandlers } = require('./prompts');
-const { spendTokens } = require('~/models/spendTokens');
-const { addSpaceIfNeeded } = require('~/server/utils');
-const { handleOpenAIErrors } = require('./tools/util');
-const { OllamaClient } = require('./OllamaClient');
-const { extractBaseURL } = require('~/utils');
-const BaseClient = require('./BaseClient');
-
-class OpenAIClient extends BaseClient {
- constructor(apiKey, options = {}) {
- super(apiKey, options);
- this.contextStrategy = options.contextStrategy
- ? options.contextStrategy.toLowerCase()
- : 'discard';
- this.shouldSummarize = this.contextStrategy === 'summarize';
- /** @type {AzureOptions} */
- this.azure = options.azure || false;
- this.setOptions(options);
- this.metadata = {};
-
- /** @type {string | undefined} - The API Completions URL */
- this.completionsUrl;
-
- /** @type {OpenAIUsageMetadata | undefined} */
- this.usage;
- /** @type {boolean|undefined} */
- this.isOmni;
- /** @type {SplitStreamHandler | undefined} */
- this.streamHandler;
- }
-
- // TODO: PluginsClient calls this 3x, unneeded
- setOptions(options) {
- if (this.options && !this.options.replaceOptions) {
- this.options.modelOptions = {
- ...this.options.modelOptions,
- ...options.modelOptions,
- };
- delete options.modelOptions;
- this.options = {
- ...this.options,
- ...options,
- };
- } else {
- this.options = options;
- }
-
- if (this.options.openaiApiKey) {
- this.apiKey = this.options.openaiApiKey;
- }
-
- this.modelOptions = Object.assign(
- {
- model: openAISettings.model.default,
- },
- this.modelOptions,
- this.options.modelOptions,
- );
-
- this.defaultVisionModel = this.options.visionModel ?? 'gpt-4-vision-preview';
- if (typeof this.options.attachments?.then === 'function') {
- this.options.attachments.then((attachments) => this.checkVisionRequest(attachments));
- } else {
- this.checkVisionRequest(this.options.attachments);
- }
-
- const omniPattern = /\b(o\d)\b/i;
- this.isOmni = omniPattern.test(this.modelOptions.model);
-
- const { OPENAI_FORCE_PROMPT } = process.env ?? {};
- const { reverseProxyUrl: reverseProxy } = this.options;
-
- if (
- !this.useOpenRouter &&
- ((reverseProxy && reverseProxy.includes(KnownEndpoints.openrouter)) ||
- (this.options.endpoint &&
- this.options.endpoint.toLowerCase().includes(KnownEndpoints.openrouter)))
- ) {
- this.useOpenRouter = true;
- }
-
- if (this.options.endpoint?.toLowerCase() === 'ollama') {
- this.isOllama = true;
- }
-
- this.FORCE_PROMPT =
- isEnabled(OPENAI_FORCE_PROMPT) ||
- (reverseProxy && reverseProxy.includes('completions') && !reverseProxy.includes('chat'));
-
- if (typeof this.options.forcePrompt === 'boolean') {
- this.FORCE_PROMPT = this.options.forcePrompt;
- }
-
- if (this.azure && process.env.AZURE_OPENAI_DEFAULT_MODEL) {
- this.azureEndpoint = genAzureChatCompletion(this.azure, this.modelOptions.model, this);
- this.modelOptions.model = process.env.AZURE_OPENAI_DEFAULT_MODEL;
- } else if (this.azure) {
- this.azureEndpoint = genAzureChatCompletion(this.azure, this.modelOptions.model, this);
- }
-
- const { model } = this.modelOptions;
-
- this.isChatCompletion =
- omniPattern.test(model) || model.includes('gpt') || this.useOpenRouter || !!reverseProxy;
- this.isChatGptModel = this.isChatCompletion;
- if (
- model.includes('text-davinci') ||
- model.includes('gpt-3.5-turbo-instruct') ||
- this.FORCE_PROMPT
- ) {
- this.isChatCompletion = false;
- this.isChatGptModel = false;
- }
- const { isChatGptModel } = this;
- this.isUnofficialChatGptModel =
- model.startsWith('text-chat') || model.startsWith('text-davinci-002-render');
-
- this.maxContextTokens =
- this.options.maxContextTokens ??
- getModelMaxTokens(
- model,
- this.options.endpointType ?? this.options.endpoint,
- this.options.endpointTokenConfig,
- ) ??
- 4095; // 1 less than maximum
-
- if (this.shouldSummarize) {
- this.maxContextTokens = Math.floor(this.maxContextTokens / 2);
- }
-
- if (this.options.debug) {
- logger.debug('[OpenAIClient] maxContextTokens', this.maxContextTokens);
- }
-
- this.maxResponseTokens =
- this.modelOptions.max_tokens ??
- getModelMaxOutputTokens(
- model,
- this.options.endpointType ?? this.options.endpoint,
- this.options.endpointTokenConfig,
- ) ??
- 1024;
- this.maxPromptTokens =
- this.options.maxPromptTokens || this.maxContextTokens - this.maxResponseTokens;
-
- if (this.maxPromptTokens + this.maxResponseTokens > this.maxContextTokens) {
- throw new Error(
- `maxPromptTokens + max_tokens (${this.maxPromptTokens} + ${this.maxResponseTokens} = ${
- this.maxPromptTokens + this.maxResponseTokens
- }) must be less than or equal to maxContextTokens (${this.maxContextTokens})`,
- );
- }
-
- this.sender =
- this.options.sender ??
- getResponseSender({
- model: this.modelOptions.model,
- endpoint: this.options.endpoint,
- endpointType: this.options.endpointType,
- modelDisplayLabel: this.options.modelDisplayLabel,
- chatGptLabel: this.options.chatGptLabel || this.options.modelLabel,
- });
-
- this.userLabel = this.options.userLabel || 'User';
- this.chatGptLabel = this.options.chatGptLabel || 'Assistant';
-
- this.setupTokens();
-
- if (reverseProxy) {
- this.completionsUrl = reverseProxy;
- this.langchainProxy = extractBaseURL(reverseProxy);
- } else if (isChatGptModel) {
- this.completionsUrl = 'https://api.openai.com/v1/chat/completions';
- } else {
- this.completionsUrl = 'https://api.openai.com/v1/completions';
- }
-
- if (this.azureEndpoint) {
- this.completionsUrl = this.azureEndpoint;
- }
-
- if (this.azureEndpoint && this.options.debug) {
- logger.debug('Using Azure endpoint');
- }
-
- return this;
- }
-
- /**
- *
- * Checks if the model is a vision model based on request attachments and sets the appropriate options:
- * - Sets `this.modelOptions.model` to `gpt-4-vision-preview` if the request is a vision request.
- * - Sets `this.isVisionModel` to `true` if vision request.
- * - Deletes `this.modelOptions.stop` if vision request.
- * @param {MongoFile[]} attachments
- */
- checkVisionRequest(attachments) {
- if (!attachments) {
- return;
- }
-
- const availableModels = this.options.modelsConfig?.[this.options.endpoint];
- if (!availableModels) {
- return;
- }
-
- let visionRequestDetected = false;
- for (const file of attachments) {
- if (file?.type?.includes('image')) {
- visionRequestDetected = true;
- break;
- }
- }
- if (!visionRequestDetected) {
- return;
- }
-
- this.isVisionModel = validateVisionModel({ model: this.modelOptions.model, availableModels });
- if (this.isVisionModel) {
- delete this.modelOptions.stop;
- return;
- }
-
- for (const model of availableModels) {
- if (!validateVisionModel({ model, availableModels })) {
- continue;
- }
- this.modelOptions.model = model;
- this.isVisionModel = true;
- delete this.modelOptions.stop;
- return;
- }
-
- if (!availableModels.includes(this.defaultVisionModel)) {
- return;
- }
- if (!validateVisionModel({ model: this.defaultVisionModel, availableModels })) {
- return;
- }
-
- this.modelOptions.model = this.defaultVisionModel;
- this.isVisionModel = true;
- delete this.modelOptions.stop;
- }
-
- setupTokens() {
- if (this.isChatCompletion) {
- this.startToken = '||>';
- this.endToken = '';
- } else if (this.isUnofficialChatGptModel) {
- this.startToken = '<|im_start|>';
- this.endToken = '<|im_end|>';
- } else {
- this.startToken = '||>';
- this.endToken = '';
- }
- }
-
- getEncoding() {
- return this.modelOptions?.model && /gpt-4[^-\s]/.test(this.modelOptions.model)
- ? 'o200k_base'
- : 'cl100k_base';
- }
-
- /**
- * Returns the token count of a given text. It also checks and resets the tokenizers if necessary.
- * @param {string} text - The text to get the token count for.
- * @returns {number} The token count of the given text.
- */
- getTokenCount(text) {
- const encoding = this.getEncoding();
- return Tokenizer.getTokenCount(text, encoding);
- }
-
- /**
- * Calculate the token cost for an image based on its dimensions and detail level.
- *
- * @param {Object} image - The image object.
- * @param {number} image.width - The width of the image.
- * @param {number} image.height - The height of the image.
- * @param {'low'|'high'|string|undefined} [image.detail] - The detail level ('low', 'high', or other).
- * @returns {number} The calculated token cost.
- */
- calculateImageTokenCost({ width, height, detail }) {
- if (detail === 'low') {
- return ImageDetailCost.LOW;
- }
-
- // Calculate the number of 512px squares
- const numSquares = Math.ceil(width / 512) * Math.ceil(height / 512);
-
- // Default to high detail cost calculation
- return numSquares * ImageDetailCost.HIGH + ImageDetailCost.ADDITIONAL;
- }
-
- getSaveOptions() {
- return {
- artifacts: this.options.artifacts,
- maxContextTokens: this.options.maxContextTokens,
- chatGptLabel: this.options.chatGptLabel,
- promptPrefix: this.options.promptPrefix,
- resendFiles: this.options.resendFiles,
- imageDetail: this.options.imageDetail,
- modelLabel: this.options.modelLabel,
- iconURL: this.options.iconURL,
- greeting: this.options.greeting,
- spec: this.options.spec,
- ...this.modelOptions,
- };
- }
-
- getBuildMessagesOptions(opts) {
- return {
- isChatCompletion: this.isChatCompletion,
- promptPrefix: opts.promptPrefix,
- abortController: opts.abortController,
- };
- }
-
- /**
- *
- * Adds image URLs to the message object and returns the files
- *
- * @param {TMessage[]} messages
- * @param {MongoFile[]} files
- * @returns {Promise}
- */
- async addImageURLs(message, attachments) {
- const { files, image_urls } = await encodeAndFormat(this.options.req, attachments, {
- endpoint: this.options.endpoint,
- });
- message.image_urls = image_urls.length ? image_urls : undefined;
- return files;
- }
-
- async buildMessages(messages, parentMessageId, { promptPrefix = null }, opts) {
- let orderedMessages = this.constructor.getMessagesForConversation({
- messages,
- parentMessageId,
- summary: this.shouldSummarize,
- });
-
- let payload;
- let instructions;
- let tokenCountMap;
- let promptTokens;
-
- promptPrefix = (promptPrefix || this.options.promptPrefix || '').trim();
- if (typeof this.options.artifactsPrompt === 'string' && this.options.artifactsPrompt) {
- promptPrefix = `${promptPrefix ?? ''}\n${this.options.artifactsPrompt}`.trim();
- }
-
- if (this.options.attachments) {
- const attachments = await this.options.attachments;
-
- if (this.message_file_map) {
- this.message_file_map[orderedMessages[orderedMessages.length - 1].messageId] = attachments;
- } else {
- this.message_file_map = {
- [orderedMessages[orderedMessages.length - 1].messageId]: attachments,
- };
- }
-
- const files = await this.addImageURLs(
- orderedMessages[orderedMessages.length - 1],
- attachments,
- );
-
- this.options.attachments = files;
- }
-
- if (this.message_file_map) {
- this.contextHandlers = createContextHandlers(
- this.options.req,
- orderedMessages[orderedMessages.length - 1].text,
- );
- }
-
- const formattedMessages = orderedMessages.map((message, i) => {
- const formattedMessage = formatMessage({
- message,
- userName: this.options?.name,
- assistantName: this.options?.chatGptLabel,
- });
-
- const needsTokenCount = this.contextStrategy && !orderedMessages[i].tokenCount;
-
- /* If tokens were never counted, or, is a Vision request and the message has files, count again */
- if (needsTokenCount || (this.isVisionModel && (message.image_urls || message.files))) {
- orderedMessages[i].tokenCount = this.getTokenCountForMessage(formattedMessage);
- }
-
- /* If message has files, calculate image token cost */
- if (this.message_file_map && this.message_file_map[message.messageId]) {
- const attachments = this.message_file_map[message.messageId];
- for (const file of attachments) {
- if (file.embedded) {
- this.contextHandlers?.processFile(file);
- continue;
- }
- if (file.metadata?.fileIdentifier) {
- continue;
- }
-
- orderedMessages[i].tokenCount += this.calculateImageTokenCost({
- width: file.width,
- height: file.height,
- detail: this.options.imageDetail ?? ImageDetail.auto,
- });
- }
- }
-
- return formattedMessage;
- });
-
- if (this.contextHandlers) {
- this.augmentedPrompt = await this.contextHandlers.createContext();
- promptPrefix = this.augmentedPrompt + promptPrefix;
- }
-
- const noSystemModelRegex = /\b(o1-preview|o1-mini)\b/i.test(this.modelOptions.model);
-
- if (promptPrefix && !noSystemModelRegex) {
- promptPrefix = `Instructions:\n${promptPrefix.trim()}`;
- instructions = {
- role: 'system',
- content: promptPrefix,
- };
-
- if (this.contextStrategy) {
- instructions.tokenCount = this.getTokenCountForMessage(instructions);
- }
- }
-
- // TODO: need to handle interleaving instructions better
- if (this.contextStrategy) {
- ({ payload, tokenCountMap, promptTokens, messages } = await this.handleContextStrategy({
- instructions,
- orderedMessages,
- formattedMessages,
- }));
- }
-
- const result = {
- prompt: payload,
- promptTokens,
- messages,
- };
-
- /** EXPERIMENTAL */
- if (promptPrefix && noSystemModelRegex) {
- const lastUserMessageIndex = payload.findLastIndex((message) => message.role === 'user');
- if (lastUserMessageIndex !== -1) {
- if (Array.isArray(payload[lastUserMessageIndex].content)) {
- const firstTextPartIndex = payload[lastUserMessageIndex].content.findIndex(
- (part) => part.type === ContentTypes.TEXT,
- );
- if (firstTextPartIndex !== -1) {
- const firstTextPart = payload[lastUserMessageIndex].content[firstTextPartIndex];
- payload[lastUserMessageIndex].content[firstTextPartIndex].text =
- `${promptPrefix}\n${firstTextPart.text}`;
- } else {
- payload[lastUserMessageIndex].content.unshift({
- type: ContentTypes.TEXT,
- text: promptPrefix,
- });
- }
- } else {
- payload[lastUserMessageIndex].content =
- `${promptPrefix}\n${payload[lastUserMessageIndex].content}`;
- }
- }
- }
-
- if (tokenCountMap) {
- tokenCountMap.instructions = instructions?.tokenCount;
- result.tokenCountMap = tokenCountMap;
- }
-
- if (promptTokens >= 0 && typeof opts?.getReqData === 'function') {
- opts.getReqData({ promptTokens });
- }
-
- return result;
- }
-
- /** @type {sendCompletion} */
- async sendCompletion(payload, opts = {}) {
- let reply = '';
- let result = null;
- let streamResult = null;
- this.modelOptions.user = this.user;
- const invalidBaseUrl = this.completionsUrl && extractBaseURL(this.completionsUrl) === null;
- const useOldMethod = !!(invalidBaseUrl || !this.isChatCompletion);
- if (typeof opts.onProgress === 'function' && useOldMethod) {
- const completionResult = await this.getCompletion(
- payload,
- (progressMessage) => {
- if (progressMessage === '[DONE]') {
- return;
- }
-
- if (progressMessage.choices) {
- streamResult = progressMessage;
- }
-
- let token = null;
- if (this.isChatCompletion) {
- token =
- progressMessage.choices?.[0]?.delta?.content ?? progressMessage.choices?.[0]?.text;
- } else {
- token = progressMessage.choices?.[0]?.text;
- }
-
- if (!token && this.useOpenRouter) {
- token = progressMessage.choices?.[0]?.message?.content;
- }
- // first event's delta content is always undefined
- if (!token) {
- return;
- }
-
- if (token === this.endToken) {
- return;
- }
- opts.onProgress(token);
- reply += token;
- },
- opts.onProgress,
- opts.abortController || new AbortController(),
- );
-
- if (completionResult && typeof completionResult === 'string') {
- reply = completionResult;
- } else if (
- completionResult &&
- typeof completionResult === 'object' &&
- Array.isArray(completionResult.choices)
- ) {
- reply = completionResult.choices[0]?.text?.replace(this.endToken, '');
- }
- } else if (typeof opts.onProgress === 'function' || this.options.useChatCompletion) {
- reply = await this.chatCompletion({
- payload,
- onProgress: opts.onProgress,
- abortController: opts.abortController,
- });
- } else {
- result = await this.getCompletion(
- payload,
- null,
- opts.onProgress,
- opts.abortController || new AbortController(),
- );
-
- if (result && typeof result === 'string') {
- return result.trim();
- }
-
- logger.debug('[OpenAIClient] sendCompletion: result', { ...result });
-
- if (this.isChatCompletion) {
- reply = result.choices[0].message.content;
- } else {
- reply = result.choices[0].text.replace(this.endToken, '');
- }
- }
-
- if (streamResult) {
- const { finish_reason } = streamResult.choices[0];
- this.metadata = { finish_reason };
- }
- return (reply ?? '').trim();
- }
-
- initializeLLM() {
- throw new Error('Deprecated');
- }
-
- /**
- * Get stream usage as returned by this client's API response.
- * @returns {OpenAIUsageMetadata} The stream usage object.
- */
- getStreamUsage() {
- if (
- this.usage &&
- typeof this.usage === 'object' &&
- 'completion_tokens_details' in this.usage &&
- this.usage.completion_tokens_details &&
- typeof this.usage.completion_tokens_details === 'object' &&
- 'reasoning_tokens' in this.usage.completion_tokens_details
- ) {
- const outputTokens = Math.abs(
- this.usage.completion_tokens_details.reasoning_tokens - this.usage[this.outputTokensKey],
- );
- return {
- ...this.usage.completion_tokens_details,
- [this.inputTokensKey]: this.usage[this.inputTokensKey],
- [this.outputTokensKey]: outputTokens,
- };
- }
- return this.usage;
- }
-
- /**
- * Calculates the correct token count for the current user message based on the token count map and API usage.
- * Edge case: If the calculation results in a negative value, it returns the original estimate.
- * If revisiting a conversation with a chat history entirely composed of token estimates,
- * the cumulative token count going forward should become more accurate as the conversation progresses.
- * @param {Object} params - The parameters for the calculation.
- * @param {Record} params.tokenCountMap - A map of message IDs to their token counts.
- * @param {string} params.currentMessageId - The ID of the current message to calculate.
- * @param {OpenAIUsageMetadata} params.usage - The usage object returned by the API.
- * @returns {number} The correct token count for the current user message.
- */
- calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage }) {
- const originalEstimate = tokenCountMap[currentMessageId] || 0;
-
- if (!usage || typeof usage[this.inputTokensKey] !== 'number') {
- return originalEstimate;
- }
-
- tokenCountMap[currentMessageId] = 0;
- const totalTokensFromMap = Object.values(tokenCountMap).reduce((sum, count) => {
- const numCount = Number(count);
- return sum + (isNaN(numCount) ? 0 : numCount);
- }, 0);
- const totalInputTokens = usage[this.inputTokensKey] ?? 0;
-
- const currentMessageTokens = totalInputTokens - totalTokensFromMap;
- return currentMessageTokens > 0 ? currentMessageTokens : originalEstimate;
- }
-
- /**
- * @param {object} params
- * @param {number} params.promptTokens
- * @param {number} params.completionTokens
- * @param {OpenAIUsageMetadata} [params.usage]
- * @param {string} [params.model]
- * @param {string} [params.context='message']
- * @returns {Promise}
- */
- async recordTokenUsage({ promptTokens, completionTokens, usage, context = 'message' }) {
- await spendTokens(
- {
- context,
- model: this.modelOptions.model,
- conversationId: this.conversationId,
- user: this.user ?? this.options.req.user?.id,
- endpointTokenConfig: this.options.endpointTokenConfig,
- },
- { promptTokens, completionTokens },
- );
-
- if (
- usage &&
- typeof usage === 'object' &&
- 'reasoning_tokens' in usage &&
- typeof usage.reasoning_tokens === 'number'
- ) {
- await spendTokens(
- {
- context: 'reasoning',
- model: this.modelOptions.model,
- conversationId: this.conversationId,
- user: this.user ?? this.options.req.user?.id,
- endpointTokenConfig: this.options.endpointTokenConfig,
- },
- { completionTokens: usage.reasoning_tokens },
- );
- }
- }
-
- getTokenCountForResponse(response) {
- return this.getTokenCountForMessage({
- role: 'assistant',
- content: response.text,
- });
- }
-
- /**
- *
- * @param {string[]} [intermediateReply]
- * @returns {string}
- */
- getStreamText(intermediateReply) {
- if (!this.streamHandler) {
- return intermediateReply?.join('') ?? '';
- }
-
- let thinkMatch;
- let remainingText;
- let reasoningText = '';
-
- if (this.streamHandler.reasoningTokens.length > 0) {
- reasoningText = this.streamHandler.reasoningTokens.join('');
- thinkMatch = reasoningText.match(/([\s\S]*?)<\/think>/)?.[1]?.trim();
- if (thinkMatch != null && thinkMatch) {
- const reasoningTokens = `:::thinking\n${thinkMatch}\n:::\n`;
- remainingText = reasoningText.split(/<\/think>/)?.[1]?.trim() || '';
- return `${reasoningTokens}${remainingText}${this.streamHandler.tokens.join('')}`;
- } else if (thinkMatch === '') {
- remainingText = reasoningText.split(/<\/think>/)?.[1]?.trim() || '';
- return `${remainingText}${this.streamHandler.tokens.join('')}`;
- }
- }
-
- const reasoningTokens =
- reasoningText.length > 0
- ? `:::thinking\n${reasoningText.replace('', '').replace(' ', '').trim()}\n:::\n`
- : '';
-
- return `${reasoningTokens}${this.streamHandler.tokens.join('')}`;
- }
-
- getMessageMapMethod() {
- /**
- * @param {TMessage} msg
- */
- return (msg) => {
- if (msg.text != null && msg.text && msg.text.startsWith(':::thinking')) {
- msg.text = msg.text.replace(/:::thinking.*?:::/gs, '').trim();
- } else if (msg.content != null) {
- msg.text = parseTextParts(msg.content, true);
- delete msg.content;
- }
-
- return msg;
- };
- }
-
- async chatCompletion({ payload, onProgress, abortController = null }) {
- const appConfig = this.options.req?.config;
- let error = null;
- let intermediateReply = [];
- const errorCallback = (err) => (error = err);
- try {
- if (!abortController) {
- abortController = new AbortController();
- }
-
- let modelOptions = { ...this.modelOptions };
-
- if (typeof onProgress === 'function') {
- modelOptions.stream = true;
- }
- if (this.isChatCompletion) {
- modelOptions.messages = payload;
- } else {
- modelOptions.prompt = payload;
- }
-
- const baseURL = extractBaseURL(this.completionsUrl);
- logger.debug('[OpenAIClient] chatCompletion', { baseURL, modelOptions });
- const opts = {
- baseURL,
- fetchOptions: {},
- };
-
- if (this.useOpenRouter) {
- opts.defaultHeaders = {
- 'HTTP-Referer': 'https://librechat.ai',
- 'X-Title': 'LibreChat',
- };
- }
-
- if (this.options.headers) {
- opts.defaultHeaders = { ...opts.defaultHeaders, ...this.options.headers };
- }
-
- if (this.options.defaultQuery) {
- opts.defaultQuery = this.options.defaultQuery;
- }
-
- if (this.options.proxy) {
- opts.fetchOptions.agent = new HttpsProxyAgent(this.options.proxy);
- }
-
- const azureConfig = appConfig?.endpoints?.[EModelEndpoint.azureOpenAI];
-
- if (
- (this.azure && this.isVisionModel && azureConfig) ||
- (azureConfig && this.isVisionModel && this.options.endpoint === EModelEndpoint.azureOpenAI)
- ) {
- const { modelGroupMap, groupMap } = azureConfig;
- const {
- azureOptions,
- baseURL,
- headers = {},
- serverless,
- } = mapModelToAzureConfig({
- modelName: modelOptions.model,
- modelGroupMap,
- groupMap,
- });
- opts.defaultHeaders = resolveHeaders({ headers });
- this.langchainProxy = extractBaseURL(baseURL);
- this.apiKey = azureOptions.azureOpenAIApiKey;
-
- const groupName = modelGroupMap[modelOptions.model].group;
- this.options.addParams = azureConfig.groupMap[groupName].addParams;
- this.options.dropParams = azureConfig.groupMap[groupName].dropParams;
- // Note: `forcePrompt` not re-assigned as only chat models are vision models
-
- this.azure = !serverless && azureOptions;
- this.azureEndpoint =
- !serverless && genAzureChatCompletion(this.azure, modelOptions.model, this);
- if (serverless === true) {
- this.options.defaultQuery = azureOptions.azureOpenAIApiVersion
- ? { 'api-version': azureOptions.azureOpenAIApiVersion }
- : undefined;
- this.options.headers['api-key'] = this.apiKey;
- }
- }
-
- if (this.azure || this.options.azure) {
- /* Azure Bug, extremely short default `max_tokens` response */
- if (!modelOptions.max_tokens && modelOptions.model === 'gpt-4-vision-preview') {
- modelOptions.max_tokens = 4000;
- }
-
- /* Azure does not accept `model` in the body, so we need to remove it. */
- delete modelOptions.model;
-
- opts.baseURL = this.langchainProxy
- ? constructAzureURL({
- baseURL: this.langchainProxy,
- azureOptions: this.azure,
- })
- : this.azureEndpoint.split(/(? msg.role === 'system');
-
- if (systemMessageIndex > 0) {
- const [systemMessage] = messages.splice(systemMessageIndex, 1);
- messages.unshift(systemMessage);
- }
-
- modelOptions.messages = messages;
- }
-
- /* If there is only one message and it's a system message, change the role to user */
- if (
- (opts.baseURL.includes('api.mistral.ai') || opts.baseURL.includes('api.perplexity.ai')) &&
- modelOptions.messages &&
- modelOptions.messages.length === 1 &&
- modelOptions.messages[0]?.role === 'system'
- ) {
- modelOptions.messages[0].role = 'user';
- }
-
- if (
- (this.options.endpoint === EModelEndpoint.openAI ||
- this.options.endpoint === EModelEndpoint.azureOpenAI) &&
- modelOptions.stream === true
- ) {
- modelOptions.stream_options = { include_usage: true };
- }
-
- if (this.options.addParams && typeof this.options.addParams === 'object') {
- const addParams = { ...this.options.addParams };
- modelOptions = {
- ...modelOptions,
- ...addParams,
- };
- logger.debug('[OpenAIClient] chatCompletion: added params', {
- addParams: addParams,
- modelOptions,
- });
- }
-
- /** Note: OpenAI Web Search models do not support any known parameters besdies `max_tokens` */
- if (modelOptions.model && /gpt-4o.*search/.test(modelOptions.model)) {
- const searchExcludeParams = [
- 'frequency_penalty',
- 'presence_penalty',
- 'temperature',
- 'top_p',
- 'top_k',
- 'stop',
- 'logit_bias',
- 'seed',
- 'response_format',
- 'n',
- 'logprobs',
- 'user',
- ];
-
- this.options.dropParams = this.options.dropParams || [];
- this.options.dropParams = [
- ...new Set([...this.options.dropParams, ...searchExcludeParams]),
- ];
- }
-
- if (this.options.dropParams && Array.isArray(this.options.dropParams)) {
- const dropParams = [...this.options.dropParams];
- dropParams.forEach((param) => {
- delete modelOptions[param];
- });
- logger.debug('[OpenAIClient] chatCompletion: dropped params', {
- dropParams: dropParams,
- modelOptions,
- });
- }
-
- const streamRate = this.options.streamRate ?? Constants.DEFAULT_STREAM_RATE;
-
- if (this.message_file_map && this.isOllama) {
- const ollamaClient = new OllamaClient({ baseURL, streamRate });
- return await ollamaClient.chatCompletion({
- payload: modelOptions,
- onProgress,
- abortController,
- });
- }
-
- let UnexpectedRoleError = false;
- /** @type {Promise} */
- let streamPromise;
- /** @type {(value: void | PromiseLike) => void} */
- let streamResolve;
-
- if (
- (!this.isOmni || /^o1-(mini|preview)/i.test(modelOptions.model)) &&
- modelOptions.reasoning_effort != null
- ) {
- delete modelOptions.reasoning_effort;
- delete modelOptions.temperature;
- }
-
- let reasoningKey = 'reasoning_content';
- if (this.useOpenRouter) {
- modelOptions.include_reasoning = true;
- reasoningKey = 'reasoning';
- }
- if (this.useOpenRouter && modelOptions.reasoning_effort != null) {
- modelOptions.reasoning = {
- effort: modelOptions.reasoning_effort,
- };
- delete modelOptions.reasoning_effort;
- }
-
- const handlers = createStreamEventHandlers(this.options.res);
- this.streamHandler = new SplitStreamHandler({
- reasoningKey,
- accumulate: true,
- runId: this.responseMessageId,
- handlers,
- });
-
- intermediateReply = this.streamHandler.tokens;
-
- if (modelOptions.stream) {
- streamPromise = new Promise((resolve) => {
- streamResolve = resolve;
- });
- /** @type {OpenAI.OpenAI.CompletionCreateParamsStreaming} */
- const params = {
- ...modelOptions,
- stream: true,
- };
- const stream = await openai.chat.completions
- .stream(params)
- .on('abort', () => {
- /* Do nothing here */
- })
- .on('error', (err) => {
- handleOpenAIErrors(err, errorCallback, 'stream');
- })
- .on('finalChatCompletion', async (finalChatCompletion) => {
- const finalMessage = finalChatCompletion?.choices?.[0]?.message;
- if (!finalMessage) {
- return;
- }
- await streamPromise;
- if (finalMessage?.role !== 'assistant') {
- finalChatCompletion.choices[0].message.role = 'assistant';
- }
-
- if (typeof finalMessage.content !== 'string' || finalMessage.content.trim() === '') {
- finalChatCompletion.choices[0].message.content = this.streamHandler.tokens.join('');
- }
- })
- .on('finalMessage', (message) => {
- if (message?.role !== 'assistant') {
- stream.messages.push({
- role: 'assistant',
- content: this.streamHandler.tokens.join(''),
- });
- UnexpectedRoleError = true;
- }
- });
-
- if (this.continued === true) {
- const latestText = addSpaceIfNeeded(
- this.currentMessages[this.currentMessages.length - 1]?.text ?? '',
- );
- this.streamHandler.handle({
- choices: [
- {
- delta: {
- content: latestText,
- },
- },
- ],
- });
- }
-
- for await (const chunk of stream) {
- // Add finish_reason: null if missing in any choice
- if (chunk.choices) {
- chunk.choices.forEach((choice) => {
- if (!('finish_reason' in choice)) {
- choice.finish_reason = null;
- }
- });
- }
- this.streamHandler.handle(chunk);
- if (abortController.signal.aborted) {
- stream.controller.abort();
- break;
- }
-
- await sleep(streamRate);
- }
-
- streamResolve();
-
- if (!UnexpectedRoleError) {
- chatCompletion = await stream.finalChatCompletion().catch((err) => {
- handleOpenAIErrors(err, errorCallback, 'finalChatCompletion');
- });
- }
- }
- // regular completion
- else {
- chatCompletion = await openai.chat.completions
- .create({
- ...modelOptions,
- })
- .catch((err) => {
- handleOpenAIErrors(err, errorCallback, 'create');
- });
- }
-
- if (openai.abortHandler && abortController.signal) {
- abortController.signal.removeEventListener('abort', openai.abortHandler);
- openai.abortHandler = undefined;
- }
-
- if (!chatCompletion && UnexpectedRoleError) {
- throw new Error(
- 'OpenAI error: Invalid final message: OpenAI expects final message to include role=assistant',
- );
- } else if (!chatCompletion && error) {
- throw new Error(error);
- } else if (!chatCompletion) {
- throw new Error('Chat completion failed');
- }
-
- const { choices } = chatCompletion;
- this.usage = chatCompletion.usage;
-
- if (!Array.isArray(choices) || choices.length === 0) {
- logger.warn('[OpenAIClient] Chat completion response has no choices');
- return this.streamHandler.tokens.join('');
- }
-
- const { message, finish_reason } = choices[0] ?? {};
- this.metadata = { finish_reason };
-
- logger.debug('[OpenAIClient] chatCompletion response', chatCompletion);
-
- if (!message) {
- logger.warn('[OpenAIClient] Message is undefined in chatCompletion response');
- return this.streamHandler.tokens.join('');
- }
-
- if (typeof message.content !== 'string' || message.content.trim() === '') {
- const reply = this.streamHandler.tokens.join('');
- logger.debug(
- '[OpenAIClient] chatCompletion: using intermediateReply due to empty message.content',
- { intermediateReply: reply },
- );
- return reply;
- }
-
- if (
- this.streamHandler.reasoningTokens.length > 0 &&
- this.options.context !== 'title' &&
- !message.content.startsWith('')
- ) {
- return this.getStreamText();
- } else if (
- this.streamHandler.reasoningTokens.length > 0 &&
- this.options.context !== 'title' &&
- message.content.startsWith('')
- ) {
- return this.getStreamText();
- }
-
- return message.content;
- } catch (err) {
- if (
- err?.message?.includes('abort') ||
- (err instanceof OpenAI.APIError && err?.message?.includes('abort'))
- ) {
- return this.getStreamText(intermediateReply);
- }
- if (
- err?.message?.includes(
- 'OpenAI error: Invalid final message: OpenAI expects final message to include role=assistant',
- ) ||
- err?.message?.includes(
- 'stream ended without producing a ChatCompletionMessage with role=assistant',
- ) ||
- err?.message?.includes('The server had an error processing your request') ||
- err?.message?.includes('missing finish_reason') ||
- err?.message?.includes('missing role') ||
- (err instanceof OpenAI.OpenAIError && err?.message?.includes('missing finish_reason'))
- ) {
- logger.error('[OpenAIClient] Known OpenAI error:', err);
- if (this.streamHandler && this.streamHandler.reasoningTokens.length) {
- return this.getStreamText();
- } else if (intermediateReply.length > 0) {
- return this.getStreamText(intermediateReply);
- } else {
- throw err;
- }
- } else if (err instanceof OpenAI.APIError) {
- if (this.streamHandler && this.streamHandler.reasoningTokens.length) {
- return this.getStreamText();
- } else if (intermediateReply.length > 0) {
- return this.getStreamText(intermediateReply);
- } else {
- throw err;
- }
- } else {
- logger.error('[OpenAIClient.chatCompletion] Unhandled error type', err);
- throw err;
- }
- }
- }
-}
-
-module.exports = OpenAIClient;
diff --git a/api/app/clients/document/index.js b/api/app/clients/document/index.js
deleted file mode 100644
index 9ff3da72f0..0000000000
--- a/api/app/clients/document/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-const tokenSplit = require('./tokenSplit');
-
-module.exports = {
- tokenSplit,
-};
diff --git a/api/app/clients/document/tokenSplit.js b/api/app/clients/document/tokenSplit.js
deleted file mode 100644
index 497249c519..0000000000
--- a/api/app/clients/document/tokenSplit.js
+++ /dev/null
@@ -1,51 +0,0 @@
-const { TokenTextSplitter } = require('@langchain/textsplitters');
-
-/**
- * Splits a given text by token chunks, based on the provided parameters for the TokenTextSplitter.
- * Note: limit or memoize use of this function as its calculation is expensive.
- *
- * @param {Object} obj - Configuration object for the text splitting operation.
- * @param {string} obj.text - The text to be split.
- * @param {string} [obj.encodingName='cl100k_base'] - Encoding name. Defaults to 'cl100k_base'.
- * @param {number} [obj.chunkSize=1] - The token size of each chunk. Defaults to 1.
- * @param {number} [obj.chunkOverlap=0] - The number of chunk elements to be overlapped between adjacent chunks. Defaults to 0.
- * @param {number} [obj.returnSize] - If specified and not 0, slices the return array from the end by this amount.
- *
- * @returns {Promise} Returns a promise that resolves to an array of text chunks.
- * If no text is provided, an empty array is returned.
- * If returnSize is specified and not 0, slices the return array from the end by returnSize.
- *
- * @async
- * @function tokenSplit
- */
-async function tokenSplit({
- text,
- encodingName = 'cl100k_base',
- chunkSize = 1,
- chunkOverlap = 0,
- returnSize,
-}) {
- if (!text) {
- return [];
- }
-
- const splitter = new TokenTextSplitter({
- encodingName,
- chunkSize,
- chunkOverlap,
- });
-
- if (!returnSize) {
- return await splitter.splitText(text);
- }
-
- const splitText = await splitter.splitText(text);
-
- if (returnSize && returnSize > 0 && splitText.length > 0) {
- return splitText.slice(-Math.abs(returnSize));
- }
-
- return splitText;
-}
-
-module.exports = tokenSplit;
diff --git a/api/app/clients/document/tokenSplit.spec.js b/api/app/clients/document/tokenSplit.spec.js
deleted file mode 100644
index d39c7d73cd..0000000000
--- a/api/app/clients/document/tokenSplit.spec.js
+++ /dev/null
@@ -1,56 +0,0 @@
-const tokenSplit = require('./tokenSplit');
-
-describe('tokenSplit', () => {
- const text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id.';
-
- it('returns correct text chunks with provided parameters', async () => {
- const result = await tokenSplit({
- text: text,
- encodingName: 'gpt2',
- chunkSize: 2,
- chunkOverlap: 1,
- returnSize: 5,
- });
-
- expect(result).toEqual(['it.', '. Null', ' Nullam', 'am id', ' id.']);
- });
-
- it('returns correct text chunks with default parameters', async () => {
- const result = await tokenSplit({ text });
- expect(result).toEqual([
- 'Lorem',
- ' ipsum',
- ' dolor',
- ' sit',
- ' amet',
- ',',
- ' consectetur',
- ' adipiscing',
- ' elit',
- '.',
- ' Null',
- 'am',
- ' id',
- '.',
- ]);
- });
-
- it('returns correct text chunks with specific return size', async () => {
- const result = await tokenSplit({ text, returnSize: 2 });
- expect(result.length).toEqual(2);
- expect(result).toEqual([' id', '.']);
- });
-
- it('returns correct text chunks with specified chunk size', async () => {
- const result = await tokenSplit({ text, chunkSize: 10 });
- expect(result).toEqual([
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
- ' Nullam id.',
- ]);
- });
-
- it('returns empty array with no text', async () => {
- const result = await tokenSplit({ text: '' });
- expect(result).toEqual([]);
- });
-});
diff --git a/api/app/clients/index.js b/api/app/clients/index.js
index d8b2bae27b..3dbe397b31 100644
--- a/api/app/clients/index.js
+++ b/api/app/clients/index.js
@@ -1,13 +1,7 @@
-const OpenAIClient = require('./OpenAIClient');
-const GoogleClient = require('./GoogleClient');
const TextStream = require('./TextStream');
-const AnthropicClient = require('./AnthropicClient');
const toolUtils = require('./tools/util');
module.exports = {
- OpenAIClient,
- GoogleClient,
TextStream,
- AnthropicClient,
...toolUtils,
};
diff --git a/api/app/clients/llm/createCoherePayload.js b/api/app/clients/llm/createCoherePayload.js
deleted file mode 100644
index 58803d76f3..0000000000
--- a/api/app/clients/llm/createCoherePayload.js
+++ /dev/null
@@ -1,85 +0,0 @@
-const { CohereConstants } = require('librechat-data-provider');
-const { titleInstruction } = require('../prompts/titlePrompts');
-
-// Mapping OpenAI roles to Cohere roles
-const roleMap = {
- user: CohereConstants.ROLE_USER,
- assistant: CohereConstants.ROLE_CHATBOT,
- system: CohereConstants.ROLE_SYSTEM, // Recognize and map the system role explicitly
-};
-
-/**
- * Adjusts an OpenAI ChatCompletionPayload to conform with Cohere's expected chat payload format.
- * Now includes handling for "system" roles explicitly mentioned.
- *
- * @param {Object} options - Object containing the model options.
- * @param {ChatCompletionPayload} options.modelOptions - The OpenAI model payload options.
- * @returns {CohereChatStreamRequest} Cohere-compatible chat API payload.
- */
-function createCoherePayload({ modelOptions }) {
- /** @type {string | undefined} */
- let preamble;
- let latestUserMessageContent = '';
- const {
- stream,
- stop,
- top_p,
- temperature,
- frequency_penalty,
- presence_penalty,
- max_tokens,
- messages,
- model,
- ...rest
- } = modelOptions;
-
- // Filter out the latest user message and transform remaining messages to Cohere's chat_history format
- let chatHistory = messages.reduce((acc, message, index, arr) => {
- const isLastUserMessage = index === arr.length - 1 && message.role === 'user';
-
- const messageContent =
- typeof message.content === 'string'
- ? message.content
- : message.content.map((part) => (part.type === 'text' ? part.text : '')).join(' ');
-
- if (isLastUserMessage) {
- latestUserMessageContent = messageContent;
- } else {
- acc.push({
- role: roleMap[message.role] || CohereConstants.ROLE_USER,
- message: messageContent,
- });
- }
-
- return acc;
- }, []);
-
- if (
- chatHistory.length === 1 &&
- chatHistory[0].role === CohereConstants.ROLE_SYSTEM &&
- !latestUserMessageContent.length
- ) {
- const message = chatHistory[0].message;
- latestUserMessageContent = message.includes(titleInstruction)
- ? CohereConstants.TITLE_MESSAGE
- : '.';
- preamble = message;
- }
-
- return {
- message: latestUserMessageContent,
- model: model,
- chatHistory,
- stream: stream ?? false,
- temperature: temperature,
- frequencyPenalty: frequency_penalty,
- presencePenalty: presence_penalty,
- maxTokens: max_tokens,
- stopSequences: stop,
- preamble,
- p: top_p,
- ...rest,
- };
-}
-
-module.exports = createCoherePayload;
diff --git a/api/app/clients/llm/index.js b/api/app/clients/llm/index.js
deleted file mode 100644
index c7770ce103..0000000000
--- a/api/app/clients/llm/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-const createCoherePayload = require('./createCoherePayload');
-
-module.exports = {
- createCoherePayload,
-};
diff --git a/api/app/clients/output_parsers/addImages.js b/api/app/clients/output_parsers/addImages.js
deleted file mode 100644
index f0860ef8bd..0000000000
--- a/api/app/clients/output_parsers/addImages.js
+++ /dev/null
@@ -1,90 +0,0 @@
-const { getBasePath } = require('@librechat/api');
-const { logger } = require('@librechat/data-schemas');
-
-/**
- * The `addImages` function corrects any erroneous image URLs in the `responseMessage.text`
- * and appends image observations from `intermediateSteps` if they are not already present.
- *
- * @function
- * @module addImages
- *
- * @param {Array.} intermediateSteps - An array of objects, each containing an observation.
- * @param {Object} responseMessage - An object containing the text property which might have image URLs.
- *
- * @property {string} intermediateSteps[].observation - The observation string which might contain an image markdown.
- * @property {string} responseMessage.text - The text which might contain image URLs.
- *
- * @example
- *
- * const intermediateSteps = [
- * { observation: '' }
- * ];
- * const responseMessage = { text: 'Some text with ' };
- *
- * addImages(intermediateSteps, responseMessage);
- *
- * logger.debug(responseMessage.text);
- * // Outputs: 'Some text with \n'
- *
- * @returns {void}
- */
-function addImages(intermediateSteps, responseMessage) {
- if (!intermediateSteps || !responseMessage) {
- return;
- }
-
- const basePath = getBasePath();
-
- // Correct any erroneous URLs in the responseMessage.text first
- intermediateSteps.forEach((step) => {
- const { observation } = step;
- if (!observation || !observation.includes('![')) {
- return;
- }
-
- const match = observation.match(/\/images\/.*\.\w*/);
- if (!match) {
- return;
- }
- const essentialImagePath = match[0];
- const fullImagePath = `${basePath}${essentialImagePath}`;
-
- const regex = /!\[.*?\]\((.*?)\)/g;
- let matchErroneous;
- while ((matchErroneous = regex.exec(responseMessage.text)) !== null) {
- if (matchErroneous[1] && !matchErroneous[1].startsWith(`${basePath}/images/`)) {
- // Replace with the full path including base path
- responseMessage.text = responseMessage.text.replace(matchErroneous[1], fullImagePath);
- }
- }
- });
-
- // Now, check if the responseMessage already includes the correct image file path and append if not
- intermediateSteps.forEach((step) => {
- const { observation } = step;
- if (!observation || !observation.includes('![')) {
- return;
- }
- const observedImagePath = observation.match(/!\[[^(]*\]\([^)]*\)/g);
- if (observedImagePath) {
- // Fix the image path to include base path if it doesn't already
- let imageMarkdown = observedImagePath[0];
- const urlMatch = imageMarkdown.match(/\(([^)]+)\)/);
- if (
- urlMatch &&
- urlMatch[1] &&
- !urlMatch[1].startsWith(`${basePath}/images/`) &&
- urlMatch[1].startsWith('/images/')
- ) {
- imageMarkdown = imageMarkdown.replace(urlMatch[1], `${basePath}${urlMatch[1]}`);
- }
-
- if (!responseMessage.text.includes(imageMarkdown)) {
- responseMessage.text += '\n' + imageMarkdown;
- logger.debug('[addImages] added image from intermediateSteps:', imageMarkdown);
- }
- }
- });
-}
-
-module.exports = addImages;
diff --git a/api/app/clients/output_parsers/addImages.spec.js b/api/app/clients/output_parsers/addImages.spec.js
deleted file mode 100644
index ef4dd22c0b..0000000000
--- a/api/app/clients/output_parsers/addImages.spec.js
+++ /dev/null
@@ -1,246 +0,0 @@
-let addImages = require('./addImages');
-
-describe('addImages', () => {
- let intermediateSteps;
- let responseMessage;
- let options;
-
- beforeEach(() => {
- intermediateSteps = [];
- responseMessage = { text: '' };
- options = { debug: false };
- this.options = options;
- addImages = addImages.bind(this);
- });
-
- it('should handle null or undefined parameters', () => {
- addImages(null, responseMessage);
- expect(responseMessage.text).toBe('');
-
- addImages(intermediateSteps, null);
- expect(responseMessage.text).toBe('');
-
- addImages(null, null);
- expect(responseMessage.text).toBe('');
- });
-
- it('should append correct image markdown if not present in responseMessage', () => {
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should not append image markdown if already present in responseMessage', () => {
- responseMessage.text = '';
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('');
- });
-
- it('should correct and append image markdown with erroneous URL', () => {
- responseMessage.text = '';
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('');
- });
-
- it('should correct multiple erroneous URLs in responseMessage', () => {
- responseMessage.text =
- ' ';
- intermediateSteps.push({ observation: '' });
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe(' ');
- });
-
- it('should not append non-image markdown observations', () => {
- intermediateSteps.push({ observation: '[desc](/images/test.png)' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('');
- });
-
- it('should handle multiple observations', () => {
- intermediateSteps.push({ observation: '' });
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n\n');
- });
-
- it('should not append if observation does not contain image markdown', () => {
- intermediateSteps.push({ observation: 'This is a test observation without image markdown.' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('');
- });
-
- it('should append correctly from a real scenario', () => {
- responseMessage.text =
- "Here is the generated image based on your request. It depicts a surreal landscape filled with floating musical notes. The style is impressionistic, with vibrant sunset hues dominating the scene. At the center, there's a silhouette of a grand piano, adding a dreamy emotion to the overall image. This could serve as a unique and creative music album cover. Would you like to make any changes or generate another image?";
- const originalText = responseMessage.text;
- const imageMarkdown = '';
- intermediateSteps.push({ observation: imageMarkdown });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe(`${originalText}\n${imageMarkdown}`);
- });
-
- it('should extract only image markdowns when there is text between them', () => {
- const markdownWithTextBetweenImages = `
- 
- Some text between images that should not be included.
- 
- More text that should be ignored.
- 
- `;
- intermediateSteps.push({ observation: markdownWithTextBetweenImages });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should only return the first image when multiple images are present', () => {
- const markdownWithMultipleImages = `
- 
- 
- 
- `;
- intermediateSteps.push({ observation: markdownWithMultipleImages });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should not include any text or metadata surrounding the image markdown', () => {
- const markdownWithMetadata = `
- Title: Test Document
- Author: John Doe
- 
- Some content after the image.
- Vector values: [0.1, 0.2, 0.3]
- `;
- intermediateSteps.push({ observation: markdownWithMetadata });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should handle complex markdown with multiple images and only return the first one', () => {
- const complexMarkdown = `
- # Document Title
-
- ## Section 1
- Here's some text with an embedded image:
- 
-
- ## Section 2
- More text here...
- 
-
- ### Subsection
- Even more content
- 
- `;
- intermediateSteps.push({ observation: complexMarkdown });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- describe('basePath functionality', () => {
- let originalDomainClient;
-
- beforeEach(() => {
- originalDomainClient = process.env.DOMAIN_CLIENT;
- });
-
- afterEach(() => {
- process.env.DOMAIN_CLIENT = originalDomainClient;
- });
-
- it('should prepend base path to image URLs when DOMAIN_CLIENT is set', () => {
- process.env.DOMAIN_CLIENT = 'http://localhost:3080/librechat';
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should not prepend base path when image URL already has base path', () => {
- process.env.DOMAIN_CLIENT = 'http://localhost:3080/librechat';
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should correct erroneous URLs with base path', () => {
- process.env.DOMAIN_CLIENT = 'http://localhost:3080/librechat';
- responseMessage.text = '';
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('');
- });
-
- it('should handle empty base path (root deployment)', () => {
- process.env.DOMAIN_CLIENT = 'http://localhost:3080/';
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should handle missing DOMAIN_CLIENT', () => {
- delete process.env.DOMAIN_CLIENT;
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should handle observation without image path match', () => {
- process.env.DOMAIN_CLIENT = 'http://localhost:3080/librechat';
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should handle nested subdirectories in base path', () => {
- process.env.DOMAIN_CLIENT = 'http://localhost:3080/apps/librechat';
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should handle multiple observations with mixed base path scenarios', () => {
- process.env.DOMAIN_CLIENT = 'http://localhost:3080/librechat';
- intermediateSteps.push({ observation: '' });
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe(
- '\n\n',
- );
- });
-
- it('should handle complex markdown with base path', () => {
- process.env.DOMAIN_CLIENT = 'http://localhost:3080/librechat';
- const complexMarkdown = `
- # Document Title
- 
- Some text between images
- 
- `;
- intermediateSteps.push({ observation: complexMarkdown });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should handle URLs that are already absolute', () => {
- process.env.DOMAIN_CLIENT = 'http://localhost:3080/librechat';
- intermediateSteps.push({ observation: '' });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe('\n');
- });
-
- it('should handle data URLs', () => {
- process.env.DOMAIN_CLIENT = 'http://localhost:3080/librechat';
- intermediateSteps.push({
- observation:
- '',
- });
- addImages(intermediateSteps, responseMessage);
- expect(responseMessage.text).toBe(
- '\n',
- );
- });
- });
-});
diff --git a/api/app/clients/output_parsers/handleOutputs.js b/api/app/clients/output_parsers/handleOutputs.js
deleted file mode 100644
index b25eaaad80..0000000000
--- a/api/app/clients/output_parsers/handleOutputs.js
+++ /dev/null
@@ -1,88 +0,0 @@
-const { instructions, imageInstructions, errorInstructions } = require('../prompts');
-
-function getActions(actions = [], functionsAgent = false) {
- let output = 'Internal thoughts & actions taken:\n"';
-
- if (actions[0]?.action && functionsAgent) {
- actions = actions.map((step) => ({
- log: `Action: ${step.action?.tool || ''}\nInput: ${
- JSON.stringify(step.action?.toolInput) || ''
- }\nObservation: ${step.observation}`,
- }));
- } else if (actions[0]?.action) {
- actions = actions.map((step) => ({
- log: `${step.action.log}\nObservation: ${step.observation}`,
- }));
- }
-
- actions.forEach((actionObj, index) => {
- output += `${actionObj.log}`;
- if (index < actions.length - 1) {
- output += '\n';
- }
- });
-
- return output + '"';
-}
-
-function buildErrorInput({ message, errorMessage, actions, functionsAgent }) {
- const log = errorMessage.includes('Could not parse LLM output:')
- ? `A formatting error occurred with your response to the human's last message. You didn't follow the formatting instructions. Remember to ${instructions}`
- : `You encountered an error while replying to the human's last message. Attempt to answer again or admit an answer cannot be given.\nError: ${errorMessage}`;
-
- return `
- ${log}
-
- ${getActions(actions, functionsAgent)}
-
- Human's last message: ${message}
- `;
-}
-
-function buildPromptPrefix({ result, message, functionsAgent }) {
- if ((result.output && result.output.includes('N/A')) || result.output === undefined) {
- return null;
- }
-
- if (
- result?.intermediateSteps?.length === 1 &&
- result?.intermediateSteps[0]?.action?.toolInput === 'N/A'
- ) {
- return null;
- }
-
- const internalActions =
- result?.intermediateSteps?.length > 0
- ? getActions(result.intermediateSteps, functionsAgent)
- : 'Internal Actions Taken: None';
-
- const toolBasedInstructions = internalActions.toLowerCase().includes('image')
- ? imageInstructions
- : '';
-
- const errorMessage = result.errorMessage ? `${errorInstructions} ${result.errorMessage}\n` : '';
-
- const preliminaryAnswer =
- result.output?.length > 0 ? `Preliminary Answer: "${result.output.trim()}"` : '';
- const prefix = preliminaryAnswer
- ? 'review and improve the answer you generated using plugins in response to the User Message below. The user hasn\'t seen your answer or thoughts yet.'
- : 'respond to the User Message below based on your preliminary thoughts & actions.';
-
- return `As a helpful AI Assistant, ${prefix}${errorMessage}\n${internalActions}
-${preliminaryAnswer}
-Reply conversationally to the User based on your ${
- preliminaryAnswer ? 'preliminary answer, ' : ''
-}internal actions, thoughts, and observations, making improvements wherever possible, but do not modify URLs.
-${
- preliminaryAnswer
- ? ''
- : '\nIf there is an incomplete thought or action, you are expected to complete it in your response now.\n'
-}You must cite sources if you are using any web links. ${toolBasedInstructions}
-Only respond with your conversational reply to the following User Message:
-"${message}"`;
-}
-
-module.exports = {
- buildErrorInput,
- buildPromptPrefix,
-};
diff --git a/api/app/clients/output_parsers/index.js b/api/app/clients/output_parsers/index.js
deleted file mode 100644
index 4c176ade49..0000000000
--- a/api/app/clients/output_parsers/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const addImages = require('./addImages');
-const handleOutputs = require('./handleOutputs');
-
-module.exports = {
- addImages,
- ...handleOutputs,
-};
diff --git a/api/app/clients/prompts/handleInputs.js b/api/app/clients/prompts/handleInputs.js
deleted file mode 100644
index 1a193e058f..0000000000
--- a/api/app/clients/prompts/handleInputs.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// Escaping curly braces is necessary for LangChain to correctly process the prompt
-function escapeBraces(str) {
- return str
- .replace(/({{2,})|(}{2,})/g, (match) => `${match[0]}`)
- .replace(/{|}/g, (match) => `${match}${match}`);
-}
-
-function getSnippet(text) {
- let limit = 50;
- let splitText = escapeBraces(text).split(' ');
-
- if (splitText.length === 1 && splitText[0].length > limit) {
- return splitText[0].substring(0, limit);
- }
-
- let result = '';
- let spaceCount = 0;
-
- for (let i = 0; i < splitText.length; i++) {
- if (result.length + splitText[i].length <= limit) {
- result += splitText[i] + ' ';
- spaceCount++;
- } else {
- break;
- }
-
- if (spaceCount == 10) {
- break;
- }
- }
-
- return result.trim();
-}
-
-module.exports = {
- escapeBraces,
- getSnippet,
-};
diff --git a/api/app/clients/prompts/index.js b/api/app/clients/prompts/index.js
index a8392348b5..ba4859efe3 100644
--- a/api/app/clients/prompts/index.js
+++ b/api/app/clients/prompts/index.js
@@ -1,7 +1,5 @@
const formatMessages = require('./formatMessages');
const summaryPrompts = require('./summaryPrompts');
-const handleInputs = require('./handleInputs');
-const instructions = require('./instructions');
const truncate = require('./truncate');
const createVisionPrompt = require('./createVisionPrompt');
const createContextHandlers = require('./createContextHandlers');
@@ -9,8 +7,6 @@ const createContextHandlers = require('./createContextHandlers');
module.exports = {
...formatMessages,
...summaryPrompts,
- ...handleInputs,
- ...instructions,
...truncate,
createVisionPrompt,
createContextHandlers,
diff --git a/api/app/clients/prompts/instructions.js b/api/app/clients/prompts/instructions.js
deleted file mode 100644
index c630711771..0000000000
--- a/api/app/clients/prompts/instructions.js
+++ /dev/null
@@ -1,10 +0,0 @@
-module.exports = {
- instructions:
- 'Remember, all your responses MUST be in the format described. Do not respond unless it\'s in the format described, using the structure of Action, Action Input, etc.',
- errorInstructions:
- '\nYou encountered an error in attempting a response. The user is not aware of the error so you shouldn\'t mention it.\nReview the actions taken carefully in case there is a partial or complete answer within them.\nError Message:',
- imageInstructions:
- 'You must include the exact image paths from above, formatted in Markdown syntax: ',
- completionInstructions:
- 'Instructions:\nYou are ChatGPT, a large language model trained by OpenAI. Respond conversationally.\nCurrent date:',
-};
diff --git a/api/app/clients/prompts/shadcn-docs/generate.js b/api/app/clients/prompts/shadcn-docs/generate.js
index 6cb56f1077..6a4cf8c7e3 100644
--- a/api/app/clients/prompts/shadcn-docs/generate.js
+++ b/api/app/clients/prompts/shadcn-docs/generate.js
@@ -18,17 +18,17 @@ function generateShadcnPrompt(options) {
Here are the components that are available, along with how to import them, and how to use them:
${Object.values(components)
- .map((component) => {
- if (useXML) {
- return dedent`
+ .map((component) => {
+ if (useXML) {
+ return dedent`
${component.componentName}
${component.importDocs}
${component.usageDocs}
`;
- } else {
- return dedent`
+ } else {
+ return dedent`
# ${component.componentName}
## Import Instructions
@@ -37,9 +37,9 @@ function generateShadcnPrompt(options) {
## Usage Instructions
${component.usageDocs}
`;
- }
- })
- .join('\n\n')}
+ }
+ })
+ .join('\n\n')}
`;
return systemPrompt;
diff --git a/api/app/clients/specs/AnthropicClient.test.js b/api/app/clients/specs/AnthropicClient.test.js
deleted file mode 100644
index 35477005fb..0000000000
--- a/api/app/clients/specs/AnthropicClient.test.js
+++ /dev/null
@@ -1,1043 +0,0 @@
-const { SplitStreamHandler } = require('@librechat/agents');
-const { anthropicSettings } = require('librechat-data-provider');
-const AnthropicClient = require('~/app/clients/AnthropicClient');
-
-const HUMAN_PROMPT = '\n\nHuman:';
-const AI_PROMPT = '\n\nAssistant:';
-
-describe('AnthropicClient', () => {
- let client;
- const model = 'claude-2';
- const parentMessageId = '1';
- const messages = [
- { role: 'user', isCreatedByUser: true, text: 'Hello', messageId: parentMessageId },
- { role: 'assistant', isCreatedByUser: false, text: 'Hi', messageId: '2', parentMessageId },
- {
- role: 'user',
- isCreatedByUser: true,
- text: "What's up",
- messageId: '3',
- parentMessageId: '2',
- },
- ];
-
- beforeEach(() => {
- const options = {
- modelOptions: {
- model,
- temperature: anthropicSettings.temperature.default,
- },
- };
- client = new AnthropicClient('test-api-key');
- client.setOptions(options);
- });
-
- describe('setOptions', () => {
- it('should set the options correctly', () => {
- expect(client.apiKey).toBe('test-api-key');
- expect(client.modelOptions.model).toBe(model);
- expect(client.modelOptions.temperature).toBe(anthropicSettings.temperature.default);
- });
-
- it('should set legacy maxOutputTokens for non-Claude-3 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-2',
- maxOutputTokens: anthropicSettings.maxOutputTokens.default,
- },
- });
- expect(client.modelOptions.maxOutputTokens).toBe(
- anthropicSettings.legacy.maxOutputTokens.default,
- );
- });
- it('should not set maxOutputTokens if not provided', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-3',
- },
- });
- expect(client.modelOptions.maxOutputTokens).toBeUndefined();
- });
-
- it('should not set legacy maxOutputTokens for Claude-3 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-3-opus-20240229',
- maxOutputTokens: anthropicSettings.legacy.maxOutputTokens.default,
- },
- });
- expect(client.modelOptions.maxOutputTokens).toBe(
- anthropicSettings.legacy.maxOutputTokens.default,
- );
- });
- });
-
- describe('getSaveOptions', () => {
- it('should return the correct save options', () => {
- const options = client.getSaveOptions();
- expect(options).toHaveProperty('modelLabel');
- expect(options).toHaveProperty('promptPrefix');
- });
- });
-
- describe('buildMessages', () => {
- it('should handle promptPrefix from options when promptPrefix argument is not provided', async () => {
- client.options.promptPrefix = 'Test Prefix from options';
- const result = await client.buildMessages(messages, parentMessageId);
- const { prompt } = result;
- expect(prompt).toContain('Test Prefix from options');
- });
-
- it('should build messages correctly for chat completion', async () => {
- const result = await client.buildMessages(messages, '2');
- expect(result).toHaveProperty('prompt');
- expect(result.prompt).toContain(HUMAN_PROMPT);
- expect(result.prompt).toContain('Hello');
- expect(result.prompt).toContain(AI_PROMPT);
- expect(result.prompt).toContain('Hi');
- });
-
- it('should group messages by the same author', async () => {
- const groupedMessages = messages.map((m) => ({ ...m, isCreatedByUser: true, role: 'user' }));
- const result = await client.buildMessages(groupedMessages, '3');
- expect(result.context).toHaveLength(1);
-
- // Check that HUMAN_PROMPT appears only once in the prompt
- const matches = result.prompt.match(new RegExp(HUMAN_PROMPT, 'g'));
- expect(matches).toHaveLength(1);
-
- groupedMessages.push({
- role: 'assistant',
- isCreatedByUser: false,
- text: 'I heard you the first time',
- messageId: '4',
- parentMessageId: '3',
- });
-
- const result2 = await client.buildMessages(groupedMessages, '4');
- expect(result2.context).toHaveLength(2);
-
- // Check that HUMAN_PROMPT appears only once in the prompt
- const human_matches = result2.prompt.match(new RegExp(HUMAN_PROMPT, 'g'));
- const ai_matches = result2.prompt.match(new RegExp(AI_PROMPT, 'g'));
- expect(human_matches).toHaveLength(1);
- expect(ai_matches).toHaveLength(1);
- });
-
- it('should handle isEdited condition', async () => {
- const editedMessages = [
- { role: 'user', isCreatedByUser: true, text: 'Hello', messageId: '1' },
- { role: 'assistant', isCreatedByUser: false, text: 'Hi', messageId: '2', parentMessageId },
- ];
-
- const trimmedLabel = AI_PROMPT.trim();
- const result = await client.buildMessages(editedMessages, '2');
- expect(result.prompt.trim().endsWith(trimmedLabel)).toBeFalsy();
-
- // Add a human message at the end to test the opposite
- editedMessages.push({
- role: 'user',
- isCreatedByUser: true,
- text: 'Hi again',
- messageId: '3',
- parentMessageId: '2',
- });
- const result2 = await client.buildMessages(editedMessages, '3');
- expect(result2.prompt.trim().endsWith(trimmedLabel)).toBeTruthy();
- });
-
- it('should build messages correctly with a promptPrefix', async () => {
- const promptPrefix = 'Test Prefix';
- client.options.promptPrefix = promptPrefix;
- const result = await client.buildMessages(messages, parentMessageId);
- const { prompt } = result;
- expect(prompt).toBeDefined();
- expect(prompt).toContain(promptPrefix);
- const textAfterPrefix = prompt.split(promptPrefix)[1];
- expect(textAfterPrefix).toContain(AI_PROMPT);
-
- const editedMessages = messages.slice(0, -1);
- const result2 = await client.buildMessages(editedMessages, parentMessageId);
- const textAfterPrefix2 = result2.prompt.split(promptPrefix)[1];
- expect(textAfterPrefix2).toContain(AI_PROMPT);
- });
-
- it('should handle identityPrefix from options', async () => {
- client.options.userLabel = 'John';
- client.options.modelLabel = 'Claude-2';
- const result = await client.buildMessages(messages, parentMessageId);
- const { prompt } = result;
- expect(prompt).toContain("Human's name: John");
- expect(prompt).toContain('You are Claude-2');
- });
- });
-
- describe('getClient', () => {
- it('should set legacy maxOutputTokens for non-Claude-3 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-2',
- maxOutputTokens: anthropicSettings.legacy.maxOutputTokens.default,
- },
- });
- expect(client.modelOptions.maxOutputTokens).toBe(
- anthropicSettings.legacy.maxOutputTokens.default,
- );
- });
-
- it('should not set legacy maxOutputTokens for Claude-3 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-3-opus-20240229',
- maxOutputTokens: anthropicSettings.legacy.maxOutputTokens.default,
- },
- });
- expect(client.modelOptions.maxOutputTokens).toBe(
- anthropicSettings.legacy.maxOutputTokens.default,
- );
- });
-
- it('should add "max-tokens" & "prompt-caching" beta header for claude-3-5-sonnet model', () => {
- const client = new AnthropicClient('test-api-key');
- const modelOptions = {
- model: 'claude-3-5-sonnet-20241022',
- };
- client.setOptions({ modelOptions, promptCache: true });
- const anthropicClient = client.getClient(modelOptions);
- expect(anthropicClient._options.defaultHeaders).toBeDefined();
- expect(anthropicClient._options.defaultHeaders).toHaveProperty('anthropic-beta');
- expect(anthropicClient._options.defaultHeaders['anthropic-beta']).toBe(
- 'max-tokens-3-5-sonnet-2024-07-15,prompt-caching-2024-07-31',
- );
- });
-
- it('should add "prompt-caching" beta header for claude-3-haiku model', () => {
- const client = new AnthropicClient('test-api-key');
- const modelOptions = {
- model: 'claude-3-haiku-2028',
- };
- client.setOptions({ modelOptions, promptCache: true });
- const anthropicClient = client.getClient(modelOptions);
- expect(anthropicClient._options.defaultHeaders).toBeDefined();
- expect(anthropicClient._options.defaultHeaders).toHaveProperty('anthropic-beta');
- expect(anthropicClient._options.defaultHeaders['anthropic-beta']).toBe(
- 'prompt-caching-2024-07-31',
- );
- });
-
- it('should add "prompt-caching" beta header for claude-3-opus model', () => {
- const client = new AnthropicClient('test-api-key');
- const modelOptions = {
- model: 'claude-3-opus-2028',
- };
- client.setOptions({ modelOptions, promptCache: true });
- const anthropicClient = client.getClient(modelOptions);
- expect(anthropicClient._options.defaultHeaders).toBeDefined();
- expect(anthropicClient._options.defaultHeaders).toHaveProperty('anthropic-beta');
- expect(anthropicClient._options.defaultHeaders['anthropic-beta']).toBe(
- 'prompt-caching-2024-07-31',
- );
- });
-
- describe('Claude 4 model headers', () => {
- it('should add "prompt-caching" and "context-1m" beta headers for claude-sonnet-4 model', () => {
- const client = new AnthropicClient('test-api-key');
- const modelOptions = {
- model: 'claude-sonnet-4-20250514',
- };
- client.setOptions({ modelOptions, promptCache: true });
- const anthropicClient = client.getClient(modelOptions);
- expect(anthropicClient._options.defaultHeaders).toBeDefined();
- expect(anthropicClient._options.defaultHeaders).toHaveProperty('anthropic-beta');
- expect(anthropicClient._options.defaultHeaders['anthropic-beta']).toBe(
- 'prompt-caching-2024-07-31,context-1m-2025-08-07',
- );
- });
-
- it('should add "prompt-caching" and "context-1m" beta headers for claude-sonnet-4 model formats', () => {
- const client = new AnthropicClient('test-api-key');
- const modelVariations = [
- 'claude-sonnet-4-20250514',
- 'claude-sonnet-4-latest',
- 'anthropic/claude-sonnet-4-20250514',
- ];
-
- modelVariations.forEach((model) => {
- const modelOptions = { model };
- client.setOptions({ modelOptions, promptCache: true });
- const anthropicClient = client.getClient(modelOptions);
- expect(anthropicClient._options.defaultHeaders).toBeDefined();
- expect(anthropicClient._options.defaultHeaders).toHaveProperty('anthropic-beta');
- expect(anthropicClient._options.defaultHeaders['anthropic-beta']).toBe(
- 'prompt-caching-2024-07-31,context-1m-2025-08-07',
- );
- });
- });
-
- it('should add "prompt-caching" beta header for claude-opus-4 model', () => {
- const client = new AnthropicClient('test-api-key');
- const modelOptions = {
- model: 'claude-opus-4-20250514',
- };
- client.setOptions({ modelOptions, promptCache: true });
- const anthropicClient = client.getClient(modelOptions);
- expect(anthropicClient._options.defaultHeaders).toBeDefined();
- expect(anthropicClient._options.defaultHeaders).toHaveProperty('anthropic-beta');
- expect(anthropicClient._options.defaultHeaders['anthropic-beta']).toBe(
- 'prompt-caching-2024-07-31',
- );
- });
-
- it('should add "prompt-caching" beta header for claude-4-opus model', () => {
- const client = new AnthropicClient('test-api-key');
- const modelOptions = {
- model: 'claude-4-opus-20250514',
- };
- client.setOptions({ modelOptions, promptCache: true });
- const anthropicClient = client.getClient(modelOptions);
- expect(anthropicClient._options.defaultHeaders).toBeDefined();
- expect(anthropicClient._options.defaultHeaders).toHaveProperty('anthropic-beta');
- expect(anthropicClient._options.defaultHeaders['anthropic-beta']).toBe(
- 'prompt-caching-2024-07-31',
- );
- });
- });
-
- it('should not add beta header for claude-3-5-sonnet-latest model', () => {
- const client = new AnthropicClient('test-api-key');
- const modelOptions = {
- model: 'anthropic/claude-3-5-sonnet-latest',
- };
- client.setOptions({ modelOptions, promptCache: true });
- const anthropicClient = client.getClient(modelOptions);
- expect(anthropicClient._options.defaultHeaders).toBeUndefined();
- });
-
- it('should not add beta header for other models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-2',
- },
- });
- const anthropicClient = client.getClient();
- expect(anthropicClient._options.defaultHeaders).toBeUndefined();
- });
- });
-
- describe('calculateCurrentTokenCount', () => {
- let client;
-
- beforeEach(() => {
- client = new AnthropicClient('test-api-key');
- });
-
- it('should calculate correct token count when usage is provided', () => {
- const tokenCountMap = {
- msg1: 10,
- msg2: 20,
- currentMsg: 30,
- };
- const currentMessageId = 'currentMsg';
- const usage = {
- input_tokens: 70,
- output_tokens: 50,
- };
-
- const result = client.calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage });
-
- expect(result).toBe(40); // 70 - (10 + 20) = 40
- });
-
- it('should return original estimate if calculation results in negative value', () => {
- const tokenCountMap = {
- msg1: 40,
- msg2: 50,
- currentMsg: 30,
- };
- const currentMessageId = 'currentMsg';
- const usage = {
- input_tokens: 80,
- output_tokens: 50,
- };
-
- const result = client.calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage });
-
- expect(result).toBe(30); // Original estimate
- });
-
- it('should handle cache creation and read input tokens', () => {
- const tokenCountMap = {
- msg1: 10,
- msg2: 20,
- currentMsg: 30,
- };
- const currentMessageId = 'currentMsg';
- const usage = {
- input_tokens: 50,
- cache_creation_input_tokens: 10,
- cache_read_input_tokens: 20,
- output_tokens: 40,
- };
-
- const result = client.calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage });
-
- expect(result).toBe(50); // (50 + 10 + 20) - (10 + 20) = 50
- });
-
- it('should handle missing usage properties', () => {
- const tokenCountMap = {
- msg1: 10,
- msg2: 20,
- currentMsg: 30,
- };
- const currentMessageId = 'currentMsg';
- const usage = {
- output_tokens: 40,
- };
-
- const result = client.calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage });
-
- expect(result).toBe(30); // Original estimate
- });
-
- it('should handle empty tokenCountMap', () => {
- const tokenCountMap = {};
- const currentMessageId = 'currentMsg';
- const usage = {
- input_tokens: 50,
- output_tokens: 40,
- };
-
- const result = client.calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage });
-
- expect(result).toBe(50);
- expect(Number.isNaN(result)).toBe(false);
- });
-
- it('should handle zero values in usage', () => {
- const tokenCountMap = {
- msg1: 10,
- currentMsg: 20,
- };
- const currentMessageId = 'currentMsg';
- const usage = {
- input_tokens: 0,
- cache_creation_input_tokens: 0,
- cache_read_input_tokens: 0,
- output_tokens: 0,
- };
-
- const result = client.calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage });
-
- expect(result).toBe(20); // Should return original estimate
- expect(Number.isNaN(result)).toBe(false);
- });
-
- it('should handle undefined usage', () => {
- const tokenCountMap = {
- msg1: 10,
- currentMsg: 20,
- };
- const currentMessageId = 'currentMsg';
- const usage = undefined;
-
- const result = client.calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage });
-
- expect(result).toBe(20); // Should return original estimate
- expect(Number.isNaN(result)).toBe(false);
- });
-
- it('should handle non-numeric values in tokenCountMap', () => {
- const tokenCountMap = {
- msg1: 'ten',
- currentMsg: 20,
- };
- const currentMessageId = 'currentMsg';
- const usage = {
- input_tokens: 30,
- output_tokens: 10,
- };
-
- const result = client.calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage });
-
- expect(result).toBe(30); // Should return 30 (input_tokens) - 0 (ignored 'ten') = 30
- expect(Number.isNaN(result)).toBe(false);
- });
- });
-
- describe('maxOutputTokens handling for different models', () => {
- it('should not cap maxOutputTokens for Claude 3.5 Sonnet models', () => {
- const client = new AnthropicClient('test-api-key');
- const highTokenValue = anthropicSettings.legacy.maxOutputTokens.default * 10;
-
- client.setOptions({
- modelOptions: {
- model: 'claude-3-5-sonnet',
- maxOutputTokens: highTokenValue,
- },
- });
-
- expect(client.modelOptions.maxOutputTokens).toBe(highTokenValue);
-
- // Test with decimal notation
- client.setOptions({
- modelOptions: {
- model: 'claude-3.5-sonnet',
- maxOutputTokens: highTokenValue,
- },
- });
-
- expect(client.modelOptions.maxOutputTokens).toBe(highTokenValue);
- });
-
- it('should not cap maxOutputTokens for Claude 3.7 models', () => {
- const client = new AnthropicClient('test-api-key');
- const highTokenValue = anthropicSettings.legacy.maxOutputTokens.default * 2;
-
- client.setOptions({
- modelOptions: {
- model: 'claude-3-7-sonnet',
- maxOutputTokens: highTokenValue,
- },
- });
-
- expect(client.modelOptions.maxOutputTokens).toBe(highTokenValue);
-
- // Test with decimal notation
- client.setOptions({
- modelOptions: {
- model: 'claude-3.7-sonnet',
- maxOutputTokens: highTokenValue,
- },
- });
-
- expect(client.modelOptions.maxOutputTokens).toBe(highTokenValue);
- });
-
- it('should not cap maxOutputTokens for Claude 4 Sonnet models', () => {
- const client = new AnthropicClient('test-api-key');
- const highTokenValue = anthropicSettings.legacy.maxOutputTokens.default * 10; // 40,960 tokens
-
- client.setOptions({
- modelOptions: {
- model: 'claude-sonnet-4-20250514',
- maxOutputTokens: highTokenValue,
- },
- });
-
- expect(client.modelOptions.maxOutputTokens).toBe(highTokenValue);
- });
-
- it('should not cap maxOutputTokens for Claude 4 Opus models', () => {
- const client = new AnthropicClient('test-api-key');
- const highTokenValue = anthropicSettings.legacy.maxOutputTokens.default * 6; // 24,576 tokens (under 32K limit)
-
- client.setOptions({
- modelOptions: {
- model: 'claude-opus-4-20250514',
- maxOutputTokens: highTokenValue,
- },
- });
-
- expect(client.modelOptions.maxOutputTokens).toBe(highTokenValue);
- });
-
- it('should cap maxOutputTokens for Claude 3.5 Haiku models', () => {
- const client = new AnthropicClient('test-api-key');
- const highTokenValue = anthropicSettings.legacy.maxOutputTokens.default * 2;
-
- client.setOptions({
- modelOptions: {
- model: 'claude-3-5-haiku',
- maxOutputTokens: highTokenValue,
- },
- });
-
- expect(client.modelOptions.maxOutputTokens).toBe(
- anthropicSettings.legacy.maxOutputTokens.default,
- );
-
- // Test with decimal notation
- client.setOptions({
- modelOptions: {
- model: 'claude-3.5-haiku',
- maxOutputTokens: highTokenValue,
- },
- });
-
- expect(client.modelOptions.maxOutputTokens).toBe(
- anthropicSettings.legacy.maxOutputTokens.default,
- );
- });
-
- it('should cap maxOutputTokens for Claude 3 Haiku and Opus models', () => {
- const client = new AnthropicClient('test-api-key');
- const highTokenValue = anthropicSettings.legacy.maxOutputTokens.default * 2;
-
- // Test haiku
- client.setOptions({
- modelOptions: {
- model: 'claude-3-haiku',
- maxOutputTokens: highTokenValue,
- },
- });
-
- expect(client.modelOptions.maxOutputTokens).toBe(
- anthropicSettings.legacy.maxOutputTokens.default,
- );
-
- // Test opus
- client.setOptions({
- modelOptions: {
- model: 'claude-3-opus',
- maxOutputTokens: highTokenValue,
- },
- });
-
- expect(client.modelOptions.maxOutputTokens).toBe(
- anthropicSettings.legacy.maxOutputTokens.default,
- );
- });
- });
-
- describe('topK/topP parameters for different models', () => {
- beforeEach(() => {
- // Mock the SplitStreamHandler
- jest.spyOn(SplitStreamHandler.prototype, 'handle').mockImplementation(() => {});
- });
-
- afterEach(() => {
- jest.restoreAllMocks();
- });
-
- it('should include top_k and top_p parameters for non-claude-3.7 models', async () => {
- const client = new AnthropicClient('test-api-key');
-
- // Create a mock async generator function
- async function* mockAsyncGenerator() {
- yield { type: 'message_start', message: { usage: {} } };
- yield { delta: { text: 'Test response' } };
- yield { type: 'message_delta', usage: {} };
- }
-
- // Mock createResponse to return the async generator
- jest.spyOn(client, 'createResponse').mockImplementation(() => {
- return mockAsyncGenerator();
- });
-
- client.setOptions({
- modelOptions: {
- model: 'claude-3-opus',
- temperature: 0.7,
- topK: 10,
- topP: 0.9,
- },
- });
-
- // Mock getClient to capture the request options
- let capturedOptions = null;
- jest.spyOn(client, 'getClient').mockImplementation((options) => {
- capturedOptions = options;
- return {};
- });
-
- const payload = [{ role: 'user', content: 'Test message' }];
- await client.sendCompletion(payload, {});
-
- // Check the options passed to getClient
- expect(capturedOptions).toHaveProperty('top_k', 10);
- expect(capturedOptions).toHaveProperty('top_p', 0.9);
- });
-
- it('should include top_k and top_p parameters for claude-3-5-sonnet models', async () => {
- const client = new AnthropicClient('test-api-key');
-
- // Create a mock async generator function
- async function* mockAsyncGenerator() {
- yield { type: 'message_start', message: { usage: {} } };
- yield { delta: { text: 'Test response' } };
- yield { type: 'message_delta', usage: {} };
- }
-
- // Mock createResponse to return the async generator
- jest.spyOn(client, 'createResponse').mockImplementation(() => {
- return mockAsyncGenerator();
- });
-
- client.setOptions({
- modelOptions: {
- model: 'claude-3-5-sonnet',
- temperature: 0.7,
- topK: 10,
- topP: 0.9,
- },
- });
-
- // Mock getClient to capture the request options
- let capturedOptions = null;
- jest.spyOn(client, 'getClient').mockImplementation((options) => {
- capturedOptions = options;
- return {};
- });
-
- const payload = [{ role: 'user', content: 'Test message' }];
- await client.sendCompletion(payload, {});
-
- // Check the options passed to getClient
- expect(capturedOptions).toHaveProperty('top_k', 10);
- expect(capturedOptions).toHaveProperty('top_p', 0.9);
- });
-
- it('should not include top_k and top_p parameters for claude-3-7-sonnet models', async () => {
- const client = new AnthropicClient('test-api-key');
-
- // Create a mock async generator function
- async function* mockAsyncGenerator() {
- yield { type: 'message_start', message: { usage: {} } };
- yield { delta: { text: 'Test response' } };
- yield { type: 'message_delta', usage: {} };
- }
-
- // Mock createResponse to return the async generator
- jest.spyOn(client, 'createResponse').mockImplementation(() => {
- return mockAsyncGenerator();
- });
-
- client.setOptions({
- modelOptions: {
- model: 'claude-3-7-sonnet',
- temperature: 0.7,
- topK: 10,
- topP: 0.9,
- },
- });
-
- // Mock getClient to capture the request options
- let capturedOptions = null;
- jest.spyOn(client, 'getClient').mockImplementation((options) => {
- capturedOptions = options;
- return {};
- });
-
- const payload = [{ role: 'user', content: 'Test message' }];
- await client.sendCompletion(payload, {});
-
- // Check the options passed to getClient
- expect(capturedOptions).not.toHaveProperty('top_k');
- expect(capturedOptions).not.toHaveProperty('top_p');
- });
-
- it('should not include top_k and top_p parameters for models with decimal notation (claude-3.7)', async () => {
- const client = new AnthropicClient('test-api-key');
-
- // Create a mock async generator function
- async function* mockAsyncGenerator() {
- yield { type: 'message_start', message: { usage: {} } };
- yield { delta: { text: 'Test response' } };
- yield { type: 'message_delta', usage: {} };
- }
-
- // Mock createResponse to return the async generator
- jest.spyOn(client, 'createResponse').mockImplementation(() => {
- return mockAsyncGenerator();
- });
-
- client.setOptions({
- modelOptions: {
- model: 'claude-3.7-sonnet',
- temperature: 0.7,
- topK: 10,
- topP: 0.9,
- },
- });
-
- // Mock getClient to capture the request options
- let capturedOptions = null;
- jest.spyOn(client, 'getClient').mockImplementation((options) => {
- capturedOptions = options;
- return {};
- });
-
- const payload = [{ role: 'user', content: 'Test message' }];
- await client.sendCompletion(payload, {});
-
- // Check the options passed to getClient
- expect(capturedOptions).not.toHaveProperty('top_k');
- expect(capturedOptions).not.toHaveProperty('top_p');
- });
- });
-
- it('should include top_k and top_p parameters for Claude-3.7 models when thinking is explicitly disabled', async () => {
- const client = new AnthropicClient('test-api-key', {
- modelOptions: {
- model: 'claude-3-7-sonnet',
- temperature: 0.7,
- topK: 10,
- topP: 0.9,
- },
- thinking: false,
- });
-
- async function* mockAsyncGenerator() {
- yield { type: 'message_start', message: { usage: {} } };
- yield { delta: { text: 'Test response' } };
- yield { type: 'message_delta', usage: {} };
- }
-
- jest.spyOn(client, 'createResponse').mockImplementation(() => {
- return mockAsyncGenerator();
- });
-
- let capturedOptions = null;
- jest.spyOn(client, 'getClient').mockImplementation((options) => {
- capturedOptions = options;
- return {};
- });
-
- const payload = [{ role: 'user', content: 'Test message' }];
- await client.sendCompletion(payload, {});
-
- expect(capturedOptions).toHaveProperty('topK', 10);
- expect(capturedOptions).toHaveProperty('topP', 0.9);
-
- client.setOptions({
- modelOptions: {
- model: 'claude-3.7-sonnet',
- temperature: 0.7,
- topK: 10,
- topP: 0.9,
- },
- thinking: false,
- });
-
- await client.sendCompletion(payload, {});
-
- expect(capturedOptions).toHaveProperty('topK', 10);
- expect(capturedOptions).toHaveProperty('topP', 0.9);
- });
-
- describe('isClaudeLatest', () => {
- it('should set isClaudeLatest to true for claude-3 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-3-sonnet-20240229',
- },
- });
- expect(client.isClaudeLatest).toBe(true);
- });
-
- it('should set isClaudeLatest to true for claude-3.5 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-3.5-sonnet-20240229',
- },
- });
- expect(client.isClaudeLatest).toBe(true);
- });
-
- it('should set isClaudeLatest to true for claude-sonnet-4 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-sonnet-4-20240229',
- },
- });
- expect(client.isClaudeLatest).toBe(true);
- });
-
- it('should set isClaudeLatest to true for claude-opus-4 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-opus-4-20240229',
- },
- });
- expect(client.isClaudeLatest).toBe(true);
- });
-
- it('should set isClaudeLatest to true for claude-3.5-haiku models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-3.5-haiku-20240229',
- },
- });
- expect(client.isClaudeLatest).toBe(true);
- });
-
- it('should set isClaudeLatest to false for claude-2 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-2',
- },
- });
- expect(client.isClaudeLatest).toBe(false);
- });
-
- it('should set isClaudeLatest to false for claude-instant models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-instant',
- },
- });
- expect(client.isClaudeLatest).toBe(false);
- });
-
- it('should set isClaudeLatest to false for claude-sonnet-3 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-sonnet-3-20240229',
- },
- });
- expect(client.isClaudeLatest).toBe(false);
- });
-
- it('should set isClaudeLatest to false for claude-opus-3 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-opus-3-20240229',
- },
- });
- expect(client.isClaudeLatest).toBe(false);
- });
-
- it('should set isClaudeLatest to false for claude-haiku-3 models', () => {
- const client = new AnthropicClient('test-api-key');
- client.setOptions({
- modelOptions: {
- model: 'claude-haiku-3-20240229',
- },
- });
- expect(client.isClaudeLatest).toBe(false);
- });
- });
-
- describe('configureReasoning', () => {
- it('should enable thinking for claude-opus-4 and claude-sonnet-4 models', async () => {
- const client = new AnthropicClient('test-api-key');
- // Create a mock async generator function
- async function* mockAsyncGenerator() {
- yield { type: 'message_start', message: { usage: {} } };
- yield { delta: { text: 'Test response' } };
- yield { type: 'message_delta', usage: {} };
- }
-
- // Mock createResponse to return the async generator
- jest.spyOn(client, 'createResponse').mockImplementation(() => {
- return mockAsyncGenerator();
- });
-
- // Test claude-opus-4
- client.setOptions({
- modelOptions: {
- model: 'claude-opus-4-20250514',
- },
- thinking: true,
- thinkingBudget: 2000,
- });
-
- let capturedOptions = null;
- jest.spyOn(client, 'getClient').mockImplementation((options) => {
- capturedOptions = options;
- return {};
- });
-
- const payload = [{ role: 'user', content: 'Test message' }];
- await client.sendCompletion(payload, {});
-
- expect(capturedOptions).toHaveProperty('thinking');
- expect(capturedOptions.thinking).toEqual({
- type: 'enabled',
- budget_tokens: 2000,
- });
-
- // Test claude-sonnet-4
- client.setOptions({
- modelOptions: {
- model: 'claude-sonnet-4-20250514',
- },
- thinking: true,
- thinkingBudget: 2000,
- });
-
- await client.sendCompletion(payload, {});
-
- expect(capturedOptions).toHaveProperty('thinking');
- expect(capturedOptions.thinking).toEqual({
- type: 'enabled',
- budget_tokens: 2000,
- });
- });
- });
-});
-
-describe('Claude Model Tests', () => {
- it('should handle Claude 3 and 4 series models correctly', () => {
- const client = new AnthropicClient('test-key');
- // Claude 3 series models
- const claude3Models = [
- 'claude-3-opus-20240229',
- 'claude-3-sonnet-20240229',
- 'claude-3-haiku-20240307',
- 'claude-3-5-sonnet-20240620',
- 'claude-3-5-haiku-20240620',
- 'claude-3.5-sonnet-20240620',
- 'claude-3.5-haiku-20240620',
- 'claude-3.7-sonnet-20240620',
- 'claude-3.7-haiku-20240620',
- 'anthropic/claude-3-opus-20240229',
- 'claude-3-opus-20240229/anthropic',
- ];
-
- // Claude 4 series models
- const claude4Models = [
- 'claude-sonnet-4-20250514',
- 'claude-opus-4-20250514',
- 'claude-4-sonnet-20250514',
- 'claude-4-opus-20250514',
- 'anthropic/claude-sonnet-4-20250514',
- 'claude-sonnet-4-20250514/anthropic',
- ];
-
- // Test Claude 3 series
- claude3Models.forEach((model) => {
- client.setOptions({ modelOptions: { model } });
- expect(
- /claude-[3-9]/.test(client.modelOptions.model) ||
- /claude-(?:sonnet|opus|haiku)-[4-9]/.test(client.modelOptions.model),
- ).toBe(true);
- });
-
- // Test Claude 4 series
- claude4Models.forEach((model) => {
- client.setOptions({ modelOptions: { model } });
- expect(
- /claude-[3-9]/.test(client.modelOptions.model) ||
- /claude-(?:sonnet|opus|haiku)-[4-9]/.test(client.modelOptions.model),
- ).toBe(true);
- });
-
- // Test non-Claude 3/4 models
- const nonClaudeModels = ['claude-2', 'claude-instant', 'gpt-4', 'gpt-3.5-turbo'];
-
- nonClaudeModels.forEach((model) => {
- client.setOptions({ modelOptions: { model } });
- expect(
- /claude-[3-9]/.test(client.modelOptions.model) ||
- /claude-(?:sonnet|opus|haiku)-[4-9]/.test(client.modelOptions.model),
- ).toBe(false);
- });
- });
-});
diff --git a/api/app/clients/specs/BaseClient.test.js b/api/app/clients/specs/BaseClient.test.js
index 3cc082ab66..15328af644 100644
--- a/api/app/clients/specs/BaseClient.test.js
+++ b/api/app/clients/specs/BaseClient.test.js
@@ -41,9 +41,9 @@ jest.mock('~/models', () => ({
const { getConvo, saveConvo } = require('~/models');
jest.mock('@librechat/agents', () => {
- const { Providers } = jest.requireActual('@librechat/agents');
+ const actual = jest.requireActual('@librechat/agents');
return {
- Providers,
+ ...actual,
ChatOpenAI: jest.fn().mockImplementation(() => {
return {};
}),
@@ -928,4 +928,123 @@ describe('BaseClient', () => {
expect(result.remainingContextTokens).toBe(2); // 25 - 20 - 3(assistant label)
});
});
+
+ describe('sendMessage file population', () => {
+ const attachment = {
+ file_id: 'file-abc',
+ filename: 'image.png',
+ filepath: '/uploads/image.png',
+ type: 'image/png',
+ bytes: 1024,
+ object: 'file',
+ user: 'user-1',
+ embedded: false,
+ usage: 0,
+ text: 'large ocr blob that should be stripped',
+ _id: 'mongo-id-1',
+ };
+
+ beforeEach(() => {
+ TestClient.options.req = { body: { files: [{ file_id: 'file-abc' }] } };
+ TestClient.options.attachments = [attachment];
+ });
+
+ test('populates userMessage.files before saveMessageToDatabase is called', async () => {
+ TestClient.saveMessageToDatabase = jest.fn().mockImplementation((msg) => {
+ return Promise.resolve({ message: msg });
+ });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave).toBeDefined();
+ expect(userSave[0].files).toBeDefined();
+ expect(userSave[0].files).toHaveLength(1);
+ expect(userSave[0].files[0].file_id).toBe('file-abc');
+ });
+
+ test('strips text and _id from files before saving', async () => {
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave[0].files[0].text).toBeUndefined();
+ expect(userSave[0].files[0]._id).toBeUndefined();
+ expect(userSave[0].files[0].filename).toBe('image.png');
+ });
+
+ test('deletes image_urls from userMessage when files are present', async () => {
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+ TestClient.options.attachments = [
+ { ...attachment, image_urls: ['data:image/png;base64,...'] },
+ ];
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave[0].image_urls).toBeUndefined();
+ });
+
+ test('does not set files when no attachments match request file IDs', async () => {
+ TestClient.options.req = { body: { files: [{ file_id: 'file-nomatch' }] } };
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave[0].files).toBeUndefined();
+ });
+
+ test('skips file population when attachments is not an array (Promise case)', async () => {
+ TestClient.options.attachments = Promise.resolve([attachment]);
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave[0].files).toBeUndefined();
+ });
+
+ test('skips file population when skipSaveUserMessage is true', async () => {
+ TestClient.skipSaveUserMessage = true;
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg?.isCreatedByUser,
+ );
+ expect(userSave).toBeUndefined();
+ });
+
+ test('ignores file_id: undefined entries in req.body.files (no set poisoning)', async () => {
+ TestClient.options.req = {
+ body: { files: [{ file_id: undefined }, { file_id: 'file-abc' }] },
+ };
+ TestClient.options.attachments = [
+ { ...attachment, file_id: undefined },
+ { ...attachment, file_id: 'file-abc' },
+ ];
+ TestClient.saveMessageToDatabase = jest.fn().mockResolvedValue({ message: {} });
+
+ await TestClient.sendMessage('Hello');
+
+ const userSave = TestClient.saveMessageToDatabase.mock.calls.find(
+ ([msg]) => msg.isCreatedByUser,
+ );
+ expect(userSave[0].files).toHaveLength(1);
+ expect(userSave[0].files[0].file_id).toBe('file-abc');
+ });
+ });
});
diff --git a/api/app/clients/specs/OpenAIClient.test.js b/api/app/clients/specs/OpenAIClient.test.js
deleted file mode 100644
index efca66a867..0000000000
--- a/api/app/clients/specs/OpenAIClient.test.js
+++ /dev/null
@@ -1,630 +0,0 @@
-jest.mock('~/cache/getLogStores');
-require('dotenv').config();
-const { fetchEventSource } = require('@waylaidwanderer/fetch-event-source');
-const getLogStores = require('~/cache/getLogStores');
-const OpenAIClient = require('../OpenAIClient');
-jest.mock('meilisearch');
-
-jest.mock('~/db/connect');
-jest.mock('~/models', () => ({
- User: jest.fn(),
- Key: jest.fn(),
- Session: jest.fn(),
- Balance: jest.fn(),
- Transaction: jest.fn(),
- getMessages: jest.fn().mockResolvedValue([]),
- saveMessage: jest.fn(),
- updateMessage: jest.fn(),
- deleteMessagesSince: jest.fn(),
- deleteMessages: jest.fn(),
- getConvoTitle: jest.fn(),
- getConvo: jest.fn(),
- saveConvo: jest.fn(),
- deleteConvos: jest.fn(),
- getPreset: jest.fn(),
- getPresets: jest.fn(),
- savePreset: jest.fn(),
- deletePresets: jest.fn(),
- findFileById: jest.fn(),
- createFile: jest.fn(),
- updateFile: jest.fn(),
- deleteFile: jest.fn(),
- deleteFiles: jest.fn(),
- getFiles: jest.fn(),
- updateFileUsage: jest.fn(),
-}));
-
-// Import the actual module but mock specific parts
-const agents = jest.requireActual('@librechat/agents');
-const { CustomOpenAIClient } = agents;
-
-// Also mock ChatOpenAI to prevent real API calls
-agents.ChatOpenAI = jest.fn().mockImplementation(() => {
- return {};
-});
-agents.AzureChatOpenAI = jest.fn().mockImplementation(() => {
- return {};
-});
-
-// Mock only the CustomOpenAIClient constructor
-jest.spyOn(CustomOpenAIClient, 'constructor').mockImplementation(function (...options) {
- return new CustomOpenAIClient(...options);
-});
-
-const finalChatCompletion = jest.fn().mockResolvedValue({
- choices: [
- {
- message: { role: 'assistant', content: 'Mock message content' },
- finish_reason: 'Mock finish reason',
- },
- ],
-});
-
-const stream = jest.fn().mockImplementation(() => {
- let isDone = false;
- let isError = false;
- let errorCallback = null;
-
- const onEventHandlers = {
- abort: () => {
- // Mock abort behavior
- },
- error: (callback) => {
- errorCallback = callback; // Save the error callback for later use
- },
- finalMessage: (callback) => {
- callback({ role: 'assistant', content: 'Mock Response' });
- isDone = true; // Set stream to done
- },
- };
-
- const mockStream = {
- on: jest.fn((event, callback) => {
- if (onEventHandlers[event]) {
- onEventHandlers[event](callback);
- }
- return mockStream;
- }),
- finalChatCompletion,
- controller: { abort: jest.fn() },
- triggerError: () => {
- isError = true;
- if (errorCallback) {
- errorCallback(new Error('Mock error'));
- }
- },
- [Symbol.asyncIterator]: () => {
- return {
- next: () => {
- if (isError) {
- return Promise.reject(new Error('Mock error'));
- }
- if (isDone) {
- return Promise.resolve({ done: true });
- }
- const chunk = { choices: [{ delta: { content: 'Mock chunk' } }] };
- return Promise.resolve({ value: chunk, done: false });
- },
- };
- },
- };
- return mockStream;
-});
-
-const create = jest.fn().mockResolvedValue({
- choices: [
- {
- message: { content: 'Mock message content' },
- finish_reason: 'Mock finish reason',
- },
- ],
-});
-
-// Mock the implementation of CustomOpenAIClient instances
-jest.spyOn(CustomOpenAIClient.prototype, 'constructor').mockImplementation(function () {
- return this;
-});
-
-// Create a mock for the CustomOpenAIClient class
-const mockCustomOpenAIClient = jest.fn().mockImplementation(() => ({
- beta: {
- chat: {
- completions: {
- stream,
- },
- },
- },
- chat: {
- completions: {
- create,
- },
- },
-}));
-
-CustomOpenAIClient.mockImplementation = mockCustomOpenAIClient;
-
-describe('OpenAIClient', () => {
- beforeEach(() => {
- const mockCache = {
- get: jest.fn().mockResolvedValue({}),
- set: jest.fn(),
- };
- getLogStores.mockReturnValue(mockCache);
- });
- let client;
- const model = 'gpt-4';
- const parentMessageId = '1';
- const messages = [
- { role: 'user', sender: 'User', text: 'Hello', messageId: parentMessageId },
- { role: 'assistant', sender: 'Assistant', text: 'Hi', messageId: '2' },
- ];
-
- const defaultOptions = {
- // debug: true,
- req: {},
- openaiApiKey: 'new-api-key',
- modelOptions: {
- model,
- temperature: 0.7,
- },
- };
-
- const defaultAzureOptions = {
- azureOpenAIApiInstanceName: 'your-instance-name',
- azureOpenAIApiDeploymentName: 'your-deployment-name',
- azureOpenAIApiVersion: '2020-07-01-preview',
- };
-
- let originalWarn;
-
- beforeAll(() => {
- originalWarn = console.warn;
- console.warn = jest.fn();
- });
-
- afterAll(() => {
- console.warn = originalWarn;
- });
-
- beforeEach(() => {
- console.warn.mockClear();
- });
-
- beforeEach(() => {
- const options = { ...defaultOptions };
- client = new OpenAIClient('test-api-key', options);
- client.summarizeMessages = jest.fn().mockResolvedValue({
- role: 'assistant',
- content: 'Refined answer',
- tokenCount: 30,
- });
- client.buildPrompt = jest
- .fn()
- .mockResolvedValue({ prompt: messages.map((m) => m.text).join('\n') });
- client.getMessages = jest.fn().mockResolvedValue([]);
- });
-
- describe('setOptions', () => {
- it('should set the options correctly', () => {
- expect(client.apiKey).toBe('new-api-key');
- expect(client.modelOptions.model).toBe(model);
- expect(client.modelOptions.temperature).toBe(0.7);
- });
-
- it('should set FORCE_PROMPT based on OPENAI_FORCE_PROMPT or reverseProxyUrl', () => {
- process.env.OPENAI_FORCE_PROMPT = 'true';
- client.setOptions({});
- expect(client.FORCE_PROMPT).toBe(true);
- delete process.env.OPENAI_FORCE_PROMPT; // Cleanup
- client.FORCE_PROMPT = undefined;
-
- client.setOptions({ reverseProxyUrl: 'https://example.com/completions' });
- expect(client.FORCE_PROMPT).toBe(true);
- client.FORCE_PROMPT = undefined;
-
- client.setOptions({ reverseProxyUrl: 'https://example.com/chat' });
- expect(client.FORCE_PROMPT).toBe(false);
- });
-
- it('should set isChatCompletion based on useOpenRouter, reverseProxyUrl, or model', () => {
- client.setOptions({ reverseProxyUrl: null });
- // true by default since default model will be gpt-4o-mini
- expect(client.isChatCompletion).toBe(true);
- client.isChatCompletion = undefined;
-
- // false because completions url will force prompt payload
- client.setOptions({ reverseProxyUrl: 'https://example.com/completions' });
- expect(client.isChatCompletion).toBe(false);
- client.isChatCompletion = undefined;
-
- client.setOptions({ modelOptions: { model: 'gpt-4o-mini' }, reverseProxyUrl: null });
- expect(client.isChatCompletion).toBe(true);
- });
-
- it('should set completionsUrl and langchainProxy based on reverseProxyUrl', () => {
- client.setOptions({ reverseProxyUrl: 'https://localhost:8080/v1/chat/completions' });
- expect(client.completionsUrl).toBe('https://localhost:8080/v1/chat/completions');
- expect(client.langchainProxy).toBe('https://localhost:8080/v1');
-
- client.setOptions({ reverseProxyUrl: 'https://example.com/completions' });
- expect(client.completionsUrl).toBe('https://example.com/completions');
- expect(client.langchainProxy).toBe('https://example.com/completions');
- });
- });
-
- describe('setOptions with Simplified Azure Integration', () => {
- afterEach(() => {
- delete process.env.AZURE_OPENAI_DEFAULT_MODEL;
- delete process.env.AZURE_USE_MODEL_AS_DEPLOYMENT_NAME;
- });
-
- const azureOpenAIApiInstanceName = 'test-instance';
- const azureOpenAIApiDeploymentName = 'test-deployment';
- const azureOpenAIApiVersion = '2020-07-01-preview';
-
- const createOptions = (model) => ({
- modelOptions: { model },
- azure: {
- azureOpenAIApiInstanceName,
- azureOpenAIApiDeploymentName,
- azureOpenAIApiVersion,
- },
- });
-
- it('should set model from AZURE_OPENAI_DEFAULT_MODEL when Azure is enabled', () => {
- process.env.AZURE_OPENAI_DEFAULT_MODEL = 'gpt-4-azure';
- const options = createOptions('test');
- client.azure = options.azure;
- client.setOptions(options);
- expect(client.modelOptions.model).toBe('gpt-4-azure');
- });
-
- it('should not change model if Azure is not enabled', () => {
- process.env.AZURE_OPENAI_DEFAULT_MODEL = 'gpt-4-azure';
- const originalModel = 'test';
- client.azure = false;
- client.setOptions(createOptions('test'));
- expect(client.modelOptions.model).toBe(originalModel);
- });
-
- it('should not change model if AZURE_OPENAI_DEFAULT_MODEL is not set and model is passed', () => {
- const originalModel = 'GROK-LLM';
- const options = createOptions(originalModel);
- client.azure = options.azure;
- client.setOptions(options);
- expect(client.modelOptions.model).toBe(originalModel);
- });
-
- it('should change model if AZURE_OPENAI_DEFAULT_MODEL is set and model is passed', () => {
- process.env.AZURE_OPENAI_DEFAULT_MODEL = 'gpt-4-azure';
- const originalModel = 'GROK-LLM';
- const options = createOptions(originalModel);
- client.azure = options.azure;
- client.setOptions(options);
- expect(client.modelOptions.model).toBe(process.env.AZURE_OPENAI_DEFAULT_MODEL);
- });
-
- it('should include model in deployment name if AZURE_USE_MODEL_AS_DEPLOYMENT_NAME is set', () => {
- process.env.AZURE_USE_MODEL_AS_DEPLOYMENT_NAME = 'true';
- const model = 'gpt-4-azure';
-
- const AzureClient = new OpenAIClient('test-api-key', createOptions(model));
-
- const expectedValue = `https://${azureOpenAIApiInstanceName}.openai.azure.com/openai/deployments/${model}/chat/completions?api-version=${azureOpenAIApiVersion}`;
-
- expect(AzureClient.modelOptions.model).toBe(model);
- expect(AzureClient.azureEndpoint).toBe(expectedValue);
- });
-
- it('should include model in deployment name if AZURE_USE_MODEL_AS_DEPLOYMENT_NAME and default model is set', () => {
- const defaultModel = 'gpt-4-azure';
- process.env.AZURE_USE_MODEL_AS_DEPLOYMENT_NAME = 'true';
- process.env.AZURE_OPENAI_DEFAULT_MODEL = defaultModel;
- const model = 'gpt-4-this-is-a-test-model-name';
-
- const AzureClient = new OpenAIClient('test-api-key', createOptions(model));
-
- const expectedValue = `https://${azureOpenAIApiInstanceName}.openai.azure.com/openai/deployments/${model}/chat/completions?api-version=${azureOpenAIApiVersion}`;
-
- expect(AzureClient.modelOptions.model).toBe(defaultModel);
- expect(AzureClient.azureEndpoint).toBe(expectedValue);
- });
-
- it('should not include model in deployment name if AZURE_USE_MODEL_AS_DEPLOYMENT_NAME is not set', () => {
- const model = 'gpt-4-azure';
-
- const AzureClient = new OpenAIClient('test-api-key', createOptions(model));
-
- const expectedValue = `https://${azureOpenAIApiInstanceName}.openai.azure.com/openai/deployments/${azureOpenAIApiDeploymentName}/chat/completions?api-version=${azureOpenAIApiVersion}`;
-
- expect(AzureClient.modelOptions.model).toBe(model);
- expect(AzureClient.azureEndpoint).toBe(expectedValue);
- });
- });
-
- describe('getTokenCount', () => {
- it('should return the correct token count', () => {
- const count = client.getTokenCount('Hello, world!');
- expect(count).toBeGreaterThan(0);
- });
- });
-
- describe('getSaveOptions', () => {
- it('should return the correct save options', () => {
- const options = client.getSaveOptions();
- expect(options).toHaveProperty('chatGptLabel');
- expect(options).toHaveProperty('modelLabel');
- expect(options).toHaveProperty('promptPrefix');
- });
- });
-
- describe('getBuildMessagesOptions', () => {
- it('should return the correct build messages options', () => {
- const options = client.getBuildMessagesOptions({ promptPrefix: 'Hello' });
- expect(options).toHaveProperty('isChatCompletion');
- expect(options).toHaveProperty('promptPrefix');
- expect(options.promptPrefix).toBe('Hello');
- });
- });
-
- describe('buildMessages', () => {
- it('should build messages correctly for chat completion', async () => {
- const result = await client.buildMessages(messages, parentMessageId, {
- isChatCompletion: true,
- });
- expect(result).toHaveProperty('prompt');
- });
-
- it('should build messages correctly for non-chat completion', async () => {
- const result = await client.buildMessages(messages, parentMessageId, {
- isChatCompletion: false,
- });
- expect(result).toHaveProperty('prompt');
- });
-
- it('should build messages correctly with a promptPrefix', async () => {
- const result = await client.buildMessages(messages, parentMessageId, {
- isChatCompletion: true,
- promptPrefix: 'Test Prefix',
- });
- expect(result).toHaveProperty('prompt');
- const instructions = result.prompt.find((item) => item.content.includes('Test Prefix'));
- expect(instructions).toBeDefined();
- expect(instructions.content).toContain('Test Prefix');
- });
-
- it('should handle context strategy correctly', async () => {
- client.contextStrategy = 'summarize';
- const result = await client.buildMessages(messages, parentMessageId, {
- isChatCompletion: true,
- });
- expect(result).toHaveProperty('prompt');
- expect(result).toHaveProperty('tokenCountMap');
- });
-
- it('should assign name property for user messages when options.name is set', async () => {
- client.options.name = 'Test User';
- const result = await client.buildMessages(messages, parentMessageId, {
- isChatCompletion: true,
- });
- const hasUserWithName = result.prompt.some(
- (item) => item.role === 'user' && item.name === 'Test_User',
- );
- expect(hasUserWithName).toBe(true);
- });
-
- it('should handle promptPrefix from options when promptPrefix argument is not provided', async () => {
- client.options.promptPrefix = 'Test Prefix from options';
- const result = await client.buildMessages(messages, parentMessageId, {
- isChatCompletion: true,
- });
- const instructions = result.prompt.find((item) =>
- item.content.includes('Test Prefix from options'),
- );
- expect(instructions.content).toContain('Test Prefix from options');
- });
-
- it('should handle case when neither promptPrefix argument nor options.promptPrefix is set', async () => {
- const result = await client.buildMessages(messages, parentMessageId, {
- isChatCompletion: true,
- });
- const instructions = result.prompt.find((item) => item.content.includes('Test Prefix'));
- expect(instructions).toBeUndefined();
- });
-
- it('should handle case when getMessagesForConversation returns null or an empty array', async () => {
- const messages = [];
- const result = await client.buildMessages(messages, parentMessageId, {
- isChatCompletion: true,
- });
- expect(result.prompt).toEqual([]);
- });
- });
-
- describe('getTokenCountForMessage', () => {
- const example_messages = [
- {
- role: 'system',
- content:
- 'You are a helpful, pattern-following assistant that translates corporate jargon into plain English.',
- },
- {
- role: 'system',
- name: 'example_user',
- content: 'New synergies will help drive top-line growth.',
- },
- {
- role: 'system',
- name: 'example_assistant',
- content: 'Things working well together will increase revenue.',
- },
- {
- role: 'system',
- name: 'example_user',
- content:
- "Let's circle back when we have more bandwidth to touch base on opportunities for increased leverage.",
- },
- {
- role: 'system',
- name: 'example_assistant',
- content: "Let's talk later when we're less busy about how to do better.",
- },
- {
- role: 'user',
- content:
- "This late pivot means we don't have time to boil the ocean for the client deliverable.",
- },
- ];
-
- const testCases = [
- { model: 'gpt-3.5-turbo-0301', expected: 127 },
- { model: 'gpt-3.5-turbo-0613', expected: 129 },
- { model: 'gpt-3.5-turbo', expected: 129 },
- { model: 'gpt-4-0314', expected: 129 },
- { model: 'gpt-4-0613', expected: 129 },
- { model: 'gpt-4', expected: 129 },
- { model: 'unknown', expected: 129 },
- ];
-
- testCases.forEach((testCase) => {
- it(`should return ${testCase.expected} tokens for model ${testCase.model}`, () => {
- client.modelOptions.model = testCase.model;
- // 3 tokens for assistant label
- let totalTokens = 3;
- for (let message of example_messages) {
- totalTokens += client.getTokenCountForMessage(message);
- }
- expect(totalTokens).toBe(testCase.expected);
- });
- });
-
- const vision_request = [
- {
- role: 'user',
- content: [
- {
- type: 'text',
- text: 'describe what is in this image?',
- },
- {
- type: 'image_url',
- image_url: {
- url: 'https://venturebeat.com/wp-content/uploads/2019/03/openai-1.png',
- detail: 'high',
- },
- },
- ],
- },
- ];
-
- const expectedTokens = 14;
- const visionModel = 'gpt-4-vision-preview';
-
- it(`should return ${expectedTokens} tokens for model ${visionModel} (Vision Request)`, () => {
- client.modelOptions.model = visionModel;
- // 3 tokens for assistant label
- let totalTokens = 3;
- for (let message of vision_request) {
- totalTokens += client.getTokenCountForMessage(message);
- }
- expect(totalTokens).toBe(expectedTokens);
- });
- });
-
- describe('checkVisionRequest functionality', () => {
- let client;
- const attachments = [{ type: 'image/png' }];
-
- beforeEach(() => {
- client = new OpenAIClient('test-api-key', {
- endpoint: 'ollama',
- modelOptions: {
- model: 'initial-model',
- },
- modelsConfig: {
- ollama: ['initial-model', 'llava', 'other-model'],
- },
- });
-
- client.defaultVisionModel = 'non-valid-default-model';
- });
-
- afterEach(() => {
- jest.restoreAllMocks();
- });
-
- it('should set "llava" as the model if it is the first valid model when default validation fails', () => {
- client.checkVisionRequest(attachments);
-
- expect(client.modelOptions.model).toBe('llava');
- expect(client.isVisionModel).toBeTruthy();
- expect(client.modelOptions.stop).toBeUndefined();
- });
- });
-
- describe('getStreamUsage', () => {
- it('should return this.usage when completion_tokens_details is null', () => {
- const client = new OpenAIClient('test-api-key', defaultOptions);
- client.usage = {
- completion_tokens_details: null,
- prompt_tokens: 10,
- completion_tokens: 20,
- };
- client.inputTokensKey = 'prompt_tokens';
- client.outputTokensKey = 'completion_tokens';
-
- const result = client.getStreamUsage();
-
- expect(result).toEqual(client.usage);
- });
-
- it('should return this.usage when completion_tokens_details is missing reasoning_tokens', () => {
- const client = new OpenAIClient('test-api-key', defaultOptions);
- client.usage = {
- completion_tokens_details: {
- other_tokens: 5,
- },
- prompt_tokens: 10,
- completion_tokens: 20,
- };
- client.inputTokensKey = 'prompt_tokens';
- client.outputTokensKey = 'completion_tokens';
-
- const result = client.getStreamUsage();
-
- expect(result).toEqual(client.usage);
- });
-
- it('should calculate output tokens correctly when completion_tokens_details is present with reasoning_tokens', () => {
- const client = new OpenAIClient('test-api-key', defaultOptions);
- client.usage = {
- completion_tokens_details: {
- reasoning_tokens: 30,
- other_tokens: 5,
- },
- prompt_tokens: 10,
- completion_tokens: 20,
- };
- client.inputTokensKey = 'prompt_tokens';
- client.outputTokensKey = 'completion_tokens';
-
- const result = client.getStreamUsage();
-
- expect(result).toEqual({
- reasoning_tokens: 30,
- other_tokens: 5,
- prompt_tokens: 10,
- completion_tokens: 10, // |30 - 20| = 10
- });
- });
-
- it('should return this.usage when it is undefined', () => {
- const client = new OpenAIClient('test-api-key', defaultOptions);
- client.usage = undefined;
-
- const result = client.getStreamUsage();
-
- expect(result).toBeUndefined();
- });
- });
-});
diff --git a/api/app/clients/specs/OpenAIClient.tokens.js b/api/app/clients/specs/OpenAIClient.tokens.js
deleted file mode 100644
index 9b556b38b9..0000000000
--- a/api/app/clients/specs/OpenAIClient.tokens.js
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- This is a test script to see how much memory is used by the client when encoding.
- On my work machine, it was able to process 10,000 encoding requests / 48.686 seconds = approximately 205.4 RPS
- I've significantly reduced the amount of encoding needed by saving token counts in the database, so these
- numbers should only be hit with a large amount of concurrent users
- It would take 103 concurrent users sending 1 message every 1 second to hit these numbers, which is rather unrealistic,
- and at that point, out-sourcing the encoding to a separate server would be a better solution
- Also, for scaling, could increase the rate at which the encoder resets; the trade-off is more resource usage on the server.
- Initial memory usage: 25.93 megabytes
- Peak memory usage: 55 megabytes
- Final memory usage: 28.03 megabytes
- Post-test (timeout of 15s): 21.91 megabytes
-*/
-
-require('dotenv').config();
-const { OpenAIClient } = require('../');
-
-function timeout(ms) {
- return new Promise((resolve) => setTimeout(resolve, ms));
-}
-
-const run = async () => {
- const text = `
- The standard Lorem Ipsum passage, used since the 1500s
-
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
- Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
-
- "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"
- 1914 translation by H. Rackham
-
- "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
- Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
-
- "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."
- 1914 translation by H. Rackham
-
- "On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."
- `;
- const model = 'gpt-3.5-turbo';
- let maxContextTokens = 4095;
- if (model === 'gpt-4') {
- maxContextTokens = 8191;
- } else if (model === 'gpt-4-32k') {
- maxContextTokens = 32767;
- }
- const clientOptions = {
- reverseProxyUrl: process.env.OPENAI_REVERSE_PROXY || null,
- maxContextTokens,
- modelOptions: {
- model,
- },
- proxy: process.env.PROXY || null,
- debug: true,
- };
-
- let apiKey = process.env.OPENAI_API_KEY;
-
- const maxMemory = 0.05 * 1024 * 1024 * 1024;
-
- // Calculate initial percentage of memory used
- const initialMemoryUsage = process.memoryUsage().heapUsed;
-
- function printProgressBar(percentageUsed) {
- const filledBlocks = Math.round(percentageUsed / 2); // Each block represents 2%
- const emptyBlocks = 50 - filledBlocks; // Total blocks is 50 (each represents 2%), so the rest are empty
- const progressBar =
- '[' +
- '█'.repeat(filledBlocks) +
- ' '.repeat(emptyBlocks) +
- '] ' +
- percentageUsed.toFixed(2) +
- '%';
- console.log(progressBar);
- }
-
- const iterations = 10000;
- console.time('loopTime');
- // Trying to catch the error doesn't help; all future calls will immediately crash
- for (let i = 0; i < iterations; i++) {
- try {
- console.log(`Iteration ${i}`);
- const client = new OpenAIClient(apiKey, clientOptions);
-
- client.getTokenCount(text);
- // const encoder = client.constructor.getTokenizer('cl100k_base');
- // console.log(`Iteration ${i}: call encode()...`);
- // encoder.encode(text, 'all');
- // encoder.free();
-
- const memoryUsageDuringLoop = process.memoryUsage().heapUsed;
- const percentageUsed = (memoryUsageDuringLoop / maxMemory) * 100;
- printProgressBar(percentageUsed);
-
- if (i === iterations - 1) {
- console.log(' done');
- // encoder.free();
- }
- } catch (e) {
- console.log(`caught error! in Iteration ${i}`);
- console.log(e);
- }
- }
-
- console.timeEnd('loopTime');
- // Calculate final percentage of memory used
- const finalMemoryUsage = process.memoryUsage().heapUsed;
- // const finalPercentageUsed = finalMemoryUsage / maxMemory * 100;
- console.log(`Initial memory usage: ${initialMemoryUsage / 1024 / 1024} megabytes`);
- console.log(`Final memory usage: ${finalMemoryUsage / 1024 / 1024} megabytes`);
- await timeout(15000);
- const memoryUsageAfterTimeout = process.memoryUsage().heapUsed;
- console.log(`Post timeout: ${memoryUsageAfterTimeout / 1024 / 1024} megabytes`);
-};
-
-run();
-
-process.on('uncaughtException', (err) => {
- if (!err.message.includes('fetch failed')) {
- console.error('There was an uncaught error:');
- console.error(err);
- }
-
- if (err.message.includes('fetch failed')) {
- console.log('fetch failed error caught');
- // process.exit(0);
- } else {
- process.exit(1);
- }
-});
diff --git a/api/app/clients/tools/.well-known/Ai_PDF.json b/api/app/clients/tools/.well-known/Ai_PDF.json
deleted file mode 100644
index e3caf6e2c7..0000000000
--- a/api/app/clients/tools/.well-known/Ai_PDF.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "Ai PDF",
- "name_for_model": "Ai_PDF",
- "description_for_human": "Super-fast, interactive chats with PDFs of any size, complete with page references for fact checking.",
- "description_for_model": "Provide a URL to a PDF and search the document. Break the user question in multiple semantic search queries and calls as needed. Think step by step.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://plugin-3c56b9d4c8a6465998395f28b6a445b2-jexkai4vea-uc.a.run.app/openapi.yaml",
- "is_user_authenticated": false
- },
- "logo_url": "https://plugin-3c56b9d4c8a6465998395f28b6a445b2-jexkai4vea-uc.a.run.app/logo.png",
- "contact_email": "support@promptapps.ai",
- "legal_info_url": "https://plugin-3c56b9d4c8a6465998395f28b6a445b2-jexkai4vea-uc.a.run.app/legal.html"
-}
diff --git a/api/app/clients/tools/.well-known/BrowserOp.json b/api/app/clients/tools/.well-known/BrowserOp.json
deleted file mode 100644
index 5a3bb86f92..0000000000
--- a/api/app/clients/tools/.well-known/BrowserOp.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "BrowserOp",
- "name_for_model": "BrowserOp",
- "description_for_human": "Browse dozens of webpages in one query. Fetch information more efficiently.",
- "description_for_model": "This tool offers the feature for users to input a URL or multiple URLs and interact with them as needed. It's designed to comprehend the user's intent and proffer tailored suggestions in line with the content and functionality of the webpage at hand. Services like text rewrites, translations and more can be requested. When users need specific information to finish a task or if they intend to perform a search, this tool becomes a bridge to the search engine and generates responses based on the results. Whether the user is seeking information about restaurants, rentals, weather, or shopping, this tool connects to the internet and delivers the most recent results.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://testplugin.feednews.com/.well-known/openapi.yaml"
- },
- "logo_url": "https://openapi-af.op-mobile.opera.com/openapi/testplugin/.well-known/logo.png",
- "contact_email": "aiplugins-contact-list@opera.com",
- "legal_info_url": "https://legal.apexnews.com/terms/"
-}
diff --git a/api/app/clients/tools/.well-known/Dr_Thoths_Tarot.json b/api/app/clients/tools/.well-known/Dr_Thoths_Tarot.json
deleted file mode 100644
index 99774d9573..0000000000
--- a/api/app/clients/tools/.well-known/Dr_Thoths_Tarot.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "Dr. Thoth's Tarot",
- "name_for_model": "Dr_Thoths_Tarot",
- "description_for_human": "Tarot card novelty entertainment & analysis, by Mnemosyne Labs.",
- "description_for_model": "Intelligent analysis program for tarot card entertaiment, data, & prompts, by Mnemosyne Labs, a division of AzothCorp.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://dr-thoth-tarot.herokuapp.com/openapi.yaml",
- "is_user_authenticated": false
- },
- "logo_url": "https://dr-thoth-tarot.herokuapp.com/logo.png",
- "contact_email": "legal@AzothCorp.com",
- "legal_info_url": "http://AzothCorp.com/legal",
- "endpoints": [
- {
- "name": "Draw Card",
- "path": "/drawcard",
- "method": "GET",
- "description": "Generate a single tarot card from the deck of 78 cards."
- },
- {
- "name": "Occult Card",
- "path": "/occult_card",
- "method": "GET",
- "description": "Generate a tarot card using the specified planet's Kamea matrix.",
- "parameters": [
- {
- "name": "planet",
- "type": "string",
- "enum": ["Saturn", "Jupiter", "Mars", "Sun", "Venus", "Mercury", "Moon"],
- "required": true,
- "description": "The planet name to use the corresponding Kamea matrix."
- }
- ]
- },
- {
- "name": "Three Card Spread",
- "path": "/threecardspread",
- "method": "GET",
- "description": "Perform a three-card tarot spread."
- },
- {
- "name": "Celtic Cross Spread",
- "path": "/celticcross",
- "method": "GET",
- "description": "Perform a Celtic Cross tarot spread with 10 cards."
- },
- {
- "name": "Past, Present, Future Spread",
- "path": "/pastpresentfuture",
- "method": "GET",
- "description": "Perform a Past, Present, Future tarot spread with 3 cards."
- },
- {
- "name": "Horseshoe Spread",
- "path": "/horseshoe",
- "method": "GET",
- "description": "Perform a Horseshoe tarot spread with 7 cards."
- },
- {
- "name": "Relationship Spread",
- "path": "/relationship",
- "method": "GET",
- "description": "Perform a Relationship tarot spread."
- },
- {
- "name": "Career Spread",
- "path": "/career",
- "method": "GET",
- "description": "Perform a Career tarot spread."
- },
- {
- "name": "Yes/No Spread",
- "path": "/yesno",
- "method": "GET",
- "description": "Perform a Yes/No tarot spread."
- },
- {
- "name": "Chakra Spread",
- "path": "/chakra",
- "method": "GET",
- "description": "Perform a Chakra tarot spread with 7 cards."
- }
- ]
-}
diff --git a/api/app/clients/tools/.well-known/DreamInterpreter.json b/api/app/clients/tools/.well-known/DreamInterpreter.json
deleted file mode 100644
index d6d5bb7cf8..0000000000
--- a/api/app/clients/tools/.well-known/DreamInterpreter.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_model": "DreamInterpreter",
- "name_for_human": "Dream Interpreter",
- "description_for_model": "Interprets your dreams using advanced techniques.",
- "description_for_human": "Interprets your dreams using advanced techniques.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://dreamplugin.bgnetmobile.com/.well-known/openapi.json",
- "has_user_authentication": false
- },
- "logo_url": "https://dreamplugin.bgnetmobile.com/.well-known/logo.png",
- "contact_email": "ismail.orkler@bgnetmobile.com",
- "legal_info_url": "https://dreamplugin.bgnetmobile.com/terms.html"
-}
diff --git a/api/app/clients/tools/.well-known/VoxScript.json b/api/app/clients/tools/.well-known/VoxScript.json
deleted file mode 100644
index 8691f0ccfd..0000000000
--- a/api/app/clients/tools/.well-known/VoxScript.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "VoxScript",
- "name_for_model": "VoxScript",
- "description_for_human": "Enables searching of YouTube transcripts, financial data sources Google Search results, and more!",
- "description_for_model": "Plugin for searching through varius data sources.",
- "auth": {
- "type": "service_http",
- "authorization_type": "bearer",
- "verification_tokens": {
- "openai": "ffc5226d1af346c08a98dee7deec9f76"
- }
- },
- "api": {
- "type": "openapi",
- "url": "https://voxscript.awt.icu/swagger/v1/swagger.yaml",
- "is_user_authenticated": false
- },
- "logo_url": "https://voxscript.awt.icu/images/VoxScript_logo_32x32.png",
- "contact_email": "voxscript@allwiretech.com",
- "legal_info_url": "https://voxscript.awt.icu/legal/"
-}
diff --git a/api/app/clients/tools/.well-known/askyourpdf.json b/api/app/clients/tools/.well-known/askyourpdf.json
deleted file mode 100644
index 0eb31e37c7..0000000000
--- a/api/app/clients/tools/.well-known/askyourpdf.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_model": "askyourpdf",
- "name_for_human": "AskYourPDF",
- "description_for_model": "This plugin is designed to expedite the extraction of information from PDF documents. It works by accepting a URL link to a PDF or a document ID (doc_id) from the user. If a URL is provided, the plugin first validates that it is a correct URL. \\nAfter validating the URL, the plugin proceeds to download the PDF and store its content in a vector database. If the user provides a doc_id, the plugin directly retrieves the document from the database. The plugin then scans through the stored PDFs to find answers to user queries or retrieve specific details.\\n\\nHowever, if an error occurs while querying the API, the user is prompted to download their document first, then manually upload it to [](https://askyourpdf.com/upload). Once the upload is complete, the user should copy the resulting doc_id and paste it back into the chat for further interaction.\nThe plugin is particularly useful when the user's question pertains to content within a PDF document. When providing answers, the plugin also specifies the page number (highlighted in bold) where the relevant information was found. Remember, the URL must be valid for a successful query. Failure to validate the URL may lead to errors or unsuccessful queries.",
- "description_for_human": "Unlock the power of your PDFs!, dive into your documents, find answers, and bring information to your fingertips.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "askyourpdf.yaml",
- "has_user_authentication": false
- },
- "logo_url": "https://plugin.askyourpdf.com/.well-known/logo.png",
- "contact_email": "plugin@askyourpdf.com",
- "legal_info_url": "https://askyourpdf.com/terms"
-}
diff --git a/api/app/clients/tools/.well-known/drink_maestro.json b/api/app/clients/tools/.well-known/drink_maestro.json
deleted file mode 100644
index d461a4e3f2..0000000000
--- a/api/app/clients/tools/.well-known/drink_maestro.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "Drink Maestro",
- "name_for_model": "drink_maestro",
- "description_for_human": "Learn to mix any drink you can imagine (real or made-up), and discover new ones. Includes drink images.",
- "description_for_model": "You are a silly bartender/comic who knows how to make any drink imaginable. You provide recipes for specific drinks, suggest new drinks, and show pictures of drinks. Be creative in your descriptions and make jokes and puns. Use a lot of emojis. If the user makes a request in another language, send API call in English, and then translate the response.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://api.drinkmaestro.space/.well-known/openapi.yaml",
- "is_user_authenticated": false
- },
- "logo_url": "https://i.imgur.com/6q8HWdz.png",
- "contact_email": "nikkmitchell@gmail.com",
- "legal_info_url": "https://github.com/nikkmitchell/DrinkMaestro/blob/main/Legal.txt"
-}
diff --git a/api/app/clients/tools/.well-known/earthImagesAndVisualizations.json b/api/app/clients/tools/.well-known/earthImagesAndVisualizations.json
deleted file mode 100644
index 695a955be1..0000000000
--- a/api/app/clients/tools/.well-known/earthImagesAndVisualizations.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "Earth",
- "name_for_model": "earthImagesAndVisualizations",
- "description_for_human": "Generates a map image based on provided location, tilt and style.",
- "description_for_model": "Generates a map image based on provided coordinates or location, tilt and style, and even geoJson to provide markers, paths, and polygons. Responds with an image-link. For the styles choose one of these: [light, dark, streets, outdoors, satellite, satellite-streets]",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://api.earth-plugin.com/openapi.yaml",
- "is_user_authenticated": false
- },
- "logo_url": "https://api.earth-plugin.com/logo.png",
- "contact_email": "contact@earth-plugin.com",
- "legal_info_url": "https://api.earth-plugin.com/legal.html"
-}
diff --git a/api/app/clients/tools/.well-known/has-issues/scholarly_graph_link.json b/api/app/clients/tools/.well-known/has-issues/scholarly_graph_link.json
deleted file mode 100644
index 8b92e6e381..0000000000
--- a/api/app/clients/tools/.well-known/has-issues/scholarly_graph_link.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "Scholarly Graph Link",
- "name_for_model": "scholarly_graph_link",
- "description_for_human": "You can search papers, authors, datasets and software. It has access to Figshare, Arxiv, and many others.",
- "description_for_model": "Run GraphQL queries against an API hosted by DataCite API. The API supports most GraphQL query but does not support mutations statements. Use `{ __schema { types { name kind } } }` to get all the types in the GraphQL schema. Use `{ datasets { nodes { id sizes citations { nodes { id titles { title } } } } } }` to get all the citations of all datasets in the API. Use `{ datasets { nodes { id sizes citations { nodes { id titles { title } } } } } }` to get all the citations of all datasets in the API. Use `{person(id:ORCID) {works(first:50) {nodes {id titles(first: 1){title} publicationYear}}}}` to get the first 50 works of a person based on their ORCID. All Ids are urls, e.g., https://orcid.org/0012-0000-1012-1110. Mutations statements are not allowed.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://api.datacite.org/graphql-openapi.yaml",
- "is_user_authenticated": false
- },
- "logo_url": "https://raw.githubusercontent.com/kjgarza/scholarly_graph_link/master/logo.png",
- "contact_email": "kj.garza@gmail.com",
- "legal_info_url": "https://github.com/kjgarza/scholarly_graph_link/blob/master/LICENSE"
-}
diff --git a/api/app/clients/tools/.well-known/has-issues/web_pilot.json b/api/app/clients/tools/.well-known/has-issues/web_pilot.json
deleted file mode 100644
index d68c919eb3..0000000000
--- a/api/app/clients/tools/.well-known/has-issues/web_pilot.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "WebPilot",
- "name_for_model": "web_pilot",
- "description_for_human": "Browse & QA Webpage/PDF/Data. Generate articles, from one or more URLs.",
- "description_for_model": "This tool allows users to provide a URL(or URLs) and optionally requests for interacting with, extracting specific information or how to do with the content from the URL. Requests may include rewrite, translate, and others. If there any requests, when accessing the /api/visit-web endpoint, the parameter 'user_has_request' should be set to 'true. And if there's no any requests, 'user_has_request' should be set to 'false'.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://webreader.webpilotai.com/openapi.yaml",
- "is_user_authenticated": false
- },
- "logo_url": "https://webreader.webpilotai.com/logo.png",
- "contact_email": "dev@webpilot.ai",
- "legal_info_url": "https://webreader.webpilotai.com/legal_info.html",
- "headers": {
- "id": "WebPilot-Friend-UID"
- },
- "params": {
- "user_has_request": true
- }
-}
diff --git a/api/app/clients/tools/.well-known/image_prompt_enhancer.json b/api/app/clients/tools/.well-known/image_prompt_enhancer.json
deleted file mode 100644
index 72f28658c8..0000000000
--- a/api/app/clients/tools/.well-known/image_prompt_enhancer.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "Image Prompt Enhancer",
- "name_for_model": "image_prompt_enhancer",
- "description_for_human": "Transform your ideas into complex, personalized image generation prompts.",
- "description_for_model": "Provides instructions for crafting an enhanced image prompt. Use this whenever the user wants to enhance a prompt.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://image-prompt-enhancer.gafo.tech/openapi.yaml",
- "is_user_authenticated": false
- },
- "logo_url": "https://image-prompt-enhancer.gafo.tech/logo.png",
- "contact_email": "gafotech1@gmail.com",
- "legal_info_url": "https://image-prompt-enhancer.gafo.tech/legal"
-}
diff --git a/api/app/clients/tools/.well-known/openapi/askyourpdf.yaml b/api/app/clients/tools/.well-known/openapi/askyourpdf.yaml
deleted file mode 100644
index cb3affc8b8..0000000000
--- a/api/app/clients/tools/.well-known/openapi/askyourpdf.yaml
+++ /dev/null
@@ -1,157 +0,0 @@
-openapi: 3.0.2
-info:
- title: FastAPI
- version: 0.1.0
-servers:
- - url: https://plugin.askyourpdf.com
-paths:
- /api/download_pdf:
- post:
- summary: Download Pdf
- description: Download a PDF file from a URL and save it to the vector database.
- operationId: download_pdf_api_download_pdf_post
- parameters:
- - required: true
- schema:
- title: Url
- type: string
- name: url
- in: query
- responses:
- '200':
- description: Successful Response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/FileResponse'
- '422':
- description: Validation Error
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/HTTPValidationError'
- /query:
- post:
- summary: Perform Query
- description: Perform a query on a document.
- operationId: perform_query_query_post
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/InputData'
- required: true
- responses:
- '200':
- description: Successful Response
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ResponseModel'
- '422':
- description: Validation Error
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/HTTPValidationError'
-components:
- schemas:
- DocumentMetadata:
- title: DocumentMetadata
- required:
- - source
- - page_number
- - author
- type: object
- properties:
- source:
- title: Source
- type: string
- page_number:
- title: Page Number
- type: integer
- author:
- title: Author
- type: string
- FileResponse:
- title: FileResponse
- required:
- - docId
- type: object
- properties:
- docId:
- title: Docid
- type: string
- error:
- title: Error
- type: string
- HTTPValidationError:
- title: HTTPValidationError
- type: object
- properties:
- detail:
- title: Detail
- type: array
- items:
- $ref: '#/components/schemas/ValidationError'
- InputData:
- title: InputData
- required:
- - doc_id
- - query
- type: object
- properties:
- doc_id:
- title: Doc Id
- type: string
- query:
- title: Query
- type: string
- ResponseModel:
- title: ResponseModel
- required:
- - results
- type: object
- properties:
- results:
- title: Results
- type: array
- items:
- $ref: '#/components/schemas/SearchResult'
- SearchResult:
- title: SearchResult
- required:
- - doc_id
- - text
- - metadata
- type: object
- properties:
- doc_id:
- title: Doc Id
- type: string
- text:
- title: Text
- type: string
- metadata:
- $ref: '#/components/schemas/DocumentMetadata'
- ValidationError:
- title: ValidationError
- required:
- - loc
- - msg
- - type
- type: object
- properties:
- loc:
- title: Location
- type: array
- items:
- anyOf:
- - type: string
- - type: integer
- msg:
- title: Message
- type: string
- type:
- title: Error Type
- type: string
diff --git a/api/app/clients/tools/.well-known/openapi/scholarai.yaml b/api/app/clients/tools/.well-known/openapi/scholarai.yaml
deleted file mode 100644
index 34cca8296f..0000000000
--- a/api/app/clients/tools/.well-known/openapi/scholarai.yaml
+++ /dev/null
@@ -1,185 +0,0 @@
-openapi: 3.0.1
-info:
- title: ScholarAI
- description: Allows the user to search facts and findings from scientific articles
- version: 'v1'
-servers:
- - url: https://scholar-ai.net
-paths:
- /api/abstracts:
- get:
- operationId: searchAbstracts
- summary: Get relevant paper abstracts by keywords search
- parameters:
- - name: keywords
- in: query
- description: Keywords of inquiry which should appear in article. Must be in English.
- required: true
- schema:
- type: string
- - name: sort
- in: query
- description: The sort order for results. Valid values are cited_by_count or publication_date. Excluding this value does a relevance based search.
- required: false
- schema:
- type: string
- enum:
- - cited_by_count
- - publication_date
- - name: query
- in: query
- description: The user query
- required: true
- schema:
- type: string
- - name: peer_reviewed_only
- in: query
- description: Whether to only return peer reviewed articles. Defaults to true, ChatGPT should cautiously suggest this value can be set to false
- required: false
- schema:
- type: string
- - name: start_year
- in: query
- description: The first year, inclusive, to include in the search range. Excluding this value will include all years.
- required: false
- schema:
- type: string
- - name: end_year
- in: query
- description: The last year, inclusive, to include in the search range. Excluding this value will include all years.
- required: false
- schema:
- type: string
- - name: offset
- in: query
- description: The offset of the first result to return. Defaults to 0.
- required: false
- schema:
- type: string
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/searchAbstractsResponse'
- /api/fulltext:
- get:
- operationId: getFullText
- summary: Get full text of a paper by URL for PDF
- parameters:
- - name: pdf_url
- in: query
- description: URL for PDF
- required: true
- schema:
- type: string
- - name: chunk
- in: query
- description: chunk number to retrieve, defaults to 1
- required: false
- schema:
- type: number
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/getFullTextResponse'
- /api/save-citation:
- get:
- operationId: saveCitation
- summary: Save citation to reference manager
- parameters:
- - name: doi
- in: query
- description: Digital Object Identifier (DOI) of article
- required: true
- schema:
- type: string
- - name: zotero_user_id
- in: query
- description: Zotero User ID
- required: true
- schema:
- type: string
- - name: zotero_api_key
- in: query
- description: Zotero API Key
- required: true
- schema:
- type: string
- responses:
- "200":
- description: OK
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/saveCitationResponse'
-components:
- schemas:
- searchAbstractsResponse:
- type: object
- properties:
- next_offset:
- type: number
- description: The offset of the next page of results.
- total_num_results:
- type: number
- description: The total number of results.
- abstracts:
- type: array
- items:
- type: object
- properties:
- title:
- type: string
- abstract:
- type: string
- description: Summary of the context, methods, results, and conclusions of the paper.
- doi:
- type: string
- description: The DOI of the paper.
- landing_page_url:
- type: string
- description: Link to the paper on its open-access host.
- pdf_url:
- type: string
- description: Link to the paper PDF.
- publicationDate:
- type: string
- description: The date the paper was published in YYYY-MM-DD format.
- relevance:
- type: number
- description: The relevance of the paper to the search query. 1 is the most relevant.
- creators:
- type: array
- items:
- type: string
- description: The name of the creator.
- cited_by_count:
- type: number
- description: The number of citations of the article.
- description: The list of relevant abstracts.
- getFullTextResponse:
- type: object
- properties:
- full_text:
- type: string
- description: The full text of the paper.
- pdf_url:
- type: string
- description: The PDF URL of the paper.
- chunk:
- type: number
- description: The chunk of the paper.
- total_chunk_num:
- type: number
- description: The total chunks of the paper.
- saveCitationResponse:
- type: object
- properties:
- message:
- type: string
- description: Confirmation of successful save or error message.
\ No newline at end of file
diff --git a/api/app/clients/tools/.well-known/qrCodes.json b/api/app/clients/tools/.well-known/qrCodes.json
deleted file mode 100644
index b5618916ac..0000000000
--- a/api/app/clients/tools/.well-known/qrCodes.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "QR Codes",
- "name_for_model": "qrCodes",
- "description_for_human": "Create QR codes.",
- "description_for_model": "Plugin for generating QR codes.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://chatgpt-qrcode-46d7d4ebefc8.herokuapp.com/openapi.yaml"
- },
- "logo_url": "https://chatgpt-qrcode-46d7d4ebefc8.herokuapp.com/logo.png",
- "contact_email": "chrismountzou@gmail.com",
- "legal_info_url": "https://raw.githubusercontent.com/mountzou/qrCodeGPTv1/master/legal"
-}
diff --git a/api/app/clients/tools/.well-known/scholarai.json b/api/app/clients/tools/.well-known/scholarai.json
deleted file mode 100644
index 1900a926c2..0000000000
--- a/api/app/clients/tools/.well-known/scholarai.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "ScholarAI",
- "name_for_model": "scholarai",
- "description_for_human": "Unleash scientific research: search 40M+ peer-reviewed papers, explore scientific PDFs, and save to reference managers.",
- "description_for_model": "Access open access scientific literature from peer-reviewed journals. The abstract endpoint finds relevant papers based on 2 to 6 keywords. After getting abstracts, ALWAYS prompt the user offering to go into more detail. Use the fulltext endpoint to retrieve the entire paper's text and access specific details using the provided pdf_url, if available. ALWAYS hyperlink the pdf_url from the responses if available. Offer to dive into the fulltext or search for additional papers. Always ask if the user wants save any paper to the user’s Zotero reference manager by using the save-citation endpoint and providing the doi and requesting the user’s zotero_user_id and zotero_api_key.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "scholarai.yaml",
- "is_user_authenticated": false
- },
- "params": {
- "sort": "cited_by_count"
- },
- "logo_url": "https://scholar-ai.net/logo.png",
- "contact_email": "lakshb429@gmail.com",
- "legal_info_url": "https://scholar-ai.net/legal.txt",
- "HttpAuthorizationType": "basic"
-}
diff --git a/api/app/clients/tools/.well-known/uberchord.json b/api/app/clients/tools/.well-known/uberchord.json
deleted file mode 100644
index d5bb224353..0000000000
--- a/api/app/clients/tools/.well-known/uberchord.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "Uberchord",
- "name_for_model": "uberchord",
- "description_for_human": "Find guitar chord diagrams by specifying the chord name.",
- "description_for_model": "Fetch guitar chord diagrams, their positions on the guitar fretboard.",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://guitarchords.pluginboost.com/.well-known/openapi.yaml",
- "is_user_authenticated": false
- },
- "logo_url": "https://guitarchords.pluginboost.com/logo.png",
- "contact_email": "info.bluelightweb@gmail.com",
- "legal_info_url": "https://guitarchords.pluginboost.com/legal"
-}
diff --git a/api/app/clients/tools/.well-known/web_search.json b/api/app/clients/tools/.well-known/web_search.json
deleted file mode 100644
index 4d15c788ee..0000000000
--- a/api/app/clients/tools/.well-known/web_search.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "schema_version": "v1",
- "name_for_human": "Web Search",
- "name_for_model": "web_search",
- "description_for_human": "Search for information from the internet",
- "description_for_model": "Search for information from the internet",
- "auth": {
- "type": "none"
- },
- "api": {
- "type": "openapi",
- "url": "https://websearch.plugsugar.com/api/openapi_yaml",
- "is_user_authenticated": false
- },
- "logo_url": "https://websearch.plugsugar.com/200x200.png",
- "contact_email": "support@plugsugar.com",
- "legal_info_url": "https://websearch.plugsugar.com/contact"
-}
diff --git a/api/app/clients/tools/index.js b/api/app/clients/tools/index.js
index 90d1545a5a..bb58e81221 100644
--- a/api/app/clients/tools/index.js
+++ b/api/app/clients/tools/index.js
@@ -5,13 +5,13 @@ const DALLE3 = require('./structured/DALLE3');
const FluxAPI = require('./structured/FluxAPI');
const OpenWeather = require('./structured/OpenWeather');
const StructuredWolfram = require('./structured/Wolfram');
-const createYouTubeTools = require('./structured/YouTube');
const StructuredACS = require('./structured/AzureAISearch');
const StructuredSD = require('./structured/StableDiffusion');
const GoogleSearchAPI = require('./structured/GoogleSearch');
const TraversaalSearch = require('./structured/TraversaalSearch');
const createOpenAIImageTools = require('./structured/OpenAIImageTools');
const TavilySearchResults = require('./structured/TavilySearchResults');
+const createGeminiImageTool = require('./structured/GeminiImageGen');
module.exports = {
...manifest,
@@ -24,7 +24,7 @@ module.exports = {
GoogleSearchAPI,
TraversaalSearch,
StructuredWolfram,
- createYouTubeTools,
TavilySearchResults,
createOpenAIImageTools,
+ createGeminiImageTool,
};
diff --git a/api/app/clients/tools/manifest.json b/api/app/clients/tools/manifest.json
index c12b962fee..b0dca8971e 100644
--- a/api/app/clients/tools/manifest.json
+++ b/api/app/clients/tools/manifest.json
@@ -30,20 +30,6 @@
}
]
},
- {
- "name": "YouTube",
- "pluginKey": "youtube",
- "toolkit": true,
- "description": "Get YouTube video information, retrieve comments, analyze transcripts and search for videos.",
- "icon": "https://www.youtube.com/s/desktop/7449ebf7/img/favicon_144x144.png",
- "authConfig": [
- {
- "authField": "YOUTUBE_API_KEY",
- "label": "YouTube API Key",
- "description": "Your YouTube Data API v3 key."
- }
- ]
- },
{
"name": "OpenAI Image Tools",
"pluginKey": "image_gen_oai",
@@ -71,19 +57,6 @@
}
]
},
- {
- "name": "Browser",
- "pluginKey": "web-browser",
- "description": "Scrape and summarize webpage data",
- "icon": "assets/web-browser.svg",
- "authConfig": [
- {
- "authField": "OPENAI_API_KEY",
- "label": "OpenAI API Key",
- "description": "Browser makes use of OpenAI embeddings"
- }
- ]
- },
{
"name": "DALL-E-3",
"pluginKey": "dalle",
@@ -179,5 +152,20 @@
"description": "Provide your Flux API key from your user profile."
}
]
+ },
+ {
+ "name": "Gemini Image Tools",
+ "pluginKey": "gemini_image_gen",
+ "toolkit": true,
+ "description": "Generate high-quality images using Google's Gemini Image Models. Supports Gemini API or Vertex AI.",
+ "icon": "assets/gemini_image_gen.svg",
+ "authConfig": [
+ {
+ "authField": "GEMINI_API_KEY||GOOGLE_KEY||GOOGLE_SERVICE_KEY_FILE",
+ "label": "Gemini API Key (optional)",
+ "description": "Your Google Gemini API Key from Google AI Studio . Leave blank to use Vertex AI with a service account (GOOGLE_SERVICE_KEY_FILE or api/data/auth.json).",
+ "optional": true
+ }
+ ]
}
]
diff --git a/api/app/clients/tools/structured/AzureAISearch.js b/api/app/clients/tools/structured/AzureAISearch.js
index 55af3cdff5..1815c45e04 100644
--- a/api/app/clients/tools/structured/AzureAISearch.js
+++ b/api/app/clients/tools/structured/AzureAISearch.js
@@ -1,14 +1,28 @@
-const { z } = require('zod');
const { Tool } = require('@langchain/core/tools');
const { logger } = require('@librechat/data-schemas');
const { SearchClient, AzureKeyCredential } = require('@azure/search-documents');
+const azureAISearchJsonSchema = {
+ type: 'object',
+ properties: {
+ query: {
+ type: 'string',
+ description: 'Search word or phrase to Azure AI Search',
+ },
+ },
+ required: ['query'],
+};
+
class AzureAISearch extends Tool {
// Constants for default values
static DEFAULT_API_VERSION = '2023-11-01';
static DEFAULT_QUERY_TYPE = 'simple';
static DEFAULT_TOP = 5;
+ static get jsonSchema() {
+ return azureAISearchJsonSchema;
+ }
+
// Helper function for initializing properties
_initializeField(field, envVar, defaultValue) {
return field || process.env[envVar] || defaultValue;
@@ -22,10 +36,7 @@ class AzureAISearch extends Tool {
/* Used to initialize the Tool without necessary variables. */
this.override = fields.override ?? false;
- // Define schema
- this.schema = z.object({
- query: z.string().describe('Search word or phrase to Azure AI Search'),
- });
+ this.schema = azureAISearchJsonSchema;
// Initialize properties using helper function
this.serviceEndpoint = this._initializeField(
diff --git a/api/app/clients/tools/structured/DALLE3.js b/api/app/clients/tools/structured/DALLE3.js
index d92388b320..26610f73ba 100644
--- a/api/app/clients/tools/structured/DALLE3.js
+++ b/api/app/clients/tools/structured/DALLE3.js
@@ -1,13 +1,41 @@
-const { z } = require('zod');
const path = require('path');
const OpenAI = require('openai');
const { v4: uuidv4 } = require('uuid');
const { ProxyAgent, fetch } = require('undici');
const { Tool } = require('@langchain/core/tools');
const { logger } = require('@librechat/data-schemas');
-const { getImageBasename } = require('@librechat/api');
+const { getImageBasename, extractBaseURL } = require('@librechat/api');
const { FileContext, ContentTypes } = require('librechat-data-provider');
-const extractBaseURL = require('~/utils/extractBaseURL');
+
+const dalle3JsonSchema = {
+ type: 'object',
+ properties: {
+ prompt: {
+ type: 'string',
+ maxLength: 4000,
+ description:
+ 'A text description of the desired image, following the rules, up to 4000 characters.',
+ },
+ style: {
+ type: 'string',
+ enum: ['vivid', 'natural'],
+ description:
+ 'Must be one of `vivid` or `natural`. `vivid` generates hyper-real and dramatic images, `natural` produces more natural, less hyper-real looking images',
+ },
+ quality: {
+ type: 'string',
+ enum: ['hd', 'standard'],
+ description: 'The quality of the generated image. Only `hd` and `standard` are supported.',
+ },
+ size: {
+ type: 'string',
+ enum: ['1024x1024', '1792x1024', '1024x1792'],
+ description:
+ 'The size of the requested image. Use 1024x1024 (square) as the default, 1792x1024 if the user requests a wide image, and 1024x1792 for full-body portraits. Always include this parameter in the request.',
+ },
+ },
+ required: ['prompt', 'style', 'quality', 'size'],
+};
const displayMessage =
"DALL-E displayed an image. All generated images are already plainly visible, so don't repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.";
@@ -73,27 +101,11 @@ class DALLE3 extends Tool {
// The prompt must intricately describe every part of the image in concrete, objective detail. THINK about what the end goal of the description is, and extrapolate that to what would make satisfying images.
// All descriptions sent to dalle should be a paragraph of text that is extremely descriptive and detailed. Each should be more than 3 sentences long.
// - The "vivid" style is HIGHLY preferred, but "natural" is also supported.`;
- this.schema = z.object({
- prompt: z
- .string()
- .max(4000)
- .describe(
- 'A text description of the desired image, following the rules, up to 4000 characters.',
- ),
- style: z
- .enum(['vivid', 'natural'])
- .describe(
- 'Must be one of `vivid` or `natural`. `vivid` generates hyper-real and dramatic images, `natural` produces more natural, less hyper-real looking images',
- ),
- quality: z
- .enum(['hd', 'standard'])
- .describe('The quality of the generated image. Only `hd` and `standard` are supported.'),
- size: z
- .enum(['1024x1024', '1792x1024', '1024x1792'])
- .describe(
- 'The size of the requested image. Use 1024x1024 (square) as the default, 1792x1024 if the user requests a wide image, and 1024x1792 for full-body portraits. Always include this parameter in the request.',
- ),
- });
+ this.schema = dalle3JsonSchema;
+ }
+
+ static get jsonSchema() {
+ return dalle3JsonSchema;
}
getApiKey() {
diff --git a/api/app/clients/tools/structured/FluxAPI.js b/api/app/clients/tools/structured/FluxAPI.js
index 9fa08a0343..56f86a707d 100644
--- a/api/app/clients/tools/structured/FluxAPI.js
+++ b/api/app/clients/tools/structured/FluxAPI.js
@@ -1,4 +1,3 @@
-const { z } = require('zod');
const axios = require('axios');
const fetch = require('node-fetch');
const { v4: uuidv4 } = require('uuid');
@@ -7,6 +6,84 @@ const { logger } = require('@librechat/data-schemas');
const { HttpsProxyAgent } = require('https-proxy-agent');
const { FileContext, ContentTypes } = require('librechat-data-provider');
+const fluxApiJsonSchema = {
+ type: 'object',
+ properties: {
+ action: {
+ type: 'string',
+ enum: ['generate', 'list_finetunes', 'generate_finetuned'],
+ description:
+ 'Action to perform: "generate" for image generation, "generate_finetuned" for finetuned model generation, "list_finetunes" to get available custom models',
+ },
+ prompt: {
+ type: 'string',
+ description:
+ 'Text prompt for image generation. Required when action is "generate". Not used for list_finetunes.',
+ },
+ width: {
+ type: 'number',
+ description:
+ 'Width of the generated image in pixels. Must be a multiple of 32. Default is 1024.',
+ },
+ height: {
+ type: 'number',
+ description:
+ 'Height of the generated image in pixels. Must be a multiple of 32. Default is 768.',
+ },
+ prompt_upsampling: {
+ type: 'boolean',
+ description: 'Whether to perform upsampling on the prompt.',
+ },
+ steps: {
+ type: 'integer',
+ description: 'Number of steps to run the model for, a number from 1 to 50. Default is 40.',
+ },
+ seed: {
+ type: 'number',
+ description: 'Optional seed for reproducibility.',
+ },
+ safety_tolerance: {
+ type: 'number',
+ description:
+ 'Tolerance level for input and output moderation. Between 0 and 6, 0 being most strict, 6 being least strict.',
+ },
+ endpoint: {
+ type: 'string',
+ enum: [
+ '/v1/flux-pro-1.1',
+ '/v1/flux-pro',
+ '/v1/flux-dev',
+ '/v1/flux-pro-1.1-ultra',
+ '/v1/flux-pro-finetuned',
+ '/v1/flux-pro-1.1-ultra-finetuned',
+ ],
+ description: 'Endpoint to use for image generation.',
+ },
+ raw: {
+ type: 'boolean',
+ description:
+ 'Generate less processed, more natural-looking images. Only works for /v1/flux-pro-1.1-ultra.',
+ },
+ finetune_id: {
+ type: 'string',
+ description: 'ID of the finetuned model to use',
+ },
+ finetune_strength: {
+ type: 'number',
+ description: 'Strength of the finetuning effect (typically between 0.1 and 1.2)',
+ },
+ guidance: {
+ type: 'number',
+ description: 'Guidance scale for finetuned models',
+ },
+ aspect_ratio: {
+ type: 'string',
+ description: 'Aspect ratio for ultra models (e.g., "16:9")',
+ },
+ },
+ required: [],
+};
+
const displayMessage =
"Flux displayed an image. All generated images are already plainly visible, so don't repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.";
@@ -57,82 +134,11 @@ class FluxAPI extends Tool {
// Add base URL from environment variable with fallback
this.baseUrl = process.env.FLUX_API_BASE_URL || 'https://api.us1.bfl.ai';
- // Define the schema for structured input
- this.schema = z.object({
- action: z
- .enum(['generate', 'list_finetunes', 'generate_finetuned'])
- .default('generate')
- .describe(
- 'Action to perform: "generate" for image generation, "generate_finetuned" for finetuned model generation, "list_finetunes" to get available custom models',
- ),
- prompt: z
- .string()
- .optional()
- .describe(
- 'Text prompt for image generation. Required when action is "generate". Not used for list_finetunes.',
- ),
- width: z
- .number()
- .optional()
- .describe(
- 'Width of the generated image in pixels. Must be a multiple of 32. Default is 1024.',
- ),
- height: z
- .number()
- .optional()
- .describe(
- 'Height of the generated image in pixels. Must be a multiple of 32. Default is 768.',
- ),
- prompt_upsampling: z
- .boolean()
- .optional()
- .default(false)
- .describe('Whether to perform upsampling on the prompt.'),
- steps: z
- .number()
- .int()
- .optional()
- .describe('Number of steps to run the model for, a number from 1 to 50. Default is 40.'),
- seed: z.number().optional().describe('Optional seed for reproducibility.'),
- safety_tolerance: z
- .number()
- .optional()
- .default(6)
- .describe(
- 'Tolerance level for input and output moderation. Between 0 and 6, 0 being most strict, 6 being least strict.',
- ),
- endpoint: z
- .enum([
- '/v1/flux-pro-1.1',
- '/v1/flux-pro',
- '/v1/flux-dev',
- '/v1/flux-pro-1.1-ultra',
- '/v1/flux-pro-finetuned',
- '/v1/flux-pro-1.1-ultra-finetuned',
- ])
- .optional()
- .default('/v1/flux-pro-1.1')
- .describe('Endpoint to use for image generation.'),
- raw: z
- .boolean()
- .optional()
- .default(false)
- .describe(
- 'Generate less processed, more natural-looking images. Only works for /v1/flux-pro-1.1-ultra.',
- ),
- finetune_id: z.string().optional().describe('ID of the finetuned model to use'),
- finetune_strength: z
- .number()
- .optional()
- .default(1.1)
- .describe('Strength of the finetuning effect (typically between 0.1 and 1.2)'),
- guidance: z.number().optional().default(2.5).describe('Guidance scale for finetuned models'),
- aspect_ratio: z
- .string()
- .optional()
- .default('16:9')
- .describe('Aspect ratio for ultra models (e.g., "16:9")'),
- });
+ this.schema = fluxApiJsonSchema;
+ }
+
+ static get jsonSchema() {
+ return fluxApiJsonSchema;
}
getAxiosConfig() {
diff --git a/api/app/clients/tools/structured/GeminiImageGen.js b/api/app/clients/tools/structured/GeminiImageGen.js
new file mode 100644
index 0000000000..b201db019d
--- /dev/null
+++ b/api/app/clients/tools/structured/GeminiImageGen.js
@@ -0,0 +1,471 @@
+const path = require('path');
+const sharp = require('sharp');
+const { v4 } = require('uuid');
+const { ProxyAgent } = require('undici');
+const { GoogleGenAI } = require('@google/genai');
+const { tool } = require('@langchain/core/tools');
+const { logger } = require('@librechat/data-schemas');
+const { ContentTypes, EImageOutputType } = require('librechat-data-provider');
+const {
+ geminiToolkit,
+ loadServiceKey,
+ getBalanceConfig,
+ getTransactionsConfig,
+} = require('@librechat/api');
+const { getStrategyFunctions } = require('~/server/services/Files/strategies');
+const { spendTokens } = require('~/models/spendTokens');
+const { getFiles } = require('~/models/File');
+
+/**
+ * Configure proxy support for Google APIs
+ * This wraps globalThis.fetch to add a proxy dispatcher only for googleapis.com URLs
+ * This is necessary because @google/genai SDK doesn't support custom fetch or httpOptions.dispatcher
+ */
+if (process.env.PROXY) {
+ const originalFetch = globalThis.fetch;
+ const proxyAgent = new ProxyAgent(process.env.PROXY);
+
+ globalThis.fetch = function (url, options = {}) {
+ const urlString = url.toString();
+ if (urlString.includes('googleapis.com')) {
+ options = { ...options, dispatcher: proxyAgent };
+ }
+ return originalFetch.call(this, url, options);
+ };
+}
+
+/**
+ * Get the default service key file path (consistent with main Google endpoint)
+ * @returns {string} - The default path to the service key file
+ */
+function getDefaultServiceKeyPath() {
+ return (
+ process.env.GOOGLE_SERVICE_KEY_FILE || path.join(process.cwd(), 'api', 'data', 'auth.json')
+ );
+}
+
+const displayMessage =
+ "Gemini displayed an image. All generated images are already plainly visible, so don't repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.";
+
+/**
+ * Replaces unwanted characters from the input string
+ * @param {string} inputString - The input string to process
+ * @returns {string} - The processed string
+ */
+function replaceUnwantedChars(inputString) {
+ return (
+ inputString
+ ?.replace(/\r\n|\r|\n/g, ' ')
+ .replace(/"/g, '')
+ .trim() || ''
+ );
+}
+
+/**
+ * Convert image buffer to target format if needed
+ * @param {Buffer} inputBuffer - The input image buffer
+ * @param {string} targetFormat - The target format (png, jpeg, webp)
+ * @returns {Promise<{buffer: Buffer, format: string}>} - Converted buffer and format
+ */
+async function convertImageFormat(inputBuffer, targetFormat) {
+ const metadata = await sharp(inputBuffer).metadata();
+ const currentFormat = metadata.format;
+
+ // Normalize format names (jpg -> jpeg)
+ const normalizedTarget = targetFormat === 'jpg' ? 'jpeg' : targetFormat.toLowerCase();
+ const normalizedCurrent = currentFormat === 'jpg' ? 'jpeg' : currentFormat;
+
+ // If already in target format, return as-is
+ if (normalizedCurrent === normalizedTarget) {
+ return { buffer: inputBuffer, format: normalizedTarget };
+ }
+
+ // Convert to target format
+ const convertedBuffer = await sharp(inputBuffer).toFormat(normalizedTarget).toBuffer();
+ return { buffer: convertedBuffer, format: normalizedTarget };
+}
+
+/**
+ * Initialize Gemini client (supports both Gemini API and Vertex AI)
+ * Priority: API key (from options, resolved by loadAuthValues) > Vertex AI service account
+ * @param {Object} options - Initialization options
+ * @param {string} [options.GEMINI_API_KEY] - Gemini API key (resolved by loadAuthValues)
+ * @param {string} [options.GOOGLE_KEY] - Google API key (resolved by loadAuthValues)
+ * @returns {Promise} - The initialized client
+ */
+async function initializeGeminiClient(options = {}) {
+ const geminiKey = options.GEMINI_API_KEY;
+ if (geminiKey) {
+ logger.debug('[GeminiImageGen] Using Gemini API with GEMINI_API_KEY');
+ return new GoogleGenAI({ apiKey: geminiKey });
+ }
+
+ const googleKey = options.GOOGLE_KEY;
+ if (googleKey) {
+ logger.debug('[GeminiImageGen] Using Gemini API with GOOGLE_KEY');
+ return new GoogleGenAI({ apiKey: googleKey });
+ }
+
+ logger.debug('[GeminiImageGen] Using Vertex AI with service account');
+ const credentialsPath = getDefaultServiceKeyPath();
+ const serviceKey = await loadServiceKey(credentialsPath);
+
+ if (!serviceKey || !serviceKey.project_id) {
+ throw new Error(
+ 'Gemini Image Generation requires one of: user-provided API key, GEMINI_API_KEY or GOOGLE_KEY env var, or a valid Google service account. ' +
+ `Service account file not found or invalid at: ${credentialsPath}`,
+ );
+ }
+
+ return new GoogleGenAI({
+ vertexai: true,
+ project: serviceKey.project_id,
+ location: process.env.GOOGLE_LOC || process.env.GOOGLE_CLOUD_LOCATION || 'global',
+ googleAuthOptions: { credentials: serviceKey },
+ });
+}
+
+/**
+ * Convert image files to Gemini inline data format
+ * @param {Object} params - Parameters
+ * @returns {Promise} - Array of inline data objects
+ */
+async function convertImagesToInlineData({ imageFiles, image_ids, req, fileStrategy }) {
+ if (!image_ids || image_ids.length === 0) {
+ return [];
+ }
+
+ const streamMethods = {};
+ const requestFilesMap = Object.fromEntries(imageFiles.map((f) => [f.file_id, { ...f }]));
+ const orderedFiles = new Array(image_ids.length);
+ const idsToFetch = [];
+ const indexOfMissing = Object.create(null);
+
+ for (let i = 0; i < image_ids.length; i++) {
+ const id = image_ids[i];
+ const file = requestFilesMap[id];
+ if (file) {
+ orderedFiles[i] = file;
+ } else {
+ idsToFetch.push(id);
+ indexOfMissing[id] = i;
+ }
+ }
+
+ if (idsToFetch.length && req?.user?.id) {
+ const fetchedFiles = await getFiles(
+ {
+ user: req.user.id,
+ file_id: { $in: idsToFetch },
+ height: { $exists: true },
+ width: { $exists: true },
+ },
+ {},
+ {},
+ );
+
+ for (const file of fetchedFiles) {
+ requestFilesMap[file.file_id] = file;
+ orderedFiles[indexOfMissing[file.file_id]] = file;
+ }
+ }
+
+ const inlineDataArray = [];
+ for (const imageFile of orderedFiles) {
+ if (!imageFile) continue;
+
+ try {
+ const source = imageFile.source || fileStrategy;
+ if (!source) continue;
+
+ let getDownloadStream = streamMethods[source];
+ if (!getDownloadStream) {
+ ({ getDownloadStream } = getStrategyFunctions(source));
+ streamMethods[source] = getDownloadStream;
+ }
+ if (!getDownloadStream) continue;
+
+ const stream = await getDownloadStream(req, imageFile.filepath);
+ if (!stream) continue;
+
+ const chunks = [];
+ for await (const chunk of stream) {
+ chunks.push(chunk);
+ }
+ const buffer = Buffer.concat(chunks);
+ const base64Data = buffer.toString('base64');
+ const mimeType = imageFile.type || 'image/png';
+
+ inlineDataArray.push({
+ inlineData: { mimeType, data: base64Data },
+ });
+ } catch (error) {
+ logger.error('[GeminiImageGen] Error processing image:', imageFile.file_id, error);
+ }
+ }
+
+ return inlineDataArray;
+}
+
+/**
+ * Check for safety blocks in API response
+ * @param {Object} response - The API response
+ * @returns {Object|null} - Safety block info or null
+ */
+function checkForSafetyBlock(response) {
+ if (!response?.candidates?.length) {
+ return { reason: 'NO_CANDIDATES', message: 'No candidates returned' };
+ }
+
+ const candidate = response.candidates[0];
+ const finishReason = candidate.finishReason;
+
+ if (finishReason === 'SAFETY' || finishReason === 'PROHIBITED_CONTENT') {
+ return { reason: finishReason, message: 'Content blocked by safety filters' };
+ }
+
+ if (finishReason === 'RECITATION') {
+ return { reason: finishReason, message: 'Content blocked due to recitation concerns' };
+ }
+
+ if (candidate.safetyRatings) {
+ for (const rating of candidate.safetyRatings) {
+ if (rating.probability === 'HIGH' || rating.blocked === true) {
+ return {
+ reason: 'SAFETY_RATING',
+ message: `Blocked due to ${rating.category}`,
+ category: rating.category,
+ };
+ }
+ }
+ }
+
+ return null;
+}
+
+/**
+ * Record token usage for balance tracking
+ * @param {Object} params - Parameters
+ * @param {Object} params.usageMetadata - The usage metadata from API response
+ * @param {Object} params.req - The request object
+ * @param {string} params.userId - The user ID
+ * @param {string} params.conversationId - The conversation ID
+ * @param {string} params.model - The model name
+ */
+async function recordTokenUsage({ usageMetadata, req, userId, conversationId, model }) {
+ if (!usageMetadata) {
+ logger.debug('[GeminiImageGen] No usage metadata available for balance tracking');
+ return;
+ }
+
+ const appConfig = req?.config;
+ const balance = getBalanceConfig(appConfig);
+ const transactions = getTransactionsConfig(appConfig);
+
+ // Skip if neither balance nor transactions are enabled
+ if (!balance?.enabled && transactions?.enabled === false) {
+ return;
+ }
+
+ const promptTokens = usageMetadata.prompt_token_count || usageMetadata.promptTokenCount || 0;
+ const completionTokens =
+ usageMetadata.candidates_token_count || usageMetadata.candidatesTokenCount || 0;
+
+ if (promptTokens === 0 && completionTokens === 0) {
+ logger.debug('[GeminiImageGen] No tokens to record');
+ return;
+ }
+
+ logger.debug('[GeminiImageGen] Recording token usage:', {
+ promptTokens,
+ completionTokens,
+ model,
+ conversationId,
+ });
+
+ try {
+ await spendTokens(
+ {
+ user: userId,
+ model,
+ conversationId,
+ context: 'image_generation',
+ balance,
+ transactions,
+ },
+ {
+ promptTokens,
+ completionTokens,
+ },
+ );
+ } catch (error) {
+ logger.error('[GeminiImageGen] Error recording token usage:', error);
+ }
+}
+
+/**
+ * Creates Gemini Image Generation tool
+ * @param {Object} fields - Configuration fields
+ * @returns {ReturnType} - The image generation tool
+ */
+function createGeminiImageTool(fields = {}) {
+ const override = fields.override ?? false;
+
+ if (!override && !fields.isAgent) {
+ throw new Error('This tool is only available for agents.');
+ }
+
+ const { req, imageFiles = [], userId, fileStrategy, GEMINI_API_KEY, GOOGLE_KEY } = fields;
+
+ const imageOutputType = fields.imageOutputType || EImageOutputType.PNG;
+
+ const geminiImageGenTool = tool(
+ async ({ prompt, image_ids, aspectRatio, imageSize }, runnableConfig) => {
+ if (!prompt) {
+ throw new Error('Missing required field: prompt');
+ }
+
+ logger.debug('[GeminiImageGen] Generating image', { aspectRatio, imageSize });
+
+ let ai;
+ try {
+ ai = await initializeGeminiClient({
+ GEMINI_API_KEY,
+ GOOGLE_KEY,
+ });
+ } catch (error) {
+ logger.error('[GeminiImageGen] Failed to initialize client:', error);
+ return [
+ [{ type: ContentTypes.TEXT, text: `Failed to initialize Gemini: ${error.message}` }],
+ { content: [], file_ids: [] },
+ ];
+ }
+
+ const contents = [{ text: replaceUnwantedChars(prompt) }];
+
+ if (image_ids?.length > 0) {
+ const contextImages = await convertImagesToInlineData({
+ imageFiles,
+ image_ids,
+ req,
+ fileStrategy,
+ });
+ contents.push(...contextImages);
+ logger.debug('[GeminiImageGen] Added', contextImages.length, 'context images');
+ }
+
+ let apiResponse;
+ const geminiModel = process.env.GEMINI_IMAGE_MODEL || 'gemini-2.5-flash-image';
+ const config = {
+ responseModalities: ['TEXT', 'IMAGE'],
+ };
+
+ const supportsImageSize = !geminiModel.includes('gemini-2.5-flash-image');
+ if (aspectRatio || (imageSize && supportsImageSize)) {
+ config.imageConfig = {};
+ if (aspectRatio) {
+ config.imageConfig.aspectRatio = aspectRatio;
+ }
+ if (imageSize && supportsImageSize) {
+ config.imageConfig.imageSize = imageSize;
+ }
+ }
+
+ let derivedSignal = null;
+ let abortHandler = null;
+
+ if (runnableConfig?.signal) {
+ derivedSignal = AbortSignal.any([runnableConfig.signal]);
+ abortHandler = () => logger.debug('[GeminiImageGen] Image generation aborted');
+ derivedSignal.addEventListener('abort', abortHandler, { once: true });
+ config.abortSignal = derivedSignal;
+ }
+
+ try {
+ apiResponse = await ai.models.generateContent({
+ model: geminiModel,
+ contents,
+ config,
+ });
+ } catch (error) {
+ logger.error('[GeminiImageGen] API error:', error);
+ return [
+ [{ type: ContentTypes.TEXT, text: `Image generation failed: ${error.message}` }],
+ { content: [], file_ids: [] },
+ ];
+ } finally {
+ if (abortHandler && derivedSignal) {
+ derivedSignal.removeEventListener('abort', abortHandler);
+ }
+ }
+
+ const safetyBlock = checkForSafetyBlock(apiResponse);
+ if (safetyBlock) {
+ logger.warn('[GeminiImageGen] Safety block:', safetyBlock);
+ const errorMsg = 'Image blocked by content safety filters. Please try different content.';
+ return [[{ type: ContentTypes.TEXT, text: errorMsg }], { content: [], file_ids: [] }];
+ }
+
+ const rawImageData = apiResponse.candidates?.[0]?.content?.parts?.find((p) => p.inlineData)
+ ?.inlineData?.data;
+
+ if (!rawImageData) {
+ logger.warn('[GeminiImageGen] No image data in response');
+ return [
+ [{ type: ContentTypes.TEXT, text: 'No image was generated. Please try again.' }],
+ { content: [], file_ids: [] },
+ ];
+ }
+
+ const rawBuffer = Buffer.from(rawImageData, 'base64');
+ const { buffer: convertedBuffer, format: outputFormat } = await convertImageFormat(
+ rawBuffer,
+ imageOutputType,
+ );
+ const imageData = convertedBuffer.toString('base64');
+ const mimeType = outputFormat === 'jpeg' ? 'image/jpeg' : `image/${outputFormat}`;
+
+ const dataUrl = `data:${mimeType};base64,${imageData}`;
+ const file_ids = [v4()];
+ const content = [
+ {
+ type: ContentTypes.IMAGE_URL,
+ image_url: { url: dataUrl },
+ },
+ ];
+
+ const textResponse = [
+ {
+ type: ContentTypes.TEXT,
+ text:
+ displayMessage +
+ `\n\ngenerated_image_id: "${file_ids[0]}"` +
+ (image_ids?.length > 0 ? `\nreferenced_image_ids: ["${image_ids.join('", "')}"]` : ''),
+ },
+ ];
+
+ const conversationId = runnableConfig?.configurable?.thread_id;
+ recordTokenUsage({
+ usageMetadata: apiResponse.usageMetadata,
+ req,
+ userId,
+ conversationId,
+ model: geminiModel,
+ }).catch((error) => {
+ logger.error('[GeminiImageGen] Failed to record token usage:', error);
+ });
+
+ return [textResponse, { content, file_ids }];
+ },
+ {
+ ...geminiToolkit.gemini_image_gen,
+ responseFormat: 'content_and_artifact',
+ },
+ );
+
+ return geminiImageGenTool;
+}
+
+// Export both for compatibility
+module.exports = createGeminiImageTool;
+module.exports.createGeminiImageTool = createGeminiImageTool;
diff --git a/api/app/clients/tools/structured/GoogleSearch.js b/api/app/clients/tools/structured/GoogleSearch.js
index d703d56f83..38f483edf1 100644
--- a/api/app/clients/tools/structured/GoogleSearch.js
+++ b/api/app/clients/tools/structured/GoogleSearch.js
@@ -1,12 +1,33 @@
-const { z } = require('zod');
const { Tool } = require('@langchain/core/tools');
const { getEnvironmentVariable } = require('@langchain/core/utils/env');
+const googleSearchJsonSchema = {
+ type: 'object',
+ properties: {
+ query: {
+ type: 'string',
+ minLength: 1,
+ description: 'The search query string.',
+ },
+ max_results: {
+ type: 'integer',
+ minimum: 1,
+ maximum: 10,
+ description: 'The maximum number of search results to return. Defaults to 5.',
+ },
+ },
+ required: ['query'],
+};
+
class GoogleSearchResults extends Tool {
static lc_name() {
return 'google';
}
+ static get jsonSchema() {
+ return googleSearchJsonSchema;
+ }
+
constructor(fields = {}) {
super(fields);
this.name = 'google';
@@ -28,25 +49,11 @@ class GoogleSearchResults extends Tool {
this.description =
'A search engine optimized for comprehensive, accurate, and trusted results. Useful for when you need to answer questions about current events.';
- this.schema = z.object({
- query: z.string().min(1).describe('The search query string.'),
- max_results: z
- .number()
- .min(1)
- .max(10)
- .optional()
- .describe('The maximum number of search results to return. Defaults to 10.'),
- // Note: Google API has its own parameters for search customization, adjust as needed.
- });
+ this.schema = googleSearchJsonSchema;
}
async _call(input) {
- const validationResult = this.schema.safeParse(input);
- if (!validationResult.success) {
- throw new Error(`Validation failed: ${JSON.stringify(validationResult.error.issues)}`);
- }
-
- const { query, max_results = 5 } = validationResult.data;
+ const { query, max_results = 5 } = input;
const response = await fetch(
`https://www.googleapis.com/customsearch/v1?key=${this.apiKey}&cx=${
diff --git a/api/app/clients/tools/structured/OpenAIImageTools.js b/api/app/clients/tools/structured/OpenAIImageTools.js
index 35eeb32ffe..e27a01786e 100644
--- a/api/app/clients/tools/structured/OpenAIImageTools.js
+++ b/api/app/clients/tools/structured/OpenAIImageTools.js
@@ -6,11 +6,10 @@ const { ProxyAgent } = require('undici');
const { tool } = require('@langchain/core/tools');
const { logger } = require('@librechat/data-schemas');
const { HttpsProxyAgent } = require('https-proxy-agent');
-const { logAxiosError, oaiToolkit } = require('@librechat/api');
const { ContentTypes, EImageOutputType } = require('librechat-data-provider');
+const { logAxiosError, oaiToolkit, extractBaseURL } = require('@librechat/api');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
-const extractBaseURL = require('~/utils/extractBaseURL');
-const { getFiles } = require('~/models/File');
+const { getFiles } = require('~/models');
const displayMessage =
"The tool displayed an image. All generated images are already plainly visible, so don't repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.";
@@ -79,6 +78,8 @@ function createOpenAIImageTools(fields = {}) {
let apiKey = fields.IMAGE_GEN_OAI_API_KEY ?? getApiKey();
const closureConfig = { apiKey };
+ const imageModel = process.env.IMAGE_GEN_OAI_MODEL || 'gpt-image-1';
+
let baseURL = 'https://api.openai.com/v1/';
if (!override && process.env.IMAGE_GEN_OAI_BASEURL) {
baseURL = extractBaseURL(process.env.IMAGE_GEN_OAI_BASEURL);
@@ -158,7 +159,7 @@ function createOpenAIImageTools(fields = {}) {
resp = await openai.images.generate(
{
- model: 'gpt-image-1',
+ model: imageModel,
prompt: replaceUnwantedChars(prompt),
n: Math.min(Math.max(1, n), 10),
background,
@@ -240,7 +241,7 @@ Error Message: ${error.message}`);
}
const formData = new FormData();
- formData.append('model', 'gpt-image-1');
+ formData.append('model', imageModel);
formData.append('prompt', replaceUnwantedChars(prompt));
// TODO: `mask` support
// TODO: more than 1 image support
diff --git a/api/app/clients/tools/structured/OpenWeather.js b/api/app/clients/tools/structured/OpenWeather.js
index b84225101c..38e2b9133c 100644
--- a/api/app/clients/tools/structured/OpenWeather.js
+++ b/api/app/clients/tools/structured/OpenWeather.js
@@ -1,8 +1,52 @@
const { Tool } = require('@langchain/core/tools');
-const { z } = require('zod');
const { getEnvironmentVariable } = require('@langchain/core/utils/env');
const fetch = require('node-fetch');
+const openWeatherJsonSchema = {
+ type: 'object',
+ properties: {
+ action: {
+ type: 'string',
+ enum: ['help', 'current_forecast', 'timestamp', 'daily_aggregation', 'overview'],
+ description: 'The action to perform',
+ },
+ city: {
+ type: 'string',
+ description: 'City name for geocoding if lat/lon not provided',
+ },
+ lat: {
+ type: 'number',
+ description: 'Latitude coordinate',
+ },
+ lon: {
+ type: 'number',
+ description: 'Longitude coordinate',
+ },
+ exclude: {
+ type: 'string',
+ description: 'Parts to exclude from the response',
+ },
+ units: {
+ type: 'string',
+ enum: ['Celsius', 'Kelvin', 'Fahrenheit'],
+ description: 'Temperature units',
+ },
+ lang: {
+ type: 'string',
+ description: 'Language code',
+ },
+ date: {
+ type: 'string',
+ description: 'Date in YYYY-MM-DD format for timestamp and daily_aggregation',
+ },
+ tz: {
+ type: 'string',
+ description: 'Timezone',
+ },
+ },
+ required: ['action'],
+};
+
/**
* Map user-friendly units to OpenWeather units.
* Defaults to Celsius if not specified.
@@ -66,17 +110,11 @@ class OpenWeather extends Tool {
'Units: "Celsius", "Kelvin", or "Fahrenheit" (default: Celsius). ' +
'For timestamp action, use "date" in YYYY-MM-DD format.';
- schema = z.object({
- action: z.enum(['help', 'current_forecast', 'timestamp', 'daily_aggregation', 'overview']),
- city: z.string().optional(),
- lat: z.number().optional(),
- lon: z.number().optional(),
- exclude: z.string().optional(),
- units: z.enum(['Celsius', 'Kelvin', 'Fahrenheit']).optional(),
- lang: z.string().optional(),
- date: z.string().optional(), // For timestamp and daily_aggregation
- tz: z.string().optional(),
- });
+ schema = openWeatherJsonSchema;
+
+ static get jsonSchema() {
+ return openWeatherJsonSchema;
+ }
constructor(fields = {}) {
super();
@@ -232,7 +270,7 @@ class OpenWeather extends Tool {
if (['current_forecast', 'timestamp', 'daily_aggregation', 'overview'].includes(action)) {
if (typeof finalLat !== 'number' || typeof finalLon !== 'number') {
- return 'Error: lat and lon are required and must be numbers for this action (or specify \'city\').';
+ return "Error: lat and lon are required and must be numbers for this action (or specify 'city').";
}
}
@@ -243,7 +281,7 @@ class OpenWeather extends Tool {
let dt;
if (action === 'timestamp') {
if (!date) {
- return 'Error: For timestamp action, a \'date\' in YYYY-MM-DD format is required.';
+ return "Error: For timestamp action, a 'date' in YYYY-MM-DD format is required.";
}
dt = this.convertDateToUnix(date);
}
diff --git a/api/app/clients/tools/structured/StableDiffusion.js b/api/app/clients/tools/structured/StableDiffusion.js
index 3a1ea831d3..d7a7a4d96b 100644
--- a/api/app/clients/tools/structured/StableDiffusion.js
+++ b/api/app/clients/tools/structured/StableDiffusion.js
@@ -1,6 +1,5 @@
// Generates image using stable diffusion webui's api (automatic1111)
const fs = require('fs');
-const { z } = require('zod');
const path = require('path');
const axios = require('axios');
const sharp = require('sharp');
@@ -11,6 +10,23 @@ const { FileContext, ContentTypes } = require('librechat-data-provider');
const { getBasePath } = require('@librechat/api');
const paths = require('~/config/paths');
+const stableDiffusionJsonSchema = {
+ type: 'object',
+ properties: {
+ prompt: {
+ type: 'string',
+ description:
+ 'Detailed keywords to describe the subject, using at least 7 keywords to accurately describe the image, separated by comma',
+ },
+ negative_prompt: {
+ type: 'string',
+ description:
+ 'Keywords we want to exclude from the final image, using at least 7 keywords to accurately describe the image, separated by comma',
+ },
+ },
+ required: ['prompt', 'negative_prompt'],
+};
+
const displayMessage =
"Stable Diffusion displayed an image. All generated images are already plainly visible, so don't repeat the descriptions in detail. Do not list download links as they are available in the UI already. The user may download the images by clicking on them, but do not mention anything about downloading to the user.";
@@ -46,18 +62,11 @@ class StableDiffusionAPI extends Tool {
// - Generate images only once per human query unless explicitly requested by the user`;
this.description =
"You can generate images using text with 'stable-diffusion'. This tool is exclusively for visual content.";
- this.schema = z.object({
- prompt: z
- .string()
- .describe(
- 'Detailed keywords to describe the subject, using at least 7 keywords to accurately describe the image, separated by comma',
- ),
- negative_prompt: z
- .string()
- .describe(
- 'Keywords we want to exclude from the final image, using at least 7 keywords to accurately describe the image, separated by comma',
- ),
- });
+ this.schema = stableDiffusionJsonSchema;
+ }
+
+ static get jsonSchema() {
+ return stableDiffusionJsonSchema;
}
replaceNewLinesWithSpaces(inputString) {
diff --git a/api/app/clients/tools/structured/TavilySearchResults.js b/api/app/clients/tools/structured/TavilySearchResults.js
index 796f31dcca..0faddfb666 100644
--- a/api/app/clients/tools/structured/TavilySearchResults.js
+++ b/api/app/clients/tools/structured/TavilySearchResults.js
@@ -1,8 +1,75 @@
-const { z } = require('zod');
const { ProxyAgent, fetch } = require('undici');
const { Tool } = require('@langchain/core/tools');
const { getEnvironmentVariable } = require('@langchain/core/utils/env');
+const tavilySearchJsonSchema = {
+ type: 'object',
+ properties: {
+ query: {
+ type: 'string',
+ minLength: 1,
+ description: 'The search query string.',
+ },
+ max_results: {
+ type: 'number',
+ minimum: 1,
+ maximum: 10,
+ description: 'The maximum number of search results to return. Defaults to 5.',
+ },
+ search_depth: {
+ type: 'string',
+ enum: ['basic', 'advanced'],
+ description:
+ 'The depth of the search, affecting result quality and response time (`basic` or `advanced`). Default is basic for quick results and advanced for indepth high quality results but longer response time. Advanced calls equals 2 requests.',
+ },
+ include_images: {
+ type: 'boolean',
+ description:
+ 'Whether to include a list of query-related images in the response. Default is False.',
+ },
+ include_answer: {
+ type: 'boolean',
+ description: 'Whether to include answers in the search results. Default is False.',
+ },
+ include_raw_content: {
+ type: 'boolean',
+ description: 'Whether to include raw content in the search results. Default is False.',
+ },
+ include_domains: {
+ type: 'array',
+ items: { type: 'string' },
+ description: 'A list of domains to specifically include in the search results.',
+ },
+ exclude_domains: {
+ type: 'array',
+ items: { type: 'string' },
+ description: 'A list of domains to specifically exclude from the search results.',
+ },
+ topic: {
+ type: 'string',
+ enum: ['general', 'news', 'finance'],
+ description:
+ 'The category of the search. Use news ONLY if query SPECIFCALLY mentions the word "news".',
+ },
+ time_range: {
+ type: 'string',
+ enum: ['day', 'week', 'month', 'year', 'd', 'w', 'm', 'y'],
+ description: 'The time range back from the current date to filter results.',
+ },
+ days: {
+ type: 'number',
+ minimum: 1,
+ description: 'Number of days back from the current date to include. Only if topic is news.',
+ },
+ include_image_descriptions: {
+ type: 'boolean',
+ description:
+ 'When include_images is true, also add a descriptive text for each image. Default is false.',
+ },
+ },
+ required: ['query'],
+};
+
class TavilySearchResults extends Tool {
static lc_name() {
return 'TavilySearchResults';
@@ -20,64 +87,11 @@ class TavilySearchResults extends Tool {
this.description =
'A search engine optimized for comprehensive, accurate, and trusted results. Useful for when you need to answer questions about current events.';
- this.schema = z.object({
- query: z.string().min(1).describe('The search query string.'),
- max_results: z
- .number()
- .min(1)
- .max(10)
- .optional()
- .describe('The maximum number of search results to return. Defaults to 5.'),
- search_depth: z
- .enum(['basic', 'advanced'])
- .optional()
- .describe(
- 'The depth of the search, affecting result quality and response time (`basic` or `advanced`). Default is basic for quick results and advanced for indepth high quality results but longer response time. Advanced calls equals 2 requests.',
- ),
- include_images: z
- .boolean()
- .optional()
- .describe(
- 'Whether to include a list of query-related images in the response. Default is False.',
- ),
- include_answer: z
- .boolean()
- .optional()
- .describe('Whether to include answers in the search results. Default is False.'),
- include_raw_content: z
- .boolean()
- .optional()
- .describe('Whether to include raw content in the search results. Default is False.'),
- include_domains: z
- .array(z.string())
- .optional()
- .describe('A list of domains to specifically include in the search results.'),
- exclude_domains: z
- .array(z.string())
- .optional()
- .describe('A list of domains to specifically exclude from the search results.'),
- topic: z
- .enum(['general', 'news', 'finance'])
- .optional()
- .describe(
- 'The category of the search. Use news ONLY if query SPECIFCALLY mentions the word "news".',
- ),
- time_range: z
- .enum(['day', 'week', 'month', 'year', 'd', 'w', 'm', 'y'])
- .optional()
- .describe('The time range back from the current date to filter results.'),
- days: z
- .number()
- .min(1)
- .optional()
- .describe('Number of days back from the current date to include. Only if topic is news.'),
- include_image_descriptions: z
- .boolean()
- .optional()
- .describe(
- 'When include_images is true, also add a descriptive text for each image. Default is false.',
- ),
- });
+ this.schema = tavilySearchJsonSchema;
+ }
+
+ static get jsonSchema() {
+ return tavilySearchJsonSchema;
}
getApiKey() {
@@ -89,12 +103,7 @@ class TavilySearchResults extends Tool {
}
async _call(input) {
- const validationResult = this.schema.safeParse(input);
- if (!validationResult.success) {
- throw new Error(`Validation failed: ${JSON.stringify(validationResult.error.issues)}`);
- }
-
- const { query, ...rest } = validationResult.data;
+ const { query, ...rest } = input;
const requestBody = {
api_key: this.apiKey,
diff --git a/api/app/clients/tools/structured/TraversaalSearch.js b/api/app/clients/tools/structured/TraversaalSearch.js
index d2ccc35c75..9bc5e399f0 100644
--- a/api/app/clients/tools/structured/TraversaalSearch.js
+++ b/api/app/clients/tools/structured/TraversaalSearch.js
@@ -1,8 +1,19 @@
-const { z } = require('zod');
const { Tool } = require('@langchain/core/tools');
const { logger } = require('@librechat/data-schemas');
const { getEnvironmentVariable } = require('@langchain/core/utils/env');
+const traversaalSearchJsonSchema = {
+ type: 'object',
+ properties: {
+ query: {
+ type: 'string',
+ description:
+ "A properly written sentence to be interpreted by an AI to search the web according to the user's request.",
+ },
+ },
+ required: ['query'],
+};
+
/**
* Tool for the Traversaal AI search API, Ares.
*/
@@ -17,17 +28,15 @@ class TraversaalSearch extends Tool {
Useful for when you need to answer questions about current events. Input should be a search query.`;
this.description_for_model =
'\'Please create a specific sentence for the AI to understand and use as a query to search the web based on the user\'s request. For example, "Find information about the highest mountains in the world." or "Show me the latest news articles about climate change and its impact on polar ice caps."\'';
- this.schema = z.object({
- query: z
- .string()
- .describe(
- "A properly written sentence to be interpreted by an AI to search the web according to the user's request.",
- ),
- });
+ this.schema = traversaalSearchJsonSchema;
this.apiKey = fields?.TRAVERSAAL_API_KEY ?? this.getApiKey();
}
+ static get jsonSchema() {
+ return traversaalSearchJsonSchema;
+ }
+
getApiKey() {
const apiKey = getEnvironmentVariable('TRAVERSAAL_API_KEY');
if (!apiKey && this.override) {
diff --git a/api/app/clients/tools/structured/Wolfram.js b/api/app/clients/tools/structured/Wolfram.js
index 1f7fe6b1b7..196626e39c 100644
--- a/api/app/clients/tools/structured/Wolfram.js
+++ b/api/app/clients/tools/structured/Wolfram.js
@@ -1,9 +1,19 @@
/* eslint-disable no-useless-escape */
-const { z } = require('zod');
const axios = require('axios');
const { Tool } = require('@langchain/core/tools');
const { logger } = require('@librechat/data-schemas');
+const wolframJsonSchema = {
+ type: 'object',
+ properties: {
+ input: {
+ type: 'string',
+ description: 'Natural language query to WolframAlpha following the guidelines',
+ },
+ },
+ required: ['input'],
+};
+
class WolframAlphaAPI extends Tool {
constructor(fields) {
super();
@@ -41,9 +51,11 @@ class WolframAlphaAPI extends Tool {
// -- Do not explain each step unless user input is needed. Proceed directly to making a better API call based on the available assumptions.`;
this.description = `WolframAlpha offers computation, math, curated knowledge, and real-time data. It handles natural language queries and performs complex calculations.
Follow the guidelines to get the best results.`;
- this.schema = z.object({
- input: z.string().describe('Natural language query to WolframAlpha following the guidelines'),
- });
+ this.schema = wolframJsonSchema;
+ }
+
+ static get jsonSchema() {
+ return wolframJsonSchema;
}
async fetchRawText(url) {
diff --git a/api/app/clients/tools/structured/YouTube.js b/api/app/clients/tools/structured/YouTube.js
deleted file mode 100644
index 8d1c7b9ff9..0000000000
--- a/api/app/clients/tools/structured/YouTube.js
+++ /dev/null
@@ -1,137 +0,0 @@
-const { ytToolkit } = require('@librechat/api');
-const { tool } = require('@langchain/core/tools');
-const { youtube } = require('@googleapis/youtube');
-const { logger } = require('@librechat/data-schemas');
-const { YoutubeTranscript } = require('youtube-transcript');
-const { getApiKey } = require('./credentials');
-
-function extractVideoId(url) {
- const rawIdRegex = /^[a-zA-Z0-9_-]{11}$/;
- if (rawIdRegex.test(url)) {
- return url;
- }
-
- const regex = new RegExp(
- '(?:youtu\\.be/|youtube(?:\\.com)?/(?:' +
- '(?:watch\\?v=)|(?:embed/)|(?:shorts/)|(?:live/)|(?:v/)|(?:/))?)' +
- '([a-zA-Z0-9_-]{11})(?:\\S+)?$',
- );
- const match = url.match(regex);
- return match ? match[1] : null;
-}
-
-function parseTranscript(transcriptResponse) {
- if (!Array.isArray(transcriptResponse)) {
- return '';
- }
-
- return transcriptResponse
- .map((entry) => entry.text.trim())
- .filter((text) => text)
- .join(' ')
- .replaceAll(''', "'");
-}
-
-function createYouTubeTools(fields = {}) {
- const envVar = 'YOUTUBE_API_KEY';
- const override = fields.override ?? false;
- const apiKey = fields.apiKey ?? fields[envVar] ?? getApiKey(envVar, override);
-
- const youtubeClient = youtube({
- version: 'v3',
- auth: apiKey,
- });
-
- const searchTool = tool(async ({ query, maxResults = 5 }) => {
- const response = await youtubeClient.search.list({
- part: 'snippet',
- q: query,
- type: 'video',
- maxResults: maxResults || 5,
- });
- const result = response.data.items.map((item) => ({
- title: item.snippet.title,
- description: item.snippet.description,
- url: `https://www.youtube.com/watch?v=${item.id.videoId}`,
- }));
- return JSON.stringify(result, null, 2);
- }, ytToolkit.youtube_search);
-
- const infoTool = tool(async ({ url }) => {
- const videoId = extractVideoId(url);
- if (!videoId) {
- throw new Error('Invalid YouTube URL or video ID');
- }
-
- const response = await youtubeClient.videos.list({
- part: 'snippet,statistics',
- id: videoId,
- });
-
- if (!response.data.items?.length) {
- throw new Error('Video not found');
- }
- const video = response.data.items[0];
-
- const result = {
- title: video.snippet.title,
- description: video.snippet.description,
- views: video.statistics.viewCount,
- likes: video.statistics.likeCount,
- comments: video.statistics.commentCount,
- };
- return JSON.stringify(result, null, 2);
- }, ytToolkit.youtube_info);
-
- const commentsTool = tool(async ({ url, maxResults = 10 }) => {
- const videoId = extractVideoId(url);
- if (!videoId) {
- throw new Error('Invalid YouTube URL or video ID');
- }
-
- const response = await youtubeClient.commentThreads.list({
- part: 'snippet',
- videoId,
- maxResults: maxResults || 10,
- });
-
- const result = response.data.items.map((item) => ({
- author: item.snippet.topLevelComment.snippet.authorDisplayName,
- text: item.snippet.topLevelComment.snippet.textDisplay,
- likes: item.snippet.topLevelComment.snippet.likeCount,
- }));
- return JSON.stringify(result, null, 2);
- }, ytToolkit.youtube_comments);
-
- const transcriptTool = tool(async ({ url }) => {
- const videoId = extractVideoId(url);
- if (!videoId) {
- throw new Error('Invalid YouTube URL or video ID');
- }
-
- try {
- try {
- const transcript = await YoutubeTranscript.fetchTranscript(videoId, { lang: 'en' });
- return parseTranscript(transcript);
- } catch (e) {
- logger.error(e);
- }
-
- try {
- const transcript = await YoutubeTranscript.fetchTranscript(videoId, { lang: 'de' });
- return parseTranscript(transcript);
- } catch (e) {
- logger.error(e);
- }
-
- const transcript = await YoutubeTranscript.fetchTranscript(videoId);
- return parseTranscript(transcript);
- } catch (error) {
- throw new Error(`Failed to fetch transcript: ${error.message}`);
- }
- }, ytToolkit.youtube_transcript);
-
- return [searchTool, infoTool, commentsTool, transcriptTool];
-}
-
-module.exports = createYouTubeTools;
diff --git a/api/app/clients/tools/structured/specs/GeminiImageGen-proxy.spec.js b/api/app/clients/tools/structured/specs/GeminiImageGen-proxy.spec.js
new file mode 100644
index 0000000000..027d2659d6
--- /dev/null
+++ b/api/app/clients/tools/structured/specs/GeminiImageGen-proxy.spec.js
@@ -0,0 +1,125 @@
+const { ProxyAgent } = require('undici');
+
+/**
+ * These tests verify the proxy wrapper behavior for GeminiImageGen.
+ * Instead of loading the full module (which has many dependencies),
+ * we directly test the wrapper logic that would be applied.
+ */
+describe('GeminiImageGen Proxy Configuration', () => {
+ let originalEnv;
+ let originalFetch;
+
+ beforeAll(() => {
+ originalEnv = { ...process.env };
+ originalFetch = globalThis.fetch;
+ });
+
+ beforeEach(() => {
+ process.env = { ...originalEnv };
+ globalThis.fetch = originalFetch;
+ });
+
+ afterEach(() => {
+ process.env = originalEnv;
+ globalThis.fetch = originalFetch;
+ });
+
+ /**
+ * Simulates the proxy wrapper that GeminiImageGen applies at module load.
+ * This is the same logic from GeminiImageGen.js lines 30-42.
+ */
+ function applyProxyWrapper() {
+ if (process.env.PROXY) {
+ const _originalFetch = globalThis.fetch;
+ const proxyAgent = new ProxyAgent(process.env.PROXY);
+
+ globalThis.fetch = function (url, options = {}) {
+ const urlString = url.toString();
+ if (urlString.includes('googleapis.com')) {
+ options = { ...options, dispatcher: proxyAgent };
+ }
+ return _originalFetch.call(this, url, options);
+ };
+ }
+ }
+
+ it('should wrap globalThis.fetch when PROXY env is set', () => {
+ process.env.PROXY = 'http://proxy.example.com:8080';
+
+ const fetchBeforeWrap = globalThis.fetch;
+
+ applyProxyWrapper();
+
+ expect(globalThis.fetch).not.toBe(fetchBeforeWrap);
+ });
+
+ it('should not wrap globalThis.fetch when PROXY env is not set', () => {
+ delete process.env.PROXY;
+
+ const fetchBeforeWrap = globalThis.fetch;
+
+ applyProxyWrapper();
+
+ expect(globalThis.fetch).toBe(fetchBeforeWrap);
+ });
+
+ it('should add dispatcher to googleapis.com URLs', async () => {
+ process.env.PROXY = 'http://proxy.example.com:8080';
+
+ let capturedOptions = null;
+ const mockFetch = jest.fn((url, options) => {
+ capturedOptions = options;
+ return Promise.resolve({ ok: true });
+ });
+ globalThis.fetch = mockFetch;
+
+ applyProxyWrapper();
+
+ await globalThis.fetch('https://generativelanguage.googleapis.com/v1/models', {});
+
+ expect(capturedOptions).toBeDefined();
+ expect(capturedOptions.dispatcher).toBeInstanceOf(ProxyAgent);
+ });
+
+ it('should not add dispatcher to non-googleapis.com URLs', async () => {
+ process.env.PROXY = 'http://proxy.example.com:8080';
+
+ let capturedOptions = null;
+ const mockFetch = jest.fn((url, options) => {
+ capturedOptions = options;
+ return Promise.resolve({ ok: true });
+ });
+ globalThis.fetch = mockFetch;
+
+ applyProxyWrapper();
+
+ await globalThis.fetch('https://api.openai.com/v1/images', {});
+
+ expect(capturedOptions).toBeDefined();
+ expect(capturedOptions.dispatcher).toBeUndefined();
+ });
+
+ it('should preserve existing options when adding dispatcher', async () => {
+ process.env.PROXY = 'http://proxy.example.com:8080';
+
+ let capturedOptions = null;
+ const mockFetch = jest.fn((url, options) => {
+ capturedOptions = options;
+ return Promise.resolve({ ok: true });
+ });
+ globalThis.fetch = mockFetch;
+
+ applyProxyWrapper();
+
+ const customHeaders = { 'X-Custom-Header': 'test' };
+ await globalThis.fetch('https://aiplatform.googleapis.com/v1/models', {
+ headers: customHeaders,
+ method: 'POST',
+ });
+
+ expect(capturedOptions).toBeDefined();
+ expect(capturedOptions.dispatcher).toBeInstanceOf(ProxyAgent);
+ expect(capturedOptions.headers).toEqual(customHeaders);
+ expect(capturedOptions.method).toBe('POST');
+ });
+});
diff --git a/api/app/clients/tools/util/fileSearch.js b/api/app/clients/tools/util/fileSearch.js
index 17b3dc3452..2654722be4 100644
--- a/api/app/clients/tools/util/fileSearch.js
+++ b/api/app/clients/tools/util/fileSearch.js
@@ -1,11 +1,22 @@
-const { z } = require('zod');
const axios = require('axios');
const { tool } = require('@langchain/core/tools');
const { logger } = require('@librechat/data-schemas');
const { generateShortLivedToken } = require('@librechat/api');
const { Tools, EToolResources } = require('librechat-data-provider');
const { filterFilesByAgentAccess } = require('~/server/services/Files/permissions');
-const { getFiles } = require('~/models/File');
+const { getFiles } = require('~/models');
+
+const fileSearchJsonSchema = {
+ type: 'object',
+ properties: {
+ query: {
+ type: 'string',
+ description:
+ "A natural language query to search for relevant information in the files. Be specific and use keywords related to the information you're looking for. The query will be used for semantic similarity matching against the file contents.",
+ },
+ },
+ required: ['query'],
+};
/**
*
@@ -182,15 +193,9 @@ Use the EXACT anchor markers shown below (copy them verbatim) immediately after
**ALWAYS mention the filename in your text before the citation marker. NEVER use markdown links or footnotes.**`
: ''
}`,
- schema: z.object({
- query: z
- .string()
- .describe(
- "A natural language query to search for relevant information in the files. Be specific and use keywords related to the information you're looking for. The query will be used for semantic similarity matching against the file contents.",
- ),
- }),
+ schema: fileSearchJsonSchema,
},
);
};
-module.exports = { createFileSearchTool, primeFiles };
+module.exports = { createFileSearchTool, primeFiles, fileSearchJsonSchema };
diff --git a/api/app/clients/tools/util/handleOpenAIErrors.js b/api/app/clients/tools/util/handleOpenAIErrors.js
deleted file mode 100644
index b3a7c2bfdc..0000000000
--- a/api/app/clients/tools/util/handleOpenAIErrors.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const OpenAI = require('openai');
-const { logger } = require('@librechat/data-schemas');
-
-/**
- * Handles errors that may occur when making requests to OpenAI's API.
- * It checks the instance of the error and prints a specific warning message
- * to the console depending on the type of error encountered.
- * It then calls an optional error callback function with the error object.
- *
- * @param {Error} err - The error object thrown by OpenAI API.
- * @param {Function} errorCallback - A callback function that is called with the error object.
- * @param {string} [context='stream'] - A string providing context where the error occurred, defaults to 'stream'.
- */
-async function handleOpenAIErrors(err, errorCallback, context = 'stream') {
- if (err instanceof OpenAI.APIError && err?.message?.includes('abort')) {
- logger.warn(`[OpenAIClient.chatCompletion][${context}] Aborted Message`);
- }
- if (err instanceof OpenAI.OpenAIError && err?.message?.includes('missing finish_reason')) {
- logger.warn(`[OpenAIClient.chatCompletion][${context}] Missing finish_reason`);
- } else if (err instanceof OpenAI.APIError) {
- logger.warn(`[OpenAIClient.chatCompletion][${context}] API error`);
- } else {
- logger.warn(`[OpenAIClient.chatCompletion][${context}] Unhandled error type`);
- }
-
- logger.error(err);
-
- if (errorCallback) {
- errorCallback(err);
- }
-}
-
-module.exports = handleOpenAIErrors;
diff --git a/api/app/clients/tools/util/handleTools.js b/api/app/clients/tools/util/handleTools.js
index 8a3e09760c..48fcf7cb83 100644
--- a/api/app/clients/tools/util/handleTools.js
+++ b/api/app/clients/tools/util/handleTools.js
@@ -10,14 +10,16 @@ const {
createSafeUser,
mcpToolPattern,
loadWebSearchAuth,
+ buildImageToolContext,
+ buildWebSearchContext,
} = require('@librechat/api');
+const { getMCPServersRegistry } = require('~/config');
const {
Tools,
Constants,
Permissions,
EToolResources,
PermissionTypes,
- replaceSpecialVars,
} = require('librechat-data-provider');
const {
availableTools,
@@ -32,8 +34,8 @@ const {
StructuredACS,
TraversaalSearch,
StructuredWolfram,
- createYouTubeTools,
TavilySearchResults,
+ createGeminiImageTool,
createOpenAIImageTools,
} = require('../');
const { primeFiles: primeCodeFiles } = require('~/server/services/Files/Code/process');
@@ -182,30 +184,15 @@ const loadTools = async ({
};
const customConstructors = {
- youtube: async (_toolContextMap) => {
- const authFields = getAuthFields('youtube');
- const authValues = await loadAuthValues({ userId: user, authFields });
- return createYouTubeTools(authValues);
- },
image_gen_oai: async (toolContextMap) => {
const authFields = getAuthFields('image_gen_oai');
const authValues = await loadAuthValues({ userId: user, authFields });
const imageFiles = options.tool_resources?.[EToolResources.image_edit]?.files ?? [];
- let toolContext = '';
- for (let i = 0; i < imageFiles.length; i++) {
- const file = imageFiles[i];
- if (!file) {
- continue;
- }
- if (i === 0) {
- toolContext =
- 'Image files provided in this request (their image IDs listed in order of appearance) available for image editing:';
- }
- toolContext += `\n\t- ${file.file_id}`;
- if (i === imageFiles.length - 1) {
- toolContext += `\n\nInclude any you need in the \`image_ids\` array when calling \`${EToolResources.image_edit}_oai\`. You may also include previously referenced or generated image IDs.`;
- }
- }
+ const toolContext = buildImageToolContext({
+ imageFiles,
+ toolName: `${EToolResources.image_edit}_oai`,
+ contextDescription: 'image editing',
+ });
if (toolContext) {
toolContextMap.image_edit_oai = toolContext;
}
@@ -218,6 +205,27 @@ const loadTools = async ({
imageFiles,
});
},
+ gemini_image_gen: async (toolContextMap) => {
+ const authFields = getAuthFields('gemini_image_gen');
+ const authValues = await loadAuthValues({ userId: user, authFields, throwError: false });
+ const imageFiles = options.tool_resources?.[EToolResources.image_edit]?.files ?? [];
+ const toolContext = buildImageToolContext({
+ imageFiles,
+ toolName: 'gemini_image_gen',
+ contextDescription: 'image context',
+ });
+ if (toolContext) {
+ toolContextMap.gemini_image_gen = toolContext;
+ }
+ return createGeminiImageTool({
+ ...authValues,
+ isAgent: !!agent,
+ req: options.req,
+ imageFiles,
+ userId: user,
+ fileStrategy,
+ });
+ },
};
const requestedTools = {};
@@ -240,6 +248,7 @@ const loadTools = async ({
flux: imageGenOptions,
dalle: imageGenOptions,
'stable-diffusion': imageGenOptions,
+ gemini_image_gen: imageGenOptions,
};
/** @type {Record} */
@@ -315,24 +324,7 @@ const loadTools = async ({
});
const { onSearchResults, onGetHighlights } = options?.[Tools.web_search] ?? {};
requestedTools[tool] = async () => {
- toolContextMap[tool] = `# \`${tool}\`:
-Current Date & Time: ${replaceSpecialVars({ text: '{{iso_datetime}}' })}
-
-**Execute immediately without preface.** After search, provide a brief summary addressing the query directly, then structure your response with clear Markdown formatting (## headers, lists, tables). Cite sources properly, tailor tone to query type, and provide comprehensive details.
-
-**CITATION FORMAT - UNICODE ESCAPE SEQUENCES ONLY:**
-Use these EXACT escape sequences (copy verbatim): \\ue202 (before each anchor), \\ue200 (group start), \\ue201 (group end), \\ue203 (highlight start), \\ue204 (highlight end)
-
-Anchor pattern: \\ue202turn{N}{type}{index} where N=turn number, type=search|news|image|ref, index=0,1,2...
-
-**Examples (copy these exactly):**
-- Single: "Statement.\\ue202turn0search0"
-- Multiple: "Statement.\\ue202turn0search0\\ue202turn0news1"
-- Group: "Statement. \\ue200\\ue202turn0search0\\ue202turn0news1\\ue201"
-- Highlight: "\\ue203Cited text.\\ue204\\ue202turn0search0"
-- Image: "See photo\\ue202turn0image0."
-
-**CRITICAL:** Output escape sequences EXACTLY as shown. Do NOT substitute with † or other symbols. Place anchors AFTER punctuation. Cite every non-obvious fact/quote. NEVER use markdown links, [1], footnotes, or HTML tags.`.trim();
+ toolContextMap[tool] = buildWebSearchContext();
return createSearchTool({
...result.authResult,
onSearchResults,
@@ -347,7 +339,10 @@ Anchor pattern: \\ue202turn{N}{type}{index} where N=turn number, type=search|new
/** Placeholder used for UI purposes */
continue;
}
- if (serverName && options.req?.config?.mcpConfig?.[serverName] == null) {
+ const serverConfig = serverName
+ ? await getMCPServersRegistry().getServerConfig(serverName, user)
+ : null;
+ if (!serverConfig) {
logger.warn(
`MCP server "${serverName}" for "${toolName}" tool is not configured${agent?.id != null && agent.id ? ` but attached to "${agent.id}"` : ''}`,
);
@@ -358,6 +353,7 @@ Anchor pattern: \\ue202turn{N}{type}{index} where N=turn number, type=search|new
{
type: 'all',
serverName,
+ config: serverConfig,
},
];
continue;
@@ -368,6 +364,7 @@ Anchor pattern: \\ue202turn{N}{type}{index} where N=turn number, type=search|new
type: 'single',
toolKey: tool,
serverName,
+ config: serverConfig,
});
continue;
}
@@ -428,9 +425,11 @@ Anchor pattern: \\ue202turn{N}{type}{index} where N=turn number, type=search|new
user: safeUser,
userMCPAuthMap,
res: options.res,
+ streamId: options.req?._resumableStreamId || null,
model: agent?.model ?? model,
serverName: config.serverName,
provider: agent?.provider ?? endpoint,
+ config: config.config,
};
if (config.type === 'all' && toolConfigs.length === 1) {
diff --git a/api/app/clients/tools/util/index.js b/api/app/clients/tools/util/index.js
index ea67bb4ced..9c96fb50f3 100644
--- a/api/app/clients/tools/util/index.js
+++ b/api/app/clients/tools/util/index.js
@@ -1,8 +1,6 @@
const { validateTools, loadTools } = require('./handleTools');
-const handleOpenAIErrors = require('./handleOpenAIErrors');
module.exports = {
- handleOpenAIErrors,
validateTools,
loadTools,
};
diff --git a/api/cache/banViolation.js b/api/cache/banViolation.js
index 3a2d9791b4..4d321889c1 100644
--- a/api/cache/banViolation.js
+++ b/api/cache/banViolation.js
@@ -47,7 +47,17 @@ const banViolation = async (req, res, errorMessage) => {
}
await deleteAllUserSessions({ userId: user_id });
+
+ /** Clear OpenID session tokens if present */
+ if (req.session?.openidTokens) {
+ delete req.session.openidTokens;
+ }
+
res.clearCookie('refreshToken');
+ res.clearCookie('openid_access_token');
+ res.clearCookie('openid_id_token');
+ res.clearCookie('openid_user_id');
+ res.clearCookie('token_provider');
const banLogs = getLogStores(ViolationTypes.BAN);
const duration = errorMessage.duration || banLogs.opts.ttl;
diff --git a/api/cache/getLogStores.js b/api/cache/getLogStores.js
index 40aac08ee6..3089192196 100644
--- a/api/cache/getLogStores.js
+++ b/api/cache/getLogStores.js
@@ -37,6 +37,7 @@ const namespaces = {
[CacheKeys.ROLES]: standardCache(CacheKeys.ROLES),
[CacheKeys.APP_CONFIG]: standardCache(CacheKeys.APP_CONFIG),
[CacheKeys.CONFIG_STORE]: standardCache(CacheKeys.CONFIG_STORE),
+ [CacheKeys.TOOL_CACHE]: standardCache(CacheKeys.TOOL_CACHE),
[CacheKeys.PENDING_REQ]: standardCache(CacheKeys.PENDING_REQ),
[CacheKeys.ENCODED_DOMAINS]: new Keyv({ store: keyvMongo, namespace: CacheKeys.ENCODED_DOMAINS }),
[CacheKeys.ABORT_KEYS]: standardCache(CacheKeys.ABORT_KEYS, Time.TEN_MINUTES),
@@ -51,6 +52,10 @@ const namespaces = {
CacheKeys.OPENID_EXCHANGED_TOKENS,
Time.TEN_MINUTES,
),
+ [CacheKeys.ADMIN_OAUTH_EXCHANGE]: standardCache(
+ CacheKeys.ADMIN_OAUTH_EXCHANGE,
+ Time.THIRTY_SECONDS,
+ ),
};
/**
diff --git a/api/config/index.js b/api/config/index.js
index 0ddbee1661..3b6d869332 100644
--- a/api/config/index.js
+++ b/api/config/index.js
@@ -1,6 +1,11 @@
const { EventSource } = require('eventsource');
const { Time } = require('librechat-data-provider');
-const { MCPManager, FlowStateManager, OAuthReconnectionManager } = require('@librechat/api');
+const {
+ MCPManager,
+ FlowStateManager,
+ MCPServersRegistry,
+ OAuthReconnectionManager,
+} = require('@librechat/api');
const logger = require('./winston');
global.EventSource = EventSource;
@@ -23,6 +28,8 @@ function getFlowStateManager(flowsCache) {
module.exports = {
logger,
+ createMCPServersRegistry: MCPServersRegistry.createInstance,
+ getMCPServersRegistry: MCPServersRegistry.getInstance,
createMCPManager: MCPManager.createInstance,
getMCPManager: MCPManager.getInstance,
getFlowStateManager,
diff --git a/api/config/meiliLogger.js b/api/config/meiliLogger.js
index c5e60ea157..398672da5c 100644
--- a/api/config/meiliLogger.js
+++ b/api/config/meiliLogger.js
@@ -1,8 +1,35 @@
const path = require('path');
+const fs = require('fs');
const winston = require('winston');
require('winston-daily-rotate-file');
-const logDir = path.join(__dirname, '..', 'logs');
+/**
+ * Determine the log directory.
+ * Priority:
+ * 1. LIBRECHAT_LOG_DIR environment variable (allows user override)
+ * 2. /app/logs if running in Docker (bind-mounted with correct permissions)
+ * 3. api/logs relative to this file (local development)
+ */
+const getLogDir = () => {
+ if (process.env.LIBRECHAT_LOG_DIR) {
+ return process.env.LIBRECHAT_LOG_DIR;
+ }
+
+ // Check if running in Docker container (cwd is /app)
+ if (process.cwd() === '/app') {
+ const dockerLogDir = '/app/logs';
+ // Ensure the directory exists
+ if (!fs.existsSync(dockerLogDir)) {
+ fs.mkdirSync(dockerLogDir, { recursive: true });
+ }
+ return dockerLogDir;
+ }
+
+ // Local development: use api/logs relative to this file
+ return path.join(__dirname, '..', 'logs');
+};
+
+const logDir = getLogDir();
const { NODE_ENV, DEBUG_LOGGING = false } = process.env;
diff --git a/api/config/winston.js b/api/config/winston.js
index 12f6053723..93b84f7c46 100644
--- a/api/config/winston.js
+++ b/api/config/winston.js
@@ -1,9 +1,36 @@
const path = require('path');
+const fs = require('fs');
const winston = require('winston');
require('winston-daily-rotate-file');
const { redactFormat, redactMessage, debugTraverse, jsonTruncateFormat } = require('./parsers');
-const logDir = path.join(__dirname, '..', 'logs');
+/**
+ * Determine the log directory.
+ * Priority:
+ * 1. LIBRECHAT_LOG_DIR environment variable (allows user override)
+ * 2. /app/logs if running in Docker (bind-mounted with correct permissions)
+ * 3. api/logs relative to this file (local development)
+ */
+const getLogDir = () => {
+ if (process.env.LIBRECHAT_LOG_DIR) {
+ return process.env.LIBRECHAT_LOG_DIR;
+ }
+
+ // Check if running in Docker container (cwd is /app)
+ if (process.cwd() === '/app') {
+ const dockerLogDir = '/app/logs';
+ // Ensure the directory exists
+ if (!fs.existsSync(dockerLogDir)) {
+ fs.mkdirSync(dockerLogDir, { recursive: true });
+ }
+ return dockerLogDir;
+ }
+
+ // Local development: use api/logs relative to this file
+ return path.join(__dirname, '..', 'logs');
+};
+
+const logDir = getLogDir();
const { NODE_ENV, DEBUG_LOGGING = true, CONSOLE_JSON = false, DEBUG_CONSOLE = false } = process.env;
diff --git a/api/db/connect.js b/api/db/connect.js
index 26166ccff8..3534884b57 100644
--- a/api/db/connect.js
+++ b/api/db/connect.js
@@ -40,6 +40,10 @@ if (!cached) {
cached = global.mongoose = { conn: null, promise: null };
}
+mongoose.connection.on('error', (err) => {
+ logger.error('[connectDb] MongoDB connection error:', err);
+});
+
async function connectDb() {
if (cached.conn && cached.conn?._readyState === 1) {
return cached.conn;
diff --git a/api/db/indexSync.js b/api/db/indexSync.js
index c86598d108..8e8e999d92 100644
--- a/api/db/indexSync.js
+++ b/api/db/indexSync.js
@@ -4,6 +4,7 @@ const { logger } = require('@librechat/data-schemas');
const { CacheKeys } = require('librechat-data-provider');
const { isEnabled, FlowStateManager } = require('@librechat/api');
const { getLogStores } = require('~/cache');
+const { batchResetMeiliFlags } = require('./utils');
const Conversation = mongoose.models.Conversation;
const Message = mongoose.models.Message;
@@ -12,6 +13,11 @@ const searchEnabled = isEnabled(process.env.SEARCH);
const indexingDisabled = isEnabled(process.env.MEILI_NO_SYNC);
let currentTimeout = null;
+const defaultSyncThreshold = 1000;
+const syncThreshold = process.env.MEILI_SYNC_THRESHOLD
+ ? parseInt(process.env.MEILI_SYNC_THRESHOLD, 10)
+ : defaultSyncThreshold;
+
class MeiliSearchClient {
static instance = null;
@@ -189,6 +195,11 @@ async function ensureFilterableAttributes(client) {
*/
async function performSync(flowManager, flowId, flowType) {
try {
+ if (indexingDisabled === true) {
+ logger.info('[indexSync] Indexing is disabled, skipping...');
+ return { messagesSync: false, convosSync: false };
+ }
+
const client = MeiliSearchClient.getInstance();
const { status } = await client.health();
@@ -196,11 +207,6 @@ async function performSync(flowManager, flowId, flowType) {
throw new Error('Meilisearch not available');
}
- if (indexingDisabled === true) {
- logger.info('[indexSync] Indexing is disabled, skipping...');
- return { messagesSync: false, convosSync: false };
- }
-
/** Ensures indexes have proper filterable attributes configured */
const { settingsUpdated, orphanedDocsFound: _orphanedDocsFound } =
await ensureFilterableAttributes(client);
@@ -215,33 +221,30 @@ async function performSync(flowManager, flowId, flowType) {
);
// Reset sync flags to force full re-sync
- await Message.collection.updateMany({ _meiliIndex: true }, { $set: { _meiliIndex: false } });
- await Conversation.collection.updateMany(
- { _meiliIndex: true },
- { $set: { _meiliIndex: false } },
- );
+ await batchResetMeiliFlags(Message.collection);
+ await batchResetMeiliFlags(Conversation.collection);
}
// Check if we need to sync messages
+ logger.info('[indexSync] Requesting message sync progress...');
const messageProgress = await Message.getSyncProgress();
if (!messageProgress.isComplete || settingsUpdated) {
logger.info(
`[indexSync] Messages need syncing: ${messageProgress.totalProcessed}/${messageProgress.totalDocuments} indexed`,
);
- // Check if we should do a full sync or incremental
- const messageCount = await Message.countDocuments();
+ const messageCount = messageProgress.totalDocuments;
const messagesIndexed = messageProgress.totalProcessed;
- const syncThreshold = parseInt(process.env.MEILI_SYNC_THRESHOLD || '1000', 10);
+ const unindexedMessages = messageCount - messagesIndexed;
- if (messageCount - messagesIndexed > syncThreshold) {
- logger.info('[indexSync] Starting full message sync due to large difference');
- await Message.syncWithMeili();
- messagesSync = true;
- } else if (messageCount !== messagesIndexed) {
- logger.warn('[indexSync] Messages out of sync, performing incremental sync');
+ if (settingsUpdated || unindexedMessages > syncThreshold) {
+ logger.info(`[indexSync] Starting message sync (${unindexedMessages} unindexed)`);
await Message.syncWithMeili();
messagesSync = true;
+ } else if (unindexedMessages > 0) {
+ logger.info(
+ `[indexSync] ${unindexedMessages} messages unindexed (below threshold: ${syncThreshold}, skipping)`,
+ );
}
} else {
logger.info(
@@ -256,18 +259,18 @@ async function performSync(flowManager, flowId, flowType) {
`[indexSync] Conversations need syncing: ${convoProgress.totalProcessed}/${convoProgress.totalDocuments} indexed`,
);
- const convoCount = await Conversation.countDocuments();
+ const convoCount = convoProgress.totalDocuments;
const convosIndexed = convoProgress.totalProcessed;
- const syncThreshold = parseInt(process.env.MEILI_SYNC_THRESHOLD || '1000', 10);
- if (convoCount - convosIndexed > syncThreshold) {
- logger.info('[indexSync] Starting full conversation sync due to large difference');
- await Conversation.syncWithMeili();
- convosSync = true;
- } else if (convoCount !== convosIndexed) {
- logger.warn('[indexSync] Convos out of sync, performing incremental sync');
+ const unindexedConvos = convoCount - convosIndexed;
+ if (settingsUpdated || unindexedConvos > syncThreshold) {
+ logger.info(`[indexSync] Starting convos sync (${unindexedConvos} unindexed)`);
await Conversation.syncWithMeili();
convosSync = true;
+ } else if (unindexedConvos > 0) {
+ logger.info(
+ `[indexSync] ${unindexedConvos} convos unindexed (below threshold: ${syncThreshold}, skipping)`,
+ );
}
} else {
logger.info(
diff --git a/api/db/indexSync.spec.js b/api/db/indexSync.spec.js
new file mode 100644
index 0000000000..c2e5901d6a
--- /dev/null
+++ b/api/db/indexSync.spec.js
@@ -0,0 +1,465 @@
+/**
+ * Unit tests for performSync() function in indexSync.js
+ *
+ * Tests use real mongoose with mocked model methods, only mocking external calls.
+ */
+
+const mongoose = require('mongoose');
+
+// Mock only external dependencies (not internal classes/models)
+const mockLogger = {
+ info: jest.fn(),
+ warn: jest.fn(),
+ error: jest.fn(),
+ debug: jest.fn(),
+};
+
+const mockMeiliHealth = jest.fn();
+const mockMeiliIndex = jest.fn();
+const mockBatchResetMeiliFlags = jest.fn();
+const mockIsEnabled = jest.fn();
+const mockGetLogStores = jest.fn();
+
+// Create mock models that will be reused
+const createMockModel = (collectionName) => ({
+ collection: { name: collectionName },
+ getSyncProgress: jest.fn(),
+ syncWithMeili: jest.fn(),
+ countDocuments: jest.fn(),
+});
+
+const originalMessageModel = mongoose.models.Message;
+const originalConversationModel = mongoose.models.Conversation;
+
+// Mock external modules
+jest.mock('@librechat/data-schemas', () => ({
+ logger: mockLogger,
+}));
+
+jest.mock('meilisearch', () => ({
+ MeiliSearch: jest.fn(() => ({
+ health: mockMeiliHealth,
+ index: mockMeiliIndex,
+ })),
+}));
+
+jest.mock('./utils', () => ({
+ batchResetMeiliFlags: mockBatchResetMeiliFlags,
+}));
+
+jest.mock('@librechat/api', () => ({
+ isEnabled: mockIsEnabled,
+ FlowStateManager: jest.fn(),
+}));
+
+jest.mock('~/cache', () => ({
+ getLogStores: mockGetLogStores,
+}));
+
+// Set environment before module load
+process.env.MEILI_HOST = 'http://localhost:7700';
+process.env.MEILI_MASTER_KEY = 'test-key';
+process.env.SEARCH = 'true';
+process.env.MEILI_SYNC_THRESHOLD = '1000'; // Set threshold before module loads
+
+describe('performSync() - syncThreshold logic', () => {
+ const ORIGINAL_ENV = process.env;
+ let Message;
+ let Conversation;
+
+ beforeAll(() => {
+ Message = createMockModel('messages');
+ Conversation = createMockModel('conversations');
+
+ mongoose.models.Message = Message;
+ mongoose.models.Conversation = Conversation;
+ });
+
+ beforeEach(() => {
+ // Reset all mocks
+ jest.clearAllMocks();
+ // Reset modules to ensure fresh load of indexSync.js and its top-level consts (like syncThreshold)
+ jest.resetModules();
+
+ // Set up environment
+ process.env = { ...ORIGINAL_ENV };
+ process.env.MEILI_HOST = 'http://localhost:7700';
+ process.env.MEILI_MASTER_KEY = 'test-key';
+ process.env.SEARCH = 'true';
+ delete process.env.MEILI_NO_SYNC;
+
+ // Re-ensure models are available in mongoose after resetModules
+ // We must require mongoose again to get the fresh instance that indexSync will use
+ const mongoose = require('mongoose');
+ mongoose.models.Message = Message;
+ mongoose.models.Conversation = Conversation;
+
+ // Mock isEnabled
+ mockIsEnabled.mockImplementation((val) => val === 'true' || val === true);
+
+ // Mock MeiliSearch client responses
+ mockMeiliHealth.mockResolvedValue({ status: 'available' });
+ mockMeiliIndex.mockReturnValue({
+ getSettings: jest.fn().mockResolvedValue({ filterableAttributes: ['user'] }),
+ updateSettings: jest.fn().mockResolvedValue({}),
+ search: jest.fn().mockResolvedValue({ hits: [] }),
+ });
+
+ mockBatchResetMeiliFlags.mockResolvedValue(undefined);
+ });
+
+ afterEach(() => {
+ process.env = ORIGINAL_ENV;
+ });
+
+ afterAll(() => {
+ mongoose.models.Message = originalMessageModel;
+ mongoose.models.Conversation = originalConversationModel;
+ });
+
+ test('triggers sync when unindexed messages exceed syncThreshold', async () => {
+ // Arrange: Set threshold before module load
+ process.env.MEILI_SYNC_THRESHOLD = '1000';
+
+ // Arrange: 1050 unindexed messages > 1000 threshold
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 100,
+ totalDocuments: 1150, // 1050 unindexed
+ isComplete: false,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 50,
+ totalDocuments: 50,
+ isComplete: true,
+ });
+
+ Message.syncWithMeili.mockResolvedValue(undefined);
+
+ // Act
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ // Assert: No countDocuments calls
+ expect(Message.countDocuments).not.toHaveBeenCalled();
+ expect(Conversation.countDocuments).not.toHaveBeenCalled();
+
+ // Assert: Message sync triggered because 1050 > 1000
+ expect(Message.syncWithMeili).toHaveBeenCalledTimes(1);
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Messages need syncing: 100/1150 indexed',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Starting message sync (1050 unindexed)',
+ );
+
+ // Assert: Conversation sync NOT triggered (already complete)
+ expect(Conversation.syncWithMeili).not.toHaveBeenCalled();
+ });
+
+ test('skips sync when unindexed messages are below syncThreshold', async () => {
+ // Arrange: 50 unindexed messages < 1000 threshold
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 100,
+ totalDocuments: 150, // 50 unindexed
+ isComplete: false,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 50,
+ totalDocuments: 50,
+ isComplete: true,
+ });
+
+ process.env.MEILI_SYNC_THRESHOLD = '1000';
+
+ // Act
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ // Assert: No countDocuments calls
+ expect(Message.countDocuments).not.toHaveBeenCalled();
+ expect(Conversation.countDocuments).not.toHaveBeenCalled();
+
+ // Assert: Message sync NOT triggered because 50 < 1000
+ expect(Message.syncWithMeili).not.toHaveBeenCalled();
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Messages need syncing: 100/150 indexed',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] 50 messages unindexed (below threshold: 1000, skipping)',
+ );
+
+ // Assert: Conversation sync NOT triggered (already complete)
+ expect(Conversation.syncWithMeili).not.toHaveBeenCalled();
+ });
+
+ test('respects syncThreshold at boundary (exactly at threshold)', async () => {
+ // Arrange: 1000 unindexed messages = 1000 threshold (NOT greater than)
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 100,
+ totalDocuments: 1100, // 1000 unindexed
+ isComplete: false,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 0,
+ totalDocuments: 0,
+ isComplete: true,
+ });
+
+ process.env.MEILI_SYNC_THRESHOLD = '1000';
+
+ // Act
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ // Assert: No countDocuments calls
+ expect(Message.countDocuments).not.toHaveBeenCalled();
+
+ // Assert: Message sync NOT triggered because 1000 is NOT > 1000
+ expect(Message.syncWithMeili).not.toHaveBeenCalled();
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Messages need syncing: 100/1100 indexed',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] 1000 messages unindexed (below threshold: 1000, skipping)',
+ );
+ });
+
+ test('triggers sync when unindexed is threshold + 1', async () => {
+ // Arrange: 1001 unindexed messages > 1000 threshold
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 100,
+ totalDocuments: 1101, // 1001 unindexed
+ isComplete: false,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 0,
+ totalDocuments: 0,
+ isComplete: true,
+ });
+
+ Message.syncWithMeili.mockResolvedValue(undefined);
+
+ process.env.MEILI_SYNC_THRESHOLD = '1000';
+
+ // Act
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ // Assert: No countDocuments calls
+ expect(Message.countDocuments).not.toHaveBeenCalled();
+
+ // Assert: Message sync triggered because 1001 > 1000
+ expect(Message.syncWithMeili).toHaveBeenCalledTimes(1);
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Messages need syncing: 100/1101 indexed',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Starting message sync (1001 unindexed)',
+ );
+ });
+
+ test('uses totalDocuments from convoProgress for conversation sync decisions', async () => {
+ // Arrange: Messages complete, conversations need sync
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 100,
+ totalDocuments: 100,
+ isComplete: true,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 50,
+ totalDocuments: 1100, // 1050 unindexed > 1000 threshold
+ isComplete: false,
+ });
+
+ Conversation.syncWithMeili.mockResolvedValue(undefined);
+
+ process.env.MEILI_SYNC_THRESHOLD = '1000';
+
+ // Act
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ // Assert: No countDocuments calls (the optimization)
+ expect(Message.countDocuments).not.toHaveBeenCalled();
+ expect(Conversation.countDocuments).not.toHaveBeenCalled();
+
+ // Assert: Only conversation sync triggered
+ expect(Message.syncWithMeili).not.toHaveBeenCalled();
+ expect(Conversation.syncWithMeili).toHaveBeenCalledTimes(1);
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Conversations need syncing: 50/1100 indexed',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Starting convos sync (1050 unindexed)',
+ );
+ });
+
+ test('skips sync when collections are fully synced', async () => {
+ // Arrange: Everything already synced
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 100,
+ totalDocuments: 100,
+ isComplete: true,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 50,
+ totalDocuments: 50,
+ isComplete: true,
+ });
+
+ // Act
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ // Assert: No countDocuments calls
+ expect(Message.countDocuments).not.toHaveBeenCalled();
+ expect(Conversation.countDocuments).not.toHaveBeenCalled();
+
+ // Assert: No sync triggered
+ expect(Message.syncWithMeili).not.toHaveBeenCalled();
+ expect(Conversation.syncWithMeili).not.toHaveBeenCalled();
+
+ // Assert: Correct logs
+ expect(mockLogger.info).toHaveBeenCalledWith('[indexSync] Messages are fully synced: 100/100');
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Conversations are fully synced: 50/50',
+ );
+ });
+
+ test('triggers message sync when settingsUpdated even if below syncThreshold', async () => {
+ // Arrange: Only 50 unindexed messages (< 1000 threshold), but settings were updated
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 100,
+ totalDocuments: 150, // 50 unindexed
+ isComplete: false,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 50,
+ totalDocuments: 50,
+ isComplete: true,
+ });
+
+ Message.syncWithMeili.mockResolvedValue(undefined);
+
+ // Mock settings update scenario
+ mockMeiliIndex.mockReturnValue({
+ getSettings: jest.fn().mockResolvedValue({ filterableAttributes: [] }), // No user field
+ updateSettings: jest.fn().mockResolvedValue({}),
+ search: jest.fn().mockResolvedValue({ hits: [] }),
+ });
+
+ process.env.MEILI_SYNC_THRESHOLD = '1000';
+
+ // Act
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ // Assert: Flags were reset due to settings update
+ expect(mockBatchResetMeiliFlags).toHaveBeenCalledWith(Message.collection);
+ expect(mockBatchResetMeiliFlags).toHaveBeenCalledWith(Conversation.collection);
+
+ // Assert: Message sync triggered despite being below threshold (50 < 1000)
+ expect(Message.syncWithMeili).toHaveBeenCalledTimes(1);
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Settings updated. Forcing full re-sync to reindex with new configuration...',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Starting message sync (50 unindexed)',
+ );
+ });
+
+ test('triggers conversation sync when settingsUpdated even if below syncThreshold', async () => {
+ // Arrange: Messages complete, conversations have 50 unindexed (< 1000 threshold), but settings were updated
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 100,
+ totalDocuments: 100,
+ isComplete: true,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 50,
+ totalDocuments: 100, // 50 unindexed
+ isComplete: false,
+ });
+
+ Conversation.syncWithMeili.mockResolvedValue(undefined);
+
+ // Mock settings update scenario
+ mockMeiliIndex.mockReturnValue({
+ getSettings: jest.fn().mockResolvedValue({ filterableAttributes: [] }), // No user field
+ updateSettings: jest.fn().mockResolvedValue({}),
+ search: jest.fn().mockResolvedValue({ hits: [] }),
+ });
+
+ process.env.MEILI_SYNC_THRESHOLD = '1000';
+
+ // Act
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ // Assert: Flags were reset due to settings update
+ expect(mockBatchResetMeiliFlags).toHaveBeenCalledWith(Message.collection);
+ expect(mockBatchResetMeiliFlags).toHaveBeenCalledWith(Conversation.collection);
+
+ // Assert: Conversation sync triggered despite being below threshold (50 < 1000)
+ expect(Conversation.syncWithMeili).toHaveBeenCalledTimes(1);
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Settings updated. Forcing full re-sync to reindex with new configuration...',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith('[indexSync] Starting convos sync (50 unindexed)');
+ });
+
+ test('triggers both message and conversation sync when settingsUpdated even if both below syncThreshold', async () => {
+ // Arrange: Set threshold before module load
+ process.env.MEILI_SYNC_THRESHOLD = '1000';
+
+ // Arrange: Both have documents below threshold (50 each), but settings were updated
+ Message.getSyncProgress.mockResolvedValue({
+ totalProcessed: 100,
+ totalDocuments: 150, // 50 unindexed
+ isComplete: false,
+ });
+
+ Conversation.getSyncProgress.mockResolvedValue({
+ totalProcessed: 50,
+ totalDocuments: 100, // 50 unindexed
+ isComplete: false,
+ });
+
+ Message.syncWithMeili.mockResolvedValue(undefined);
+ Conversation.syncWithMeili.mockResolvedValue(undefined);
+
+ // Mock settings update scenario
+ mockMeiliIndex.mockReturnValue({
+ getSettings: jest.fn().mockResolvedValue({ filterableAttributes: [] }), // No user field
+ updateSettings: jest.fn().mockResolvedValue({}),
+ search: jest.fn().mockResolvedValue({ hits: [] }),
+ });
+
+ // Act
+ const indexSync = require('./indexSync');
+ await indexSync();
+
+ // Assert: Flags were reset due to settings update
+ expect(mockBatchResetMeiliFlags).toHaveBeenCalledWith(Message.collection);
+ expect(mockBatchResetMeiliFlags).toHaveBeenCalledWith(Conversation.collection);
+
+ // Assert: Both syncs triggered despite both being below threshold
+ expect(Message.syncWithMeili).toHaveBeenCalledTimes(1);
+ expect(Conversation.syncWithMeili).toHaveBeenCalledTimes(1);
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Settings updated. Forcing full re-sync to reindex with new configuration...',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith(
+ '[indexSync] Starting message sync (50 unindexed)',
+ );
+ expect(mockLogger.info).toHaveBeenCalledWith('[indexSync] Starting convos sync (50 unindexed)');
+ });
+});
diff --git a/api/db/utils.js b/api/db/utils.js
new file mode 100644
index 0000000000..32051be78d
--- /dev/null
+++ b/api/db/utils.js
@@ -0,0 +1,90 @@
+const { logger } = require('@librechat/data-schemas');
+
+const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
+
+/**
+ * Batch update documents in chunks to avoid timeouts on weak instances
+ * @param {mongoose.Collection} collection - MongoDB collection
+ * @returns {Promise} - Total modified count
+ * @throws {Error} - Throws if database operations fail (e.g., network issues, connection loss, permission problems)
+ */
+async function batchResetMeiliFlags(collection) {
+ const DEFAULT_BATCH_SIZE = 1000;
+
+ let BATCH_SIZE = parseEnvInt('MEILI_SYNC_BATCH_SIZE', DEFAULT_BATCH_SIZE);
+ if (BATCH_SIZE === 0) {
+ logger.warn(
+ `[batchResetMeiliFlags] MEILI_SYNC_BATCH_SIZE cannot be 0. Using default: ${DEFAULT_BATCH_SIZE}`,
+ );
+ BATCH_SIZE = DEFAULT_BATCH_SIZE;
+ }
+
+ const BATCH_DELAY_MS = parseEnvInt('MEILI_SYNC_DELAY_MS', 100);
+ let totalModified = 0;
+ let hasMore = true;
+
+ try {
+ while (hasMore) {
+ const docs = await collection
+ .find({ expiredAt: null, _meiliIndex: { $ne: false } }, { projection: { _id: 1 } })
+ .limit(BATCH_SIZE)
+ .toArray();
+
+ if (docs.length === 0) {
+ break;
+ }
+
+ const ids = docs.map((doc) => doc._id);
+ const result = await collection.updateMany(
+ { _id: { $in: ids } },
+ { $set: { _meiliIndex: false } },
+ );
+
+ totalModified += result.modifiedCount;
+ process.stdout.write(
+ `\r Updating ${collection.collectionName}: ${totalModified} documents...`,
+ );
+
+ if (docs.length < BATCH_SIZE) {
+ hasMore = false;
+ }
+
+ if (hasMore && BATCH_DELAY_MS > 0) {
+ await sleep(BATCH_DELAY_MS);
+ }
+ }
+
+ return totalModified;
+ } catch (error) {
+ throw new Error(
+ `Failed to batch reset Meili flags for collection '${collection.collectionName}' after processing ${totalModified} documents: ${error.message}`,
+ );
+ }
+}
+
+/**
+ * Parse and validate an environment variable as a positive integer
+ * @param {string} varName - Environment variable name
+ * @param {number} defaultValue - Default value to use if invalid or missing
+ * @returns {number} - Parsed value or default
+ */
+function parseEnvInt(varName, defaultValue) {
+ const value = process.env[varName];
+ if (!value) {
+ return defaultValue;
+ }
+
+ const parsed = parseInt(value, 10);
+ if (isNaN(parsed) || parsed < 0) {
+ logger.warn(
+ `[batchResetMeiliFlags] Invalid value for ${varName}="${value}". Expected a positive integer. Using default: ${defaultValue}`,
+ );
+ return defaultValue;
+ }
+
+ return parsed;
+}
+
+module.exports = {
+ batchResetMeiliFlags,
+};
diff --git a/api/db/utils.spec.js b/api/db/utils.spec.js
new file mode 100644
index 0000000000..adf4f6cd86
--- /dev/null
+++ b/api/db/utils.spec.js
@@ -0,0 +1,523 @@
+const mongoose = require('mongoose');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+const { batchResetMeiliFlags } = require('./utils');
+
+describe('batchResetMeiliFlags', () => {
+ let mongoServer;
+ let testCollection;
+ const ORIGINAL_BATCH_SIZE = process.env.MEILI_SYNC_BATCH_SIZE;
+ const ORIGINAL_BATCH_DELAY = process.env.MEILI_SYNC_DELAY_MS;
+
+ beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ const mongoUri = mongoServer.getUri();
+ await mongoose.connect(mongoUri);
+ });
+
+ afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+
+ // Restore original env variables
+ if (ORIGINAL_BATCH_SIZE !== undefined) {
+ process.env.MEILI_SYNC_BATCH_SIZE = ORIGINAL_BATCH_SIZE;
+ } else {
+ delete process.env.MEILI_SYNC_BATCH_SIZE;
+ }
+
+ if (ORIGINAL_BATCH_DELAY !== undefined) {
+ process.env.MEILI_SYNC_DELAY_MS = ORIGINAL_BATCH_DELAY;
+ } else {
+ delete process.env.MEILI_SYNC_DELAY_MS;
+ }
+ });
+
+ beforeEach(async () => {
+ // Create a fresh collection for each test
+ testCollection = mongoose.connection.db.collection('test_meili_batch');
+ await testCollection.deleteMany({});
+
+ // Reset env variables to defaults
+ delete process.env.MEILI_SYNC_BATCH_SIZE;
+ delete process.env.MEILI_SYNC_DELAY_MS;
+ });
+
+ afterEach(async () => {
+ if (testCollection) {
+ await testCollection.deleteMany({});
+ }
+ });
+
+ describe('basic functionality', () => {
+ it('should reset _meiliIndex flag for documents with expiredAt: null and _meiliIndex: true', async () => {
+ // Insert test documents
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true, name: 'doc1' },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true, name: 'doc2' },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true, name: 'doc3' },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(3);
+
+ const updatedDocs = await testCollection.find({ _meiliIndex: false }).toArray();
+ expect(updatedDocs).toHaveLength(3);
+
+ const notUpdatedDocs = await testCollection.find({ _meiliIndex: true }).toArray();
+ expect(notUpdatedDocs).toHaveLength(0);
+ });
+
+ it('should not modify documents with expiredAt set', async () => {
+ const expiredDate = new Date();
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: expiredDate, _meiliIndex: true },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1);
+
+ const expiredDoc = await testCollection.findOne({ expiredAt: expiredDate });
+ expect(expiredDoc._meiliIndex).toBe(true);
+ });
+
+ it('should not modify documents with _meiliIndex: false', async () => {
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: false },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1);
+ });
+
+ it('should return 0 when no documents match the criteria', async () => {
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: new Date(), _meiliIndex: true },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: false },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(0);
+ });
+
+ it('should return 0 when collection is empty', async () => {
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(0);
+ });
+ });
+
+ describe('batch processing', () => {
+ it('should process documents in batches according to MEILI_SYNC_BATCH_SIZE', async () => {
+ process.env.MEILI_SYNC_BATCH_SIZE = '2';
+
+ const docs = [];
+ for (let i = 0; i < 5; i++) {
+ docs.push({
+ _id: new mongoose.Types.ObjectId(),
+ expiredAt: null,
+ _meiliIndex: true,
+ name: `doc${i}`,
+ });
+ }
+ await testCollection.insertMany(docs);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(5);
+
+ const updatedDocs = await testCollection.find({ _meiliIndex: false }).toArray();
+ expect(updatedDocs).toHaveLength(5);
+ });
+
+ it('should handle large datasets with small batch sizes', async () => {
+ process.env.MEILI_SYNC_BATCH_SIZE = '10';
+
+ const docs = [];
+ for (let i = 0; i < 25; i++) {
+ docs.push({
+ _id: new mongoose.Types.ObjectId(),
+ expiredAt: null,
+ _meiliIndex: true,
+ });
+ }
+ await testCollection.insertMany(docs);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(25);
+ });
+
+ it('should use default batch size of 1000 when env variable is not set', async () => {
+ // Create exactly 1000 documents to verify default batch behavior
+ const docs = [];
+ for (let i = 0; i < 1000; i++) {
+ docs.push({
+ _id: new mongoose.Types.ObjectId(),
+ expiredAt: null,
+ _meiliIndex: true,
+ });
+ }
+ await testCollection.insertMany(docs);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1000);
+ });
+ });
+
+ describe('return value', () => {
+ it('should return correct modified count', async () => {
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ await expect(batchResetMeiliFlags(testCollection)).resolves.toBe(1);
+ });
+ });
+
+ describe('batch delay', () => {
+ it('should respect MEILI_SYNC_DELAY_MS between batches', async () => {
+ process.env.MEILI_SYNC_BATCH_SIZE = '2';
+ process.env.MEILI_SYNC_DELAY_MS = '50';
+
+ const docs = [];
+ for (let i = 0; i < 5; i++) {
+ docs.push({
+ _id: new mongoose.Types.ObjectId(),
+ expiredAt: null,
+ _meiliIndex: true,
+ });
+ }
+ await testCollection.insertMany(docs);
+
+ const startTime = Date.now();
+ await batchResetMeiliFlags(testCollection);
+ const endTime = Date.now();
+
+ // With 5 documents and batch size 2, we need 3 batches
+ // That means 2 delays between batches (not after the last one)
+ // So minimum time should be around 100ms (2 * 50ms)
+ // Using a slightly lower threshold to account for timing variations
+ const elapsed = endTime - startTime;
+ expect(elapsed).toBeGreaterThanOrEqual(80);
+ });
+
+ it('should not delay when MEILI_SYNC_DELAY_MS is 0', async () => {
+ process.env.MEILI_SYNC_BATCH_SIZE = '2';
+ process.env.MEILI_SYNC_DELAY_MS = '0';
+
+ const docs = [];
+ for (let i = 0; i < 5; i++) {
+ docs.push({
+ _id: new mongoose.Types.ObjectId(),
+ expiredAt: null,
+ _meiliIndex: true,
+ });
+ }
+ await testCollection.insertMany(docs);
+
+ const startTime = Date.now();
+ await batchResetMeiliFlags(testCollection);
+ const endTime = Date.now();
+
+ const elapsed = endTime - startTime;
+ // Should complete without intentional delays, but database operations still take time
+ // Just verify it completes and returns the correct count
+ expect(elapsed).toBeLessThan(1000); // More reasonable upper bound
+
+ const result = await testCollection.countDocuments({ _meiliIndex: false });
+ expect(result).toBe(5);
+ });
+
+ it('should not delay after the last batch', async () => {
+ process.env.MEILI_SYNC_BATCH_SIZE = '3';
+ process.env.MEILI_SYNC_DELAY_MS = '100';
+
+ // Exactly 3 documents - should fit in one batch, no delay
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ // Verify all 3 documents were processed in a single batch
+ expect(result).toBe(3);
+
+ const updatedDocs = await testCollection.countDocuments({ _meiliIndex: false });
+ expect(updatedDocs).toBe(3);
+ });
+ });
+
+ describe('edge cases', () => {
+ it('should handle documents without _meiliIndex field', async () => {
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ // both documents should be updated
+ expect(result).toBe(2);
+ });
+
+ it('should handle mixed document states correctly', async () => {
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: false },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: new Date(), _meiliIndex: true },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: null },
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(4);
+
+ const flaggedDocs = await testCollection
+ .find({ expiredAt: null, _meiliIndex: false })
+ .toArray();
+ expect(flaggedDocs).toHaveLength(5); // 4 were updated, 1 was already false
+ });
+ });
+
+ describe('error handling', () => {
+ it('should throw error with context when find operation fails', async () => {
+ const mockCollection = {
+ collectionName: 'test_meili_batch',
+ find: jest.fn().mockReturnValue({
+ limit: jest.fn().mockReturnValue({
+ toArray: jest.fn().mockRejectedValue(new Error('Network error')),
+ }),
+ }),
+ };
+
+ await expect(batchResetMeiliFlags(mockCollection)).rejects.toThrow(
+ "Failed to batch reset Meili flags for collection 'test_meili_batch' after processing 0 documents: Network error",
+ );
+ });
+
+ it('should throw error with context when updateMany operation fails', async () => {
+ const mockCollection = {
+ collectionName: 'test_meili_batch',
+ find: jest.fn().mockReturnValue({
+ limit: jest.fn().mockReturnValue({
+ toArray: jest
+ .fn()
+ .mockResolvedValue([
+ { _id: new mongoose.Types.ObjectId() },
+ { _id: new mongoose.Types.ObjectId() },
+ ]),
+ }),
+ }),
+ updateMany: jest.fn().mockRejectedValue(new Error('Connection lost')),
+ };
+
+ await expect(batchResetMeiliFlags(mockCollection)).rejects.toThrow(
+ "Failed to batch reset Meili flags for collection 'test_meili_batch' after processing 0 documents: Connection lost",
+ );
+ });
+
+ it('should include documents processed count in error when failure occurs mid-batch', async () => {
+ // Set batch size to 2 to force multiple batches
+ process.env.MEILI_SYNC_BATCH_SIZE = '2';
+ process.env.MEILI_SYNC_DELAY_MS = '0'; // No delay for faster test
+
+ let findCallCount = 0;
+ let updateCallCount = 0;
+
+ const mockCollection = {
+ collectionName: 'test_meili_batch',
+ find: jest.fn().mockReturnValue({
+ limit: jest.fn().mockReturnValue({
+ toArray: jest.fn().mockImplementation(() => {
+ findCallCount++;
+ // Return 2 documents for first two calls (to keep loop going)
+ // Return 2 documents for third call (to trigger third update which will fail)
+ if (findCallCount <= 3) {
+ return Promise.resolve([
+ { _id: new mongoose.Types.ObjectId() },
+ { _id: new mongoose.Types.ObjectId() },
+ ]);
+ }
+ // Should not reach here due to error
+ return Promise.resolve([]);
+ }),
+ }),
+ }),
+ updateMany: jest.fn().mockImplementation(() => {
+ updateCallCount++;
+ if (updateCallCount === 1) {
+ return Promise.resolve({ modifiedCount: 2 });
+ } else if (updateCallCount === 2) {
+ return Promise.resolve({ modifiedCount: 2 });
+ } else {
+ return Promise.reject(new Error('Database timeout'));
+ }
+ }),
+ };
+
+ await expect(batchResetMeiliFlags(mockCollection)).rejects.toThrow(
+ "Failed to batch reset Meili flags for collection 'test_meili_batch' after processing 4 documents: Database timeout",
+ );
+ });
+
+ it('should use collection.collectionName in error messages', async () => {
+ const mockCollection = {
+ collectionName: 'messages',
+ find: jest.fn().mockReturnValue({
+ limit: jest.fn().mockReturnValue({
+ toArray: jest.fn().mockRejectedValue(new Error('Permission denied')),
+ }),
+ }),
+ };
+
+ await expect(batchResetMeiliFlags(mockCollection)).rejects.toThrow(
+ "Failed to batch reset Meili flags for collection 'messages' after processing 0 documents: Permission denied",
+ );
+ });
+ });
+
+ describe('environment variable validation', () => {
+ let warnSpy;
+
+ beforeEach(() => {
+ // Mock logger.warn to track warning calls
+ const { logger } = require('@librechat/data-schemas');
+ warnSpy = jest.spyOn(logger, 'warn').mockImplementation(() => {});
+ });
+
+ afterEach(() => {
+ if (warnSpy) {
+ warnSpy.mockRestore();
+ }
+ });
+
+ it('should log warning and use default when MEILI_SYNC_BATCH_SIZE is not a number', async () => {
+ process.env.MEILI_SYNC_BATCH_SIZE = 'abc';
+
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1);
+ expect(warnSpy).toHaveBeenCalledWith(
+ expect.stringContaining('Invalid value for MEILI_SYNC_BATCH_SIZE="abc"'),
+ );
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Using default: 1000'));
+ });
+
+ it('should log warning and use default when MEILI_SYNC_DELAY_MS is not a number', async () => {
+ process.env.MEILI_SYNC_DELAY_MS = 'xyz';
+
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1);
+ expect(warnSpy).toHaveBeenCalledWith(
+ expect.stringContaining('Invalid value for MEILI_SYNC_DELAY_MS="xyz"'),
+ );
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Using default: 100'));
+ });
+
+ it('should log warning and use default when MEILI_SYNC_BATCH_SIZE is negative', async () => {
+ process.env.MEILI_SYNC_BATCH_SIZE = '-50';
+
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1);
+ expect(warnSpy).toHaveBeenCalledWith(
+ expect.stringContaining('Invalid value for MEILI_SYNC_BATCH_SIZE="-50"'),
+ );
+ });
+
+ it('should log warning and use default when MEILI_SYNC_DELAY_MS is negative', async () => {
+ process.env.MEILI_SYNC_DELAY_MS = '-100';
+
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1);
+ expect(warnSpy).toHaveBeenCalledWith(
+ expect.stringContaining('Invalid value for MEILI_SYNC_DELAY_MS="-100"'),
+ );
+ });
+
+ it('should accept valid positive integer values without warnings', async () => {
+ process.env.MEILI_SYNC_BATCH_SIZE = '500';
+ process.env.MEILI_SYNC_DELAY_MS = '50';
+
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1);
+ expect(warnSpy).not.toHaveBeenCalled();
+ });
+
+ it('should log warning and use default when MEILI_SYNC_BATCH_SIZE is zero', async () => {
+ process.env.MEILI_SYNC_BATCH_SIZE = '0';
+
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1);
+ expect(warnSpy).toHaveBeenCalledWith(
+ expect.stringContaining('MEILI_SYNC_BATCH_SIZE cannot be 0. Using default: 1000'),
+ );
+ });
+
+ it('should accept zero as a valid value for MEILI_SYNC_DELAY_MS without warnings', async () => {
+ process.env.MEILI_SYNC_DELAY_MS = '0';
+
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1);
+ expect(warnSpy).not.toHaveBeenCalled();
+ });
+
+ it('should not log warnings when environment variables are not set', async () => {
+ delete process.env.MEILI_SYNC_BATCH_SIZE;
+ delete process.env.MEILI_SYNC_DELAY_MS;
+
+ await testCollection.insertMany([
+ { _id: new mongoose.Types.ObjectId(), expiredAt: null, _meiliIndex: true },
+ ]);
+
+ const result = await batchResetMeiliFlags(testCollection);
+
+ expect(result).toBe(1);
+ expect(warnSpy).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/api/jest.config.js b/api/jest.config.js
index fd8bd31bd9..20ee3c6aed 100644
--- a/api/jest.config.js
+++ b/api/jest.config.js
@@ -4,11 +4,7 @@ module.exports = {
roots: [''],
coverageDirectory: 'coverage',
testTimeout: 30000, // 30 seconds timeout for all tests
- setupFiles: [
- './test/jestSetup.js',
- './test/__mocks__/logger.js',
- './test/__mocks__/fetchEventSource.js',
- ],
+ setupFiles: ['./test/jestSetup.js', './test/__mocks__/logger.js'],
moduleNameMapper: {
'~/(.*)': '/$1',
'~/data/auth.json': '/__mocks__/auth.mock.json',
diff --git a/api/lib/utils/mergeSort.js b/api/lib/utils/mergeSort.js
deleted file mode 100644
index b93e3e9902..0000000000
--- a/api/lib/utils/mergeSort.js
+++ /dev/null
@@ -1,29 +0,0 @@
-function mergeSort(arr, compareFn) {
- if (arr.length <= 1) {
- return arr;
- }
-
- const mid = Math.floor(arr.length / 2);
- const leftArr = arr.slice(0, mid);
- const rightArr = arr.slice(mid);
-
- return merge(mergeSort(leftArr, compareFn), mergeSort(rightArr, compareFn), compareFn);
-}
-
-function merge(leftArr, rightArr, compareFn) {
- const result = [];
- let leftIndex = 0;
- let rightIndex = 0;
-
- while (leftIndex < leftArr.length && rightIndex < rightArr.length) {
- if (compareFn(leftArr[leftIndex], rightArr[rightIndex]) < 0) {
- result.push(leftArr[leftIndex++]);
- } else {
- result.push(rightArr[rightIndex++]);
- }
- }
-
- return result.concat(leftArr.slice(leftIndex)).concat(rightArr.slice(rightIndex));
-}
-
-module.exports = mergeSort;
diff --git a/api/lib/utils/misc.js b/api/lib/utils/misc.js
deleted file mode 100644
index f7b0e66cbf..0000000000
--- a/api/lib/utils/misc.js
+++ /dev/null
@@ -1,8 +0,0 @@
-const cleanUpPrimaryKeyValue = (value) => {
- // For Bing convoId handling
- return value.replace(/--/g, '|');
-};
-
-module.exports = {
- cleanUpPrimaryKeyValue,
-};
diff --git a/api/models/Agent.js b/api/models/Agent.js
index 1cd6ba3ed9..663285183a 100644
--- a/api/models/Agent.js
+++ b/api/models/Agent.js
@@ -1,20 +1,50 @@
const mongoose = require('mongoose');
const crypto = require('node:crypto');
const { logger } = require('@librechat/data-schemas');
-const { ResourceType, SystemRoles, Tools, actionDelimiter } = require('librechat-data-provider');
-const { GLOBAL_PROJECT_NAME, EPHEMERAL_AGENT_ID, mcp_all, mcp_delimiter } =
- require('librechat-data-provider').Constants;
+const { getCustomEndpointConfig } = require('@librechat/api');
+const {
+ Tools,
+ SystemRoles,
+ ResourceType,
+ actionDelimiter,
+ isAgentsEndpoint,
+ isEphemeralAgentId,
+ encodeEphemeralAgentId,
+} = require('librechat-data-provider');
+const { mcp_all, mcp_delimiter } = require('librechat-data-provider').Constants;
const {
removeAgentFromAllProjects,
removeAgentIdsFromProject,
addAgentIdsToProject,
- getProjectByName,
} = require('./Project');
const { removeAllPermissions } = require('~/server/services/PermissionService');
const { getMCPServerTools } = require('~/server/services/Config');
-const { Agent, AclEntry } = require('~/db/models');
+const { Agent, AclEntry, User } = require('~/db/models');
const { getActions } = require('./Action');
+/**
+ * Extracts unique MCP server names from tools array
+ * Tools format: "toolName_mcp_serverName" or "sys__server__sys_mcp_serverName"
+ * @param {string[]} tools - Array of tool identifiers
+ * @returns {string[]} Array of unique MCP server names
+ */
+const extractMCPServerNames = (tools) => {
+ if (!tools || !Array.isArray(tools)) {
+ return [];
+ }
+ const serverNames = new Set();
+ for (const tool of tools) {
+ if (!tool || !tool.includes(mcp_delimiter)) {
+ continue;
+ }
+ const parts = tool.split(mcp_delimiter);
+ if (parts.length >= 2) {
+ serverNames.add(parts[parts.length - 1]);
+ }
+ }
+ return Array.from(serverNames);
+};
+
/**
* Create an agent with the provided data.
* @param {Object} agentData - The agent data to create.
@@ -34,6 +64,7 @@ const createAgent = async (agentData) => {
},
],
category: agentData.category || 'general',
+ mcpServerNames: extractMCPServerNames(agentData.tools),
};
return (await Agent.create(initialAgentData)).toObject();
@@ -68,7 +99,7 @@ const getAgents = async (searchParameter) => await Agent.find(searchParameter).l
* @param {import('@librechat/agents').ClientOptions} [params.model_parameters]
* @returns {Promise} The agent document as a plain object, or null if not found.
*/
-const loadEphemeralAgent = async ({ req, spec, agent_id, endpoint, model_parameters: _m }) => {
+const loadEphemeralAgent = async ({ req, spec, endpoint, model_parameters: _m }) => {
const { model, ...model_parameters } = _m;
const modelSpecs = req.config?.modelSpecs?.list;
/** @type {TModelSpec | null} */
@@ -115,8 +146,28 @@ const loadEphemeralAgent = async ({ req, spec, agent_id, endpoint, model_paramet
}
const instructions = req.body.promptPrefix;
+
+ // Get endpoint config for modelDisplayLabel fallback
+ const appConfig = req.config;
+ let endpointConfig = appConfig?.endpoints?.[endpoint];
+ if (!isAgentsEndpoint(endpoint) && !endpointConfig) {
+ try {
+ endpointConfig = getCustomEndpointConfig({ endpoint, appConfig });
+ } catch (err) {
+ logger.error('[loadEphemeralAgent] Error getting custom endpoint config', err);
+ }
+ }
+
+ // For ephemeral agents, use modelLabel if provided, then model spec's label,
+ // then modelDisplayLabel from endpoint config, otherwise empty string to show model name
+ const sender =
+ model_parameters?.modelLabel ?? modelSpec?.label ?? endpointConfig?.modelDisplayLabel ?? '';
+
+ // Encode ephemeral agent ID with endpoint, model, and computed sender for display
+ const ephemeralId = encodeEphemeralAgentId({ endpoint, model, sender });
+
const result = {
- id: agent_id,
+ id: ephemeralId,
instructions,
provider: endpoint,
model_parameters,
@@ -145,8 +196,8 @@ const loadAgent = async ({ req, spec, agent_id, endpoint, model_parameters }) =>
if (!agent_id) {
return null;
}
- if (agent_id === EPHEMERAL_AGENT_ID) {
- return await loadEphemeralAgent({ req, spec, agent_id, endpoint, model_parameters });
+ if (isEphemeralAgentId(agent_id)) {
+ return await loadEphemeralAgent({ req, spec, endpoint, model_parameters });
}
const agent = await getAgent({
id: agent_id,
@@ -354,6 +405,13 @@ const updateAgent = async (searchParameter, updateData, options = {}) => {
} = currentAgent.toObject();
const { $push, $pull, $addToSet, ...directUpdates } = updateData;
+ // Sync mcpServerNames when tools are updated
+ if (directUpdates.tools !== undefined) {
+ const mcpServerNames = extractMCPServerNames(directUpdates.tools);
+ directUpdates.mcpServerNames = mcpServerNames;
+ updateData.mcpServerNames = mcpServerNames; // Also update the original updateData
+ }
+
let actionsHash = null;
// Generate actions hash if agent has actions
@@ -531,10 +589,29 @@ const deleteAgent = async (searchParameter) => {
const agent = await Agent.findOneAndDelete(searchParameter);
if (agent) {
await removeAgentFromAllProjects(agent.id);
- await removeAllPermissions({
- resourceType: ResourceType.AGENT,
- resourceId: agent._id,
- });
+ await Promise.all([
+ removeAllPermissions({
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ }),
+ removeAllPermissions({
+ resourceType: ResourceType.REMOTE_AGENT,
+ resourceId: agent._id,
+ }),
+ ]);
+ try {
+ await Agent.updateMany({ 'edges.to': agent.id }, { $pull: { edges: { to: agent.id } } });
+ } catch (error) {
+ logger.error('[deleteAgent] Error removing agent from handoff edges', error);
+ }
+ try {
+ await User.updateMany(
+ { 'favorites.agentId': agent.id },
+ { $pull: { favorites: { agentId: agent.id } } },
+ );
+ } catch (error) {
+ logger.error('[deleteAgent] Error removing agent from user favorites', error);
+ }
}
return agent;
};
@@ -560,10 +637,19 @@ const deleteUserAgents = async (userId) => {
}
await AclEntry.deleteMany({
- resourceType: ResourceType.AGENT,
+ resourceType: { $in: [ResourceType.AGENT, ResourceType.REMOTE_AGENT] },
resourceId: { $in: agentObjectIds },
});
+ try {
+ await User.updateMany(
+ { 'favorites.agentId': { $in: agentIds } },
+ { $pull: { favorites: { agentId: { $in: agentIds } } } },
+ );
+ } catch (error) {
+ logger.error('[deleteUserAgents] Error removing agents from user favorites', error);
+ }
+
await Agent.deleteMany({ author: userId });
} catch (error) {
logger.error('[deleteUserAgents] General error:', error);
@@ -670,59 +756,6 @@ const getListAgentsByAccess = async ({
};
};
-/**
- * Get all agents.
- * @deprecated Use getListAgentsByAccess for ACL-aware agent listing
- * @param {Object} searchParameter - The search parameters to find matching agents.
- * @param {string} searchParameter.author - The user ID of the agent's author.
- * @returns {Promise} A promise that resolves to an object containing the agents data and pagination info.
- */
-const getListAgents = async (searchParameter) => {
- const { author, ...otherParams } = searchParameter;
-
- let query = Object.assign({ author }, otherParams);
-
- const globalProject = await getProjectByName(GLOBAL_PROJECT_NAME, ['agentIds']);
- if (globalProject && (globalProject.agentIds?.length ?? 0) > 0) {
- const globalQuery = { id: { $in: globalProject.agentIds }, ...otherParams };
- delete globalQuery.author;
- query = { $or: [globalQuery, query] };
- }
- const agents = (
- await Agent.find(query, {
- id: 1,
- _id: 1,
- name: 1,
- avatar: 1,
- author: 1,
- projectIds: 1,
- description: 1,
- // @deprecated - isCollaborative replaced by ACL permissions
- isCollaborative: 1,
- category: 1,
- }).lean()
- ).map((agent) => {
- if (agent.author?.toString() !== author) {
- delete agent.author;
- }
- if (agent.author) {
- agent.author = agent.author.toString();
- }
- return agent;
- });
-
- const hasMore = agents.length > 0;
- const firstId = agents.length > 0 ? agents[0].id : null;
- const lastId = agents.length > 0 ? agents[agents.length - 1].id : null;
-
- return {
- data: agents,
- has_more: hasMore,
- first_id: firstId,
- last_id: lastId,
- };
-};
-
/**
* Updates the projects associated with an agent, adding and removing project IDs as specified.
* This function also updates the corresponding projects to include or exclude the agent ID.
@@ -888,12 +921,11 @@ module.exports = {
updateAgent,
deleteAgent,
deleteUserAgents,
- getListAgents,
revertAgentVersion,
updateAgentProjects,
+ countPromotedAgents,
addAgentResourceFile,
getListAgentsByAccess,
removeAgentResourceFiles,
generateActionMetadataHash,
- countPromotedAgents,
};
diff --git a/api/models/Agent.spec.js b/api/models/Agent.spec.js
index 6c7db6121e..baceb3e8f3 100644
--- a/api/models/Agent.spec.js
+++ b/api/models/Agent.spec.js
@@ -22,17 +22,17 @@ const {
createAgent,
updateAgent,
deleteAgent,
- getListAgents,
- getListAgentsByAccess,
+ deleteUserAgents,
revertAgentVersion,
updateAgentProjects,
addAgentResourceFile,
+ getListAgentsByAccess,
removeAgentResourceFiles,
generateActionMetadataHash,
} = require('./Agent');
const permissionService = require('~/server/services/PermissionService');
const { getCachedTools, getMCPServerTools } = require('~/server/services/Config');
-const { AclEntry } = require('~/db/models');
+const { AclEntry, User } = require('~/db/models');
/**
* @type {import('mongoose').Model}
@@ -59,6 +59,7 @@ describe('models/Agent', () => {
beforeEach(async () => {
await Agent.deleteMany({});
+ await User.deleteMany({});
});
test('should add tool_resource to tools if missing', async () => {
@@ -532,43 +533,531 @@ describe('models/Agent', () => {
expect(aclEntriesAfter).toHaveLength(0);
});
- test('should list agents by author', async () => {
+ test('should remove handoff edges referencing deleted agent from other agents', async () => {
+ const authorId = new mongoose.Types.ObjectId();
+ const targetAgentId = `agent_${uuidv4()}`;
+ const sourceAgentId = `agent_${uuidv4()}`;
+
+ // Create target agent (handoff destination)
+ await createAgent({
+ id: targetAgentId,
+ name: 'Target Agent',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ // Create source agent with handoff edge to target
+ await createAgent({
+ id: sourceAgentId,
+ name: 'Source Agent',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ edges: [
+ {
+ from: sourceAgentId,
+ to: targetAgentId,
+ edgeType: 'handoff',
+ },
+ ],
+ });
+
+ // Verify edge exists before deletion
+ const sourceAgentBefore = await getAgent({ id: sourceAgentId });
+ expect(sourceAgentBefore.edges).toHaveLength(1);
+ expect(sourceAgentBefore.edges[0].to).toBe(targetAgentId);
+
+ // Delete the target agent
+ await deleteAgent({ id: targetAgentId });
+
+ // Verify the edge is removed from source agent
+ const sourceAgentAfter = await getAgent({ id: sourceAgentId });
+ expect(sourceAgentAfter.edges).toHaveLength(0);
+ });
+
+ test('should remove agent from user favorites when agent is deleted', async () => {
+ const agentId = `agent_${uuidv4()}`;
+ const authorId = new mongoose.Types.ObjectId();
+ const userId = new mongoose.Types.ObjectId();
+
+ // Create agent
+ await createAgent({
+ id: agentId,
+ name: 'Agent To Delete',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ // Create user with the agent in favorites
+ await User.create({
+ _id: userId,
+ name: 'Test User',
+ email: `test-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [{ agentId: agentId }, { model: 'gpt-4', endpoint: 'openAI' }],
+ });
+
+ // Verify user has agent in favorites
+ const userBefore = await User.findById(userId);
+ expect(userBefore.favorites).toHaveLength(2);
+ expect(userBefore.favorites.some((f) => f.agentId === agentId)).toBe(true);
+
+ // Delete the agent
+ await deleteAgent({ id: agentId });
+
+ // Verify agent is deleted
+ const agentAfterDelete = await getAgent({ id: agentId });
+ expect(agentAfterDelete).toBeNull();
+
+ // Verify agent is removed from user favorites
+ const userAfter = await User.findById(userId);
+ expect(userAfter.favorites).toHaveLength(1);
+ expect(userAfter.favorites.some((f) => f.agentId === agentId)).toBe(false);
+ expect(userAfter.favorites.some((f) => f.model === 'gpt-4')).toBe(true);
+ });
+
+ test('should remove agent from multiple users favorites when agent is deleted', async () => {
+ const agentId = `agent_${uuidv4()}`;
+ const authorId = new mongoose.Types.ObjectId();
+ const user1Id = new mongoose.Types.ObjectId();
+ const user2Id = new mongoose.Types.ObjectId();
+
+ // Create agent
+ await createAgent({
+ id: agentId,
+ name: 'Agent To Delete',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ // Create two users with the agent in favorites
+ await User.create({
+ _id: user1Id,
+ name: 'Test User 1',
+ email: `test1-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [{ agentId: agentId }],
+ });
+
+ await User.create({
+ _id: user2Id,
+ name: 'Test User 2',
+ email: `test2-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [{ agentId: agentId }, { agentId: `agent_${uuidv4()}` }],
+ });
+
+ // Delete the agent
+ await deleteAgent({ id: agentId });
+
+ // Verify agent is removed from both users' favorites
+ const user1After = await User.findById(user1Id);
+ const user2After = await User.findById(user2Id);
+
+ expect(user1After.favorites).toHaveLength(0);
+ expect(user2After.favorites).toHaveLength(1);
+ expect(user2After.favorites.some((f) => f.agentId === agentId)).toBe(false);
+ });
+
+ test('should preserve other agents in database when one agent is deleted', async () => {
+ const agentToDeleteId = `agent_${uuidv4()}`;
+ const agentToKeep1Id = `agent_${uuidv4()}`;
+ const agentToKeep2Id = `agent_${uuidv4()}`;
+ const authorId = new mongoose.Types.ObjectId();
+
+ // Create multiple agents
+ await createAgent({
+ id: agentToDeleteId,
+ name: 'Agent To Delete',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ await createAgent({
+ id: agentToKeep1Id,
+ name: 'Agent To Keep 1',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ await createAgent({
+ id: agentToKeep2Id,
+ name: 'Agent To Keep 2',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ // Verify all agents exist
+ expect(await getAgent({ id: agentToDeleteId })).not.toBeNull();
+ expect(await getAgent({ id: agentToKeep1Id })).not.toBeNull();
+ expect(await getAgent({ id: agentToKeep2Id })).not.toBeNull();
+
+ // Delete one agent
+ await deleteAgent({ id: agentToDeleteId });
+
+ // Verify only the deleted agent is removed, others remain intact
+ expect(await getAgent({ id: agentToDeleteId })).toBeNull();
+ const keptAgent1 = await getAgent({ id: agentToKeep1Id });
+ const keptAgent2 = await getAgent({ id: agentToKeep2Id });
+ expect(keptAgent1).not.toBeNull();
+ expect(keptAgent1.name).toBe('Agent To Keep 1');
+ expect(keptAgent2).not.toBeNull();
+ expect(keptAgent2.name).toBe('Agent To Keep 2');
+ });
+
+ test('should preserve other agents in user favorites when one agent is deleted', async () => {
+ const agentToDeleteId = `agent_${uuidv4()}`;
+ const agentToKeep1Id = `agent_${uuidv4()}`;
+ const agentToKeep2Id = `agent_${uuidv4()}`;
+ const authorId = new mongoose.Types.ObjectId();
+ const userId = new mongoose.Types.ObjectId();
+
+ // Create multiple agents
+ await createAgent({
+ id: agentToDeleteId,
+ name: 'Agent To Delete',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ await createAgent({
+ id: agentToKeep1Id,
+ name: 'Agent To Keep 1',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ await createAgent({
+ id: agentToKeep2Id,
+ name: 'Agent To Keep 2',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ // Create user with all three agents in favorites
+ await User.create({
+ _id: userId,
+ name: 'Test User',
+ email: `test-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [
+ { agentId: agentToDeleteId },
+ { agentId: agentToKeep1Id },
+ { agentId: agentToKeep2Id },
+ ],
+ });
+
+ // Verify user has all three agents in favorites
+ const userBefore = await User.findById(userId);
+ expect(userBefore.favorites).toHaveLength(3);
+
+ // Delete one agent
+ await deleteAgent({ id: agentToDeleteId });
+
+ // Verify only the deleted agent is removed from favorites
+ const userAfter = await User.findById(userId);
+ expect(userAfter.favorites).toHaveLength(2);
+ expect(userAfter.favorites.some((f) => f.agentId === agentToDeleteId)).toBe(false);
+ expect(userAfter.favorites.some((f) => f.agentId === agentToKeep1Id)).toBe(true);
+ expect(userAfter.favorites.some((f) => f.agentId === agentToKeep2Id)).toBe(true);
+ });
+
+ test('should not affect users who do not have deleted agent in favorites', async () => {
+ const agentToDeleteId = `agent_${uuidv4()}`;
+ const otherAgentId = `agent_${uuidv4()}`;
+ const authorId = new mongoose.Types.ObjectId();
+ const userWithDeletedAgentId = new mongoose.Types.ObjectId();
+ const userWithoutDeletedAgentId = new mongoose.Types.ObjectId();
+
+ // Create agents
+ await createAgent({
+ id: agentToDeleteId,
+ name: 'Agent To Delete',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ await createAgent({
+ id: otherAgentId,
+ name: 'Other Agent',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ // Create user with the agent to be deleted
+ await User.create({
+ _id: userWithDeletedAgentId,
+ name: 'User With Deleted Agent',
+ email: `user1-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [{ agentId: agentToDeleteId }, { model: 'gpt-4', endpoint: 'openAI' }],
+ });
+
+ // Create user without the agent to be deleted
+ await User.create({
+ _id: userWithoutDeletedAgentId,
+ name: 'User Without Deleted Agent',
+ email: `user2-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [{ agentId: otherAgentId }, { model: 'claude-3', endpoint: 'anthropic' }],
+ });
+
+ // Delete the agent
+ await deleteAgent({ id: agentToDeleteId });
+
+ // Verify user with deleted agent has it removed
+ const userWithDeleted = await User.findById(userWithDeletedAgentId);
+ expect(userWithDeleted.favorites).toHaveLength(1);
+ expect(userWithDeleted.favorites.some((f) => f.agentId === agentToDeleteId)).toBe(false);
+ expect(userWithDeleted.favorites.some((f) => f.model === 'gpt-4')).toBe(true);
+
+ // Verify user without deleted agent is completely unaffected
+ const userWithoutDeleted = await User.findById(userWithoutDeletedAgentId);
+ expect(userWithoutDeleted.favorites).toHaveLength(2);
+ expect(userWithoutDeleted.favorites.some((f) => f.agentId === otherAgentId)).toBe(true);
+ expect(userWithoutDeleted.favorites.some((f) => f.model === 'claude-3')).toBe(true);
+ });
+
+ test('should remove all user agents from favorites when deleteUserAgents is called', async () => {
const authorId = new mongoose.Types.ObjectId();
const otherAuthorId = new mongoose.Types.ObjectId();
+ const userId = new mongoose.Types.ObjectId();
- const agentIds = [];
- for (let i = 0; i < 5; i++) {
- const id = `agent_${uuidv4()}`;
- agentIds.push(id);
- await createAgent({
- id,
- name: `Agent ${i}`,
- provider: 'test',
- model: 'test-model',
- author: authorId,
- });
- }
+ const agent1Id = `agent_${uuidv4()}`;
+ const agent2Id = `agent_${uuidv4()}`;
+ const otherAuthorAgentId = `agent_${uuidv4()}`;
- for (let i = 0; i < 3; i++) {
- await createAgent({
- id: `other_agent_${uuidv4()}`,
- name: `Other Agent ${i}`,
- provider: 'test',
- model: 'test-model',
- author: otherAuthorId,
- });
- }
+ // Create agents by the author to be deleted
+ await createAgent({
+ id: agent1Id,
+ name: 'Author Agent 1',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
- const result = await getListAgents({ author: authorId.toString() });
+ await createAgent({
+ id: agent2Id,
+ name: 'Author Agent 2',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
- expect(result).toBeDefined();
- expect(result.data).toBeDefined();
- expect(result.data).toHaveLength(5);
- expect(result.has_more).toBe(true);
+ // Create agent by different author (should not be deleted)
+ await createAgent({
+ id: otherAuthorAgentId,
+ name: 'Other Author Agent',
+ provider: 'test',
+ model: 'test-model',
+ author: otherAuthorId,
+ });
- for (const agent of result.data) {
- expect(agent.author).toBe(authorId.toString());
- }
+ // Create user with all agents in favorites
+ await User.create({
+ _id: userId,
+ name: 'Test User',
+ email: `test-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [
+ { agentId: agent1Id },
+ { agentId: agent2Id },
+ { agentId: otherAuthorAgentId },
+ { model: 'gpt-4', endpoint: 'openAI' },
+ ],
+ });
+
+ // Verify user has all favorites
+ const userBefore = await User.findById(userId);
+ expect(userBefore.favorites).toHaveLength(4);
+
+ // Delete all agents by the author
+ await deleteUserAgents(authorId.toString());
+
+ // Verify author's agents are deleted from database
+ expect(await getAgent({ id: agent1Id })).toBeNull();
+ expect(await getAgent({ id: agent2Id })).toBeNull();
+
+ // Verify other author's agent still exists
+ expect(await getAgent({ id: otherAuthorAgentId })).not.toBeNull();
+
+ // Verify user favorites: author's agents removed, others remain
+ const userAfter = await User.findById(userId);
+ expect(userAfter.favorites).toHaveLength(2);
+ expect(userAfter.favorites.some((f) => f.agentId === agent1Id)).toBe(false);
+ expect(userAfter.favorites.some((f) => f.agentId === agent2Id)).toBe(false);
+ expect(userAfter.favorites.some((f) => f.agentId === otherAuthorAgentId)).toBe(true);
+ expect(userAfter.favorites.some((f) => f.model === 'gpt-4')).toBe(true);
+ });
+
+ test('should handle deleteUserAgents when agents are in multiple users favorites', async () => {
+ const authorId = new mongoose.Types.ObjectId();
+ const user1Id = new mongoose.Types.ObjectId();
+ const user2Id = new mongoose.Types.ObjectId();
+ const user3Id = new mongoose.Types.ObjectId();
+
+ const agent1Id = `agent_${uuidv4()}`;
+ const agent2Id = `agent_${uuidv4()}`;
+ const unrelatedAgentId = `agent_${uuidv4()}`;
+
+ // Create agents by the author
+ await createAgent({
+ id: agent1Id,
+ name: 'Author Agent 1',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ await createAgent({
+ id: agent2Id,
+ name: 'Author Agent 2',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ // Create users with various favorites configurations
+ await User.create({
+ _id: user1Id,
+ name: 'User 1',
+ email: `user1-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [{ agentId: agent1Id }, { agentId: agent2Id }],
+ });
+
+ await User.create({
+ _id: user2Id,
+ name: 'User 2',
+ email: `user2-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [{ agentId: agent1Id }, { model: 'claude-3', endpoint: 'anthropic' }],
+ });
+
+ await User.create({
+ _id: user3Id,
+ name: 'User 3',
+ email: `user3-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [{ agentId: unrelatedAgentId }, { model: 'gpt-4', endpoint: 'openAI' }],
+ });
+
+ // Delete all agents by the author
+ await deleteUserAgents(authorId.toString());
+
+ // Verify all users' favorites are correctly updated
+ const user1After = await User.findById(user1Id);
+ expect(user1After.favorites).toHaveLength(0);
+
+ const user2After = await User.findById(user2Id);
+ expect(user2After.favorites).toHaveLength(1);
+ expect(user2After.favorites.some((f) => f.agentId === agent1Id)).toBe(false);
+ expect(user2After.favorites.some((f) => f.model === 'claude-3')).toBe(true);
+
+ // User 3 should be completely unaffected
+ const user3After = await User.findById(user3Id);
+ expect(user3After.favorites).toHaveLength(2);
+ expect(user3After.favorites.some((f) => f.agentId === unrelatedAgentId)).toBe(true);
+ expect(user3After.favorites.some((f) => f.model === 'gpt-4')).toBe(true);
+ });
+
+ test('should handle deleteUserAgents when user has no agents', async () => {
+ const authorWithNoAgentsId = new mongoose.Types.ObjectId();
+ const otherAuthorId = new mongoose.Types.ObjectId();
+ const userId = new mongoose.Types.ObjectId();
+
+ const existingAgentId = `agent_${uuidv4()}`;
+
+ // Create agent by different author
+ await createAgent({
+ id: existingAgentId,
+ name: 'Existing Agent',
+ provider: 'test',
+ model: 'test-model',
+ author: otherAuthorId,
+ });
+
+ // Create user with favorites
+ await User.create({
+ _id: userId,
+ name: 'Test User',
+ email: `test-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [{ agentId: existingAgentId }, { model: 'gpt-4', endpoint: 'openAI' }],
+ });
+
+ // Delete agents for user with no agents (should be a no-op)
+ await deleteUserAgents(authorWithNoAgentsId.toString());
+
+ // Verify existing agent still exists
+ expect(await getAgent({ id: existingAgentId })).not.toBeNull();
+
+ // Verify user favorites are unchanged
+ const userAfter = await User.findById(userId);
+ expect(userAfter.favorites).toHaveLength(2);
+ expect(userAfter.favorites.some((f) => f.agentId === existingAgentId)).toBe(true);
+ expect(userAfter.favorites.some((f) => f.model === 'gpt-4')).toBe(true);
+ });
+
+ test('should handle deleteUserAgents when agents are not in any favorites', async () => {
+ const authorId = new mongoose.Types.ObjectId();
+ const userId = new mongoose.Types.ObjectId();
+
+ const agent1Id = `agent_${uuidv4()}`;
+ const agent2Id = `agent_${uuidv4()}`;
+
+ // Create agents by the author
+ await createAgent({
+ id: agent1Id,
+ name: 'Agent 1',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ await createAgent({
+ id: agent2Id,
+ name: 'Agent 2',
+ provider: 'test',
+ model: 'test-model',
+ author: authorId,
+ });
+
+ // Create user with favorites that don't include these agents
+ await User.create({
+ _id: userId,
+ name: 'Test User',
+ email: `test-${uuidv4()}@example.com`,
+ provider: 'local',
+ favorites: [{ model: 'gpt-4', endpoint: 'openAI' }],
+ });
+
+ // Verify agents exist
+ expect(await getAgent({ id: agent1Id })).not.toBeNull();
+ expect(await getAgent({ id: agent2Id })).not.toBeNull();
+
+ // Delete all agents by the author
+ await deleteUserAgents(authorId.toString());
+
+ // Verify agents are deleted
+ expect(await getAgent({ id: agent1Id })).toBeNull();
+ expect(await getAgent({ id: agent2Id })).toBeNull();
+
+ // Verify user favorites are unchanged
+ const userAfter = await User.findById(userId);
+ expect(userAfter.favorites).toHaveLength(1);
+ expect(userAfter.favorites.some((f) => f.model === 'gpt-4')).toBe(true);
});
test('should update agent projects', async () => {
@@ -690,26 +1179,6 @@ describe('models/Agent', () => {
expect(result).toBe(expected);
});
- test('should handle getListAgents with invalid author format', async () => {
- try {
- const result = await getListAgents({ author: 'invalid-object-id' });
- expect(result.data).toEqual([]);
- } catch (error) {
- expect(error).toBeDefined();
- }
- });
-
- test('should handle getListAgents with no agents', async () => {
- const authorId = new mongoose.Types.ObjectId();
- const result = await getListAgents({ author: authorId.toString() });
-
- expect(result).toBeDefined();
- expect(result.data).toEqual([]);
- expect(result.has_more).toBe(false);
- expect(result.first_id).toBeNull();
- expect(result.last_id).toBeNull();
- });
-
test('should handle updateAgentProjects with non-existent agent', async () => {
const nonExistentId = `agent_${uuidv4()}`;
const userId = new mongoose.Types.ObjectId();
@@ -1960,7 +2429,8 @@ describe('models/Agent', () => {
});
if (result) {
- expect(result.id).toBe(EPHEMERAL_AGENT_ID);
+ // Ephemeral agent ID is encoded with endpoint and model
+ expect(result.id).toBe('openai__gpt-4');
expect(result.instructions).toBe('Test instructions');
expect(result.provider).toBe('openai');
expect(result.model).toBe('gpt-4');
@@ -1978,7 +2448,7 @@ describe('models/Agent', () => {
const mockReq = { user: { id: 'user123' } };
const result = await loadAgent({
req: mockReq,
- agent_id: 'non_existent_agent',
+ agent_id: 'agent_non_existent',
endpoint: 'openai',
model_parameters: { model: 'gpt-4' },
});
@@ -2105,7 +2575,7 @@ describe('models/Agent', () => {
test('should handle loadAgent with malformed req object', async () => {
const result = await loadAgent({
req: null,
- agent_id: 'test',
+ agent_id: 'agent_test',
endpoint: 'openai',
model_parameters: { model: 'gpt-4' },
});
@@ -2322,17 +2792,6 @@ describe('models/Agent', () => {
expect(result).toBeNull();
});
- test('should handle getListAgents with no agents', async () => {
- const authorId = new mongoose.Types.ObjectId();
- const result = await getListAgents({ author: authorId.toString() });
-
- expect(result).toBeDefined();
- expect(result.data).toEqual([]);
- expect(result.has_more).toBe(false);
- expect(result.first_id).toBeNull();
- expect(result.last_id).toBeNull();
- });
-
test('should handle updateAgent with MongoDB operators mixed with direct updates', async () => {
const agentId = `agent_${uuidv4()}`;
const authorId = new mongoose.Types.ObjectId();
diff --git a/api/models/Conversation.js b/api/models/Conversation.js
index 13c329aa4a..32eac1a764 100644
--- a/api/models/Conversation.js
+++ b/api/models/Conversation.js
@@ -28,7 +28,7 @@ const getConvo = async (user, conversationId) => {
return await Conversation.findOne({ user, conversationId }).lean();
} catch (error) {
logger.error('[getConvo] Error getting single conversation', error);
- return { message: 'Error getting single conversation' };
+ throw new Error('Error getting single conversation');
}
};
@@ -124,10 +124,15 @@ module.exports = {
updateOperation,
{
new: true,
- upsert: true,
+ upsert: metadata?.noUpsert !== true,
},
);
+ if (!conversation) {
+ logger.debug('[saveConvo] Conversation not found, skipping update');
+ return null;
+ }
+
return conversation.toObject();
} catch (error) {
logger.error('[saveConvo] Error saving conversation', error);
@@ -151,13 +156,21 @@ module.exports = {
const result = await Conversation.bulkWrite(bulkOps);
return result;
} catch (error) {
- logger.error('[saveBulkConversations] Error saving conversations in bulk', error);
+ logger.error('[bulkSaveConvos] Error saving conversations in bulk', error);
throw new Error('Failed to save conversations in bulk.');
}
},
getConvosByCursor: async (
user,
- { cursor, limit = 25, isArchived = false, tags, search, order = 'desc' } = {},
+ {
+ cursor,
+ limit = 25,
+ isArchived = false,
+ tags,
+ search,
+ sortBy = 'updatedAt',
+ sortDirection = 'desc',
+ } = {},
) => {
const filters = [{ user }];
if (isArchived) {
@@ -184,35 +197,79 @@ module.exports = {
filters.push({ conversationId: { $in: matchingIds } });
} catch (error) {
logger.error('[getConvosByCursor] Error during meiliSearch', error);
- return { message: 'Error during meiliSearch' };
+ throw new Error('Error during meiliSearch');
}
}
+ const validSortFields = ['title', 'createdAt', 'updatedAt'];
+ if (!validSortFields.includes(sortBy)) {
+ throw new Error(
+ `Invalid sortBy field: ${sortBy}. Must be one of ${validSortFields.join(', ')}`,
+ );
+ }
+ const finalSortBy = sortBy;
+ const finalSortDirection = sortDirection === 'asc' ? 'asc' : 'desc';
+
+ let cursorFilter = null;
if (cursor) {
- filters.push({ updatedAt: { $lt: new Date(cursor) } });
+ try {
+ const decoded = JSON.parse(Buffer.from(cursor, 'base64').toString());
+ const { primary, secondary } = decoded;
+ const primaryValue = finalSortBy === 'title' ? primary : new Date(primary);
+ const secondaryValue = new Date(secondary);
+ const op = finalSortDirection === 'asc' ? '$gt' : '$lt';
+
+ cursorFilter = {
+ $or: [
+ { [finalSortBy]: { [op]: primaryValue } },
+ {
+ [finalSortBy]: primaryValue,
+ updatedAt: { [op]: secondaryValue },
+ },
+ ],
+ };
+ } catch (err) {
+ logger.warn('[getConvosByCursor] Invalid cursor format, starting from beginning');
+ }
+ if (cursorFilter) {
+ filters.push(cursorFilter);
+ }
}
const query = filters.length === 1 ? filters[0] : { $and: filters };
try {
+ const sortOrder = finalSortDirection === 'asc' ? 1 : -1;
+ const sortObj = { [finalSortBy]: sortOrder };
+
+ if (finalSortBy !== 'updatedAt') {
+ sortObj.updatedAt = sortOrder;
+ }
+
const convos = await Conversation.find(query)
.select(
'conversationId endpoint title createdAt updatedAt user model agent_id assistant_id spec iconURL',
)
- .sort({ updatedAt: order === 'asc' ? 1 : -1 })
+ .sort(sortObj)
.limit(limit + 1)
.lean();
let nextCursor = null;
if (convos.length > limit) {
- const lastConvo = convos.pop();
- nextCursor = lastConvo.updatedAt.toISOString();
+ convos.pop(); // Remove extra item used to detect next page
+ // Create cursor from the last RETURNED item (not the popped one)
+ const lastReturned = convos[convos.length - 1];
+ const primaryValue = lastReturned[finalSortBy];
+ const primaryStr = finalSortBy === 'title' ? primaryValue : primaryValue.toISOString();
+ const secondaryStr = lastReturned.updatedAt.toISOString();
+ const composite = { primary: primaryStr, secondary: secondaryStr };
+ nextCursor = Buffer.from(JSON.stringify(composite)).toString('base64');
}
return { conversations: convos, nextCursor };
} catch (error) {
logger.error('[getConvosByCursor] Error getting conversations', error);
- return { message: 'Error getting conversations' };
+ throw new Error('Error getting conversations');
}
},
getConvosQueried: async (user, convoIds, cursor = null, limit = 25) => {
@@ -240,8 +297,9 @@ module.exports = {
const limited = filtered.slice(0, limit + 1);
let nextCursor = null;
if (limited.length > limit) {
- const lastConvo = limited.pop();
- nextCursor = lastConvo.updatedAt.toISOString();
+ limited.pop(); // Remove extra item used to detect next page
+ // Create cursor from the last RETURNED item (not the popped one)
+ nextCursor = limited[limited.length - 1].updatedAt.toISOString();
}
const convoMap = {};
@@ -252,7 +310,7 @@ module.exports = {
return { conversations: limited, nextCursor, convoMap };
} catch (error) {
logger.error('[getConvosQueried] Error getting conversations', error);
- return { message: 'Error fetching conversations' };
+ throw new Error('Error fetching conversations');
}
},
getConvo,
@@ -269,7 +327,7 @@ module.exports = {
}
} catch (error) {
logger.error('[getConvoTitle] Error getting conversation title', error);
- return { message: 'Error getting conversation title' };
+ throw new Error('Error getting conversation title');
}
},
/**
diff --git a/api/models/Conversation.spec.js b/api/models/Conversation.spec.js
index c5030aed3c..bd415b4165 100644
--- a/api/models/Conversation.spec.js
+++ b/api/models/Conversation.spec.js
@@ -106,6 +106,47 @@ describe('Conversation Operations', () => {
expect(result.conversationId).toBe(newConversationId);
});
+ it('should not create a conversation when noUpsert is true and conversation does not exist', async () => {
+ const nonExistentId = uuidv4();
+ const result = await saveConvo(
+ mockReq,
+ { conversationId: nonExistentId, title: 'Ghost Title' },
+ { noUpsert: true },
+ );
+
+ expect(result).toBeNull();
+
+ const dbConvo = await Conversation.findOne({ conversationId: nonExistentId });
+ expect(dbConvo).toBeNull();
+ });
+
+ it('should update an existing conversation when noUpsert is true', async () => {
+ await saveConvo(mockReq, mockConversationData);
+
+ const result = await saveConvo(
+ mockReq,
+ { conversationId: mockConversationData.conversationId, title: 'Updated Title' },
+ { noUpsert: true },
+ );
+
+ expect(result).not.toBeNull();
+ expect(result.title).toBe('Updated Title');
+ expect(result.conversationId).toBe(mockConversationData.conversationId);
+ });
+
+ it('should still upsert by default when noUpsert is not provided', async () => {
+ const newId = uuidv4();
+ const result = await saveConvo(mockReq, {
+ conversationId: newId,
+ title: 'New Conversation',
+ endpoint: EModelEndpoint.openAI,
+ });
+
+ expect(result).not.toBeNull();
+ expect(result.conversationId).toBe(newId);
+ expect(result.title).toBe('New Conversation');
+ });
+
it('should handle unsetFields metadata', async () => {
const metadata = {
unsetFields: { someField: 1 },
@@ -122,7 +163,6 @@ describe('Conversation Operations', () => {
describe('isTemporary conversation handling', () => {
it('should save a conversation with expiredAt when isTemporary is true', async () => {
- // Mock app config with 24 hour retention
mockReq.config.interfaceConfig.temporaryChatRetention = 24;
mockReq.body = { isTemporary: true };
@@ -135,7 +175,6 @@ describe('Conversation Operations', () => {
expect(result.expiredAt).toBeDefined();
expect(result.expiredAt).toBeInstanceOf(Date);
- // Verify expiredAt is approximately 24 hours in the future
const expectedExpirationTime = new Date(beforeSave.getTime() + 24 * 60 * 60 * 1000);
const actualExpirationTime = new Date(result.expiredAt);
@@ -157,7 +196,6 @@ describe('Conversation Operations', () => {
});
it('should save a conversation without expiredAt when isTemporary is not provided', async () => {
- // No isTemporary in body
mockReq.body = {};
const result = await saveConvo(mockReq, mockConversationData);
@@ -167,7 +205,6 @@ describe('Conversation Operations', () => {
});
it('should use custom retention period from config', async () => {
- // Mock app config with 48 hour retention
mockReq.config.interfaceConfig.temporaryChatRetention = 48;
mockReq.body = { isTemporary: true };
@@ -567,4 +604,267 @@ describe('Conversation Operations', () => {
await mongoose.connect(mongoServer.getUri());
});
});
+
+ describe('getConvosByCursor pagination', () => {
+ /**
+ * Helper to create conversations with specific timestamps
+ * Uses collection.insertOne to bypass Mongoose timestamps entirely
+ */
+ const createConvoWithTimestamps = async (index, createdAt, updatedAt) => {
+ const conversationId = uuidv4();
+ // Use collection-level insert to bypass Mongoose timestamps
+ await Conversation.collection.insertOne({
+ conversationId,
+ user: 'user123',
+ title: `Conversation ${index}`,
+ endpoint: EModelEndpoint.openAI,
+ expiredAt: null,
+ isArchived: false,
+ createdAt,
+ updatedAt,
+ });
+ return Conversation.findOne({ conversationId }).lean();
+ };
+
+ it('should not skip conversations at page boundaries', async () => {
+ // Create 30 conversations to ensure pagination (limit is 25)
+ const baseTime = new Date('2026-01-01T00:00:00.000Z');
+ const convos = [];
+
+ for (let i = 0; i < 30; i++) {
+ const updatedAt = new Date(baseTime.getTime() - i * 60000); // Each 1 minute apart
+ const convo = await createConvoWithTimestamps(i, updatedAt, updatedAt);
+ convos.push(convo);
+ }
+
+ // Fetch first page
+ const page1 = await getConvosByCursor('user123', { limit: 25 });
+
+ expect(page1.conversations).toHaveLength(25);
+ expect(page1.nextCursor).toBeTruthy();
+
+ // Fetch second page using cursor
+ const page2 = await getConvosByCursor('user123', {
+ limit: 25,
+ cursor: page1.nextCursor,
+ });
+
+ // Should get remaining 5 conversations
+ expect(page2.conversations).toHaveLength(5);
+ expect(page2.nextCursor).toBeNull();
+
+ // Verify no duplicates and no gaps
+ const allIds = [
+ ...page1.conversations.map((c) => c.conversationId),
+ ...page2.conversations.map((c) => c.conversationId),
+ ];
+ const uniqueIds = new Set(allIds);
+
+ expect(uniqueIds.size).toBe(30); // All 30 conversations accounted for
+ expect(allIds.length).toBe(30); // No duplicates
+ });
+
+ it('should include conversation at exact page boundary (item 26 bug fix)', async () => {
+ // This test specifically verifies the fix for the bug where item 26
+ // (the first item that should appear on page 2) was being skipped
+
+ const baseTime = new Date('2026-01-01T12:00:00.000Z');
+
+ // Create exactly 26 conversations
+ const convos = [];
+ for (let i = 0; i < 26; i++) {
+ const updatedAt = new Date(baseTime.getTime() - i * 60000);
+ const convo = await createConvoWithTimestamps(i, updatedAt, updatedAt);
+ convos.push(convo);
+ }
+
+ // The 26th conversation (index 25) should be on page 2
+ const item26 = convos[25];
+
+ // Fetch first page with limit 25
+ const page1 = await getConvosByCursor('user123', { limit: 25 });
+
+ expect(page1.conversations).toHaveLength(25);
+ expect(page1.nextCursor).toBeTruthy();
+
+ // Item 26 should NOT be in page 1
+ const page1Ids = page1.conversations.map((c) => c.conversationId);
+ expect(page1Ids).not.toContain(item26.conversationId);
+
+ // Fetch second page
+ const page2 = await getConvosByCursor('user123', {
+ limit: 25,
+ cursor: page1.nextCursor,
+ });
+
+ // Item 26 MUST be in page 2 (this was the bug - it was being skipped)
+ expect(page2.conversations).toHaveLength(1);
+ expect(page2.conversations[0].conversationId).toBe(item26.conversationId);
+ });
+
+ it('should sort by updatedAt DESC by default', async () => {
+ // Create conversations with different updatedAt times
+ // Note: createdAt is older but updatedAt varies
+ const convo1 = await createConvoWithTimestamps(
+ 1,
+ new Date('2026-01-01T00:00:00.000Z'), // oldest created
+ new Date('2026-01-03T00:00:00.000Z'), // most recently updated
+ );
+
+ const convo2 = await createConvoWithTimestamps(
+ 2,
+ new Date('2026-01-02T00:00:00.000Z'), // middle created
+ new Date('2026-01-02T00:00:00.000Z'), // middle updated
+ );
+
+ const convo3 = await createConvoWithTimestamps(
+ 3,
+ new Date('2026-01-03T00:00:00.000Z'), // newest created
+ new Date('2026-01-01T00:00:00.000Z'), // oldest updated
+ );
+
+ const result = await getConvosByCursor('user123');
+
+ // Should be sorted by updatedAt DESC (most recent first)
+ expect(result.conversations).toHaveLength(3);
+ expect(result.conversations[0].conversationId).toBe(convo1.conversationId); // Jan 3 updatedAt
+ expect(result.conversations[1].conversationId).toBe(convo2.conversationId); // Jan 2 updatedAt
+ expect(result.conversations[2].conversationId).toBe(convo3.conversationId); // Jan 1 updatedAt
+ });
+
+ it('should handle conversations with same updatedAt (tie-breaker)', async () => {
+ const sameTime = new Date('2026-01-01T12:00:00.000Z');
+
+ // Create 3 conversations with exact same updatedAt
+ const convo1 = await createConvoWithTimestamps(1, sameTime, sameTime);
+ const convo2 = await createConvoWithTimestamps(2, sameTime, sameTime);
+ const convo3 = await createConvoWithTimestamps(3, sameTime, sameTime);
+
+ const result = await getConvosByCursor('user123');
+
+ // All 3 should be returned (no skipping due to same timestamps)
+ expect(result.conversations).toHaveLength(3);
+
+ const returnedIds = result.conversations.map((c) => c.conversationId);
+ expect(returnedIds).toContain(convo1.conversationId);
+ expect(returnedIds).toContain(convo2.conversationId);
+ expect(returnedIds).toContain(convo3.conversationId);
+ });
+
+ it('should handle cursor pagination with conversations updated during pagination', async () => {
+ // Simulate the scenario where a conversation is updated between page fetches
+ const baseTime = new Date('2026-01-01T00:00:00.000Z');
+
+ // Create 30 conversations
+ for (let i = 0; i < 30; i++) {
+ const updatedAt = new Date(baseTime.getTime() - i * 60000);
+ await createConvoWithTimestamps(i, updatedAt, updatedAt);
+ }
+
+ // Fetch first page
+ const page1 = await getConvosByCursor('user123', { limit: 25 });
+ expect(page1.conversations).toHaveLength(25);
+
+ // Now update one of the conversations that should be on page 2
+ // to have a newer updatedAt (simulating user activity during pagination)
+ const convosOnPage2 = await Conversation.find({ user: 'user123' })
+ .sort({ updatedAt: -1 })
+ .skip(25)
+ .limit(5);
+
+ if (convosOnPage2.length > 0) {
+ const updatedConvo = convosOnPage2[0];
+ await Conversation.updateOne(
+ { _id: updatedConvo._id },
+ { updatedAt: new Date('2026-01-02T00:00:00.000Z') }, // Much newer
+ );
+ }
+
+ // Fetch second page with original cursor
+ const page2 = await getConvosByCursor('user123', {
+ limit: 25,
+ cursor: page1.nextCursor,
+ });
+
+ // The updated conversation might not be in page 2 anymore
+ // (it moved to the front), but we should still get remaining items
+ // without errors and without infinite loops
+ expect(page2.conversations.length).toBeGreaterThanOrEqual(0);
+ });
+
+ it('should correctly decode and use cursor for pagination', async () => {
+ const baseTime = new Date('2026-01-01T00:00:00.000Z');
+
+ // Create 30 conversations
+ for (let i = 0; i < 30; i++) {
+ const updatedAt = new Date(baseTime.getTime() - i * 60000);
+ await createConvoWithTimestamps(i, updatedAt, updatedAt);
+ }
+
+ // Fetch first page
+ const page1 = await getConvosByCursor('user123', { limit: 25 });
+
+ // Decode the cursor to verify it's based on the last RETURNED item
+ const decodedCursor = JSON.parse(Buffer.from(page1.nextCursor, 'base64').toString());
+
+ // The cursor should match the last item in page1 (item at index 24)
+ const lastReturnedItem = page1.conversations[24];
+
+ expect(new Date(decodedCursor.primary).getTime()).toBe(
+ new Date(lastReturnedItem.updatedAt).getTime(),
+ );
+ });
+
+ it('should support sortBy createdAt when explicitly requested', async () => {
+ // Create conversations with different timestamps
+ const convo1 = await createConvoWithTimestamps(
+ 1,
+ new Date('2026-01-03T00:00:00.000Z'), // newest created
+ new Date('2026-01-01T00:00:00.000Z'), // oldest updated
+ );
+
+ const convo2 = await createConvoWithTimestamps(
+ 2,
+ new Date('2026-01-01T00:00:00.000Z'), // oldest created
+ new Date('2026-01-03T00:00:00.000Z'), // newest updated
+ );
+
+ // Verify timestamps were set correctly
+ expect(new Date(convo1.createdAt).getTime()).toBe(
+ new Date('2026-01-03T00:00:00.000Z').getTime(),
+ );
+ expect(new Date(convo2.createdAt).getTime()).toBe(
+ new Date('2026-01-01T00:00:00.000Z').getTime(),
+ );
+
+ const result = await getConvosByCursor('user123', { sortBy: 'createdAt' });
+
+ // Should be sorted by createdAt DESC
+ expect(result.conversations).toHaveLength(2);
+ expect(result.conversations[0].conversationId).toBe(convo1.conversationId); // Jan 3 createdAt
+ expect(result.conversations[1].conversationId).toBe(convo2.conversationId); // Jan 1 createdAt
+ });
+
+ it('should handle empty result set gracefully', async () => {
+ const result = await getConvosByCursor('user123');
+
+ expect(result.conversations).toHaveLength(0);
+ expect(result.nextCursor).toBeNull();
+ });
+
+ it('should handle exactly limit number of conversations (no next page)', async () => {
+ const baseTime = new Date('2026-01-01T00:00:00.000Z');
+
+ // Create exactly 25 conversations (equal to default limit)
+ for (let i = 0; i < 25; i++) {
+ const updatedAt = new Date(baseTime.getTime() - i * 60000);
+ await createConvoWithTimestamps(i, updatedAt, updatedAt);
+ }
+
+ const result = await getConvosByCursor('user123', { limit: 25 });
+
+ expect(result.conversations).toHaveLength(25);
+ expect(result.nextCursor).toBeNull(); // No next page
+ });
+ });
});
diff --git a/api/models/File.js b/api/models/File.js
index 5e90c86fe4..1a01ef12f9 100644
--- a/api/models/File.js
+++ b/api/models/File.js
@@ -26,7 +26,8 @@ const getFiles = async (filter, _sortOptions, selectFields = { text: 0 }) => {
};
/**
- * Retrieves tool files (files that are embedded or have a fileIdentifier) from an array of file IDs
+ * Retrieves tool files (files that are embedded or have a fileIdentifier) from an array of file IDs.
+ * Note: execute_code files are handled separately by getCodeGeneratedFiles.
* @param {string[]} fileIds - Array of file_id strings to search for
* @param {Set} toolResourceSet - Optional filter for tool resources
* @returns {Promise>} Files that match the criteria
@@ -37,21 +38,25 @@ const getToolFilesByIds = async (fileIds, toolResourceSet) => {
}
try {
- const filter = {
- file_id: { $in: fileIds },
- $or: [],
- };
+ const orConditions = [];
if (toolResourceSet.has(EToolResources.context)) {
- filter.$or.push({ text: { $exists: true, $ne: null }, context: FileContext.agents });
+ orConditions.push({ text: { $exists: true, $ne: null }, context: FileContext.agents });
}
if (toolResourceSet.has(EToolResources.file_search)) {
- filter.$or.push({ embedded: true });
+ orConditions.push({ embedded: true });
}
- if (toolResourceSet.has(EToolResources.execute_code)) {
- filter.$or.push({ 'metadata.fileIdentifier': { $exists: true } });
+
+ if (orConditions.length === 0) {
+ return [];
}
+ const filter = {
+ file_id: { $in: fileIds },
+ context: { $ne: FileContext.execute_code }, // Exclude code-generated files
+ $or: orConditions,
+ };
+
const selectFields = { text: 0 };
const sortOptions = { updatedAt: -1 };
@@ -62,6 +67,70 @@ const getToolFilesByIds = async (fileIds, toolResourceSet) => {
}
};
+/**
+ * Retrieves files generated by code execution for a given conversation.
+ * These files are stored locally with fileIdentifier metadata for code env re-upload.
+ * @param {string} conversationId - The conversation ID to search for
+ * @param {string[]} [messageIds] - Optional array of messageIds to filter by (for linear thread filtering)
+ * @returns {Promise>} Files generated by code execution in the conversation
+ */
+const getCodeGeneratedFiles = async (conversationId, messageIds) => {
+ if (!conversationId) {
+ return [];
+ }
+
+ /** messageIds are required for proper thread filtering of code-generated files */
+ if (!messageIds || messageIds.length === 0) {
+ return [];
+ }
+
+ try {
+ const filter = {
+ conversationId,
+ context: FileContext.execute_code,
+ messageId: { $exists: true, $in: messageIds },
+ 'metadata.fileIdentifier': { $exists: true },
+ };
+
+ const selectFields = { text: 0 };
+ const sortOptions = { createdAt: 1 };
+
+ return await getFiles(filter, sortOptions, selectFields);
+ } catch (error) {
+ logger.error('[getCodeGeneratedFiles] Error retrieving code generated files:', error);
+ return [];
+ }
+};
+
+/**
+ * Retrieves user-uploaded execute_code files (not code-generated) by their file IDs.
+ * These are files with fileIdentifier metadata but context is NOT execute_code (e.g., agents or message_attachment).
+ * File IDs should be collected from message.files arrays in the current thread.
+ * @param {string[]} fileIds - Array of file IDs to fetch (from message.files in the thread)
+ * @returns {Promise>} User-uploaded execute_code files
+ */
+const getUserCodeFiles = async (fileIds) => {
+ if (!fileIds || fileIds.length === 0) {
+ return [];
+ }
+
+ try {
+ const filter = {
+ file_id: { $in: fileIds },
+ context: { $ne: FileContext.execute_code },
+ 'metadata.fileIdentifier': { $exists: true },
+ };
+
+ const selectFields = { text: 0 };
+ const sortOptions = { createdAt: 1 };
+
+ return await getFiles(filter, sortOptions, selectFields);
+ } catch (error) {
+ logger.error('[getUserCodeFiles] Error retrieving user code files:', error);
+ return [];
+ }
+};
+
/**
* Creates a new file with a TTL of 1 hour.
* @param {MongoFile} data - The file data to be created, must contain file_id.
@@ -169,6 +238,8 @@ module.exports = {
findFileById,
getFiles,
getToolFilesByIds,
+ getCodeGeneratedFiles,
+ getUserCodeFiles,
createFile,
updateFile,
updateFileUsage,
diff --git a/api/models/File.spec.js b/api/models/File.spec.js
index c92224ea3e..2d4282cff7 100644
--- a/api/models/File.spec.js
+++ b/api/models/File.spec.js
@@ -1,7 +1,7 @@
const mongoose = require('mongoose');
const { v4: uuidv4 } = require('uuid');
-const { createModels } = require('@librechat/data-schemas');
const { MongoMemoryServer } = require('mongodb-memory-server');
+const { createModels, createMethods } = require('@librechat/data-schemas');
const {
SystemRoles,
ResourceType,
@@ -9,8 +9,6 @@ const {
PrincipalType,
} = require('librechat-data-provider');
const { grantPermission } = require('~/server/services/PermissionService');
-const { getFiles, createFile } = require('./File');
-const { seedDefaultRoles } = require('~/models');
const { createAgent } = require('./Agent');
let File;
@@ -18,6 +16,10 @@ let Agent;
let AclEntry;
let User;
let modelsToCleanup = [];
+let methods;
+let getFiles;
+let createFile;
+let seedDefaultRoles;
describe('File Access Control', () => {
let mongoServer;
@@ -42,6 +44,12 @@ describe('File Access Control', () => {
AclEntry = dbModels.AclEntry;
User = dbModels.User;
+ // Create methods from data-schemas (includes file methods)
+ methods = createMethods(mongoose);
+ getFiles = methods.getFiles;
+ createFile = methods.createFile;
+ seedDefaultRoles = methods.seedDefaultRoles;
+
// Seed default roles
await seedDefaultRoles();
});
diff --git a/api/models/Message.spec.js b/api/models/Message.spec.js
index 2dab6b2866..39b5b4337c 100644
--- a/api/models/Message.spec.js
+++ b/api/models/Message.spec.js
@@ -573,4 +573,326 @@ describe('Message Operations', () => {
expect(bulk2.expiredAt).toBeNull();
});
});
+
+ describe('Message cursor pagination', () => {
+ /**
+ * Helper to create messages with specific timestamps
+ * Uses collection.insertOne to bypass Mongoose timestamps
+ */
+ const createMessageWithTimestamp = async (index, conversationId, createdAt) => {
+ const messageId = uuidv4();
+ await Message.collection.insertOne({
+ messageId,
+ conversationId,
+ user: 'user123',
+ text: `Message ${index}`,
+ isCreatedByUser: index % 2 === 0,
+ createdAt,
+ updatedAt: createdAt,
+ });
+ return Message.findOne({ messageId }).lean();
+ };
+
+ /**
+ * Simulates the pagination logic from api/server/routes/messages.js
+ * This tests the exact query pattern used in the route
+ */
+ const getMessagesByCursor = async ({
+ conversationId,
+ user,
+ pageSize = 25,
+ cursor = null,
+ sortBy = 'createdAt',
+ sortDirection = 'desc',
+ }) => {
+ const sortOrder = sortDirection === 'asc' ? 1 : -1;
+ const sortField = ['createdAt', 'updatedAt'].includes(sortBy) ? sortBy : 'createdAt';
+ const cursorOperator = sortDirection === 'asc' ? '$gt' : '$lt';
+
+ const filter = { conversationId, user };
+ if (cursor) {
+ filter[sortField] = { [cursorOperator]: new Date(cursor) };
+ }
+
+ const messages = await Message.find(filter)
+ .sort({ [sortField]: sortOrder })
+ .limit(pageSize + 1)
+ .lean();
+
+ let nextCursor = null;
+ if (messages.length > pageSize) {
+ messages.pop(); // Remove extra item used to detect next page
+ // Create cursor from the last RETURNED item (not the popped one)
+ nextCursor = messages[messages.length - 1][sortField];
+ }
+
+ return { messages, nextCursor };
+ };
+
+ it('should return messages for a conversation with pagination', async () => {
+ const conversationId = uuidv4();
+ const baseTime = new Date('2026-01-01T00:00:00.000Z');
+
+ // Create 30 messages to test pagination
+ for (let i = 0; i < 30; i++) {
+ const createdAt = new Date(baseTime.getTime() - i * 60000); // Each 1 minute apart
+ await createMessageWithTimestamp(i, conversationId, createdAt);
+ }
+
+ // Fetch first page (pageSize 25)
+ const page1 = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ pageSize: 25,
+ });
+
+ expect(page1.messages).toHaveLength(25);
+ expect(page1.nextCursor).toBeTruthy();
+
+ // Fetch second page using cursor
+ const page2 = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ pageSize: 25,
+ cursor: page1.nextCursor,
+ });
+
+ // Should get remaining 5 messages
+ expect(page2.messages).toHaveLength(5);
+ expect(page2.nextCursor).toBeNull();
+
+ // Verify no duplicates and no gaps
+ const allMessageIds = [
+ ...page1.messages.map((m) => m.messageId),
+ ...page2.messages.map((m) => m.messageId),
+ ];
+ const uniqueIds = new Set(allMessageIds);
+
+ expect(uniqueIds.size).toBe(30); // All 30 messages accounted for
+ expect(allMessageIds.length).toBe(30); // No duplicates
+ });
+
+ it('should not skip message at page boundary (item 26 bug fix)', async () => {
+ const conversationId = uuidv4();
+ const baseTime = new Date('2026-01-01T12:00:00.000Z');
+
+ // Create exactly 26 messages
+ const messages = [];
+ for (let i = 0; i < 26; i++) {
+ const createdAt = new Date(baseTime.getTime() - i * 60000);
+ const msg = await createMessageWithTimestamp(i, conversationId, createdAt);
+ messages.push(msg);
+ }
+
+ // The 26th message (index 25) should be on page 2
+ const item26 = messages[25];
+
+ // Fetch first page with pageSize 25
+ const page1 = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ pageSize: 25,
+ });
+
+ expect(page1.messages).toHaveLength(25);
+ expect(page1.nextCursor).toBeTruthy();
+
+ // Item 26 should NOT be in page 1
+ const page1Ids = page1.messages.map((m) => m.messageId);
+ expect(page1Ids).not.toContain(item26.messageId);
+
+ // Fetch second page
+ const page2 = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ pageSize: 25,
+ cursor: page1.nextCursor,
+ });
+
+ // Item 26 MUST be in page 2 (this was the bug - it was being skipped)
+ expect(page2.messages).toHaveLength(1);
+ expect(page2.messages[0].messageId).toBe(item26.messageId);
+ });
+
+ it('should sort by createdAt DESC by default', async () => {
+ const conversationId = uuidv4();
+
+ // Create messages with specific timestamps
+ const msg1 = await createMessageWithTimestamp(
+ 1,
+ conversationId,
+ new Date('2026-01-01T00:00:00.000Z'),
+ );
+ const msg2 = await createMessageWithTimestamp(
+ 2,
+ conversationId,
+ new Date('2026-01-02T00:00:00.000Z'),
+ );
+ const msg3 = await createMessageWithTimestamp(
+ 3,
+ conversationId,
+ new Date('2026-01-03T00:00:00.000Z'),
+ );
+
+ const result = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ });
+
+ // Should be sorted by createdAt DESC (newest first) by default
+ expect(result.messages).toHaveLength(3);
+ expect(result.messages[0].messageId).toBe(msg3.messageId);
+ expect(result.messages[1].messageId).toBe(msg2.messageId);
+ expect(result.messages[2].messageId).toBe(msg1.messageId);
+ });
+
+ it('should support ascending sort direction', async () => {
+ const conversationId = uuidv4();
+
+ const msg1 = await createMessageWithTimestamp(
+ 1,
+ conversationId,
+ new Date('2026-01-01T00:00:00.000Z'),
+ );
+ const msg2 = await createMessageWithTimestamp(
+ 2,
+ conversationId,
+ new Date('2026-01-02T00:00:00.000Z'),
+ );
+
+ const result = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ sortDirection: 'asc',
+ });
+
+ // Should be sorted by createdAt ASC (oldest first)
+ expect(result.messages).toHaveLength(2);
+ expect(result.messages[0].messageId).toBe(msg1.messageId);
+ expect(result.messages[1].messageId).toBe(msg2.messageId);
+ });
+
+ it('should handle empty conversation', async () => {
+ const conversationId = uuidv4();
+
+ const result = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ });
+
+ expect(result.messages).toHaveLength(0);
+ expect(result.nextCursor).toBeNull();
+ });
+
+ it('should only return messages for the specified user', async () => {
+ const conversationId = uuidv4();
+ const createdAt = new Date();
+
+ // Create a message for user123
+ await Message.collection.insertOne({
+ messageId: uuidv4(),
+ conversationId,
+ user: 'user123',
+ text: 'User message',
+ createdAt,
+ updatedAt: createdAt,
+ });
+
+ // Create a message for a different user
+ await Message.collection.insertOne({
+ messageId: uuidv4(),
+ conversationId,
+ user: 'otherUser',
+ text: 'Other user message',
+ createdAt,
+ updatedAt: createdAt,
+ });
+
+ const result = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ });
+
+ // Should only return user123's message
+ expect(result.messages).toHaveLength(1);
+ expect(result.messages[0].user).toBe('user123');
+ });
+
+ it('should handle exactly pageSize number of messages (no next page)', async () => {
+ const conversationId = uuidv4();
+ const baseTime = new Date('2026-01-01T00:00:00.000Z');
+
+ // Create exactly 25 messages (equal to default pageSize)
+ for (let i = 0; i < 25; i++) {
+ const createdAt = new Date(baseTime.getTime() - i * 60000);
+ await createMessageWithTimestamp(i, conversationId, createdAt);
+ }
+
+ const result = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ pageSize: 25,
+ });
+
+ expect(result.messages).toHaveLength(25);
+ expect(result.nextCursor).toBeNull(); // No next page
+ });
+
+ it('should handle pageSize of 1', async () => {
+ const conversationId = uuidv4();
+ const baseTime = new Date('2026-01-01T00:00:00.000Z');
+
+ // Create 3 messages
+ for (let i = 0; i < 3; i++) {
+ const createdAt = new Date(baseTime.getTime() - i * 60000);
+ await createMessageWithTimestamp(i, conversationId, createdAt);
+ }
+
+ // Fetch with pageSize 1
+ let cursor = null;
+ const allMessages = [];
+
+ for (let page = 0; page < 5; page++) {
+ const result = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ pageSize: 1,
+ cursor,
+ });
+
+ allMessages.push(...result.messages);
+ cursor = result.nextCursor;
+
+ if (!cursor) {
+ break;
+ }
+ }
+
+ // Should get all 3 messages without duplicates
+ expect(allMessages).toHaveLength(3);
+ const uniqueIds = new Set(allMessages.map((m) => m.messageId));
+ expect(uniqueIds.size).toBe(3);
+ });
+
+ it('should handle messages with same createdAt timestamp', async () => {
+ const conversationId = uuidv4();
+ const sameTime = new Date('2026-01-01T12:00:00.000Z');
+
+ // Create multiple messages with the exact same timestamp
+ const messages = [];
+ for (let i = 0; i < 5; i++) {
+ const msg = await createMessageWithTimestamp(i, conversationId, sameTime);
+ messages.push(msg);
+ }
+
+ const result = await getMessagesByCursor({
+ conversationId,
+ user: 'user123',
+ pageSize: 10,
+ });
+
+ // All messages should be returned
+ expect(result.messages).toHaveLength(5);
+ });
+ });
});
diff --git a/api/models/Role.js b/api/models/Role.js
index 1766dc9b08..b7f806f3b6 100644
--- a/api/models/Role.js
+++ b/api/models/Role.js
@@ -114,6 +114,28 @@ async function updateAccessPermissions(roleName, permissionsUpdate, roleData) {
}
}
+ // Migrate legacy SHARED_GLOBAL → SHARE for PROMPTS and AGENTS.
+ // SHARED_GLOBAL was removed in favour of SHARE in PR #11283. If the DB still has
+ // SHARED_GLOBAL but not SHARE, inherit the value so sharing intent is preserved.
+ const legacySharedGlobalTypes = ['PROMPTS', 'AGENTS'];
+ for (const legacyPermType of legacySharedGlobalTypes) {
+ const existingTypePerms = currentPermissions[legacyPermType];
+ if (
+ existingTypePerms &&
+ 'SHARED_GLOBAL' in existingTypePerms &&
+ !('SHARE' in existingTypePerms) &&
+ updates[legacyPermType] &&
+ // Don't override an explicit SHARE value the caller already provided
+ !('SHARE' in updates[legacyPermType])
+ ) {
+ const inheritedValue = existingTypePerms['SHARED_GLOBAL'];
+ updates[legacyPermType]['SHARE'] = inheritedValue;
+ logger.info(
+ `Migrating '${roleName}' role ${legacyPermType}.SHARED_GLOBAL=${inheritedValue} → SHARE`,
+ );
+ }
+ }
+
for (const [permissionType, permissions] of Object.entries(updates)) {
const currentTypePermissions = currentPermissions[permissionType] || {};
updatedPermissions[permissionType] = { ...currentTypePermissions };
@@ -129,6 +151,32 @@ async function updateAccessPermissions(roleName, permissionsUpdate, roleData) {
}
}
+ // Clean up orphaned SHARED_GLOBAL fields left in DB after the schema rename.
+ // Since we $set the full permissions object, deleting from updatedPermissions
+ // is sufficient to remove the field from MongoDB.
+ for (const legacyPermType of legacySharedGlobalTypes) {
+ const existingTypePerms = currentPermissions[legacyPermType];
+ if (existingTypePerms && 'SHARED_GLOBAL' in existingTypePerms) {
+ if (!updates[legacyPermType]) {
+ // permType wasn't in the update payload so the migration block above didn't run.
+ // Create a writable copy and handle the SHARED_GLOBAL → SHARE inheritance here
+ // to avoid removing SHARED_GLOBAL without writing SHARE (data loss).
+ updatedPermissions[legacyPermType] = { ...existingTypePerms };
+ if (!('SHARE' in existingTypePerms)) {
+ updatedPermissions[legacyPermType]['SHARE'] = existingTypePerms['SHARED_GLOBAL'];
+ logger.info(
+ `Migrating '${roleName}' role ${legacyPermType}.SHARED_GLOBAL=${existingTypePerms['SHARED_GLOBAL']} → SHARE`,
+ );
+ }
+ }
+ delete updatedPermissions[legacyPermType]['SHARED_GLOBAL'];
+ hasChanges = true;
+ logger.info(
+ `Removed legacy SHARED_GLOBAL field from '${roleName}' role ${legacyPermType} permissions`,
+ );
+ }
+ }
+
if (hasChanges) {
const updateObj = { permissions: updatedPermissions };
diff --git a/api/models/Role.spec.js b/api/models/Role.spec.js
index c344f719dd..0ec2f831e2 100644
--- a/api/models/Role.spec.js
+++ b/api/models/Role.spec.js
@@ -46,7 +46,7 @@ describe('updateAccessPermissions', () => {
[PermissionTypes.PROMPTS]: {
CREATE: true,
USE: true,
- SHARED_GLOBAL: false,
+ SHARE: false,
},
},
}).save();
@@ -55,7 +55,7 @@ describe('updateAccessPermissions', () => {
[PermissionTypes.PROMPTS]: {
CREATE: true,
USE: true,
- SHARED_GLOBAL: true,
+ SHARE: true,
},
});
@@ -63,7 +63,7 @@ describe('updateAccessPermissions', () => {
expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({
CREATE: true,
USE: true,
- SHARED_GLOBAL: true,
+ SHARE: true,
});
});
@@ -74,7 +74,7 @@ describe('updateAccessPermissions', () => {
[PermissionTypes.PROMPTS]: {
CREATE: true,
USE: true,
- SHARED_GLOBAL: false,
+ SHARE: false,
},
},
}).save();
@@ -83,7 +83,7 @@ describe('updateAccessPermissions', () => {
[PermissionTypes.PROMPTS]: {
CREATE: true,
USE: true,
- SHARED_GLOBAL: false,
+ SHARE: false,
},
});
@@ -91,7 +91,7 @@ describe('updateAccessPermissions', () => {
expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({
CREATE: true,
USE: true,
- SHARED_GLOBAL: false,
+ SHARE: false,
});
});
@@ -110,20 +110,20 @@ describe('updateAccessPermissions', () => {
[PermissionTypes.PROMPTS]: {
CREATE: true,
USE: true,
- SHARED_GLOBAL: false,
+ SHARE: false,
},
},
}).save();
await updateAccessPermissions(SystemRoles.USER, {
- [PermissionTypes.PROMPTS]: { SHARED_GLOBAL: true },
+ [PermissionTypes.PROMPTS]: { SHARE: true },
});
const updatedRole = await getRoleByName(SystemRoles.USER);
expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({
CREATE: true,
USE: true,
- SHARED_GLOBAL: true,
+ SHARE: true,
});
});
@@ -134,7 +134,7 @@ describe('updateAccessPermissions', () => {
[PermissionTypes.PROMPTS]: {
CREATE: true,
USE: true,
- SHARED_GLOBAL: false,
+ SHARE: false,
},
},
}).save();
@@ -147,7 +147,7 @@ describe('updateAccessPermissions', () => {
expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({
CREATE: true,
USE: false,
- SHARED_GLOBAL: false,
+ SHARE: false,
});
});
@@ -155,13 +155,13 @@ describe('updateAccessPermissions', () => {
await new Role({
name: SystemRoles.USER,
permissions: {
- [PermissionTypes.PROMPTS]: { CREATE: true, USE: true, SHARED_GLOBAL: false },
+ [PermissionTypes.PROMPTS]: { CREATE: true, USE: true, SHARE: false },
[PermissionTypes.BOOKMARKS]: { USE: true },
},
}).save();
await updateAccessPermissions(SystemRoles.USER, {
- [PermissionTypes.PROMPTS]: { USE: false, SHARED_GLOBAL: true },
+ [PermissionTypes.PROMPTS]: { USE: false, SHARE: true },
[PermissionTypes.BOOKMARKS]: { USE: false },
});
@@ -169,7 +169,7 @@ describe('updateAccessPermissions', () => {
expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({
CREATE: true,
USE: false,
- SHARED_GLOBAL: true,
+ SHARE: true,
});
expect(updatedRole.permissions[PermissionTypes.BOOKMARKS]).toEqual({ USE: false });
});
@@ -178,19 +178,19 @@ describe('updateAccessPermissions', () => {
await new Role({
name: SystemRoles.USER,
permissions: {
- [PermissionTypes.PROMPTS]: { CREATE: true, USE: true, SHARED_GLOBAL: false },
+ [PermissionTypes.PROMPTS]: { CREATE: true, USE: true, SHARE: false },
},
}).save();
await updateAccessPermissions(SystemRoles.USER, {
- [PermissionTypes.PROMPTS]: { USE: false, SHARED_GLOBAL: true },
+ [PermissionTypes.PROMPTS]: { USE: false, SHARE: true },
});
const updatedRole = await getRoleByName(SystemRoles.USER);
expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({
CREATE: true,
USE: false,
- SHARED_GLOBAL: true,
+ SHARE: true,
});
});
@@ -214,13 +214,13 @@ describe('updateAccessPermissions', () => {
await new Role({
name: SystemRoles.USER,
permissions: {
- [PermissionTypes.PROMPTS]: { CREATE: true, USE: true, SHARED_GLOBAL: false },
+ [PermissionTypes.PROMPTS]: { CREATE: true, USE: true, SHARE: false },
[PermissionTypes.MULTI_CONVO]: { USE: false },
},
}).save();
await updateAccessPermissions(SystemRoles.USER, {
- [PermissionTypes.PROMPTS]: { SHARED_GLOBAL: true },
+ [PermissionTypes.PROMPTS]: { SHARE: true },
[PermissionTypes.MULTI_CONVO]: { USE: true },
});
@@ -228,11 +228,117 @@ describe('updateAccessPermissions', () => {
expect(updatedRole.permissions[PermissionTypes.PROMPTS]).toEqual({
CREATE: true,
USE: true,
- SHARED_GLOBAL: true,
+ SHARE: true,
});
expect(updatedRole.permissions[PermissionTypes.MULTI_CONVO]).toEqual({ USE: true });
});
+ it('should inherit SHARED_GLOBAL value into SHARE when SHARE is absent from both DB and update', async () => {
+ // Simulates the startup backfill path: caller sends SHARE_PUBLIC but not SHARE;
+ // migration should inherit SHARED_GLOBAL to preserve the deployment's sharing intent.
+ await Role.collection.insertOne({
+ name: SystemRoles.USER,
+ permissions: {
+ [PermissionTypes.PROMPTS]: { USE: true, CREATE: true, SHARED_GLOBAL: true },
+ [PermissionTypes.AGENTS]: { USE: true, CREATE: true, SHARED_GLOBAL: false },
+ },
+ });
+
+ await updateAccessPermissions(SystemRoles.USER, {
+ // No explicit SHARE — migration should inherit from SHARED_GLOBAL
+ [PermissionTypes.PROMPTS]: { SHARE_PUBLIC: false },
+ [PermissionTypes.AGENTS]: { SHARE_PUBLIC: false },
+ });
+
+ const updatedRole = await getRoleByName(SystemRoles.USER);
+
+ // SHARED_GLOBAL=true → SHARE=true (inherited)
+ expect(updatedRole.permissions[PermissionTypes.PROMPTS].SHARE).toBe(true);
+ // SHARED_GLOBAL=false → SHARE=false (inherited)
+ expect(updatedRole.permissions[PermissionTypes.AGENTS].SHARE).toBe(false);
+ // SHARED_GLOBAL cleaned up
+ expect(updatedRole.permissions[PermissionTypes.PROMPTS].SHARED_GLOBAL).toBeUndefined();
+ expect(updatedRole.permissions[PermissionTypes.AGENTS].SHARED_GLOBAL).toBeUndefined();
+ });
+
+ it('should respect explicit SHARE in update payload and not override it with SHARED_GLOBAL', async () => {
+ // Caller explicitly passes SHARE: false even though SHARED_GLOBAL=true in DB.
+ // The explicit intent must win; migration must not silently overwrite it.
+ await Role.collection.insertOne({
+ name: SystemRoles.USER,
+ permissions: {
+ [PermissionTypes.PROMPTS]: { USE: true, SHARED_GLOBAL: true },
+ },
+ });
+
+ await updateAccessPermissions(SystemRoles.USER, {
+ [PermissionTypes.PROMPTS]: { SHARE: false }, // explicit false — should be preserved
+ });
+
+ const updatedRole = await getRoleByName(SystemRoles.USER);
+
+ expect(updatedRole.permissions[PermissionTypes.PROMPTS].SHARE).toBe(false);
+ expect(updatedRole.permissions[PermissionTypes.PROMPTS].SHARED_GLOBAL).toBeUndefined();
+ });
+
+ it('should migrate SHARED_GLOBAL to SHARE even when the permType is not in the update payload', async () => {
+ // Bug #2 regression: cleanup block removes SHARED_GLOBAL but migration block only
+ // runs when the permType is in the update payload. Without the fix, SHARE would be
+ // lost when any other permType (e.g. MULTI_CONVO) is the only thing being updated.
+ await Role.collection.insertOne({
+ name: SystemRoles.USER,
+ permissions: {
+ [PermissionTypes.PROMPTS]: {
+ USE: true,
+ SHARED_GLOBAL: true, // legacy — NO SHARE present
+ },
+ [PermissionTypes.MULTI_CONVO]: { USE: false },
+ },
+ });
+
+ // Only update MULTI_CONVO — PROMPTS is intentionally absent from the payload
+ await updateAccessPermissions(SystemRoles.USER, {
+ [PermissionTypes.MULTI_CONVO]: { USE: true },
+ });
+
+ const updatedRole = await getRoleByName(SystemRoles.USER);
+
+ // SHARE should have been inherited from SHARED_GLOBAL, not silently dropped
+ expect(updatedRole.permissions[PermissionTypes.PROMPTS].SHARE).toBe(true);
+ // SHARED_GLOBAL should be removed
+ expect(updatedRole.permissions[PermissionTypes.PROMPTS].SHARED_GLOBAL).toBeUndefined();
+ // Original USE should be untouched
+ expect(updatedRole.permissions[PermissionTypes.PROMPTS].USE).toBe(true);
+ // The actual update should have applied
+ expect(updatedRole.permissions[PermissionTypes.MULTI_CONVO].USE).toBe(true);
+ });
+
+ it('should remove orphaned SHARED_GLOBAL when SHARE already exists and permType is not in update', async () => {
+ // Safe cleanup case: SHARE already set, SHARED_GLOBAL is just orphaned noise.
+ // SHARE must not be changed; SHARED_GLOBAL must be removed.
+ await Role.collection.insertOne({
+ name: SystemRoles.USER,
+ permissions: {
+ [PermissionTypes.PROMPTS]: {
+ USE: true,
+ SHARE: true, // already migrated
+ SHARED_GLOBAL: true, // orphaned
+ },
+ [PermissionTypes.MULTI_CONVO]: { USE: false },
+ },
+ });
+
+ await updateAccessPermissions(SystemRoles.USER, {
+ [PermissionTypes.MULTI_CONVO]: { USE: true },
+ });
+
+ const updatedRole = await getRoleByName(SystemRoles.USER);
+
+ expect(updatedRole.permissions[PermissionTypes.PROMPTS].SHARED_GLOBAL).toBeUndefined();
+ expect(updatedRole.permissions[PermissionTypes.PROMPTS].SHARE).toBe(true);
+ expect(updatedRole.permissions[PermissionTypes.MULTI_CONVO].USE).toBe(true);
+ });
+
it('should not update MULTI_CONVO permissions when no changes are needed', async () => {
await new Role({
name: SystemRoles.USER,
@@ -271,7 +377,7 @@ describe('initializeRoles', () => {
});
// Example: Check default values for ADMIN role
- expect(adminRole.permissions[PermissionTypes.PROMPTS].SHARED_GLOBAL).toBe(true);
+ expect(adminRole.permissions[PermissionTypes.PROMPTS].SHARE).toBe(true);
expect(adminRole.permissions[PermissionTypes.BOOKMARKS].USE).toBe(true);
expect(adminRole.permissions[PermissionTypes.AGENTS].CREATE).toBe(true);
});
@@ -283,7 +389,7 @@ describe('initializeRoles', () => {
[PermissionTypes.PROMPTS]: {
[Permissions.USE]: false,
[Permissions.CREATE]: true,
- [Permissions.SHARED_GLOBAL]: true,
+ [Permissions.SHARE]: true,
},
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false },
},
@@ -320,7 +426,7 @@ describe('initializeRoles', () => {
expect(userRole.permissions[PermissionTypes.AGENTS]).toBeDefined();
expect(userRole.permissions[PermissionTypes.AGENTS].CREATE).toBeDefined();
expect(userRole.permissions[PermissionTypes.AGENTS].USE).toBeDefined();
- expect(userRole.permissions[PermissionTypes.AGENTS].SHARED_GLOBAL).toBeDefined();
+ expect(userRole.permissions[PermissionTypes.AGENTS].SHARE).toBeDefined();
});
it('should handle multiple runs without duplicating or modifying data', async () => {
@@ -348,7 +454,7 @@ describe('initializeRoles', () => {
[PermissionTypes.PROMPTS]: {
[Permissions.USE]: false,
[Permissions.CREATE]: false,
- [Permissions.SHARED_GLOBAL]: false,
+ [Permissions.SHARE]: false,
},
[PermissionTypes.BOOKMARKS]:
roleDefaults[SystemRoles.ADMIN].permissions[PermissionTypes.BOOKMARKS],
@@ -365,7 +471,7 @@ describe('initializeRoles', () => {
expect(adminRole.permissions[PermissionTypes.AGENTS]).toBeDefined();
expect(adminRole.permissions[PermissionTypes.AGENTS].CREATE).toBeDefined();
expect(adminRole.permissions[PermissionTypes.AGENTS].USE).toBeDefined();
- expect(adminRole.permissions[PermissionTypes.AGENTS].SHARED_GLOBAL).toBeDefined();
+ expect(adminRole.permissions[PermissionTypes.AGENTS].SHARE).toBeDefined();
});
it('should include MULTI_CONVO permissions when creating default roles', async () => {
diff --git a/api/models/Transaction.js b/api/models/Transaction.js
index 5fa20f1ddf..e553e2bb3b 100644
--- a/api/models/Transaction.js
+++ b/api/models/Transaction.js
@@ -138,11 +138,10 @@ const updateBalance = async ({ user, incrementValue, setValues }) => {
/** Method to calculate and set the tokenValue for a transaction */
function calculateTokenValue(txn) {
- if (!txn.valueKey || !txn.tokenType) {
- txn.tokenValue = txn.rawAmount;
- }
- const { valueKey, tokenType, model, endpointTokenConfig } = txn;
- const multiplier = Math.abs(getMultiplier({ valueKey, tokenType, model, endpointTokenConfig }));
+ const { valueKey, tokenType, model, endpointTokenConfig, inputTokenCount } = txn;
+ const multiplier = Math.abs(
+ getMultiplier({ valueKey, tokenType, model, endpointTokenConfig, inputTokenCount }),
+ );
txn.rate = multiplier;
txn.tokenValue = txn.rawAmount * multiplier;
if (txn.context && txn.tokenType === 'completion' && txn.context === 'incomplete') {
@@ -166,6 +165,7 @@ async function createAutoRefillTransaction(txData) {
}
const transaction = new Transaction(txData);
transaction.endpointTokenConfig = txData.endpointTokenConfig;
+ transaction.inputTokenCount = txData.inputTokenCount;
calculateTokenValue(transaction);
await transaction.save();
@@ -200,6 +200,7 @@ async function createTransaction(_txData) {
const transaction = new Transaction(txData);
transaction.endpointTokenConfig = txData.endpointTokenConfig;
+ transaction.inputTokenCount = txData.inputTokenCount;
calculateTokenValue(transaction);
await transaction.save();
@@ -231,10 +232,9 @@ async function createStructuredTransaction(_txData) {
return;
}
- const transaction = new Transaction({
- ...txData,
- endpointTokenConfig: txData.endpointTokenConfig,
- });
+ const transaction = new Transaction(txData);
+ transaction.endpointTokenConfig = txData.endpointTokenConfig;
+ transaction.inputTokenCount = txData.inputTokenCount;
calculateStructuredTokenValue(transaction);
@@ -266,10 +266,15 @@ function calculateStructuredTokenValue(txn) {
return;
}
- const { model, endpointTokenConfig } = txn;
+ const { model, endpointTokenConfig, inputTokenCount } = txn;
if (txn.tokenType === 'prompt') {
- const inputMultiplier = getMultiplier({ tokenType: 'prompt', model, endpointTokenConfig });
+ const inputMultiplier = getMultiplier({
+ tokenType: 'prompt',
+ model,
+ endpointTokenConfig,
+ inputTokenCount,
+ });
const writeMultiplier =
getCacheMultiplier({ cacheType: 'write', model, endpointTokenConfig }) ?? inputMultiplier;
const readMultiplier =
@@ -304,7 +309,12 @@ function calculateStructuredTokenValue(txn) {
txn.rawAmount = -totalPromptTokens;
} else if (txn.tokenType === 'completion') {
- const multiplier = getMultiplier({ tokenType: txn.tokenType, model, endpointTokenConfig });
+ const multiplier = getMultiplier({
+ tokenType: txn.tokenType,
+ model,
+ endpointTokenConfig,
+ inputTokenCount,
+ });
txn.rate = Math.abs(multiplier);
txn.tokenValue = -Math.abs(txn.rawAmount) * multiplier;
txn.rawAmount = -Math.abs(txn.rawAmount);
diff --git a/api/models/Transaction.spec.js b/api/models/Transaction.spec.js
index 2df9fc67f2..545c7b2755 100644
--- a/api/models/Transaction.spec.js
+++ b/api/models/Transaction.spec.js
@@ -1,7 +1,7 @@
const mongoose = require('mongoose');
const { MongoMemoryServer } = require('mongodb-memory-server');
const { spendTokens, spendStructuredTokens } = require('./spendTokens');
-const { getMultiplier, getCacheMultiplier } = require('./tx');
+const { getMultiplier, getCacheMultiplier, premiumTokenValues, tokenValues } = require('./tx');
const { createTransaction, createStructuredTransaction } = require('./Transaction');
const { Balance, Transaction } = require('~/db/models');
@@ -564,3 +564,424 @@ describe('Transactions Config Tests', () => {
expect(balance.tokenCredits).toBe(initialBalance);
});
});
+
+describe('calculateTokenValue Edge Cases', () => {
+ test('should derive multiplier from model when valueKey is not provided', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'gpt-4';
+ const promptTokens = 1000;
+
+ const result = await createTransaction({
+ user: userId,
+ conversationId: 'test-no-valuekey',
+ model,
+ tokenType: 'prompt',
+ rawAmount: -promptTokens,
+ context: 'test',
+ balance: { enabled: true },
+ });
+
+ const expectedRate = getMultiplier({ model, tokenType: 'prompt' });
+ expect(result.rate).toBe(expectedRate);
+
+ const tx = await Transaction.findOne({ user: userId });
+ expect(tx.tokenValue).toBe(-promptTokens * expectedRate);
+ expect(tx.rate).toBe(expectedRate);
+ });
+
+ test('should derive valueKey and apply correct rate for an unknown model with tokenType', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ await createTransaction({
+ user: userId,
+ conversationId: 'test-unknown-model',
+ model: 'some-unrecognized-model-xyz',
+ tokenType: 'prompt',
+ rawAmount: -500,
+ context: 'test',
+ balance: { enabled: true },
+ });
+
+ const tx = await Transaction.findOne({ user: userId });
+ expect(tx.rate).toBeDefined();
+ expect(tx.rate).toBeGreaterThan(0);
+ expect(tx.tokenValue).toBe(tx.rawAmount * tx.rate);
+ });
+
+ test('should correctly apply model-derived multiplier without valueKey for completion', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'claude-opus-4-6';
+ const completionTokens = 500;
+
+ const result = await createTransaction({
+ user: userId,
+ conversationId: 'test-completion-no-valuekey',
+ model,
+ tokenType: 'completion',
+ rawAmount: -completionTokens,
+ context: 'test',
+ balance: { enabled: true },
+ });
+
+ const expectedRate = getMultiplier({ model, tokenType: 'completion' });
+ expect(expectedRate).toBe(tokenValues[model].completion);
+ expect(result.rate).toBe(expectedRate);
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(updatedBalance.tokenCredits).toBeCloseTo(
+ initialBalance - completionTokens * expectedRate,
+ 0,
+ );
+ });
+});
+
+describe('Premium Token Pricing Integration Tests', () => {
+ test('spendTokens should apply standard pricing when prompt tokens are below premium threshold', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'claude-opus-4-6';
+ const promptTokens = 100000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-premium-below',
+ model,
+ context: 'test',
+ endpointTokenConfig: null,
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const standardPromptRate = tokenValues[model].prompt;
+ const standardCompletionRate = tokenValues[model].completion;
+ const expectedCost =
+ promptTokens * standardPromptRate + completionTokens * standardCompletionRate;
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(updatedBalance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ test('spendTokens should apply premium pricing when prompt tokens exceed premium threshold', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'claude-opus-4-6';
+ const promptTokens = 250000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-premium-above',
+ model,
+ context: 'test',
+ endpointTokenConfig: null,
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const premiumPromptRate = premiumTokenValues[model].prompt;
+ const premiumCompletionRate = premiumTokenValues[model].completion;
+ const expectedCost =
+ promptTokens * premiumPromptRate + completionTokens * premiumCompletionRate;
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(updatedBalance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ test('spendTokens should apply standard pricing at exactly the premium threshold', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'claude-opus-4-6';
+ const promptTokens = premiumTokenValues[model].threshold;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-premium-exact',
+ model,
+ context: 'test',
+ endpointTokenConfig: null,
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const standardPromptRate = tokenValues[model].prompt;
+ const standardCompletionRate = tokenValues[model].completion;
+ const expectedCost =
+ promptTokens * standardPromptRate + completionTokens * standardCompletionRate;
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(updatedBalance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ test('spendStructuredTokens should apply premium pricing when total input tokens exceed threshold', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'claude-opus-4-6';
+ const txData = {
+ user: userId,
+ conversationId: 'test-structured-premium',
+ model,
+ context: 'message',
+ endpointTokenConfig: null,
+ balance: { enabled: true },
+ };
+
+ const tokenUsage = {
+ promptTokens: {
+ input: 200000,
+ write: 10000,
+ read: 5000,
+ },
+ completionTokens: 1000,
+ };
+
+ const totalInput =
+ tokenUsage.promptTokens.input + tokenUsage.promptTokens.write + tokenUsage.promptTokens.read;
+
+ await spendStructuredTokens(txData, tokenUsage);
+
+ const premiumPromptRate = premiumTokenValues[model].prompt;
+ const premiumCompletionRate = premiumTokenValues[model].completion;
+ const writeMultiplier = getCacheMultiplier({ model, cacheType: 'write' });
+ const readMultiplier = getCacheMultiplier({ model, cacheType: 'read' });
+
+ const expectedPromptCost =
+ tokenUsage.promptTokens.input * premiumPromptRate +
+ tokenUsage.promptTokens.write * writeMultiplier +
+ tokenUsage.promptTokens.read * readMultiplier;
+ const expectedCompletionCost = tokenUsage.completionTokens * premiumCompletionRate;
+ const expectedTotalCost = expectedPromptCost + expectedCompletionCost;
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(totalInput).toBeGreaterThan(premiumTokenValues[model].threshold);
+ expect(updatedBalance.tokenCredits).toBeCloseTo(initialBalance - expectedTotalCost, 0);
+ });
+
+ test('spendStructuredTokens should apply standard pricing when total input tokens are below threshold', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'claude-opus-4-6';
+ const txData = {
+ user: userId,
+ conversationId: 'test-structured-standard',
+ model,
+ context: 'message',
+ endpointTokenConfig: null,
+ balance: { enabled: true },
+ };
+
+ const tokenUsage = {
+ promptTokens: {
+ input: 50000,
+ write: 10000,
+ read: 5000,
+ },
+ completionTokens: 1000,
+ };
+
+ const totalInput =
+ tokenUsage.promptTokens.input + tokenUsage.promptTokens.write + tokenUsage.promptTokens.read;
+
+ await spendStructuredTokens(txData, tokenUsage);
+
+ const standardPromptRate = tokenValues[model].prompt;
+ const standardCompletionRate = tokenValues[model].completion;
+ const writeMultiplier = getCacheMultiplier({ model, cacheType: 'write' });
+ const readMultiplier = getCacheMultiplier({ model, cacheType: 'read' });
+
+ const expectedPromptCost =
+ tokenUsage.promptTokens.input * standardPromptRate +
+ tokenUsage.promptTokens.write * writeMultiplier +
+ tokenUsage.promptTokens.read * readMultiplier;
+ const expectedCompletionCost = tokenUsage.completionTokens * standardCompletionRate;
+ const expectedTotalCost = expectedPromptCost + expectedCompletionCost;
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(totalInput).toBeLessThanOrEqual(premiumTokenValues[model].threshold);
+ expect(updatedBalance.tokenCredits).toBeCloseTo(initialBalance - expectedTotalCost, 0);
+ });
+
+ test('spendTokens should apply standard pricing for gemini-3.1-pro-preview below threshold', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'gemini-3.1-pro-preview';
+ const promptTokens = 100000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-gemini31-below',
+ model,
+ context: 'test',
+ endpointTokenConfig: null,
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const standardPromptRate = tokenValues['gemini-3.1'].prompt;
+ const standardCompletionRate = tokenValues['gemini-3.1'].completion;
+ const expectedCost =
+ promptTokens * standardPromptRate + completionTokens * standardCompletionRate;
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(updatedBalance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ test('spendTokens should apply premium pricing for gemini-3.1-pro-preview above threshold', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'gemini-3.1-pro-preview';
+ const promptTokens = 250000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-gemini31-above',
+ model,
+ context: 'test',
+ endpointTokenConfig: null,
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const premiumPromptRate = premiumTokenValues['gemini-3.1'].prompt;
+ const premiumCompletionRate = premiumTokenValues['gemini-3.1'].completion;
+ const expectedCost =
+ promptTokens * premiumPromptRate + completionTokens * premiumCompletionRate;
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(updatedBalance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ test('spendTokens should apply standard pricing for gemini-3.1-pro-preview at exactly the threshold', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'gemini-3.1-pro-preview';
+ const promptTokens = premiumTokenValues['gemini-3.1'].threshold;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-gemini31-exact',
+ model,
+ context: 'test',
+ endpointTokenConfig: null,
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const standardPromptRate = tokenValues['gemini-3.1'].prompt;
+ const standardCompletionRate = tokenValues['gemini-3.1'].completion;
+ const expectedCost =
+ promptTokens * standardPromptRate + completionTokens * standardCompletionRate;
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(updatedBalance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ test('spendStructuredTokens should apply premium pricing for gemini-3.1 when total input exceeds threshold', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'gemini-3.1-pro-preview';
+ const txData = {
+ user: userId,
+ conversationId: 'test-gemini31-structured-premium',
+ model,
+ context: 'message',
+ endpointTokenConfig: null,
+ balance: { enabled: true },
+ };
+
+ const tokenUsage = {
+ promptTokens: {
+ input: 200000,
+ write: 10000,
+ read: 5000,
+ },
+ completionTokens: 1000,
+ };
+
+ const totalInput =
+ tokenUsage.promptTokens.input + tokenUsage.promptTokens.write + tokenUsage.promptTokens.read;
+
+ await spendStructuredTokens(txData, tokenUsage);
+
+ const premiumPromptRate = premiumTokenValues['gemini-3.1'].prompt;
+ const premiumCompletionRate = premiumTokenValues['gemini-3.1'].completion;
+ const writeMultiplier = getCacheMultiplier({ model, cacheType: 'write' });
+ const readMultiplier = getCacheMultiplier({ model, cacheType: 'read' });
+
+ const expectedPromptCost =
+ tokenUsage.promptTokens.input * premiumPromptRate +
+ tokenUsage.promptTokens.write * writeMultiplier +
+ tokenUsage.promptTokens.read * readMultiplier;
+ const expectedCompletionCost = tokenUsage.completionTokens * premiumCompletionRate;
+ const expectedTotalCost = expectedPromptCost + expectedCompletionCost;
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(totalInput).toBeGreaterThan(premiumTokenValues['gemini-3.1'].threshold);
+ expect(updatedBalance.tokenCredits).toBeCloseTo(initialBalance - expectedTotalCost, 0);
+ });
+
+ test('non-premium models should not be affected by inputTokenCount regardless of prompt size', async () => {
+ const userId = new mongoose.Types.ObjectId();
+ const initialBalance = 100000000;
+ await Balance.create({ user: userId, tokenCredits: initialBalance });
+
+ const model = 'claude-opus-4-5';
+ const promptTokens = 300000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-no-premium',
+ model,
+ context: 'test',
+ endpointTokenConfig: null,
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const standardPromptRate = getMultiplier({ model, tokenType: 'prompt' });
+ const standardCompletionRate = getMultiplier({ model, tokenType: 'completion' });
+ const expectedCost =
+ promptTokens * standardPromptRate + completionTokens * standardCompletionRate;
+
+ const updatedBalance = await Balance.findOne({ user: userId });
+ expect(updatedBalance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+});
diff --git a/api/models/index.js b/api/models/index.js
index 7f2c651941..d0b10be079 100644
--- a/api/models/index.js
+++ b/api/models/index.js
@@ -2,15 +2,6 @@ const mongoose = require('mongoose');
const { createMethods } = require('@librechat/data-schemas');
const methods = createMethods(mongoose);
const { comparePassword } = require('./userMethods');
-const {
- findFileById,
- createFile,
- updateFile,
- deleteFile,
- deleteFiles,
- getFiles,
- updateFileUsage,
-} = require('./File');
const {
getMessage,
getMessages,
@@ -34,13 +25,6 @@ module.exports = {
...methods,
seedDatabase,
comparePassword,
- findFileById,
- createFile,
- updateFile,
- deleteFile,
- deleteFiles,
- getFiles,
- updateFileUsage,
getMessage,
getMessages,
diff --git a/api/models/inviteUser.js b/api/models/inviteUser.js
index eeb42841bf..eda8394225 100644
--- a/api/models/inviteUser.js
+++ b/api/models/inviteUser.js
@@ -1,6 +1,5 @@
const mongoose = require('mongoose');
-const { getRandomValues } = require('@librechat/api');
-const { logger, hashToken } = require('@librechat/data-schemas');
+const { logger, hashToken, getRandomValues } = require('@librechat/data-schemas');
const { createToken, findToken } = require('~/models');
/**
diff --git a/api/models/loadAddedAgent.js b/api/models/loadAddedAgent.js
new file mode 100644
index 0000000000..aa83375eae
--- /dev/null
+++ b/api/models/loadAddedAgent.js
@@ -0,0 +1,218 @@
+const { logger } = require('@librechat/data-schemas');
+const { getCustomEndpointConfig } = require('@librechat/api');
+const {
+ Tools,
+ Constants,
+ isAgentsEndpoint,
+ isEphemeralAgentId,
+ appendAgentIdSuffix,
+ encodeEphemeralAgentId,
+} = require('librechat-data-provider');
+const { getMCPServerTools } = require('~/server/services/Config');
+
+const { mcp_all, mcp_delimiter } = Constants;
+
+/**
+ * Constant for added conversation agent ID
+ */
+const ADDED_AGENT_ID = 'added_agent';
+
+/**
+ * Get an agent document based on the provided ID.
+ * @param {Object} searchParameter - The search parameters to find the agent.
+ * @param {string} searchParameter.id - The ID of the agent.
+ * @returns {Promise}
+ */
+let getAgent;
+
+/**
+ * Set the getAgent function (dependency injection to avoid circular imports)
+ * @param {Function} fn
+ */
+const setGetAgent = (fn) => {
+ getAgent = fn;
+};
+
+/**
+ * Load an agent from an added conversation (TConversation).
+ * Used for multi-convo parallel agent execution.
+ *
+ * @param {Object} params
+ * @param {import('express').Request} params.req
+ * @param {import('librechat-data-provider').TConversation} params.conversation - The added conversation
+ * @param {import('librechat-data-provider').Agent} [params.primaryAgent] - The primary agent (used to duplicate tools when both are ephemeral)
+ * @returns {Promise} The agent config as a plain object, or null if invalid.
+ */
+const loadAddedAgent = async ({ req, conversation, primaryAgent }) => {
+ if (!conversation) {
+ return null;
+ }
+
+ // If there's an agent_id, load the existing agent
+ if (conversation.agent_id && !isEphemeralAgentId(conversation.agent_id)) {
+ if (!getAgent) {
+ throw new Error('getAgent not initialized - call setGetAgent first');
+ }
+ const agent = await getAgent({
+ id: conversation.agent_id,
+ });
+
+ if (!agent) {
+ logger.warn(`[loadAddedAgent] Agent ${conversation.agent_id} not found`);
+ return null;
+ }
+
+ agent.version = agent.versions ? agent.versions.length : 0;
+ // Append suffix to distinguish from primary agent (matches ephemeral format)
+ // This is needed when both agents have the same ID or for consistent parallel content attribution
+ agent.id = appendAgentIdSuffix(agent.id, 1);
+ return agent;
+ }
+
+ // Otherwise, create an ephemeral agent config from the conversation
+ const { model, endpoint, promptPrefix, spec, ...rest } = conversation;
+
+ if (!endpoint || !model) {
+ logger.warn('[loadAddedAgent] Missing required endpoint or model for ephemeral agent');
+ return null;
+ }
+
+ // If both primary and added agents are ephemeral, duplicate tools from primary agent
+ const primaryIsEphemeral = primaryAgent && isEphemeralAgentId(primaryAgent.id);
+ if (primaryIsEphemeral && Array.isArray(primaryAgent.tools)) {
+ // Get endpoint config and model spec for display name fallbacks
+ const appConfig = req.config;
+ let endpointConfig = appConfig?.endpoints?.[endpoint];
+ if (!isAgentsEndpoint(endpoint) && !endpointConfig) {
+ try {
+ endpointConfig = getCustomEndpointConfig({ endpoint, appConfig });
+ } catch (err) {
+ logger.error('[loadAddedAgent] Error getting custom endpoint config', err);
+ }
+ }
+
+ // Look up model spec for label fallback
+ const modelSpecs = appConfig?.modelSpecs?.list;
+ const modelSpec = spec != null && spec !== '' ? modelSpecs?.find((s) => s.name === spec) : null;
+
+ // For ephemeral agents, use modelLabel if provided, then model spec's label,
+ // then modelDisplayLabel from endpoint config, otherwise empty string to show model name
+ const sender = rest.modelLabel ?? modelSpec?.label ?? endpointConfig?.modelDisplayLabel ?? '';
+
+ const ephemeralId = encodeEphemeralAgentId({ endpoint, model, sender, index: 1 });
+
+ return {
+ id: ephemeralId,
+ instructions: promptPrefix || '',
+ provider: endpoint,
+ model_parameters: {},
+ model,
+ tools: [...primaryAgent.tools],
+ };
+ }
+
+ // Extract ephemeral agent options from conversation if present
+ const ephemeralAgent = rest.ephemeralAgent;
+ const mcpServers = new Set(ephemeralAgent?.mcp);
+ const userId = req.user?.id;
+
+ // Check model spec for MCP servers
+ const modelSpecs = req.config?.modelSpecs?.list;
+ let modelSpec = null;
+ if (spec != null && spec !== '') {
+ modelSpec = modelSpecs?.find((s) => s.name === spec) || null;
+ }
+ if (modelSpec?.mcpServers) {
+ for (const mcpServer of modelSpec.mcpServers) {
+ mcpServers.add(mcpServer);
+ }
+ }
+
+ /** @type {string[]} */
+ const tools = [];
+ if (ephemeralAgent?.execute_code === true || modelSpec?.executeCode === true) {
+ tools.push(Tools.execute_code);
+ }
+ if (ephemeralAgent?.file_search === true || modelSpec?.fileSearch === true) {
+ tools.push(Tools.file_search);
+ }
+ if (ephemeralAgent?.web_search === true || modelSpec?.webSearch === true) {
+ tools.push(Tools.web_search);
+ }
+
+ const addedServers = new Set();
+ if (mcpServers.size > 0) {
+ for (const mcpServer of mcpServers) {
+ if (addedServers.has(mcpServer)) {
+ continue;
+ }
+ const serverTools = await getMCPServerTools(userId, mcpServer);
+ if (!serverTools) {
+ tools.push(`${mcp_all}${mcp_delimiter}${mcpServer}`);
+ addedServers.add(mcpServer);
+ continue;
+ }
+ tools.push(...Object.keys(serverTools));
+ addedServers.add(mcpServer);
+ }
+ }
+
+ // Build model_parameters from conversation fields
+ const model_parameters = {};
+ const paramKeys = [
+ 'temperature',
+ 'top_p',
+ 'topP',
+ 'topK',
+ 'presence_penalty',
+ 'frequency_penalty',
+ 'maxOutputTokens',
+ 'maxTokens',
+ 'max_tokens',
+ ];
+
+ for (const key of paramKeys) {
+ if (rest[key] != null) {
+ model_parameters[key] = rest[key];
+ }
+ }
+
+ // Get endpoint config for modelDisplayLabel fallback
+ const appConfig = req.config;
+ let endpointConfig = appConfig?.endpoints?.[endpoint];
+ if (!isAgentsEndpoint(endpoint) && !endpointConfig) {
+ try {
+ endpointConfig = getCustomEndpointConfig({ endpoint, appConfig });
+ } catch (err) {
+ logger.error('[loadAddedAgent] Error getting custom endpoint config', err);
+ }
+ }
+
+ // For ephemeral agents, use modelLabel if provided, then model spec's label,
+ // then modelDisplayLabel from endpoint config, otherwise empty string to show model name
+ const sender = rest.modelLabel ?? modelSpec?.label ?? endpointConfig?.modelDisplayLabel ?? '';
+
+ /** Encoded ephemeral agent ID with endpoint, model, sender, and index=1 to distinguish from primary */
+ const ephemeralId = encodeEphemeralAgentId({ endpoint, model, sender, index: 1 });
+
+ const result = {
+ id: ephemeralId,
+ instructions: promptPrefix || '',
+ provider: endpoint,
+ model_parameters,
+ model,
+ tools,
+ };
+
+ if (ephemeralAgent?.artifacts != null && ephemeralAgent.artifacts) {
+ result.artifacts = ephemeralAgent.artifacts;
+ }
+
+ return result;
+};
+
+module.exports = {
+ ADDED_AGENT_ID,
+ loadAddedAgent,
+ setGetAgent,
+};
diff --git a/api/models/spendTokens.js b/api/models/spendTokens.js
index cfd983f6bb..afe05969d8 100644
--- a/api/models/spendTokens.js
+++ b/api/models/spendTokens.js
@@ -24,12 +24,14 @@ const spendTokens = async (txData, tokenUsage) => {
},
);
let prompt, completion;
+ const normalizedPromptTokens = Math.max(promptTokens ?? 0, 0);
try {
if (promptTokens !== undefined) {
prompt = await createTransaction({
...txData,
tokenType: 'prompt',
- rawAmount: promptTokens === 0 ? 0 : -Math.max(promptTokens, 0),
+ rawAmount: promptTokens === 0 ? 0 : -normalizedPromptTokens,
+ inputTokenCount: normalizedPromptTokens,
});
}
@@ -38,6 +40,7 @@ const spendTokens = async (txData, tokenUsage) => {
...txData,
tokenType: 'completion',
rawAmount: completionTokens === 0 ? 0 : -Math.max(completionTokens, 0),
+ inputTokenCount: normalizedPromptTokens,
});
}
@@ -87,21 +90,31 @@ const spendStructuredTokens = async (txData, tokenUsage) => {
let prompt, completion;
try {
if (promptTokens) {
- const { input = 0, write = 0, read = 0 } = promptTokens;
+ const input = Math.max(promptTokens.input ?? 0, 0);
+ const write = Math.max(promptTokens.write ?? 0, 0);
+ const read = Math.max(promptTokens.read ?? 0, 0);
+ const totalInputTokens = input + write + read;
prompt = await createStructuredTransaction({
...txData,
tokenType: 'prompt',
inputTokens: -input,
writeTokens: -write,
readTokens: -read,
+ inputTokenCount: totalInputTokens,
});
}
if (completionTokens) {
+ const totalInputTokens = promptTokens
+ ? Math.max(promptTokens.input ?? 0, 0) +
+ Math.max(promptTokens.write ?? 0, 0) +
+ Math.max(promptTokens.read ?? 0, 0)
+ : undefined;
completion = await createTransaction({
...txData,
tokenType: 'completion',
- rawAmount: -completionTokens,
+ rawAmount: -Math.max(completionTokens, 0),
+ inputTokenCount: totalInputTokens,
});
}
diff --git a/api/models/spendTokens.spec.js b/api/models/spendTokens.spec.js
index eee6572736..dfeec5ee83 100644
--- a/api/models/spendTokens.spec.js
+++ b/api/models/spendTokens.spec.js
@@ -1,7 +1,8 @@
const mongoose = require('mongoose');
const { MongoMemoryServer } = require('mongodb-memory-server');
-const { spendTokens, spendStructuredTokens } = require('./spendTokens');
const { createTransaction, createAutoRefillTransaction } = require('./Transaction');
+const { tokenValues, premiumTokenValues, getCacheMultiplier } = require('./tx');
+const { spendTokens, spendStructuredTokens } = require('./spendTokens');
require('~/db/models');
@@ -734,4 +735,457 @@ describe('spendTokens', () => {
expect(balance).toBeDefined();
expect(balance.tokenCredits).toBeLessThan(10000); // Balance should be reduced
});
+
+ describe('premium token pricing', () => {
+ it('should charge standard rates for claude-opus-4-6 when prompt tokens are below threshold', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'claude-opus-4-6';
+ const promptTokens = 100000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-standard-pricing',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const expectedCost =
+ promptTokens * tokenValues[model].prompt + completionTokens * tokenValues[model].completion;
+
+ const balance = await Balance.findOne({ user: userId });
+ expect(balance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ it('should charge premium rates for claude-opus-4-6 when prompt tokens exceed threshold', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'claude-opus-4-6';
+ const promptTokens = 250000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-premium-pricing',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const expectedCost =
+ promptTokens * premiumTokenValues[model].prompt +
+ completionTokens * premiumTokenValues[model].completion;
+
+ const balance = await Balance.findOne({ user: userId });
+ expect(balance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ it('should charge premium rates for both prompt and completion in structured tokens when above threshold', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'claude-opus-4-6';
+ const txData = {
+ user: userId,
+ conversationId: 'test-structured-premium',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ const tokenUsage = {
+ promptTokens: {
+ input: 200000,
+ write: 10000,
+ read: 5000,
+ },
+ completionTokens: 1000,
+ };
+
+ const result = await spendStructuredTokens(txData, tokenUsage);
+
+ const premiumPromptRate = premiumTokenValues[model].prompt;
+ const premiumCompletionRate = premiumTokenValues[model].completion;
+ const writeRate = getCacheMultiplier({ model, cacheType: 'write' });
+ const readRate = getCacheMultiplier({ model, cacheType: 'read' });
+
+ const expectedPromptCost =
+ tokenUsage.promptTokens.input * premiumPromptRate +
+ tokenUsage.promptTokens.write * writeRate +
+ tokenUsage.promptTokens.read * readRate;
+ const expectedCompletionCost = tokenUsage.completionTokens * premiumCompletionRate;
+
+ expect(result.prompt.prompt).toBeCloseTo(-expectedPromptCost, 0);
+ expect(result.completion.completion).toBeCloseTo(-expectedCompletionCost, 0);
+ });
+
+ it('should charge standard rates for structured tokens when below threshold', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'claude-opus-4-6';
+ const txData = {
+ user: userId,
+ conversationId: 'test-structured-standard',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ const tokenUsage = {
+ promptTokens: {
+ input: 50000,
+ write: 10000,
+ read: 5000,
+ },
+ completionTokens: 1000,
+ };
+
+ const result = await spendStructuredTokens(txData, tokenUsage);
+
+ const standardPromptRate = tokenValues[model].prompt;
+ const standardCompletionRate = tokenValues[model].completion;
+ const writeRate = getCacheMultiplier({ model, cacheType: 'write' });
+ const readRate = getCacheMultiplier({ model, cacheType: 'read' });
+
+ const expectedPromptCost =
+ tokenUsage.promptTokens.input * standardPromptRate +
+ tokenUsage.promptTokens.write * writeRate +
+ tokenUsage.promptTokens.read * readRate;
+ const expectedCompletionCost = tokenUsage.completionTokens * standardCompletionRate;
+
+ expect(result.prompt.prompt).toBeCloseTo(-expectedPromptCost, 0);
+ expect(result.completion.completion).toBeCloseTo(-expectedCompletionCost, 0);
+ });
+
+ it('should charge standard rates for gemini-3.1-pro-preview when prompt tokens are below threshold', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'gemini-3.1-pro-preview';
+ const promptTokens = 100000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-gemini31-standard-pricing',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const expectedCost =
+ promptTokens * tokenValues['gemini-3.1'].prompt +
+ completionTokens * tokenValues['gemini-3.1'].completion;
+
+ const balance = await Balance.findOne({ user: userId });
+ expect(balance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ it('should charge premium rates for gemini-3.1-pro-preview when prompt tokens exceed threshold', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'gemini-3.1-pro-preview';
+ const promptTokens = 250000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-gemini31-premium-pricing',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const expectedCost =
+ promptTokens * premiumTokenValues['gemini-3.1'].prompt +
+ completionTokens * premiumTokenValues['gemini-3.1'].completion;
+
+ const balance = await Balance.findOne({ user: userId });
+ expect(balance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ it('should charge premium rates for gemini-3.1-pro-preview-customtools when prompt tokens exceed threshold', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'gemini-3.1-pro-preview-customtools';
+ const promptTokens = 250000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-gemini31-customtools-premium',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const expectedCost =
+ promptTokens * premiumTokenValues['gemini-3.1'].prompt +
+ completionTokens * premiumTokenValues['gemini-3.1'].completion;
+
+ const balance = await Balance.findOne({ user: userId });
+ expect(balance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+
+ it('should charge premium rates for structured gemini-3.1 tokens when total input exceeds threshold', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'gemini-3.1-pro-preview';
+ const txData = {
+ user: userId,
+ conversationId: 'test-gemini31-structured-premium',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ const tokenUsage = {
+ promptTokens: {
+ input: 200000,
+ write: 10000,
+ read: 5000,
+ },
+ completionTokens: 1000,
+ };
+
+ const result = await spendStructuredTokens(txData, tokenUsage);
+
+ const premiumPromptRate = premiumTokenValues['gemini-3.1'].prompt;
+ const premiumCompletionRate = premiumTokenValues['gemini-3.1'].completion;
+ const writeRate = getCacheMultiplier({ model, cacheType: 'write' });
+ const readRate = getCacheMultiplier({ model, cacheType: 'read' });
+
+ const expectedPromptCost =
+ tokenUsage.promptTokens.input * premiumPromptRate +
+ tokenUsage.promptTokens.write * writeRate +
+ tokenUsage.promptTokens.read * readRate;
+ const expectedCompletionCost = tokenUsage.completionTokens * premiumCompletionRate;
+
+ expect(result.prompt.prompt).toBeCloseTo(-expectedPromptCost, 0);
+ expect(result.completion.completion).toBeCloseTo(-expectedCompletionCost, 0);
+ });
+
+ it('should not apply premium pricing to non-premium models regardless of prompt size', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'claude-opus-4-5';
+ const promptTokens = 300000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-no-premium',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const expectedCost =
+ promptTokens * tokenValues[model].prompt + completionTokens * tokenValues[model].completion;
+
+ const balance = await Balance.findOne({ user: userId });
+ expect(balance.tokenCredits).toBeCloseTo(initialBalance - expectedCost, 0);
+ });
+ });
+
+ describe('inputTokenCount Normalization', () => {
+ it('should normalize negative promptTokens to zero for inputTokenCount', async () => {
+ await Balance.create({
+ user: userId,
+ tokenCredits: 100000000,
+ });
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-negative-prompt',
+ model: 'claude-opus-4-6',
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens: -500, completionTokens: 100 });
+
+ const transactions = await Transaction.find({ user: userId }).sort({ tokenType: 1 });
+
+ const completionTx = transactions.find((t) => t.tokenType === 'completion');
+ const promptTx = transactions.find((t) => t.tokenType === 'prompt');
+
+ expect(Math.abs(promptTx.rawAmount)).toBe(0);
+ expect(completionTx.rawAmount).toBe(-100);
+
+ const standardCompletionRate = tokenValues['claude-opus-4-6'].completion;
+ expect(completionTx.rate).toBe(standardCompletionRate);
+ });
+
+ it('should use normalized inputTokenCount for premium threshold check on completion', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'claude-opus-4-6';
+ const promptTokens = 250000;
+ const completionTokens = 500;
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-normalized-premium',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens, completionTokens });
+
+ const transactions = await Transaction.find({ user: userId }).sort({ tokenType: 1 });
+ const completionTx = transactions.find((t) => t.tokenType === 'completion');
+ const promptTx = transactions.find((t) => t.tokenType === 'prompt');
+
+ const premiumPromptRate = premiumTokenValues[model].prompt;
+ const premiumCompletionRate = premiumTokenValues[model].completion;
+ expect(promptTx.rate).toBe(premiumPromptRate);
+ expect(completionTx.rate).toBe(premiumCompletionRate);
+ });
+
+ it('should keep inputTokenCount as zero when promptTokens is zero', async () => {
+ await Balance.create({
+ user: userId,
+ tokenCredits: 100000000,
+ });
+
+ const txData = {
+ user: userId,
+ conversationId: 'test-zero-prompt',
+ model: 'claude-opus-4-6',
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens: 0, completionTokens: 100 });
+
+ const transactions = await Transaction.find({ user: userId }).sort({ tokenType: 1 });
+ const completionTx = transactions.find((t) => t.tokenType === 'completion');
+ const promptTx = transactions.find((t) => t.tokenType === 'prompt');
+
+ expect(Math.abs(promptTx.rawAmount)).toBe(0);
+
+ const standardCompletionRate = tokenValues['claude-opus-4-6'].completion;
+ expect(completionTx.rate).toBe(standardCompletionRate);
+ });
+
+ it('should not trigger premium pricing with negative promptTokens on premium model', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'claude-opus-4-6';
+ const txData = {
+ user: userId,
+ conversationId: 'test-negative-no-premium',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ await spendTokens(txData, { promptTokens: -300000, completionTokens: 500 });
+
+ const transactions = await Transaction.find({ user: userId }).sort({ tokenType: 1 });
+ const completionTx = transactions.find((t) => t.tokenType === 'completion');
+
+ const standardCompletionRate = tokenValues[model].completion;
+ expect(completionTx.rate).toBe(standardCompletionRate);
+ });
+
+ it('should normalize negative structured token values to zero in spendStructuredTokens', async () => {
+ const initialBalance = 100000000;
+ await Balance.create({
+ user: userId,
+ tokenCredits: initialBalance,
+ });
+
+ const model = 'claude-opus-4-6';
+ const txData = {
+ user: userId,
+ conversationId: 'test-negative-structured',
+ model,
+ context: 'test',
+ balance: { enabled: true },
+ };
+
+ const tokenUsage = {
+ promptTokens: { input: -100, write: 50, read: -30 },
+ completionTokens: -200,
+ };
+
+ await spendStructuredTokens(txData, tokenUsage);
+
+ const transactions = await Transaction.find({
+ user: userId,
+ conversationId: 'test-negative-structured',
+ }).sort({ tokenType: 1 });
+
+ const completionTx = transactions.find((t) => t.tokenType === 'completion');
+ const promptTx = transactions.find((t) => t.tokenType === 'prompt');
+
+ expect(Math.abs(promptTx.inputTokens)).toBe(0);
+ expect(promptTx.writeTokens).toBe(-50);
+ expect(Math.abs(promptTx.readTokens)).toBe(0);
+
+ expect(Math.abs(completionTx.rawAmount)).toBe(0);
+
+ const standardRate = tokenValues[model].completion;
+ expect(completionTx.rate).toBe(standardRate);
+ });
+ });
});
diff --git a/api/models/tx.js b/api/models/tx.js
index aa213d3475..a13143a862 100644
--- a/api/models/tx.js
+++ b/api/models/tx.js
@@ -1,10 +1,40 @@
const { matchModelName, findMatchingPattern } = require('@librechat/api');
const defaultRate = 6;
+/**
+ * Token Pricing Configuration
+ *
+ * IMPORTANT: Key Ordering for Pattern Matching
+ * ============================================
+ * The `findMatchingPattern` function iterates through object keys in REVERSE order
+ * (last-defined keys are checked first) and uses `modelName.includes(key)` for matching.
+ *
+ * This means:
+ * 1. BASE PATTERNS must be defined FIRST (e.g., "kimi", "moonshot")
+ * 2. SPECIFIC PATTERNS must be defined AFTER their base patterns (e.g., "kimi-k2", "kimi-k2.5")
+ *
+ * Example ordering for Kimi models:
+ * kimi: { prompt: 0.6, completion: 2.5 }, // Base pattern - checked last
+ * 'kimi-k2': { prompt: 0.6, completion: 2.5 }, // More specific - checked before "kimi"
+ * 'kimi-k2.5': { prompt: 0.6, completion: 3.0 }, // Most specific - checked first
+ *
+ * Why this matters:
+ * - Model name "kimi-k2.5" contains both "kimi" and "kimi-k2" as substrings
+ * - If "kimi" were checked first, it would incorrectly match and return wrong pricing
+ * - By defining specific patterns AFTER base patterns, they're checked first in reverse iteration
+ *
+ * This applies to BOTH `tokenValues` and `cacheTokenValues` objects.
+ *
+ * When adding new model families:
+ * 1. Define the base/generic pattern first
+ * 2. Define increasingly specific patterns after
+ * 3. Ensure no pattern is a substring of another that should match differently
+ */
+
/**
* AWS Bedrock pricing
* source: https://aws.amazon.com/bedrock/pricing/
- * */
+ */
const bedrockValues = {
// Basic llama2 patterns (base defaults to smallest variant)
llama2: { prompt: 0.75, completion: 1.0 },
@@ -80,6 +110,11 @@ const bedrockValues = {
'nova-pro': { prompt: 0.8, completion: 3.2 },
'nova-premier': { prompt: 2.5, completion: 12.5 },
'deepseek.r1': { prompt: 1.35, completion: 5.4 },
+ // Moonshot/Kimi models on Bedrock
+ 'moonshot.kimi': { prompt: 0.6, completion: 2.5 },
+ 'moonshot.kimi-k2': { prompt: 0.6, completion: 2.5 },
+ 'moonshot.kimi-k2.5': { prompt: 0.6, completion: 3.0 },
+ 'moonshot.kimi-k2-thinking': { prompt: 0.6, completion: 2.5 },
};
/**
@@ -113,6 +148,8 @@ const tokenValues = Object.assign(
'gpt-4o-2024-05-13': { prompt: 5, completion: 15 },
'gpt-4o-mini': { prompt: 0.15, completion: 0.6 },
'gpt-5': { prompt: 1.25, completion: 10 },
+ 'gpt-5.1': { prompt: 1.25, completion: 10 },
+ 'gpt-5.2': { prompt: 1.75, completion: 14 },
'gpt-5-nano': { prompt: 0.05, completion: 0.4 },
'gpt-5-mini': { prompt: 0.25, completion: 2 },
'gpt-5-pro': { prompt: 15, completion: 120 },
@@ -137,7 +174,9 @@ const tokenValues = Object.assign(
'claude-haiku-4-5': { prompt: 1, completion: 5 },
'claude-opus-4': { prompt: 15, completion: 75 },
'claude-opus-4-5': { prompt: 5, completion: 25 },
+ 'claude-opus-4-6': { prompt: 5, completion: 25 },
'claude-sonnet-4': { prompt: 3, completion: 15 },
+ 'claude-sonnet-4-6': { prompt: 3, completion: 15 },
'command-r': { prompt: 0.5, completion: 1.5 },
'command-r-plus': { prompt: 3, completion: 15 },
'command-text': { prompt: 1.5, completion: 2.0 },
@@ -158,7 +197,10 @@ const tokenValues = Object.assign(
'gemini-2.5-flash': { prompt: 0.3, completion: 2.5 },
'gemini-2.5-flash-lite': { prompt: 0.1, completion: 0.4 },
'gemini-2.5-pro': { prompt: 1.25, completion: 10 },
+ 'gemini-2.5-flash-image': { prompt: 0.15, completion: 30 },
'gemini-3': { prompt: 2, completion: 12 },
+ 'gemini-3-pro-image': { prompt: 2, completion: 120 },
+ 'gemini-3.1': { prompt: 2, completion: 12 },
'gemini-pro-vision': { prompt: 0.5, completion: 1.5 },
grok: { prompt: 2.0, completion: 10.0 }, // Base pattern defaults to grok-2
'grok-beta': { prompt: 5.0, completion: 15.0 },
@@ -185,7 +227,31 @@ const tokenValues = Object.assign(
'pixtral-large': { prompt: 2.0, completion: 6.0 },
'mistral-large': { prompt: 2.0, completion: 6.0 },
'mixtral-8x22b': { prompt: 0.65, completion: 0.65 },
- kimi: { prompt: 0.14, completion: 2.49 }, // Base pattern (using kimi-k2 pricing)
+ // Moonshot/Kimi models (base patterns first, specific patterns last for correct matching)
+ kimi: { prompt: 0.6, completion: 2.5 }, // Base pattern
+ moonshot: { prompt: 2.0, completion: 5.0 }, // Base pattern (using 128k pricing)
+ 'kimi-latest': { prompt: 0.2, completion: 2.0 }, // Uses 8k/32k/128k pricing dynamically
+ 'kimi-k2': { prompt: 0.6, completion: 2.5 },
+ 'kimi-k2.5': { prompt: 0.6, completion: 3.0 },
+ 'kimi-k2-turbo': { prompt: 1.15, completion: 8.0 },
+ 'kimi-k2-turbo-preview': { prompt: 1.15, completion: 8.0 },
+ 'kimi-k2-0905': { prompt: 0.6, completion: 2.5 },
+ 'kimi-k2-0905-preview': { prompt: 0.6, completion: 2.5 },
+ 'kimi-k2-0711': { prompt: 0.6, completion: 2.5 },
+ 'kimi-k2-0711-preview': { prompt: 0.6, completion: 2.5 },
+ 'kimi-k2-thinking': { prompt: 0.6, completion: 2.5 },
+ 'kimi-k2-thinking-turbo': { prompt: 1.15, completion: 8.0 },
+ 'moonshot-v1': { prompt: 2.0, completion: 5.0 },
+ 'moonshot-v1-auto': { prompt: 2.0, completion: 5.0 },
+ 'moonshot-v1-8k': { prompt: 0.2, completion: 2.0 },
+ 'moonshot-v1-8k-vision': { prompt: 0.2, completion: 2.0 },
+ 'moonshot-v1-8k-vision-preview': { prompt: 0.2, completion: 2.0 },
+ 'moonshot-v1-32k': { prompt: 1.0, completion: 3.0 },
+ 'moonshot-v1-32k-vision': { prompt: 1.0, completion: 3.0 },
+ 'moonshot-v1-32k-vision-preview': { prompt: 1.0, completion: 3.0 },
+ 'moonshot-v1-128k': { prompt: 2.0, completion: 5.0 },
+ 'moonshot-v1-128k-vision': { prompt: 2.0, completion: 5.0 },
+ 'moonshot-v1-128k-vision-preview': { prompt: 2.0, completion: 5.0 },
// GPT-OSS models (specific sizes)
'gpt-oss:20b': { prompt: 0.05, completion: 0.2 },
'gpt-oss-20b': { prompt: 0.05, completion: 0.2 },
@@ -245,12 +311,39 @@ const cacheTokenValues = {
'claude-3-haiku': { write: 0.3, read: 0.03 },
'claude-haiku-4-5': { write: 1.25, read: 0.1 },
'claude-sonnet-4': { write: 3.75, read: 0.3 },
+ 'claude-sonnet-4-6': { write: 3.75, read: 0.3 },
'claude-opus-4': { write: 18.75, read: 1.5 },
'claude-opus-4-5': { write: 6.25, read: 0.5 },
+ 'claude-opus-4-6': { write: 6.25, read: 0.5 },
// DeepSeek models - cache hit: $0.028/1M, cache miss: $0.28/1M
deepseek: { write: 0.28, read: 0.028 },
'deepseek-chat': { write: 0.28, read: 0.028 },
'deepseek-reasoner': { write: 0.28, read: 0.028 },
+ // Moonshot/Kimi models - cache hit: $0.15/1M (k2) or $0.10/1M (k2.5), cache miss: $0.60/1M
+ kimi: { write: 0.6, read: 0.15 },
+ 'kimi-k2': { write: 0.6, read: 0.15 },
+ 'kimi-k2.5': { write: 0.6, read: 0.1 },
+ 'kimi-k2-turbo': { write: 1.15, read: 0.15 },
+ 'kimi-k2-turbo-preview': { write: 1.15, read: 0.15 },
+ 'kimi-k2-0905': { write: 0.6, read: 0.15 },
+ 'kimi-k2-0905-preview': { write: 0.6, read: 0.15 },
+ 'kimi-k2-0711': { write: 0.6, read: 0.15 },
+ 'kimi-k2-0711-preview': { write: 0.6, read: 0.15 },
+ 'kimi-k2-thinking': { write: 0.6, read: 0.15 },
+ 'kimi-k2-thinking-turbo': { write: 1.15, read: 0.15 },
+ // Gemini 3.1 models - cache read: $0.20/1M (<=200k), cache write: standard input price
+ 'gemini-3.1': { write: 2, read: 0.2 },
+};
+
+/**
+ * Premium (tiered) pricing for models whose rates change based on prompt size.
+ * Each entry specifies the token threshold and the rates that apply above it.
+ * @type {Object.}
+ */
+const premiumTokenValues = {
+ 'claude-opus-4-6': { threshold: 200000, prompt: 10, completion: 37.5 },
+ 'claude-sonnet-4-6': { threshold: 200000, prompt: 6, completion: 22.5 },
+ 'gemini-3.1': { threshold: 200000, prompt: 4, completion: 18 },
};
/**
@@ -309,15 +402,27 @@ const getValueKey = (model, endpoint) => {
* @param {string} [params.model] - The model name to derive the value key from if not provided.
* @param {string} [params.endpoint] - The endpoint name to derive the value key from if not provided.
* @param {EndpointTokenConfig} [params.endpointTokenConfig] - The token configuration for the endpoint.
+ * @param {number} [params.inputTokenCount] - Total input token count for tiered pricing.
* @returns {number} The multiplier for the given parameters, or a default value if not found.
*/
-const getMultiplier = ({ valueKey, tokenType, model, endpoint, endpointTokenConfig }) => {
+const getMultiplier = ({
+ model,
+ valueKey,
+ endpoint,
+ tokenType,
+ inputTokenCount,
+ endpointTokenConfig,
+}) => {
if (endpointTokenConfig) {
return endpointTokenConfig?.[model]?.[tokenType] ?? defaultRate;
}
if (valueKey && tokenType) {
- return tokenValues[valueKey][tokenType] ?? defaultRate;
+ const premiumRate = getPremiumRate(valueKey, tokenType, inputTokenCount);
+ if (premiumRate != null) {
+ return premiumRate;
+ }
+ return tokenValues[valueKey]?.[tokenType] ?? defaultRate;
}
if (!tokenType || !model) {
@@ -329,10 +434,33 @@ const getMultiplier = ({ valueKey, tokenType, model, endpoint, endpointTokenConf
return defaultRate;
}
- // If we got this far, and values[tokenType] is undefined somehow, return a rough average of default multipliers
+ const premiumRate = getPremiumRate(valueKey, tokenType, inputTokenCount);
+ if (premiumRate != null) {
+ return premiumRate;
+ }
+
return tokenValues[valueKey]?.[tokenType] ?? defaultRate;
};
+/**
+ * Checks if premium (tiered) pricing applies and returns the premium rate.
+ * Each model defines its own threshold in `premiumTokenValues`.
+ * @param {string} valueKey
+ * @param {string} tokenType
+ * @param {number} [inputTokenCount]
+ * @returns {number|null}
+ */
+const getPremiumRate = (valueKey, tokenType, inputTokenCount) => {
+ if (inputTokenCount == null) {
+ return null;
+ }
+ const premiumEntry = premiumTokenValues[valueKey];
+ if (!premiumEntry || inputTokenCount <= premiumEntry.threshold) {
+ return null;
+ }
+ return premiumEntry[tokenType] ?? null;
+};
+
/**
* Retrieves the cache multiplier for a given value key and token type. If no value key is provided,
* it attempts to derive it from the model name.
@@ -369,8 +497,10 @@ const getCacheMultiplier = ({ valueKey, cacheType, model, endpoint, endpointToke
module.exports = {
tokenValues,
+ premiumTokenValues,
getValueKey,
getMultiplier,
+ getPremiumRate,
getCacheMultiplier,
defaultRate,
cacheTokenValues,
diff --git a/api/models/tx.spec.js b/api/models/tx.spec.js
index 18030abb21..b58afa9c70 100644
--- a/api/models/tx.spec.js
+++ b/api/models/tx.spec.js
@@ -1,3 +1,4 @@
+/** Note: No hard-coded values should be used in this file. */
const { maxTokensMap } = require('@librechat/api');
const { EModelEndpoint } = require('librechat-data-provider');
const {
@@ -5,8 +6,10 @@ const {
tokenValues,
getValueKey,
getMultiplier,
+ getPremiumRate,
cacheTokenValues,
getCacheMultiplier,
+ premiumTokenValues,
} = require('./tx');
describe('getValueKey', () => {
@@ -36,6 +39,19 @@ describe('getValueKey', () => {
expect(getValueKey('gpt-5-0130')).toBe('gpt-5');
});
+ it('should return "gpt-5.1" for model name containing "gpt-5.1"', () => {
+ expect(getValueKey('gpt-5.1')).toBe('gpt-5.1');
+ expect(getValueKey('gpt-5.1-chat')).toBe('gpt-5.1');
+ expect(getValueKey('gpt-5.1-codex')).toBe('gpt-5.1');
+ expect(getValueKey('openai/gpt-5.1')).toBe('gpt-5.1');
+ });
+
+ it('should return "gpt-5.2" for model name containing "gpt-5.2"', () => {
+ expect(getValueKey('gpt-5.2')).toBe('gpt-5.2');
+ expect(getValueKey('gpt-5.2-chat')).toBe('gpt-5.2');
+ expect(getValueKey('openai/gpt-5.2')).toBe('gpt-5.2');
+ });
+
it('should return "gpt-3.5-turbo-1106" for model name containing "gpt-3.5-turbo-1106"', () => {
expect(getValueKey('gpt-3.5-turbo-1106-some-other-info')).toBe('gpt-3.5-turbo-1106');
expect(getValueKey('openai/gpt-3.5-turbo-1106')).toBe('gpt-3.5-turbo-1106');
@@ -226,6 +242,15 @@ describe('getMultiplier', () => {
expect(getMultiplier({ valueKey: '8k', tokenType: 'unknownType' })).toBe(defaultRate);
});
+ it('should return defaultRate if valueKey does not exist in tokenValues', () => {
+ expect(getMultiplier({ valueKey: 'non-existent-model', tokenType: 'prompt' })).toBe(
+ defaultRate,
+ );
+ expect(getMultiplier({ valueKey: 'non-existent-model', tokenType: 'completion' })).toBe(
+ defaultRate,
+ );
+ });
+
it('should derive the valueKey from the model if not provided', () => {
expect(getMultiplier({ tokenType: 'prompt', model: 'gpt-4-some-other-info' })).toBe(
tokenValues['8k'].prompt,
@@ -311,6 +336,30 @@ describe('getMultiplier', () => {
);
});
+ it('should return the correct multiplier for gpt-5.1', () => {
+ expect(getMultiplier({ model: 'gpt-5.1', tokenType: 'prompt' })).toBe(
+ tokenValues['gpt-5.1'].prompt,
+ );
+ expect(getMultiplier({ model: 'gpt-5.1', tokenType: 'completion' })).toBe(
+ tokenValues['gpt-5.1'].completion,
+ );
+ expect(getMultiplier({ model: 'openai/gpt-5.1', tokenType: 'prompt' })).toBe(
+ tokenValues['gpt-5.1'].prompt,
+ );
+ });
+
+ it('should return the correct multiplier for gpt-5.2', () => {
+ expect(getMultiplier({ model: 'gpt-5.2', tokenType: 'prompt' })).toBe(
+ tokenValues['gpt-5.2'].prompt,
+ );
+ expect(getMultiplier({ model: 'gpt-5.2', tokenType: 'completion' })).toBe(
+ tokenValues['gpt-5.2'].completion,
+ );
+ expect(getMultiplier({ model: 'openai/gpt-5.2', tokenType: 'prompt' })).toBe(
+ tokenValues['gpt-5.2'].prompt,
+ );
+ });
+
it('should return the correct multiplier for gpt-4o', () => {
const valueKey = getValueKey('gpt-4o-2024-08-06');
expect(getMultiplier({ valueKey, tokenType: 'prompt' })).toBe(tokenValues['gpt-4o'].prompt);
@@ -774,8 +823,6 @@ describe('Deepseek Model Tests', () => {
expect(getMultiplier({ model: 'deepseek-chat', tokenType: 'completion' })).toBe(
tokenValues['deepseek-chat'].completion,
);
- expect(tokenValues['deepseek-chat'].prompt).toBe(0.28);
- expect(tokenValues['deepseek-chat'].completion).toBe(0.42);
});
it('should return correct pricing for deepseek-reasoner', () => {
@@ -785,8 +832,6 @@ describe('Deepseek Model Tests', () => {
expect(getMultiplier({ model: 'deepseek-reasoner', tokenType: 'completion' })).toBe(
tokenValues['deepseek-reasoner'].completion,
);
- expect(tokenValues['deepseek-reasoner'].prompt).toBe(0.28);
- expect(tokenValues['deepseek-reasoner'].completion).toBe(0.42);
});
it('should handle DeepSeek model name variations with provider prefixes', () => {
@@ -799,8 +844,8 @@ describe('Deepseek Model Tests', () => {
modelVariations.forEach((model) => {
const promptMultiplier = getMultiplier({ model, tokenType: 'prompt' });
const completionMultiplier = getMultiplier({ model, tokenType: 'completion' });
- expect(promptMultiplier).toBe(0.28);
- expect(completionMultiplier).toBe(0.42);
+ expect(promptMultiplier).toBe(tokenValues['deepseek-chat'].prompt);
+ expect(completionMultiplier).toBe(tokenValues['deepseek-chat'].completion);
});
});
@@ -819,13 +864,13 @@ describe('Deepseek Model Tests', () => {
);
});
- it('should return correct cache pricing values for DeepSeek models', () => {
- expect(cacheTokenValues['deepseek-chat'].write).toBe(0.28);
- expect(cacheTokenValues['deepseek-chat'].read).toBe(0.028);
- expect(cacheTokenValues['deepseek-reasoner'].write).toBe(0.28);
- expect(cacheTokenValues['deepseek-reasoner'].read).toBe(0.028);
- expect(cacheTokenValues['deepseek'].write).toBe(0.28);
- expect(cacheTokenValues['deepseek'].read).toBe(0.028);
+ it('should have consistent cache pricing across DeepSeek model variants', () => {
+ expect(cacheTokenValues['deepseek'].write).toBe(cacheTokenValues['deepseek-chat'].write);
+ expect(cacheTokenValues['deepseek'].read).toBe(cacheTokenValues['deepseek-chat'].read);
+ expect(cacheTokenValues['deepseek-reasoner'].write).toBe(
+ cacheTokenValues['deepseek-chat'].write,
+ );
+ expect(cacheTokenValues['deepseek-reasoner'].read).toBe(cacheTokenValues['deepseek-chat'].read);
});
it('should handle DeepSeek cache multipliers with model variations', () => {
@@ -834,8 +879,195 @@ describe('Deepseek Model Tests', () => {
modelVariations.forEach((model) => {
const writeMultiplier = getCacheMultiplier({ model, cacheType: 'write' });
const readMultiplier = getCacheMultiplier({ model, cacheType: 'read' });
- expect(writeMultiplier).toBe(0.28);
- expect(readMultiplier).toBe(0.028);
+ expect(writeMultiplier).toBe(cacheTokenValues['deepseek-chat'].write);
+ expect(readMultiplier).toBe(cacheTokenValues['deepseek-chat'].read);
+ });
+ });
+});
+
+describe('Moonshot/Kimi Model Tests - Pricing', () => {
+ describe('Kimi Models', () => {
+ it('should return correct pricing for kimi base pattern', () => {
+ expect(getMultiplier({ model: 'kimi', tokenType: 'prompt' })).toBe(
+ tokenValues['kimi'].prompt,
+ );
+ expect(getMultiplier({ model: 'kimi', tokenType: 'completion' })).toBe(
+ tokenValues['kimi'].completion,
+ );
+ });
+
+ it('should return correct pricing for kimi-k2.5', () => {
+ expect(getMultiplier({ model: 'kimi-k2.5', tokenType: 'prompt' })).toBe(
+ tokenValues['kimi-k2.5'].prompt,
+ );
+ expect(getMultiplier({ model: 'kimi-k2.5', tokenType: 'completion' })).toBe(
+ tokenValues['kimi-k2.5'].completion,
+ );
+ });
+
+ it('should return correct pricing for kimi-k2 series', () => {
+ expect(getMultiplier({ model: 'kimi-k2', tokenType: 'prompt' })).toBe(
+ tokenValues['kimi-k2'].prompt,
+ );
+ expect(getMultiplier({ model: 'kimi-k2', tokenType: 'completion' })).toBe(
+ tokenValues['kimi-k2'].completion,
+ );
+ });
+
+ it('should return correct pricing for kimi-k2-turbo (higher pricing)', () => {
+ expect(getMultiplier({ model: 'kimi-k2-turbo', tokenType: 'prompt' })).toBe(
+ tokenValues['kimi-k2-turbo'].prompt,
+ );
+ expect(getMultiplier({ model: 'kimi-k2-turbo', tokenType: 'completion' })).toBe(
+ tokenValues['kimi-k2-turbo'].completion,
+ );
+ });
+
+ it('should return correct pricing for kimi-k2-thinking models', () => {
+ expect(getMultiplier({ model: 'kimi-k2-thinking', tokenType: 'prompt' })).toBe(
+ tokenValues['kimi-k2-thinking'].prompt,
+ );
+ expect(getMultiplier({ model: 'kimi-k2-thinking', tokenType: 'completion' })).toBe(
+ tokenValues['kimi-k2-thinking'].completion,
+ );
+ expect(getMultiplier({ model: 'kimi-k2-thinking-turbo', tokenType: 'prompt' })).toBe(
+ tokenValues['kimi-k2-thinking-turbo'].prompt,
+ );
+ expect(getMultiplier({ model: 'kimi-k2-thinking-turbo', tokenType: 'completion' })).toBe(
+ tokenValues['kimi-k2-thinking-turbo'].completion,
+ );
+ });
+
+ it('should handle Kimi model variations with provider prefixes', () => {
+ const modelVariations = ['openrouter/kimi-k2', 'openrouter/kimi-k2.5', 'openrouter/kimi'];
+
+ modelVariations.forEach((model) => {
+ const promptMultiplier = getMultiplier({ model, tokenType: 'prompt' });
+ const completionMultiplier = getMultiplier({ model, tokenType: 'completion' });
+ expect(promptMultiplier).toBe(tokenValues['kimi'].prompt);
+ expect([tokenValues['kimi'].completion, tokenValues['kimi-k2.5'].completion]).toContain(
+ completionMultiplier,
+ );
+ });
+ });
+ });
+
+ describe('Moonshot Models', () => {
+ it('should return correct pricing for moonshot base pattern (128k pricing)', () => {
+ expect(getMultiplier({ model: 'moonshot', tokenType: 'prompt' })).toBe(
+ tokenValues['moonshot'].prompt,
+ );
+ expect(getMultiplier({ model: 'moonshot', tokenType: 'completion' })).toBe(
+ tokenValues['moonshot'].completion,
+ );
+ });
+
+ it('should return correct pricing for moonshot-v1-8k', () => {
+ expect(getMultiplier({ model: 'moonshot-v1-8k', tokenType: 'prompt' })).toBe(
+ tokenValues['moonshot-v1-8k'].prompt,
+ );
+ expect(getMultiplier({ model: 'moonshot-v1-8k', tokenType: 'completion' })).toBe(
+ tokenValues['moonshot-v1-8k'].completion,
+ );
+ });
+
+ it('should return correct pricing for moonshot-v1-32k', () => {
+ expect(getMultiplier({ model: 'moonshot-v1-32k', tokenType: 'prompt' })).toBe(
+ tokenValues['moonshot-v1-32k'].prompt,
+ );
+ expect(getMultiplier({ model: 'moonshot-v1-32k', tokenType: 'completion' })).toBe(
+ tokenValues['moonshot-v1-32k'].completion,
+ );
+ });
+
+ it('should return correct pricing for moonshot-v1-128k', () => {
+ expect(getMultiplier({ model: 'moonshot-v1-128k', tokenType: 'prompt' })).toBe(
+ tokenValues['moonshot-v1-128k'].prompt,
+ );
+ expect(getMultiplier({ model: 'moonshot-v1-128k', tokenType: 'completion' })).toBe(
+ tokenValues['moonshot-v1-128k'].completion,
+ );
+ });
+
+ it('should return correct pricing for moonshot-v1 vision models', () => {
+ expect(getMultiplier({ model: 'moonshot-v1-8k-vision', tokenType: 'prompt' })).toBe(
+ tokenValues['moonshot-v1-8k-vision'].prompt,
+ );
+ expect(getMultiplier({ model: 'moonshot-v1-8k-vision', tokenType: 'completion' })).toBe(
+ tokenValues['moonshot-v1-8k-vision'].completion,
+ );
+ expect(getMultiplier({ model: 'moonshot-v1-32k-vision', tokenType: 'prompt' })).toBe(
+ tokenValues['moonshot-v1-32k-vision'].prompt,
+ );
+ expect(getMultiplier({ model: 'moonshot-v1-32k-vision', tokenType: 'completion' })).toBe(
+ tokenValues['moonshot-v1-32k-vision'].completion,
+ );
+ expect(getMultiplier({ model: 'moonshot-v1-128k-vision', tokenType: 'prompt' })).toBe(
+ tokenValues['moonshot-v1-128k-vision'].prompt,
+ );
+ expect(getMultiplier({ model: 'moonshot-v1-128k-vision', tokenType: 'completion' })).toBe(
+ tokenValues['moonshot-v1-128k-vision'].completion,
+ );
+ });
+ });
+
+ describe('Kimi Cache Multipliers', () => {
+ it('should return correct cache multipliers for kimi-k2 models', () => {
+ expect(getCacheMultiplier({ model: 'kimi', cacheType: 'write' })).toBe(
+ cacheTokenValues['kimi'].write,
+ );
+ expect(getCacheMultiplier({ model: 'kimi', cacheType: 'read' })).toBe(
+ cacheTokenValues['kimi'].read,
+ );
+ });
+
+ it('should return correct cache multipliers for kimi-k2.5 (lower read price)', () => {
+ expect(getCacheMultiplier({ model: 'kimi-k2.5', cacheType: 'write' })).toBe(
+ cacheTokenValues['kimi-k2.5'].write,
+ );
+ expect(getCacheMultiplier({ model: 'kimi-k2.5', cacheType: 'read' })).toBe(
+ cacheTokenValues['kimi-k2.5'].read,
+ );
+ });
+
+ it('should return correct cache multipliers for kimi-k2-turbo', () => {
+ expect(getCacheMultiplier({ model: 'kimi-k2-turbo', cacheType: 'write' })).toBe(
+ cacheTokenValues['kimi-k2-turbo'].write,
+ );
+ expect(getCacheMultiplier({ model: 'kimi-k2-turbo', cacheType: 'read' })).toBe(
+ cacheTokenValues['kimi-k2-turbo'].read,
+ );
+ });
+
+ it('should handle Kimi cache multipliers with model variations', () => {
+ const modelVariations = ['openrouter/kimi-k2', 'openrouter/kimi'];
+
+ modelVariations.forEach((model) => {
+ const writeMultiplier = getCacheMultiplier({ model, cacheType: 'write' });
+ const readMultiplier = getCacheMultiplier({ model, cacheType: 'read' });
+ expect(writeMultiplier).toBe(cacheTokenValues['kimi'].write);
+ expect(readMultiplier).toBe(cacheTokenValues['kimi'].read);
+ });
+ });
+ });
+
+ describe('Bedrock Moonshot Models', () => {
+ it('should return correct pricing for Bedrock moonshot models', () => {
+ expect(getMultiplier({ model: 'moonshot.kimi', tokenType: 'prompt' })).toBe(
+ tokenValues['moonshot.kimi'].prompt,
+ );
+ expect(getMultiplier({ model: 'moonshot.kimi', tokenType: 'completion' })).toBe(
+ tokenValues['moonshot.kimi'].completion,
+ );
+ expect(getMultiplier({ model: 'moonshot.kimi-k2', tokenType: 'prompt' })).toBe(
+ tokenValues['moonshot.kimi-k2'].prompt,
+ );
+ expect(getMultiplier({ model: 'moonshot.kimi-k2.5', tokenType: 'prompt' })).toBe(
+ tokenValues['moonshot.kimi-k2.5'].prompt,
+ );
+ expect(getMultiplier({ model: 'moonshot.kimi-k2.5', tokenType: 'completion' })).toBe(
+ tokenValues['moonshot.kimi-k2.5'].completion,
+ );
});
});
});
@@ -1113,6 +1345,8 @@ describe('getCacheMultiplier', () => {
describe('Google Model Tests', () => {
const googleModels = [
'gemini-3',
+ 'gemini-3.1-pro-preview',
+ 'gemini-3.1-pro-preview-customtools',
'gemini-2.5-pro',
'gemini-2.5-flash',
'gemini-2.5-flash-lite',
@@ -1157,6 +1391,8 @@ describe('Google Model Tests', () => {
it('should map to the correct model keys', () => {
const expected = {
'gemini-3': 'gemini-3',
+ 'gemini-3.1-pro-preview': 'gemini-3.1',
+ 'gemini-3.1-pro-preview-customtools': 'gemini-3.1',
'gemini-2.5-pro': 'gemini-2.5-pro',
'gemini-2.5-flash': 'gemini-2.5-flash',
'gemini-2.5-flash-lite': 'gemini-2.5-flash-lite',
@@ -1200,6 +1436,174 @@ describe('Google Model Tests', () => {
).toBe(tokenValues[expected].completion);
});
});
+
+ it('should return correct prompt and completion rates for Gemini 3.1', () => {
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview',
+ tokenType: 'prompt',
+ endpoint: EModelEndpoint.google,
+ }),
+ ).toBe(tokenValues['gemini-3.1'].prompt);
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview',
+ tokenType: 'completion',
+ endpoint: EModelEndpoint.google,
+ }),
+ ).toBe(tokenValues['gemini-3.1'].completion);
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview-customtools',
+ tokenType: 'prompt',
+ endpoint: EModelEndpoint.google,
+ }),
+ ).toBe(tokenValues['gemini-3.1'].prompt);
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview-customtools',
+ tokenType: 'completion',
+ endpoint: EModelEndpoint.google,
+ }),
+ ).toBe(tokenValues['gemini-3.1'].completion);
+ });
+
+ it('should return correct cache rates for Gemini 3.1', () => {
+ ['gemini-3.1-pro-preview', 'gemini-3.1-pro-preview-customtools'].forEach((model) => {
+ expect(getCacheMultiplier({ model, cacheType: 'write' })).toBe(
+ cacheTokenValues['gemini-3.1'].write,
+ );
+ expect(getCacheMultiplier({ model, cacheType: 'read' })).toBe(
+ cacheTokenValues['gemini-3.1'].read,
+ );
+ });
+ });
+});
+
+describe('Gemini 3.1 Premium Token Pricing', () => {
+ const premiumKey = 'gemini-3.1';
+ const premiumEntry = premiumTokenValues[premiumKey];
+ const { threshold } = premiumEntry;
+ const belowThreshold = threshold - 1;
+ const aboveThreshold = threshold + 1;
+ const wellAboveThreshold = threshold * 2;
+
+ it('should have premium pricing defined for gemini-3.1', () => {
+ expect(premiumEntry).toBeDefined();
+ expect(premiumEntry.threshold).toBeDefined();
+ expect(premiumEntry.prompt).toBeDefined();
+ expect(premiumEntry.completion).toBeDefined();
+ expect(premiumEntry.prompt).toBeGreaterThan(tokenValues[premiumKey].prompt);
+ expect(premiumEntry.completion).toBeGreaterThan(tokenValues[premiumKey].completion);
+ });
+
+ it('should return null from getPremiumRate when inputTokenCount is below or at threshold', () => {
+ expect(getPremiumRate(premiumKey, 'prompt', belowThreshold)).toBeNull();
+ expect(getPremiumRate(premiumKey, 'completion', belowThreshold)).toBeNull();
+ expect(getPremiumRate(premiumKey, 'prompt', threshold)).toBeNull();
+ });
+
+ it('should return premium rate from getPremiumRate when inputTokenCount exceeds threshold', () => {
+ expect(getPremiumRate(premiumKey, 'prompt', aboveThreshold)).toBe(premiumEntry.prompt);
+ expect(getPremiumRate(premiumKey, 'completion', aboveThreshold)).toBe(premiumEntry.completion);
+ expect(getPremiumRate(premiumKey, 'prompt', wellAboveThreshold)).toBe(premiumEntry.prompt);
+ });
+
+ it('should return null from getPremiumRate when inputTokenCount is undefined or null', () => {
+ expect(getPremiumRate(premiumKey, 'prompt', undefined)).toBeNull();
+ expect(getPremiumRate(premiumKey, 'prompt', null)).toBeNull();
+ });
+
+ it('should return standard rate from getMultiplier when inputTokenCount is below threshold', () => {
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview',
+ tokenType: 'prompt',
+ inputTokenCount: belowThreshold,
+ }),
+ ).toBe(tokenValues[premiumKey].prompt);
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview',
+ tokenType: 'completion',
+ inputTokenCount: belowThreshold,
+ }),
+ ).toBe(tokenValues[premiumKey].completion);
+ });
+
+ it('should return premium rate from getMultiplier when inputTokenCount exceeds threshold', () => {
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview',
+ tokenType: 'prompt',
+ inputTokenCount: aboveThreshold,
+ }),
+ ).toBe(premiumEntry.prompt);
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview',
+ tokenType: 'completion',
+ inputTokenCount: aboveThreshold,
+ }),
+ ).toBe(premiumEntry.completion);
+ });
+
+ it('should return standard rate from getMultiplier when inputTokenCount is exactly at threshold', () => {
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview',
+ tokenType: 'prompt',
+ inputTokenCount: threshold,
+ }),
+ ).toBe(tokenValues[premiumKey].prompt);
+ });
+
+ it('should apply premium pricing to customtools variant above threshold', () => {
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview-customtools',
+ tokenType: 'prompt',
+ inputTokenCount: aboveThreshold,
+ }),
+ ).toBe(premiumEntry.prompt);
+ expect(
+ getMultiplier({
+ model: 'gemini-3.1-pro-preview-customtools',
+ tokenType: 'completion',
+ inputTokenCount: aboveThreshold,
+ }),
+ ).toBe(premiumEntry.completion);
+ });
+
+ it('should use standard rate when inputTokenCount is not provided', () => {
+ expect(getMultiplier({ model: 'gemini-3.1-pro-preview', tokenType: 'prompt' })).toBe(
+ tokenValues[premiumKey].prompt,
+ );
+ expect(getMultiplier({ model: 'gemini-3.1-pro-preview', tokenType: 'completion' })).toBe(
+ tokenValues[premiumKey].completion,
+ );
+ });
+
+ it('should apply premium pricing through getMultiplier with valueKey path', () => {
+ const valueKey = getValueKey('gemini-3.1-pro-preview');
+ expect(valueKey).toBe(premiumKey);
+ expect(getMultiplier({ valueKey, tokenType: 'prompt', inputTokenCount: aboveThreshold })).toBe(
+ premiumEntry.prompt,
+ );
+ expect(
+ getMultiplier({ valueKey, tokenType: 'completion', inputTokenCount: aboveThreshold }),
+ ).toBe(premiumEntry.completion);
+ });
+
+ it('should apply standard pricing through getMultiplier with valueKey path when below threshold', () => {
+ const valueKey = getValueKey('gemini-3.1-pro-preview');
+ expect(getMultiplier({ valueKey, tokenType: 'prompt', inputTokenCount: belowThreshold })).toBe(
+ tokenValues[premiumKey].prompt,
+ );
+ expect(
+ getMultiplier({ valueKey, tokenType: 'completion', inputTokenCount: belowThreshold }),
+ ).toBe(tokenValues[premiumKey].completion);
+ });
});
describe('Grok Model Tests - Pricing', () => {
@@ -1648,6 +2052,201 @@ describe('Claude Model Tests', () => {
);
});
});
+
+ it('should return correct prompt and completion rates for Claude Opus 4.6', () => {
+ expect(getMultiplier({ model: 'claude-opus-4-6', tokenType: 'prompt' })).toBe(
+ tokenValues['claude-opus-4-6'].prompt,
+ );
+ expect(getMultiplier({ model: 'claude-opus-4-6', tokenType: 'completion' })).toBe(
+ tokenValues['claude-opus-4-6'].completion,
+ );
+ });
+
+ it('should handle Claude Opus 4.6 model name variations', () => {
+ const modelVariations = [
+ 'claude-opus-4-6',
+ 'claude-opus-4-6-20250801',
+ 'claude-opus-4-6-latest',
+ 'anthropic/claude-opus-4-6',
+ 'claude-opus-4-6/anthropic',
+ 'claude-opus-4-6-preview',
+ ];
+
+ modelVariations.forEach((model) => {
+ const valueKey = getValueKey(model);
+ expect(valueKey).toBe('claude-opus-4-6');
+ expect(getMultiplier({ model, tokenType: 'prompt' })).toBe(
+ tokenValues['claude-opus-4-6'].prompt,
+ );
+ expect(getMultiplier({ model, tokenType: 'completion' })).toBe(
+ tokenValues['claude-opus-4-6'].completion,
+ );
+ });
+ });
+
+ it('should return correct cache rates for Claude Opus 4.6', () => {
+ expect(getCacheMultiplier({ model: 'claude-opus-4-6', cacheType: 'write' })).toBe(
+ cacheTokenValues['claude-opus-4-6'].write,
+ );
+ expect(getCacheMultiplier({ model: 'claude-opus-4-6', cacheType: 'read' })).toBe(
+ cacheTokenValues['claude-opus-4-6'].read,
+ );
+ });
+
+ it('should handle Claude Opus 4.6 cache rates with model name variations', () => {
+ const modelVariations = [
+ 'claude-opus-4-6',
+ 'claude-opus-4-6-20250801',
+ 'claude-opus-4-6-latest',
+ 'anthropic/claude-opus-4-6',
+ 'claude-opus-4-6/anthropic',
+ 'claude-opus-4-6-preview',
+ ];
+
+ modelVariations.forEach((model) => {
+ expect(getCacheMultiplier({ model, cacheType: 'write' })).toBe(
+ cacheTokenValues['claude-opus-4-6'].write,
+ );
+ expect(getCacheMultiplier({ model, cacheType: 'read' })).toBe(
+ cacheTokenValues['claude-opus-4-6'].read,
+ );
+ });
+ });
+});
+
+describe('Premium Token Pricing', () => {
+ const premiumModel = 'claude-opus-4-6';
+ const premiumEntry = premiumTokenValues[premiumModel];
+ const { threshold } = premiumEntry;
+ const belowThreshold = threshold - 1;
+ const aboveThreshold = threshold + 1;
+ const wellAboveThreshold = threshold * 2;
+
+ it('should have premium pricing defined for claude-opus-4-6', () => {
+ expect(premiumEntry).toBeDefined();
+ expect(premiumEntry.threshold).toBeDefined();
+ expect(premiumEntry.prompt).toBeDefined();
+ expect(premiumEntry.completion).toBeDefined();
+ expect(premiumEntry.prompt).toBeGreaterThan(tokenValues[premiumModel].prompt);
+ expect(premiumEntry.completion).toBeGreaterThan(tokenValues[premiumModel].completion);
+ });
+
+ it('should return null from getPremiumRate when inputTokenCount is below threshold', () => {
+ expect(getPremiumRate(premiumModel, 'prompt', belowThreshold)).toBeNull();
+ expect(getPremiumRate(premiumModel, 'completion', belowThreshold)).toBeNull();
+ expect(getPremiumRate(premiumModel, 'prompt', threshold)).toBeNull();
+ });
+
+ it('should return premium rate from getPremiumRate when inputTokenCount exceeds threshold', () => {
+ expect(getPremiumRate(premiumModel, 'prompt', aboveThreshold)).toBe(premiumEntry.prompt);
+ expect(getPremiumRate(premiumModel, 'completion', aboveThreshold)).toBe(
+ premiumEntry.completion,
+ );
+ expect(getPremiumRate(premiumModel, 'prompt', wellAboveThreshold)).toBe(premiumEntry.prompt);
+ });
+
+ it('should return null from getPremiumRate when inputTokenCount is undefined or null', () => {
+ expect(getPremiumRate(premiumModel, 'prompt', undefined)).toBeNull();
+ expect(getPremiumRate(premiumModel, 'prompt', null)).toBeNull();
+ });
+
+ it('should return null from getPremiumRate for models without premium pricing', () => {
+ expect(getPremiumRate('claude-opus-4-5', 'prompt', wellAboveThreshold)).toBeNull();
+ expect(getPremiumRate('claude-sonnet-4', 'prompt', wellAboveThreshold)).toBeNull();
+ expect(getPremiumRate('gpt-4o', 'prompt', wellAboveThreshold)).toBeNull();
+ });
+
+ it('should return standard rate from getMultiplier when inputTokenCount is below threshold', () => {
+ expect(
+ getMultiplier({
+ model: premiumModel,
+ tokenType: 'prompt',
+ inputTokenCount: belowThreshold,
+ }),
+ ).toBe(tokenValues[premiumModel].prompt);
+ expect(
+ getMultiplier({
+ model: premiumModel,
+ tokenType: 'completion',
+ inputTokenCount: belowThreshold,
+ }),
+ ).toBe(tokenValues[premiumModel].completion);
+ });
+
+ it('should return premium rate from getMultiplier when inputTokenCount exceeds threshold', () => {
+ expect(
+ getMultiplier({
+ model: premiumModel,
+ tokenType: 'prompt',
+ inputTokenCount: aboveThreshold,
+ }),
+ ).toBe(premiumEntry.prompt);
+ expect(
+ getMultiplier({
+ model: premiumModel,
+ tokenType: 'completion',
+ inputTokenCount: aboveThreshold,
+ }),
+ ).toBe(premiumEntry.completion);
+ });
+
+ it('should return standard rate from getMultiplier when inputTokenCount is exactly at threshold', () => {
+ expect(
+ getMultiplier({ model: premiumModel, tokenType: 'prompt', inputTokenCount: threshold }),
+ ).toBe(tokenValues[premiumModel].prompt);
+ });
+
+ it('should return premium rate from getMultiplier when inputTokenCount is one above threshold', () => {
+ expect(
+ getMultiplier({ model: premiumModel, tokenType: 'prompt', inputTokenCount: aboveThreshold }),
+ ).toBe(premiumEntry.prompt);
+ });
+
+ it('should not apply premium pricing to models without premium entries', () => {
+ expect(
+ getMultiplier({
+ model: 'claude-opus-4-5',
+ tokenType: 'prompt',
+ inputTokenCount: wellAboveThreshold,
+ }),
+ ).toBe(tokenValues['claude-opus-4-5'].prompt);
+ expect(
+ getMultiplier({
+ model: 'claude-sonnet-4',
+ tokenType: 'prompt',
+ inputTokenCount: wellAboveThreshold,
+ }),
+ ).toBe(tokenValues['claude-sonnet-4'].prompt);
+ });
+
+ it('should use standard rate when inputTokenCount is not provided', () => {
+ expect(getMultiplier({ model: premiumModel, tokenType: 'prompt' })).toBe(
+ tokenValues[premiumModel].prompt,
+ );
+ expect(getMultiplier({ model: premiumModel, tokenType: 'completion' })).toBe(
+ tokenValues[premiumModel].completion,
+ );
+ });
+
+ it('should apply premium pricing through getMultiplier with valueKey path', () => {
+ const valueKey = getValueKey(premiumModel);
+ expect(getMultiplier({ valueKey, tokenType: 'prompt', inputTokenCount: aboveThreshold })).toBe(
+ premiumEntry.prompt,
+ );
+ expect(
+ getMultiplier({ valueKey, tokenType: 'completion', inputTokenCount: aboveThreshold }),
+ ).toBe(premiumEntry.completion);
+ });
+
+ it('should apply standard pricing through getMultiplier with valueKey path when below threshold', () => {
+ const valueKey = getValueKey(premiumModel);
+ expect(getMultiplier({ valueKey, tokenType: 'prompt', inputTokenCount: belowThreshold })).toBe(
+ tokenValues[premiumModel].prompt,
+ );
+ expect(
+ getMultiplier({ valueKey, tokenType: 'completion', inputTokenCount: belowThreshold }),
+ ).toBe(tokenValues[premiumModel].completion);
+ });
});
describe('tokens.ts and tx.js sync validation', () => {
diff --git a/api/package.json b/api/package.json
index efee26920a..1447087b38 100644
--- a/api/package.json
+++ b/api/package.json
@@ -1,13 +1,13 @@
{
"name": "@librechat/backend",
- "version": "v0.8.1",
+ "version": "v0.8.3-rc1",
"description": "",
"scripts": {
"start": "echo 'please run this from the root directory'",
"server-dev": "echo 'please run this from the root directory'",
"test": "cross-env NODE_ENV=test jest",
"b:test": "NODE_ENV=test bun jest",
- "test:ci": "jest --ci",
+ "test:ci": "jest --ci --logHeapUsage",
"add-balance": "node ./add-balance.js",
"list-balances": "node ./list-balances.js",
"user-stats": "node ./user-stats.js",
@@ -34,27 +34,24 @@
},
"homepage": "https://librechat.ai",
"dependencies": {
- "@anthropic-ai/sdk": "^0.52.0",
- "@aws-sdk/client-s3": "^3.758.0",
+ "@anthropic-ai/vertex-sdk": "^0.14.3",
+ "@aws-sdk/client-bedrock-runtime": "^3.980.0",
+ "@aws-sdk/client-s3": "^3.980.0",
"@aws-sdk/s3-request-presigner": "^3.758.0",
"@azure/identity": "^4.7.0",
"@azure/search-documents": "^12.0.0",
- "@azure/storage-blob": "^12.27.0",
- "@google/generative-ai": "^0.24.0",
- "@googleapis/youtube": "^20.0.0",
+ "@azure/storage-blob": "^12.30.0",
+ "@google/genai": "^1.19.0",
"@keyv/redis": "^4.3.3",
- "@langchain/core": "^0.3.79",
- "@langchain/google-genai": "^0.2.13",
- "@langchain/google-vertexai": "^0.2.13",
- "@langchain/textsplitters": "^0.1.0",
- "@librechat/agents": "^3.0.50",
+ "@langchain/core": "^0.3.80",
+ "@librechat/agents": "^3.1.52",
"@librechat/api": "*",
"@librechat/data-schemas": "*",
"@microsoft/microsoft-graph-client": "^3.0.7",
- "@modelcontextprotocol/sdk": "^1.21.0",
+ "@modelcontextprotocol/sdk": "^1.27.1",
"@node-saml/passport-saml": "^5.1.0",
- "@waylaidwanderer/fetch-event-source": "^3.0.1",
- "axios": "^1.12.1",
+ "@smithy/node-http-handler": "^4.4.5",
+ "axios": "^1.13.5",
"bcryptjs": "^2.4.3",
"compression": "^1.8.1",
"connect-redis": "^8.1.0",
@@ -64,15 +61,14 @@
"dedent": "^1.5.3",
"dotenv": "^16.0.3",
"eventsource": "^3.0.2",
- "express": "^4.21.2",
+ "express": "^5.2.1",
"express-mongo-sanitize": "^2.2.0",
- "express-rate-limit": "^7.4.1",
+ "express-rate-limit": "^8.2.1",
"express-session": "^1.18.2",
"express-static-gzip": "^2.2.0",
"file-type": "^18.7.0",
"firebase": "^11.0.2",
"form-data": "^4.0.4",
- "googleapis": "^126.0.1",
"handlebars": "^4.7.7",
"https-proxy-agent": "^7.0.6",
"ioredis": "^5.3.2",
@@ -83,7 +79,9 @@
"keyv-file": "^5.1.2",
"klona": "^2.0.6",
"librechat-data-provider": "*",
- "lodash": "^4.17.21",
+ "lodash": "^4.17.23",
+ "mammoth": "^1.11.0",
+ "mathjs": "^15.1.0",
"meilisearch": "^0.38.0",
"memorystore": "^1.6.7",
"mime": "^3.0.0",
@@ -105,15 +103,16 @@
"passport-jwt": "^4.0.1",
"passport-ldapauth": "^3.0.1",
"passport-local": "^1.0.0",
+ "pdfjs-dist": "^5.4.624",
"rate-limit-redis": "^4.2.0",
"sharp": "^0.33.5",
"tiktoken": "^1.0.15",
"traverse": "^0.6.7",
"ua-parser-js": "^1.0.36",
- "undici": "^7.10.0",
+ "undici": "^7.18.2",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^5.0.0",
- "youtube-transcript": "^1.2.1",
+ "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
"zod": "^3.22.4"
},
"devDependencies": {
diff --git a/api/server/cleanup.js b/api/server/cleanup.js
index 8e19c853ea..364c02cd8a 100644
--- a/api/server/cleanup.js
+++ b/api/server/cleanup.js
@@ -35,7 +35,6 @@ const graphPropsToClean = [
'tools',
'signal',
'config',
- 'agentContexts',
'messages',
'contentData',
'stepKeyIds',
@@ -277,7 +276,16 @@ function disposeClient(client) {
if (client.run) {
if (client.run.Graph) {
- client.run.Graph.resetValues();
+ if (typeof client.run.Graph.clearHeavyState === 'function') {
+ client.run.Graph.clearHeavyState();
+ } else {
+ client.run.Graph.resetValues();
+ }
+
+ if (client.run.Graph.agentContexts) {
+ client.run.Graph.agentContexts.clear();
+ client.run.Graph.agentContexts = null;
+ }
graphPropsToClean.forEach((prop) => {
if (client.run.Graph[prop] !== undefined) {
@@ -350,9 +358,6 @@ function disposeClient(client) {
if (client.agentConfigs) {
client.agentConfigs = null;
}
- if (client.agentIdMap) {
- client.agentIdMap = null;
- }
if (client.artifactPromises) {
client.artifactPromises = null;
}
diff --git a/api/server/controllers/AuthController.js b/api/server/controllers/AuthController.js
index dfef2bbfa1..13d024cd03 100644
--- a/api/server/controllers/AuthController.js
+++ b/api/server/controllers/AuthController.js
@@ -10,10 +10,15 @@ const {
setAuthTokens,
registerUser,
} = require('~/server/services/AuthService');
-const { findUser, getUserById, deleteAllUserSessions, findSession } = require('~/models');
+const {
+ deleteAllUserSessions,
+ getUserById,
+ findSession,
+ updateUser,
+ findUser,
+} = require('~/models');
const { getGraphApiToken } = require('~/server/services/GraphTokenService');
-const { getOAuthReconnectionManager } = require('~/config');
-const { getOpenIdConfig } = require('~/strategies');
+const { getOpenIdConfig, getOpenIdEmail } = require('~/strategies');
const registrationController = async (req, res) => {
try {
@@ -60,29 +65,59 @@ const resetPasswordController = async (req, res) => {
};
const refreshController = async (req, res) => {
- const refreshToken = req.headers.cookie ? cookies.parse(req.headers.cookie).refreshToken : null;
- const token_provider = req.headers.cookie
- ? cookies.parse(req.headers.cookie).token_provider
- : null;
- if (!refreshToken) {
- return res.status(200).send('Refresh token not provided');
- }
- if (token_provider === 'openid' && isEnabled(process.env.OPENID_REUSE_TOKENS) === true) {
+ const parsedCookies = req.headers.cookie ? cookies.parse(req.headers.cookie) : {};
+ const token_provider = parsedCookies.token_provider;
+
+ if (token_provider === 'openid' && isEnabled(process.env.OPENID_REUSE_TOKENS)) {
+ /** For OpenID users, read refresh token from session to avoid large cookie issues */
+ const refreshToken = req.session?.openidTokens?.refreshToken || parsedCookies.refreshToken;
+
+ if (!refreshToken) {
+ return res.status(200).send('Refresh token not provided');
+ }
+
try {
const openIdConfig = getOpenIdConfig();
- const tokenset = await openIdClient.refreshTokenGrant(openIdConfig, refreshToken);
+ const refreshParams = process.env.OPENID_SCOPE ? { scope: process.env.OPENID_SCOPE } : {};
+ const tokenset = await openIdClient.refreshTokenGrant(
+ openIdConfig,
+ refreshToken,
+ refreshParams,
+ );
const claims = tokenset.claims();
- const { user, error } = await findOpenIDUser({
+ const { user, error, migration } = await findOpenIDUser({
findUser,
- email: claims.email,
+ email: getOpenIdEmail(claims),
openidId: claims.sub,
idOnTheSource: claims.oid,
strategyName: 'refreshController',
});
+
+ logger.debug(
+ `[refreshController] findOpenIDUser result: user=${user?.email ?? 'null'}, error=${error ?? 'null'}, migration=${migration}, userOpenidId=${user?.openidId ?? 'null'}, claimsSub=${claims.sub}`,
+ );
+
if (error || !user) {
+ logger.warn(
+ `[refreshController] Redirecting to /login: error=${error ?? 'null'}, user=${user ? 'exists' : 'null'}`,
+ );
return res.status(401).redirect('/login');
}
- const token = setOpenIDAuthTokens(tokenset, res, user._id.toString(), refreshToken);
+
+ // Handle migration: update user with openidId if found by email without openidId
+ // Also handle case where user has mismatched openidId (e.g., after database switch)
+ if (migration || user.openidId !== claims.sub) {
+ const reason = migration ? 'migration' : 'openidId mismatch';
+ await updateUser(user._id.toString(), {
+ provider: 'openid',
+ openidId: claims.sub,
+ });
+ logger.info(
+ `[refreshController] Updated user ${user.email} openidId (${reason}): ${user.openidId ?? 'null'} -> ${claims.sub}`,
+ );
+ }
+
+ const token = setOpenIDAuthTokens(tokenset, req, res, user._id.toString(), refreshToken);
user.federatedTokens = {
access_token: tokenset.access_token,
@@ -97,6 +132,13 @@ const refreshController = async (req, res) => {
return res.status(403).send('Invalid OpenID refresh token');
}
}
+
+ /** For non-OpenID users, read refresh token from cookies */
+ const refreshToken = parsedCookies.refreshToken;
+ if (!refreshToken) {
+ return res.status(200).send('Refresh token not provided');
+ }
+
try {
const payload = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);
const user = await getUserById(payload.id, '-password -__v -totpSecret -backupCodes');
@@ -123,17 +165,6 @@ const refreshController = async (req, res) => {
if (session && session.expiration > new Date()) {
const token = await setAuthTokens(userId, res, session);
- // trigger OAuth MCP server reconnection asynchronously (best effort)
- try {
- void getOAuthReconnectionManager()
- .reconnectServers(userId)
- .catch((err) => {
- logger.error('[refreshController] Error reconnecting OAuth MCP servers:', err);
- });
- } catch (err) {
- logger.warn(`[refreshController] Cannot attempt OAuth MCP servers reconnection:`, err);
- }
-
res.status(200).send({ token, user });
} else if (req?.query?.retry) {
// Retrying from a refresh token request that failed (401)
@@ -165,15 +196,6 @@ const graphTokenController = async (req, res) => {
});
}
- // Extract access token from Authorization header
- const authHeader = req.headers.authorization;
- if (!authHeader || !authHeader.startsWith('Bearer ')) {
- return res.status(401).json({
- message: 'Valid authorization token required',
- });
- }
-
- // Get scopes from query parameters
const scopes = req.query.scopes;
if (!scopes) {
return res.status(400).json({
@@ -181,7 +203,13 @@ const graphTokenController = async (req, res) => {
});
}
- const accessToken = authHeader.substring(7); // Remove 'Bearer ' prefix
+ const accessToken = req.user.federatedTokens?.access_token;
+ if (!accessToken) {
+ return res.status(401).json({
+ message: 'No federated access token available for token exchange',
+ });
+ }
+
const tokenResponse = await getGraphApiToken(req.user, accessToken, scopes);
res.json(tokenResponse);
diff --git a/api/server/controllers/AuthController.spec.js b/api/server/controllers/AuthController.spec.js
new file mode 100644
index 0000000000..fef670baa8
--- /dev/null
+++ b/api/server/controllers/AuthController.spec.js
@@ -0,0 +1,302 @@
+jest.mock('@librechat/data-schemas', () => ({
+ logger: { error: jest.fn(), debug: jest.fn(), warn: jest.fn(), info: jest.fn() },
+}));
+jest.mock('~/server/services/GraphTokenService', () => ({
+ getGraphApiToken: jest.fn(),
+}));
+jest.mock('~/server/services/AuthService', () => ({
+ requestPasswordReset: jest.fn(),
+ setOpenIDAuthTokens: jest.fn(),
+ resetPassword: jest.fn(),
+ setAuthTokens: jest.fn(),
+ registerUser: jest.fn(),
+}));
+jest.mock('~/strategies', () => ({ getOpenIdConfig: jest.fn(), getOpenIdEmail: jest.fn() }));
+jest.mock('openid-client', () => ({ refreshTokenGrant: jest.fn() }));
+jest.mock('~/models', () => ({
+ deleteAllUserSessions: jest.fn(),
+ getUserById: jest.fn(),
+ findSession: jest.fn(),
+ updateUser: jest.fn(),
+ findUser: jest.fn(),
+}));
+jest.mock('@librechat/api', () => ({
+ isEnabled: jest.fn(),
+ findOpenIDUser: jest.fn(),
+}));
+
+const openIdClient = require('openid-client');
+const { isEnabled, findOpenIDUser } = require('@librechat/api');
+const { graphTokenController, refreshController } = require('./AuthController');
+const { getGraphApiToken } = require('~/server/services/GraphTokenService');
+const { setOpenIDAuthTokens } = require('~/server/services/AuthService');
+const { getOpenIdConfig, getOpenIdEmail } = require('~/strategies');
+const { updateUser } = require('~/models');
+
+describe('graphTokenController', () => {
+ let req, res;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ isEnabled.mockReturnValue(true);
+
+ req = {
+ user: {
+ openidId: 'oid-123',
+ provider: 'openid',
+ federatedTokens: {
+ access_token: 'federated-access-token',
+ id_token: 'federated-id-token',
+ },
+ },
+ headers: { authorization: 'Bearer app-jwt-which-is-id-token' },
+ query: { scopes: 'https://graph.microsoft.com/.default' },
+ };
+
+ res = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn(),
+ };
+
+ getGraphApiToken.mockResolvedValue({
+ access_token: 'graph-access-token',
+ token_type: 'Bearer',
+ expires_in: 3600,
+ });
+ });
+
+ it('should pass federatedTokens.access_token as OBO assertion, not the auth header bearer token', async () => {
+ await graphTokenController(req, res);
+
+ expect(getGraphApiToken).toHaveBeenCalledWith(
+ req.user,
+ 'federated-access-token',
+ 'https://graph.microsoft.com/.default',
+ );
+ expect(getGraphApiToken).not.toHaveBeenCalledWith(
+ expect.anything(),
+ 'app-jwt-which-is-id-token',
+ expect.anything(),
+ );
+ });
+
+ it('should return the graph token response on success', async () => {
+ await graphTokenController(req, res);
+
+ expect(res.json).toHaveBeenCalledWith({
+ access_token: 'graph-access-token',
+ token_type: 'Bearer',
+ expires_in: 3600,
+ });
+ });
+
+ it('should return 403 when user is not authenticated via Entra ID', async () => {
+ req.user.provider = 'google';
+ req.user.openidId = undefined;
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(getGraphApiToken).not.toHaveBeenCalled();
+ });
+
+ it('should return 403 when OPENID_REUSE_TOKENS is not enabled', async () => {
+ isEnabled.mockReturnValue(false);
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(getGraphApiToken).not.toHaveBeenCalled();
+ });
+
+ it('should return 400 when scopes query param is missing', async () => {
+ req.query.scopes = undefined;
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(400);
+ expect(getGraphApiToken).not.toHaveBeenCalled();
+ });
+
+ it('should return 401 when federatedTokens.access_token is missing', async () => {
+ req.user.federatedTokens = {};
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(getGraphApiToken).not.toHaveBeenCalled();
+ });
+
+ it('should return 401 when federatedTokens is absent entirely', async () => {
+ req.user.federatedTokens = undefined;
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(getGraphApiToken).not.toHaveBeenCalled();
+ });
+
+ it('should return 500 when getGraphApiToken throws', async () => {
+ getGraphApiToken.mockRejectedValue(new Error('OBO exchange failed'));
+
+ await graphTokenController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(500);
+ expect(res.json).toHaveBeenCalledWith({
+ message: 'Failed to obtain Microsoft Graph token',
+ });
+ });
+});
+
+describe('refreshController – OpenID path', () => {
+ const mockTokenset = {
+ claims: jest.fn(),
+ access_token: 'new-access',
+ id_token: 'new-id',
+ refresh_token: 'new-refresh',
+ };
+
+ const baseClaims = {
+ sub: 'oidc-sub-123',
+ oid: 'oid-456',
+ email: 'user@example.com',
+ exp: 9999999999,
+ };
+
+ let req, res;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ isEnabled.mockReturnValue(true);
+ getOpenIdConfig.mockReturnValue({ some: 'config' });
+ openIdClient.refreshTokenGrant.mockResolvedValue(mockTokenset);
+ mockTokenset.claims.mockReturnValue(baseClaims);
+ getOpenIdEmail.mockReturnValue(baseClaims.email);
+ setOpenIDAuthTokens.mockReturnValue('new-app-token');
+ updateUser.mockResolvedValue({});
+
+ req = {
+ headers: { cookie: 'token_provider=openid; refreshToken=stored-refresh' },
+ session: {},
+ };
+
+ res = {
+ status: jest.fn().mockReturnThis(),
+ send: jest.fn().mockReturnThis(),
+ redirect: jest.fn(),
+ };
+ });
+
+ it('should call getOpenIdEmail with token claims and use result for findOpenIDUser', async () => {
+ const user = {
+ _id: 'user-db-id',
+ email: baseClaims.email,
+ openidId: baseClaims.sub,
+ };
+ findOpenIDUser.mockResolvedValue({ user, error: null, migration: false });
+
+ await refreshController(req, res);
+
+ expect(getOpenIdEmail).toHaveBeenCalledWith(baseClaims);
+ expect(findOpenIDUser).toHaveBeenCalledWith(
+ expect.objectContaining({ email: baseClaims.email }),
+ );
+ expect(res.status).toHaveBeenCalledWith(200);
+ });
+
+ it('should use OPENID_EMAIL_CLAIM-resolved value when claim is present in token', async () => {
+ const claimsWithUpn = { ...baseClaims, upn: 'user@corp.example.com' };
+ mockTokenset.claims.mockReturnValue(claimsWithUpn);
+ getOpenIdEmail.mockReturnValue('user@corp.example.com');
+
+ const user = {
+ _id: 'user-db-id',
+ email: 'user@corp.example.com',
+ openidId: baseClaims.sub,
+ };
+ findOpenIDUser.mockResolvedValue({ user, error: null, migration: false });
+
+ await refreshController(req, res);
+
+ expect(getOpenIdEmail).toHaveBeenCalledWith(claimsWithUpn);
+ expect(findOpenIDUser).toHaveBeenCalledWith(
+ expect.objectContaining({ email: 'user@corp.example.com' }),
+ );
+ expect(res.status).toHaveBeenCalledWith(200);
+ });
+
+ it('should fall back to claims.email when configured claim is absent from token claims', async () => {
+ getOpenIdEmail.mockReturnValue(baseClaims.email);
+
+ const user = {
+ _id: 'user-db-id',
+ email: baseClaims.email,
+ openidId: baseClaims.sub,
+ };
+ findOpenIDUser.mockResolvedValue({ user, error: null, migration: false });
+
+ await refreshController(req, res);
+
+ expect(findOpenIDUser).toHaveBeenCalledWith(
+ expect.objectContaining({ email: baseClaims.email }),
+ );
+ });
+
+ it('should update openidId when migration is triggered on refresh', async () => {
+ const user = { _id: 'user-db-id', email: baseClaims.email, openidId: null };
+ findOpenIDUser.mockResolvedValue({ user, error: null, migration: true });
+
+ await refreshController(req, res);
+
+ expect(updateUser).toHaveBeenCalledWith(
+ 'user-db-id',
+ expect.objectContaining({ provider: 'openid', openidId: baseClaims.sub }),
+ );
+ expect(res.status).toHaveBeenCalledWith(200);
+ });
+
+ it('should return 401 and redirect to /login when findOpenIDUser returns no user', async () => {
+ findOpenIDUser.mockResolvedValue({ user: null, error: null, migration: false });
+
+ await refreshController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(res.redirect).toHaveBeenCalledWith('/login');
+ });
+
+ it('should return 401 and redirect when findOpenIDUser returns an error', async () => {
+ findOpenIDUser.mockResolvedValue({ user: null, error: 'AUTH_FAILED', migration: false });
+
+ await refreshController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(res.redirect).toHaveBeenCalledWith('/login');
+ });
+
+ it('should skip OpenID path when token_provider is not openid', async () => {
+ req.headers.cookie = 'token_provider=local; refreshToken=some-token';
+
+ await refreshController(req, res);
+
+ expect(openIdClient.refreshTokenGrant).not.toHaveBeenCalled();
+ });
+
+ it('should skip OpenID path when OPENID_REUSE_TOKENS is disabled', async () => {
+ isEnabled.mockReturnValue(false);
+
+ await refreshController(req, res);
+
+ expect(openIdClient.refreshTokenGrant).not.toHaveBeenCalled();
+ });
+
+ it('should return 200 with token not provided when refresh token is absent', async () => {
+ req.headers.cookie = 'token_provider=openid';
+ req.session = {};
+
+ await refreshController(req, res);
+
+ expect(res.status).toHaveBeenCalledWith(200);
+ expect(res.send).toHaveBeenCalledWith('Refresh token not provided');
+ });
+});
diff --git a/api/server/controllers/EditController.js b/api/server/controllers/EditController.js
deleted file mode 100644
index d24e87ce3a..0000000000
--- a/api/server/controllers/EditController.js
+++ /dev/null
@@ -1,247 +0,0 @@
-const { sendEvent } = require('@librechat/api');
-const { logger } = require('@librechat/data-schemas');
-const { getResponseSender } = require('librechat-data-provider');
-const {
- handleAbortError,
- createAbortController,
- cleanupAbortController,
-} = require('~/server/middleware');
-const {
- disposeClient,
- processReqData,
- clientRegistry,
- requestDataMap,
-} = require('~/server/cleanup');
-const { createOnProgress } = require('~/server/utils');
-const { saveMessage } = require('~/models');
-
-const EditController = async (req, res, next, initializeClient) => {
- let {
- text,
- generation,
- endpointOption,
- conversationId,
- modelDisplayLabel,
- responseMessageId,
- isContinued = false,
- parentMessageId = null,
- overrideParentMessageId = null,
- } = req.body;
-
- let client = null;
- let abortKey = null;
- let cleanupHandlers = [];
- let clientRef = null; // Declare clientRef here
-
- logger.debug('[EditController]', {
- text,
- generation,
- isContinued,
- conversationId,
- ...endpointOption,
- modelsConfig: endpointOption.modelsConfig ? 'exists' : '',
- });
-
- let userMessage = null;
- let userMessagePromise = null;
- let promptTokens = null;
- let getAbortData = null;
-
- const sender = getResponseSender({
- ...endpointOption,
- model: endpointOption.modelOptions.model,
- modelDisplayLabel,
- });
- const userMessageId = parentMessageId;
- const userId = req.user.id;
-
- let reqDataContext = { userMessage, userMessagePromise, responseMessageId, promptTokens };
-
- const updateReqData = (data = {}) => {
- reqDataContext = processReqData(data, reqDataContext);
- abortKey = reqDataContext.abortKey;
- userMessage = reqDataContext.userMessage;
- userMessagePromise = reqDataContext.userMessagePromise;
- responseMessageId = reqDataContext.responseMessageId;
- promptTokens = reqDataContext.promptTokens;
- };
-
- let { onProgress: progressCallback, getPartialText } = createOnProgress({
- generation,
- });
-
- const performCleanup = () => {
- logger.debug('[EditController] Performing cleanup');
- if (Array.isArray(cleanupHandlers)) {
- for (const handler of cleanupHandlers) {
- try {
- if (typeof handler === 'function') {
- handler();
- }
- } catch (e) {
- // Ignore
- }
- }
- }
-
- if (abortKey) {
- logger.debug('[EditController] Cleaning up abort controller');
- cleanupAbortController(abortKey);
- abortKey = null;
- }
-
- if (client) {
- disposeClient(client);
- client = null;
- }
-
- reqDataContext = null;
- userMessage = null;
- userMessagePromise = null;
- promptTokens = null;
- getAbortData = null;
- progressCallback = null;
- endpointOption = null;
- cleanupHandlers = null;
-
- if (requestDataMap.has(req)) {
- requestDataMap.delete(req);
- }
- logger.debug('[EditController] Cleanup completed');
- };
-
- try {
- ({ client } = await initializeClient({ req, res, endpointOption }));
-
- if (clientRegistry && client) {
- clientRegistry.register(client, { userId }, client);
- }
-
- if (client) {
- requestDataMap.set(req, { client });
- }
-
- clientRef = new WeakRef(client);
-
- getAbortData = () => {
- const currentClient = clientRef?.deref();
- const currentText =
- currentClient?.getStreamText != null ? currentClient.getStreamText() : getPartialText();
-
- return {
- sender,
- conversationId,
- messageId: reqDataContext.responseMessageId,
- parentMessageId: overrideParentMessageId ?? userMessageId,
- text: currentText,
- userMessage: userMessage,
- userMessagePromise: userMessagePromise,
- promptTokens: reqDataContext.promptTokens,
- };
- };
-
- const { onStart, abortController } = createAbortController(
- req,
- res,
- getAbortData,
- updateReqData,
- );
-
- const closeHandler = () => {
- logger.debug('[EditController] Request closed');
- if (!abortController || abortController.signal.aborted || abortController.requestCompleted) {
- return;
- }
- abortController.abort();
- logger.debug('[EditController] Request aborted on close');
- };
-
- res.on('close', closeHandler);
- cleanupHandlers.push(() => {
- try {
- res.removeListener('close', closeHandler);
- } catch (e) {
- // Ignore
- }
- });
-
- let response = await client.sendMessage(text, {
- user: userId,
- generation,
- isContinued,
- isEdited: true,
- conversationId,
- parentMessageId,
- responseMessageId: reqDataContext.responseMessageId,
- overrideParentMessageId,
- getReqData: updateReqData,
- onStart,
- abortController,
- progressCallback,
- progressOptions: {
- res,
- },
- });
-
- const databasePromise = response.databasePromise;
- delete response.databasePromise;
-
- const { conversation: convoData = {} } = await databasePromise;
- const conversation = { ...convoData };
- conversation.title =
- conversation && !conversation.title ? null : conversation?.title || 'New Chat';
-
- if (client?.options?.attachments && endpointOption?.modelOptions?.model) {
- conversation.model = endpointOption.modelOptions.model;
- }
-
- if (!abortController.signal.aborted) {
- const finalUserMessage = reqDataContext.userMessage;
- const finalResponseMessage = { ...response };
-
- sendEvent(res, {
- final: true,
- conversation,
- title: conversation.title,
- requestMessage: finalUserMessage,
- responseMessage: finalResponseMessage,
- });
- res.end();
-
- await saveMessage(
- req,
- { ...finalResponseMessage, user: userId },
- { context: 'api/server/controllers/EditController.js - response end' },
- );
- }
-
- performCleanup();
- } catch (error) {
- logger.error('[EditController] Error handling request', error);
- let partialText = '';
- try {
- const currentClient = clientRef?.deref();
- partialText =
- currentClient?.getStreamText != null ? currentClient.getStreamText() : getPartialText();
- } catch (getTextError) {
- logger.error('[EditController] Error calling getText() during error handling', getTextError);
- }
-
- handleAbortError(res, req, error, {
- sender,
- partialText,
- conversationId,
- messageId: reqDataContext.responseMessageId,
- parentMessageId: overrideParentMessageId ?? userMessageId ?? parentMessageId,
- userMessageId,
- })
- .catch((err) => {
- logger.error('[EditController] Error in `handleAbortError` during catch block', err);
- })
- .finally(() => {
- performCleanup();
- });
- }
-};
-
-module.exports = EditController;
diff --git a/api/server/controllers/FavoritesController.js b/api/server/controllers/FavoritesController.js
new file mode 100644
index 0000000000..186dd810bf
--- /dev/null
+++ b/api/server/controllers/FavoritesController.js
@@ -0,0 +1,99 @@
+const { updateUser, getUserById } = require('~/models');
+
+const MAX_FAVORITES = 50;
+const MAX_STRING_LENGTH = 256;
+
+const updateFavoritesController = async (req, res) => {
+ try {
+ const { favorites } = req.body;
+ const userId = req.user.id;
+
+ if (!favorites) {
+ return res.status(400).json({ message: 'Favorites data is required' });
+ }
+
+ if (!Array.isArray(favorites)) {
+ return res.status(400).json({ message: 'Favorites must be an array' });
+ }
+
+ if (favorites.length > MAX_FAVORITES) {
+ return res.status(400).json({
+ code: 'MAX_FAVORITES_EXCEEDED',
+ message: `Maximum ${MAX_FAVORITES} favorites allowed`,
+ limit: MAX_FAVORITES,
+ });
+ }
+
+ for (const fav of favorites) {
+ const hasAgent = !!fav.agentId;
+ const hasModel = !!(fav.model && fav.endpoint);
+
+ if (fav.agentId && fav.agentId.length > MAX_STRING_LENGTH) {
+ return res
+ .status(400)
+ .json({ message: `agentId exceeds maximum length of ${MAX_STRING_LENGTH}` });
+ }
+ if (fav.model && fav.model.length > MAX_STRING_LENGTH) {
+ return res
+ .status(400)
+ .json({ message: `model exceeds maximum length of ${MAX_STRING_LENGTH}` });
+ }
+ if (fav.endpoint && fav.endpoint.length > MAX_STRING_LENGTH) {
+ return res
+ .status(400)
+ .json({ message: `endpoint exceeds maximum length of ${MAX_STRING_LENGTH}` });
+ }
+
+ if (!hasAgent && !hasModel) {
+ return res.status(400).json({
+ message: 'Each favorite must have either agentId or model+endpoint',
+ });
+ }
+
+ if (hasAgent && hasModel) {
+ return res.status(400).json({
+ message: 'Favorite cannot have both agentId and model/endpoint',
+ });
+ }
+ }
+
+ const user = await updateUser(userId, { favorites });
+
+ if (!user) {
+ return res.status(404).json({ message: 'User not found' });
+ }
+
+ res.status(200).json(user.favorites);
+ } catch (error) {
+ console.error('Error updating favorites:', error);
+ res.status(500).json({ message: 'Internal server error' });
+ }
+};
+
+const getFavoritesController = async (req, res) => {
+ try {
+ const userId = req.user.id;
+ const user = await getUserById(userId, 'favorites');
+
+ if (!user) {
+ return res.status(404).json({ message: 'User not found' });
+ }
+
+ let favorites = user.favorites || [];
+
+ if (!Array.isArray(favorites)) {
+ favorites = [];
+ await updateUser(userId, { favorites: [] });
+ }
+
+ res.status(200).json(favorites);
+ } catch (error) {
+ console.error('Error fetching favorites:', error);
+ res.status(500).json({ message: 'Internal server error' });
+ }
+};
+
+module.exports = {
+ updateFavoritesController,
+ getFavoritesController,
+};
diff --git a/api/server/controllers/PermissionsController.js b/api/server/controllers/PermissionsController.js
index f44aebae7b..51993d083c 100644
--- a/api/server/controllers/PermissionsController.js
+++ b/api/server/controllers/PermissionsController.js
@@ -4,15 +4,17 @@
const mongoose = require('mongoose');
const { logger } = require('@librechat/data-schemas');
-const { ResourceType, PrincipalType } = require('librechat-data-provider');
+const { ResourceType, PrincipalType, PermissionBits } = require('librechat-data-provider');
+const { enrichRemoteAgentPrincipals, backfillRemoteAgentPermissions } = require('@librechat/api');
const {
bulkUpdateResourcePermissions,
ensureGroupPrincipalExists,
getEffectivePermissions,
ensurePrincipalExists,
getAvailableRoles,
+ findAccessibleResources,
+ getResourcePermissionsMap,
} = require('~/server/services/PermissionService');
-const { AclEntry } = require('~/db/models');
const {
searchPrincipals: searchLocalPrincipals,
sortPrincipalsByRelevance,
@@ -22,6 +24,7 @@ const {
entraIdPrincipalFeatureEnabled,
searchEntraIdPrincipals,
} = require('~/server/services/GraphApiService');
+const { AclEntry, AccessRole } = require('~/db/models');
/**
* Generic controller for resource permission endpoints
@@ -232,7 +235,7 @@ const getResourcePermissions = async (req, res) => {
},
]);
- const principals = [];
+ let principals = [];
let publicPermission = null;
// Process aggregation results
@@ -278,6 +281,13 @@ const getResourcePermissions = async (req, res) => {
}
}
+ if (resourceType === ResourceType.REMOTE_AGENT) {
+ const enricherDeps = { AclEntry, AccessRole, logger };
+ const enrichResult = await enrichRemoteAgentPrincipals(enricherDeps, resourceId, principals);
+ principals = enrichResult.principals;
+ backfillRemoteAgentPermissions(enricherDeps, resourceId, enrichResult.entriesToBackfill);
+ }
+
// Return response in format expected by frontend
const response = {
resourceType,
@@ -475,10 +485,58 @@ const searchPrincipals = async (req, res) => {
}
};
+/**
+ * Get user's effective permissions for all accessible resources of a type
+ * @route GET /api/permissions/{resourceType}/effective/all
+ */
+const getAllEffectivePermissions = async (req, res) => {
+ try {
+ const { resourceType } = req.params;
+ validateResourceType(resourceType);
+
+ const { id: userId } = req.user;
+
+ // Find all resources the user has at least VIEW access to
+ const accessibleResourceIds = await findAccessibleResources({
+ userId,
+ role: req.user.role,
+ resourceType,
+ requiredPermissions: PermissionBits.VIEW,
+ });
+
+ if (accessibleResourceIds.length === 0) {
+ return res.status(200).json({});
+ }
+
+ // Get effective permissions for all accessible resources
+ const permissionsMap = await getResourcePermissionsMap({
+ userId,
+ role: req.user.role,
+ resourceType,
+ resourceIds: accessibleResourceIds,
+ });
+
+ // Convert Map to plain object for JSON response
+ const result = {};
+ for (const [resourceId, permBits] of permissionsMap) {
+ result[resourceId] = permBits;
+ }
+
+ res.status(200).json(result);
+ } catch (error) {
+ logger.error('Error getting all effective permissions:', error);
+ res.status(500).json({
+ error: 'Failed to get all effective permissions',
+ details: error.message,
+ });
+ }
+};
+
module.exports = {
updateResourcePermissions,
getResourcePermissions,
getResourceRoles,
getUserEffectivePermissions,
+ getAllEffectivePermissions,
searchPrincipals,
};
diff --git a/api/server/controllers/PluginController.js b/api/server/controllers/PluginController.js
index c5e074b8ff..279ffb15fd 100644
--- a/api/server/controllers/PluginController.js
+++ b/api/server/controllers/PluginController.js
@@ -8,7 +8,7 @@ const { getLogStores } = require('~/cache');
const getAvailablePluginsController = async (req, res) => {
try {
- const cache = getLogStores(CacheKeys.CONFIG_STORE);
+ const cache = getLogStores(CacheKeys.TOOL_CACHE);
const cachedPlugins = await cache.get(CacheKeys.PLUGINS);
if (cachedPlugins) {
res.status(200).json(cachedPlugins);
@@ -63,7 +63,7 @@ const getAvailableTools = async (req, res) => {
logger.warn('[getAvailableTools] User ID not found in request');
return res.status(401).json({ message: 'Unauthorized' });
}
- const cache = getLogStores(CacheKeys.CONFIG_STORE);
+ const cache = getLogStores(CacheKeys.TOOL_CACHE);
const cachedToolsArray = await cache.get(CacheKeys.TOOLS);
const appConfig = req.config ?? (await getAppConfig({ role: req.user?.role }));
diff --git a/api/server/controllers/PluginController.spec.js b/api/server/controllers/PluginController.spec.js
index d7d3f83a8b..06a51a3bd6 100644
--- a/api/server/controllers/PluginController.spec.js
+++ b/api/server/controllers/PluginController.spec.js
@@ -1,3 +1,4 @@
+const { CacheKeys } = require('librechat-data-provider');
const { getCachedTools, getAppConfig } = require('~/server/services/Config');
const { getLogStores } = require('~/cache');
@@ -63,6 +64,28 @@ describe('PluginController', () => {
});
});
+ describe('cache namespace', () => {
+ it('getAvailablePluginsController should use TOOL_CACHE namespace', async () => {
+ mockCache.get.mockResolvedValue([]);
+ await getAvailablePluginsController(mockReq, mockRes);
+ expect(getLogStores).toHaveBeenCalledWith(CacheKeys.TOOL_CACHE);
+ });
+
+ it('getAvailableTools should use TOOL_CACHE namespace', async () => {
+ mockCache.get.mockResolvedValue([]);
+ await getAvailableTools(mockReq, mockRes);
+ expect(getLogStores).toHaveBeenCalledWith(CacheKeys.TOOL_CACHE);
+ });
+
+ it('should NOT use CONFIG_STORE namespace for tool/plugin operations', async () => {
+ mockCache.get.mockResolvedValue([]);
+ await getAvailablePluginsController(mockReq, mockRes);
+ await getAvailableTools(mockReq, mockRes);
+ const allCalls = getLogStores.mock.calls.flat();
+ expect(allCalls).not.toContain(CacheKeys.CONFIG_STORE);
+ });
+ });
+
describe('getAvailablePluginsController', () => {
it('should use filterUniquePlugins to remove duplicate plugins', async () => {
// Add plugins with duplicates to availableTools
diff --git a/api/server/controllers/TwoFactorController.js b/api/server/controllers/TwoFactorController.js
index 9ef2718108..fde5965261 100644
--- a/api/server/controllers/TwoFactorController.js
+++ b/api/server/controllers/TwoFactorController.js
@@ -1,11 +1,10 @@
-const { encryptV3 } = require('@librechat/api');
-const { logger } = require('@librechat/data-schemas');
+const { encryptV3, logger } = require('@librechat/data-schemas');
const {
- verifyTOTP,
- getTOTPSecret,
- verifyBackupCode,
- generateTOTPSecret,
generateBackupCodes,
+ generateTOTPSecret,
+ verifyBackupCode,
+ getTOTPSecret,
+ verifyTOTP,
} = require('~/server/services/twoFactorService');
const { getUserById, updateUser } = require('~/models');
diff --git a/api/server/controllers/UserController.js b/api/server/controllers/UserController.js
index 9bdf6c5e28..7a9dd8125e 100644
--- a/api/server/controllers/UserController.js
+++ b/api/server/controllers/UserController.js
@@ -3,16 +3,17 @@ const { Tools, CacheKeys, Constants, FileSources } = require('librechat-data-pro
const {
MCPOAuthHandler,
MCPTokenStorage,
- mcpServersRegistry,
normalizeHttpError,
extractWebSearchEnvVars,
} = require('@librechat/api');
const {
deleteAllUserSessions,
deleteAllSharedLinks,
+ updateUserPlugins,
deleteUserById,
deleteMessages,
deletePresets,
+ deleteUserKey,
deleteConvos,
deleteFiles,
updateUser,
@@ -21,6 +22,7 @@ const {
} = require('~/models');
const {
ConversationTag,
+ AgentApiKey,
Transaction,
MemoryEntry,
Assistant,
@@ -32,11 +34,11 @@ const {
User,
} = require('~/db/models');
const { updateUserPluginAuth, deleteUserPluginAuth } = require('~/server/services/PluginService');
-const { updateUserPluginsService, deleteUserKey } = require('~/server/services/UserService');
const { verifyEmail, resendVerificationEmail } = require('~/server/services/AuthService');
+const { getMCPManager, getFlowStateManager, getMCPServersRegistry } = require('~/config');
+const { invalidateCachedTools } = require('~/server/services/Config/getCachedTools');
const { needsRefresh, getNewS3URL } = require('~/server/services/Files/S3/crud');
const { processDeleteRequest } = require('~/server/services/Files/process');
-const { getMCPManager, getFlowStateManager } = require('~/config');
const { getAppConfig } = require('~/server/services/Config');
const { deleteToolCalls } = require('~/models/ToolCall');
const { deleteUserPrompts } = require('~/models/Prompt');
@@ -115,13 +117,7 @@ const updateUserPluginsController = async (req, res) => {
const { pluginKey, action, auth, isEntityTool } = req.body;
try {
if (!isEntityTool) {
- const userPluginsService = await updateUserPluginsService(user, pluginKey, action);
-
- if (userPluginsService instanceof Error) {
- logger.error('[userPluginsService]', userPluginsService);
- const { status, message } = normalizeHttpError(userPluginsService);
- return res.status(status).send({ message });
- }
+ await updateUserPlugins(user._id, user.plugins, pluginKey, action);
}
if (auth == null) {
@@ -220,6 +216,7 @@ const updateUserPluginsController = async (req, res) => {
`[updateUserPluginsController] Attempting disconnect of MCP server "${serverName}" for user ${user.id} after plugin auth update.`,
);
await mcpManager.disconnectUserConnection(user.id, serverName);
+ await invalidateCachedTools({ userId: user.id, serverName });
}
} catch (disconnectError) {
logger.error(
@@ -262,6 +259,7 @@ const deleteUserController = async (req, res) => {
await deleteFiles(null, user.id); // delete database files in case of orphaned files from previous steps
await deleteToolCalls(user.id); // delete user tool calls
await deleteUserAgents(user.id); // delete user agents
+ await AgentApiKey.deleteMany({ user: user._id }); // delete user agent API keys
await Assistant.deleteMany({ user: user.id }); // delete user assistants
await ConversationTag.deleteMany({ user: user.id }); // delete user conversation tags
await MemoryEntry.deleteMany({ userId: user.id }); // delete user memory entries
@@ -321,9 +319,9 @@ const maybeUninstallOAuthMCP = async (userId, pluginKey, appConfig) => {
const serverName = pluginKey.replace(Constants.mcp_prefix, '');
const serverConfig =
- (await mcpServersRegistry.getServerConfig(serverName, userId)) ??
+ (await getMCPServersRegistry().getServerConfig(serverName, userId)) ??
appConfig?.mcpServers?.[serverName];
- const oauthServers = await mcpServersRegistry.getOAuthServers();
+ const oauthServers = await getMCPServersRegistry().getOAuthServers(userId);
if (!oauthServers.has(serverName)) {
// this server does not use OAuth, so nothing to do here as well
return;
diff --git a/api/server/controllers/agents/__tests__/callbacks.spec.js b/api/server/controllers/agents/__tests__/callbacks.spec.js
index 25f00bab8d..8bd711f9c6 100644
--- a/api/server/controllers/agents/__tests__/callbacks.spec.js
+++ b/api/server/controllers/agents/__tests__/callbacks.spec.js
@@ -16,13 +16,10 @@ jest.mock('@librechat/data-schemas', () => ({
}));
jest.mock('@librechat/agents', () => ({
- EnvVar: { CODE_API_KEY: 'CODE_API_KEY' },
- Providers: { GOOGLE: 'google' },
- GraphEvents: {},
+ ...jest.requireActual('@librechat/agents'),
getMessageId: jest.fn(),
ToolEndHandler: jest.fn(),
handleToolCalls: jest.fn(),
- ChatModelStreamHandler: jest.fn(),
}));
jest.mock('~/server/services/Files/Citations', () => ({
@@ -73,10 +70,10 @@ describe('createToolEndCallback', () => {
tool_call_id: 'tool123',
artifact: {
[Tools.ui_resources]: {
- data: {
- 0: { type: 'button', label: 'Click me' },
- 1: { type: 'input', placeholder: 'Enter text' },
- },
+ data: [
+ { type: 'button', label: 'Click me' },
+ { type: 'input', placeholder: 'Enter text' },
+ ],
},
},
};
@@ -100,10 +97,10 @@ describe('createToolEndCallback', () => {
messageId: 'run456',
toolCallId: 'tool123',
conversationId: 'thread789',
- [Tools.ui_resources]: {
- 0: { type: 'button', label: 'Click me' },
- 1: { type: 'input', placeholder: 'Enter text' },
- },
+ [Tools.ui_resources]: [
+ { type: 'button', label: 'Click me' },
+ { type: 'input', placeholder: 'Enter text' },
+ ],
});
});
@@ -115,9 +112,7 @@ describe('createToolEndCallback', () => {
tool_call_id: 'tool123',
artifact: {
[Tools.ui_resources]: {
- data: {
- 0: { type: 'carousel', items: [] },
- },
+ data: [{ type: 'carousel', items: [] }],
},
},
};
@@ -136,9 +131,7 @@ describe('createToolEndCallback', () => {
messageId: 'run456',
toolCallId: 'tool123',
conversationId: 'thread789',
- [Tools.ui_resources]: {
- 0: { type: 'carousel', items: [] },
- },
+ [Tools.ui_resources]: [{ type: 'carousel', items: [] }],
});
});
@@ -155,9 +148,7 @@ describe('createToolEndCallback', () => {
tool_call_id: 'tool123',
artifact: {
[Tools.ui_resources]: {
- data: {
- 0: { type: 'test' },
- },
+ data: [{ type: 'test' }],
},
},
};
@@ -184,9 +175,7 @@ describe('createToolEndCallback', () => {
tool_call_id: 'tool123',
artifact: {
[Tools.ui_resources]: {
- data: {
- 0: { type: 'chart', data: [] },
- },
+ data: [{ type: 'chart', data: [] }],
},
[Tools.web_search]: {
results: ['result1', 'result2'],
@@ -209,9 +198,7 @@ describe('createToolEndCallback', () => {
// Check ui_resources attachment
const uiResourceAttachment = results.find((r) => r?.type === Tools.ui_resources);
expect(uiResourceAttachment).toBeTruthy();
- expect(uiResourceAttachment[Tools.ui_resources]).toEqual({
- 0: { type: 'chart', data: [] },
- });
+ expect(uiResourceAttachment[Tools.ui_resources]).toEqual([{ type: 'chart', data: [] }]);
// Check web_search attachment
const webSearchAttachment = results.find((r) => r?.type === Tools.web_search);
@@ -250,7 +237,7 @@ describe('createToolEndCallback', () => {
tool_call_id: 'tool123',
artifact: {
[Tools.ui_resources]: {
- data: {},
+ data: [],
},
},
};
@@ -268,7 +255,7 @@ describe('createToolEndCallback', () => {
messageId: 'run456',
toolCallId: 'tool123',
conversationId: 'thread789',
- [Tools.ui_resources]: {},
+ [Tools.ui_resources]: [],
});
});
diff --git a/api/server/controllers/agents/__tests__/jobReplacement.spec.js b/api/server/controllers/agents/__tests__/jobReplacement.spec.js
new file mode 100644
index 0000000000..efa79ca4ba
--- /dev/null
+++ b/api/server/controllers/agents/__tests__/jobReplacement.spec.js
@@ -0,0 +1,281 @@
+/**
+ * Tests for job replacement detection in ResumableAgentController
+ *
+ * Tests the following fixes from PR #11462:
+ * 1. Job creation timestamp tracking
+ * 2. Stale job detection and event skipping
+ * 3. Response message saving before final event emission
+ */
+
+const mockLogger = {
+ debug: jest.fn(),
+ warn: jest.fn(),
+ error: jest.fn(),
+ info: jest.fn(),
+};
+
+const mockGenerationJobManager = {
+ createJob: jest.fn(),
+ getJob: jest.fn(),
+ emitDone: jest.fn(),
+ emitChunk: jest.fn(),
+ completeJob: jest.fn(),
+ updateMetadata: jest.fn(),
+ setContentParts: jest.fn(),
+ subscribe: jest.fn(),
+};
+
+const mockSaveMessage = jest.fn();
+const mockDecrementPendingRequest = jest.fn();
+
+jest.mock('@librechat/data-schemas', () => ({
+ logger: mockLogger,
+}));
+
+jest.mock('@librechat/api', () => ({
+ isEnabled: jest.fn().mockReturnValue(false),
+ GenerationJobManager: mockGenerationJobManager,
+ checkAndIncrementPendingRequest: jest.fn().mockResolvedValue({ allowed: true }),
+ decrementPendingRequest: (...args) => mockDecrementPendingRequest(...args),
+ getViolationInfo: jest.fn(),
+ sanitizeMessageForTransmit: jest.fn((msg) => msg),
+ sanitizeFileForTransmit: jest.fn((file) => file),
+ Constants: { NO_PARENT: '00000000-0000-0000-0000-000000000000' },
+}));
+
+jest.mock('~/models', () => ({
+ saveMessage: (...args) => mockSaveMessage(...args),
+}));
+
+describe('Job Replacement Detection', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('Job Creation Timestamp Tracking', () => {
+ it('should capture createdAt when job is created', async () => {
+ const streamId = 'test-stream-123';
+ const createdAt = Date.now();
+
+ mockGenerationJobManager.createJob.mockResolvedValue({
+ createdAt,
+ readyPromise: Promise.resolve(),
+ abortController: new AbortController(),
+ emitter: { on: jest.fn() },
+ });
+
+ const job = await mockGenerationJobManager.createJob(streamId, 'user-123', streamId);
+
+ expect(job.createdAt).toBe(createdAt);
+ });
+ });
+
+ describe('Job Replacement Detection Logic', () => {
+ /**
+ * Simulates the job replacement detection logic from request.js
+ * This is extracted for unit testing since the full controller is complex
+ */
+ const detectJobReplacement = async (streamId, originalCreatedAt) => {
+ const currentJob = await mockGenerationJobManager.getJob(streamId);
+ return !currentJob || currentJob.createdAt !== originalCreatedAt;
+ };
+
+ it('should detect when job was replaced (different createdAt)', async () => {
+ const streamId = 'test-stream-123';
+ const originalCreatedAt = 1000;
+ const newCreatedAt = 2000;
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ createdAt: newCreatedAt,
+ });
+
+ const wasReplaced = await detectJobReplacement(streamId, originalCreatedAt);
+
+ expect(wasReplaced).toBe(true);
+ });
+
+ it('should detect when job was deleted', async () => {
+ const streamId = 'test-stream-123';
+ const originalCreatedAt = 1000;
+
+ mockGenerationJobManager.getJob.mockResolvedValue(null);
+
+ const wasReplaced = await detectJobReplacement(streamId, originalCreatedAt);
+
+ expect(wasReplaced).toBe(true);
+ });
+
+ it('should not detect replacement when same job (same createdAt)', async () => {
+ const streamId = 'test-stream-123';
+ const originalCreatedAt = 1000;
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ createdAt: originalCreatedAt,
+ });
+
+ const wasReplaced = await detectJobReplacement(streamId, originalCreatedAt);
+
+ expect(wasReplaced).toBe(false);
+ });
+ });
+
+ describe('Event Emission Behavior', () => {
+ /**
+ * Simulates the final event emission logic from request.js
+ */
+ const emitFinalEventIfNotReplaced = async ({
+ streamId,
+ originalCreatedAt,
+ finalEvent,
+ userId,
+ }) => {
+ const currentJob = await mockGenerationJobManager.getJob(streamId);
+ const jobWasReplaced = !currentJob || currentJob.createdAt !== originalCreatedAt;
+
+ if (jobWasReplaced) {
+ mockLogger.debug('Skipping FINAL emit - job was replaced', {
+ streamId,
+ originalCreatedAt,
+ currentCreatedAt: currentJob?.createdAt,
+ });
+ await mockDecrementPendingRequest(userId);
+ return false;
+ }
+
+ mockGenerationJobManager.emitDone(streamId, finalEvent);
+ mockGenerationJobManager.completeJob(streamId);
+ await mockDecrementPendingRequest(userId);
+ return true;
+ };
+
+ it('should skip emitting when job was replaced', async () => {
+ const streamId = 'test-stream-123';
+ const originalCreatedAt = 1000;
+ const newCreatedAt = 2000;
+ const userId = 'user-123';
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ createdAt: newCreatedAt,
+ });
+
+ const emitted = await emitFinalEventIfNotReplaced({
+ streamId,
+ originalCreatedAt,
+ finalEvent: { final: true },
+ userId,
+ });
+
+ expect(emitted).toBe(false);
+ expect(mockGenerationJobManager.emitDone).not.toHaveBeenCalled();
+ expect(mockGenerationJobManager.completeJob).not.toHaveBeenCalled();
+ expect(mockDecrementPendingRequest).toHaveBeenCalledWith(userId);
+ expect(mockLogger.debug).toHaveBeenCalledWith(
+ 'Skipping FINAL emit - job was replaced',
+ expect.objectContaining({
+ streamId,
+ originalCreatedAt,
+ currentCreatedAt: newCreatedAt,
+ }),
+ );
+ });
+
+ it('should emit when job was not replaced', async () => {
+ const streamId = 'test-stream-123';
+ const originalCreatedAt = 1000;
+ const userId = 'user-123';
+ const finalEvent = { final: true, conversation: { conversationId: streamId } };
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ createdAt: originalCreatedAt,
+ });
+
+ const emitted = await emitFinalEventIfNotReplaced({
+ streamId,
+ originalCreatedAt,
+ finalEvent,
+ userId,
+ });
+
+ expect(emitted).toBe(true);
+ expect(mockGenerationJobManager.emitDone).toHaveBeenCalledWith(streamId, finalEvent);
+ expect(mockGenerationJobManager.completeJob).toHaveBeenCalledWith(streamId);
+ expect(mockDecrementPendingRequest).toHaveBeenCalledWith(userId);
+ });
+ });
+
+ describe('Response Message Saving Order', () => {
+ /**
+ * Tests that response messages are saved BEFORE final events are emitted
+ * This prevents race conditions where clients send follow-up messages
+ * before the response is in the database
+ */
+ it('should save message before emitting final event', async () => {
+ const callOrder = [];
+
+ mockSaveMessage.mockImplementation(async () => {
+ callOrder.push('saveMessage');
+ });
+
+ mockGenerationJobManager.emitDone.mockImplementation(() => {
+ callOrder.push('emitDone');
+ });
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ createdAt: 1000,
+ });
+
+ // Simulate the order of operations from request.js
+ const streamId = 'test-stream-123';
+ const originalCreatedAt = 1000;
+ const response = { messageId: 'response-123' };
+ const userId = 'user-123';
+
+ // Step 1: Save message
+ await mockSaveMessage({}, { ...response, user: userId }, { context: 'test' });
+
+ // Step 2: Check for replacement
+ const currentJob = await mockGenerationJobManager.getJob(streamId);
+ const jobWasReplaced = !currentJob || currentJob.createdAt !== originalCreatedAt;
+
+ // Step 3: Emit if not replaced
+ if (!jobWasReplaced) {
+ mockGenerationJobManager.emitDone(streamId, { final: true });
+ }
+
+ expect(callOrder).toEqual(['saveMessage', 'emitDone']);
+ });
+ });
+
+ describe('Aborted Request Handling', () => {
+ it('should use unfinished: true instead of error: true for aborted requests', () => {
+ const response = { messageId: 'response-123', content: [] };
+
+ // The new format for aborted responses
+ const abortedResponse = { ...response, unfinished: true };
+
+ expect(abortedResponse.unfinished).toBe(true);
+ expect(abortedResponse.error).toBeUndefined();
+ });
+
+ it('should include unfinished flag in final event for aborted requests', () => {
+ const response = { messageId: 'response-123', content: [] };
+
+ // Old format (deprecated)
+ const _oldFinalEvent = {
+ final: true,
+ responseMessage: { ...response, error: true },
+ error: { message: 'Request was aborted' },
+ };
+
+ // New format (PR #11462)
+ const newFinalEvent = {
+ final: true,
+ responseMessage: { ...response, unfinished: true },
+ };
+
+ expect(newFinalEvent.responseMessage.unfinished).toBe(true);
+ expect(newFinalEvent.error).toBeUndefined();
+ expect(newFinalEvent.responseMessage.error).toBeUndefined();
+ });
+ });
+});
diff --git a/api/server/controllers/agents/__tests__/openai.spec.js b/api/server/controllers/agents/__tests__/openai.spec.js
new file mode 100644
index 0000000000..8592c79a2d
--- /dev/null
+++ b/api/server/controllers/agents/__tests__/openai.spec.js
@@ -0,0 +1,204 @@
+/**
+ * Unit tests for OpenAI-compatible API controller
+ * Tests that recordCollectedUsage is called correctly for token spending
+ */
+
+const mockSpendTokens = jest.fn().mockResolvedValue({});
+const mockSpendStructuredTokens = jest.fn().mockResolvedValue({});
+const mockRecordCollectedUsage = jest
+ .fn()
+ .mockResolvedValue({ input_tokens: 100, output_tokens: 50 });
+const mockGetBalanceConfig = jest.fn().mockReturnValue({ enabled: true });
+const mockGetTransactionsConfig = jest.fn().mockReturnValue({ enabled: true });
+
+jest.mock('nanoid', () => ({
+ nanoid: jest.fn(() => 'mock-nanoid-123'),
+}));
+
+jest.mock('@librechat/data-schemas', () => ({
+ logger: {
+ debug: jest.fn(),
+ error: jest.fn(),
+ warn: jest.fn(),
+ },
+}));
+
+jest.mock('@librechat/agents', () => ({
+ Callback: { TOOL_ERROR: 'TOOL_ERROR' },
+ ToolEndHandler: jest.fn(),
+ formatAgentMessages: jest.fn().mockReturnValue({
+ messages: [],
+ indexTokenCountMap: {},
+ }),
+}));
+
+jest.mock('@librechat/api', () => ({
+ writeSSE: jest.fn(),
+ createRun: jest.fn().mockResolvedValue({
+ processStream: jest.fn().mockResolvedValue(undefined),
+ }),
+ createChunk: jest.fn().mockReturnValue({}),
+ buildToolSet: jest.fn().mockReturnValue(new Set()),
+ sendFinalChunk: jest.fn(),
+ createSafeUser: jest.fn().mockReturnValue({ id: 'user-123' }),
+ validateRequest: jest
+ .fn()
+ .mockReturnValue({ request: { model: 'agent-123', messages: [], stream: false } }),
+ initializeAgent: jest.fn().mockResolvedValue({
+ model: 'gpt-4',
+ model_parameters: {},
+ toolRegistry: {},
+ }),
+ getBalanceConfig: mockGetBalanceConfig,
+ createErrorResponse: jest.fn(),
+ getTransactionsConfig: mockGetTransactionsConfig,
+ recordCollectedUsage: mockRecordCollectedUsage,
+ buildNonStreamingResponse: jest.fn().mockReturnValue({ id: 'resp-123' }),
+ createOpenAIStreamTracker: jest.fn().mockReturnValue({
+ addText: jest.fn(),
+ addReasoning: jest.fn(),
+ toolCalls: new Map(),
+ usage: { promptTokens: 0, completionTokens: 0, reasoningTokens: 0 },
+ }),
+ createOpenAIContentAggregator: jest.fn().mockReturnValue({
+ addText: jest.fn(),
+ addReasoning: jest.fn(),
+ getText: jest.fn().mockReturnValue(''),
+ getReasoning: jest.fn().mockReturnValue(''),
+ toolCalls: new Map(),
+ usage: { promptTokens: 100, completionTokens: 50, reasoningTokens: 0 },
+ }),
+ createToolExecuteHandler: jest.fn().mockReturnValue({ handle: jest.fn() }),
+ isChatCompletionValidationFailure: jest.fn().mockReturnValue(false),
+}));
+
+jest.mock('~/server/services/ToolService', () => ({
+ loadAgentTools: jest.fn().mockResolvedValue([]),
+ loadToolsForExecution: jest.fn().mockResolvedValue([]),
+}));
+
+jest.mock('~/models/spendTokens', () => ({
+ spendTokens: mockSpendTokens,
+ spendStructuredTokens: mockSpendStructuredTokens,
+}));
+
+jest.mock('~/server/controllers/agents/callbacks', () => ({
+ createToolEndCallback: jest.fn().mockReturnValue(jest.fn()),
+}));
+
+jest.mock('~/server/services/PermissionService', () => ({
+ findAccessibleResources: jest.fn().mockResolvedValue([]),
+}));
+
+jest.mock('~/models/Conversation', () => ({
+ getConvoFiles: jest.fn().mockResolvedValue([]),
+}));
+
+jest.mock('~/models/Agent', () => ({
+ getAgent: jest.fn().mockResolvedValue({
+ id: 'agent-123',
+ provider: 'openAI',
+ model_parameters: { model: 'gpt-4' },
+ }),
+ getAgents: jest.fn().mockResolvedValue([]),
+}));
+
+jest.mock('~/models', () => ({
+ getFiles: jest.fn(),
+ getUserKey: jest.fn(),
+ getMessages: jest.fn(),
+ updateFilesUsage: jest.fn(),
+ getUserKeyValues: jest.fn(),
+ getUserCodeFiles: jest.fn(),
+ getToolFilesByIds: jest.fn(),
+ getCodeGeneratedFiles: jest.fn(),
+}));
+
+describe('OpenAIChatCompletionController', () => {
+ let OpenAIChatCompletionController;
+ let req, res;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ const controller = require('../openai');
+ OpenAIChatCompletionController = controller.OpenAIChatCompletionController;
+
+ req = {
+ body: {
+ model: 'agent-123',
+ messages: [{ role: 'user', content: 'Hello' }],
+ stream: false,
+ },
+ user: { id: 'user-123' },
+ config: {
+ endpoints: {
+ agents: { allowedProviders: ['openAI'] },
+ },
+ },
+ on: jest.fn(),
+ };
+
+ res = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn(),
+ setHeader: jest.fn(),
+ flushHeaders: jest.fn(),
+ end: jest.fn(),
+ write: jest.fn(),
+ };
+ });
+
+ describe('token usage recording', () => {
+ it('should call recordCollectedUsage after successful non-streaming completion', async () => {
+ await OpenAIChatCompletionController(req, res);
+
+ expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
+ { spendTokens: mockSpendTokens, spendStructuredTokens: mockSpendStructuredTokens },
+ expect.objectContaining({
+ user: 'user-123',
+ conversationId: expect.any(String),
+ collectedUsage: expect.any(Array),
+ context: 'message',
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ }),
+ );
+ });
+
+ it('should pass balance and transactions config to recordCollectedUsage', async () => {
+ mockGetBalanceConfig.mockReturnValue({ enabled: true, startBalance: 1000 });
+ mockGetTransactionsConfig.mockReturnValue({ enabled: true, rateLimit: 100 });
+
+ await OpenAIChatCompletionController(req, res);
+
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
+ expect.any(Object),
+ expect.objectContaining({
+ balance: { enabled: true, startBalance: 1000 },
+ transactions: { enabled: true, rateLimit: 100 },
+ }),
+ );
+ });
+
+ it('should pass spendTokens and spendStructuredTokens as dependencies', async () => {
+ await OpenAIChatCompletionController(req, res);
+
+ const [deps] = mockRecordCollectedUsage.mock.calls[0];
+ expect(deps).toHaveProperty('spendTokens', mockSpendTokens);
+ expect(deps).toHaveProperty('spendStructuredTokens', mockSpendStructuredTokens);
+ });
+
+ it('should include model from primaryConfig in recordCollectedUsage params', async () => {
+ await OpenAIChatCompletionController(req, res);
+
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
+ expect.any(Object),
+ expect.objectContaining({
+ model: 'gpt-4',
+ }),
+ );
+ });
+ });
+});
diff --git a/api/server/controllers/agents/__tests__/responses.unit.spec.js b/api/server/controllers/agents/__tests__/responses.unit.spec.js
new file mode 100644
index 0000000000..e16ca394b2
--- /dev/null
+++ b/api/server/controllers/agents/__tests__/responses.unit.spec.js
@@ -0,0 +1,312 @@
+/**
+ * Unit tests for Open Responses API controller
+ * Tests that recordCollectedUsage is called correctly for token spending
+ */
+
+const mockSpendTokens = jest.fn().mockResolvedValue({});
+const mockSpendStructuredTokens = jest.fn().mockResolvedValue({});
+const mockRecordCollectedUsage = jest
+ .fn()
+ .mockResolvedValue({ input_tokens: 100, output_tokens: 50 });
+const mockGetBalanceConfig = jest.fn().mockReturnValue({ enabled: true });
+const mockGetTransactionsConfig = jest.fn().mockReturnValue({ enabled: true });
+
+jest.mock('nanoid', () => ({
+ nanoid: jest.fn(() => 'mock-nanoid-123'),
+}));
+
+jest.mock('uuid', () => ({
+ v4: jest.fn(() => 'mock-uuid-456'),
+}));
+
+jest.mock('@librechat/data-schemas', () => ({
+ logger: {
+ debug: jest.fn(),
+ error: jest.fn(),
+ warn: jest.fn(),
+ },
+}));
+
+jest.mock('@librechat/agents', () => ({
+ Callback: { TOOL_ERROR: 'TOOL_ERROR' },
+ ToolEndHandler: jest.fn(),
+ formatAgentMessages: jest.fn().mockReturnValue({
+ messages: [],
+ indexTokenCountMap: {},
+ }),
+}));
+
+jest.mock('@librechat/api', () => ({
+ createRun: jest.fn().mockResolvedValue({
+ processStream: jest.fn().mockResolvedValue(undefined),
+ }),
+ buildToolSet: jest.fn().mockReturnValue(new Set()),
+ createSafeUser: jest.fn().mockReturnValue({ id: 'user-123' }),
+ initializeAgent: jest.fn().mockResolvedValue({
+ model: 'claude-3',
+ model_parameters: {},
+ toolRegistry: {},
+ }),
+ getBalanceConfig: mockGetBalanceConfig,
+ getTransactionsConfig: mockGetTransactionsConfig,
+ recordCollectedUsage: mockRecordCollectedUsage,
+ createToolExecuteHandler: jest.fn().mockReturnValue({ handle: jest.fn() }),
+ // Responses API
+ writeDone: jest.fn(),
+ buildResponse: jest.fn().mockReturnValue({ id: 'resp_123', output: [] }),
+ generateResponseId: jest.fn().mockReturnValue('resp_mock-123'),
+ isValidationFailure: jest.fn().mockReturnValue(false),
+ emitResponseCreated: jest.fn(),
+ createResponseContext: jest.fn().mockReturnValue({ responseId: 'resp_123' }),
+ createResponseTracker: jest.fn().mockReturnValue({
+ usage: { promptTokens: 100, completionTokens: 50 },
+ }),
+ setupStreamingResponse: jest.fn(),
+ emitResponseInProgress: jest.fn(),
+ convertInputToMessages: jest.fn().mockReturnValue([]),
+ validateResponseRequest: jest.fn().mockReturnValue({
+ request: { model: 'agent-123', input: 'Hello', stream: false },
+ }),
+ buildAggregatedResponse: jest.fn().mockReturnValue({
+ id: 'resp_123',
+ status: 'completed',
+ output: [],
+ usage: { input_tokens: 100, output_tokens: 50, total_tokens: 150 },
+ }),
+ createResponseAggregator: jest.fn().mockReturnValue({
+ usage: { promptTokens: 100, completionTokens: 50 },
+ }),
+ sendResponsesErrorResponse: jest.fn(),
+ createResponsesEventHandlers: jest.fn().mockReturnValue({
+ handlers: {
+ on_message_delta: { handle: jest.fn() },
+ on_reasoning_delta: { handle: jest.fn() },
+ on_run_step: { handle: jest.fn() },
+ on_run_step_delta: { handle: jest.fn() },
+ on_chat_model_end: { handle: jest.fn() },
+ },
+ finalizeStream: jest.fn(),
+ }),
+ createAggregatorEventHandlers: jest.fn().mockReturnValue({
+ on_message_delta: { handle: jest.fn() },
+ on_reasoning_delta: { handle: jest.fn() },
+ on_run_step: { handle: jest.fn() },
+ on_run_step_delta: { handle: jest.fn() },
+ on_chat_model_end: { handle: jest.fn() },
+ }),
+}));
+
+jest.mock('~/server/services/ToolService', () => ({
+ loadAgentTools: jest.fn().mockResolvedValue([]),
+ loadToolsForExecution: jest.fn().mockResolvedValue([]),
+}));
+
+jest.mock('~/models/spendTokens', () => ({
+ spendTokens: mockSpendTokens,
+ spendStructuredTokens: mockSpendStructuredTokens,
+}));
+
+jest.mock('~/server/controllers/agents/callbacks', () => ({
+ createToolEndCallback: jest.fn().mockReturnValue(jest.fn()),
+ createResponsesToolEndCallback: jest.fn().mockReturnValue(jest.fn()),
+}));
+
+jest.mock('~/server/services/PermissionService', () => ({
+ findAccessibleResources: jest.fn().mockResolvedValue([]),
+}));
+
+jest.mock('~/models/Conversation', () => ({
+ getConvoFiles: jest.fn().mockResolvedValue([]),
+ saveConvo: jest.fn().mockResolvedValue({}),
+ getConvo: jest.fn().mockResolvedValue(null),
+}));
+
+jest.mock('~/models/Agent', () => ({
+ getAgent: jest.fn().mockResolvedValue({
+ id: 'agent-123',
+ name: 'Test Agent',
+ provider: 'anthropic',
+ model_parameters: { model: 'claude-3' },
+ }),
+ getAgents: jest.fn().mockResolvedValue([]),
+}));
+
+jest.mock('~/models', () => ({
+ getFiles: jest.fn(),
+ getUserKey: jest.fn(),
+ getMessages: jest.fn().mockResolvedValue([]),
+ saveMessage: jest.fn().mockResolvedValue({}),
+ updateFilesUsage: jest.fn(),
+ getUserKeyValues: jest.fn(),
+ getUserCodeFiles: jest.fn(),
+ getToolFilesByIds: jest.fn(),
+ getCodeGeneratedFiles: jest.fn(),
+}));
+
+describe('createResponse controller', () => {
+ let createResponse;
+ let req, res;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ const controller = require('../responses');
+ createResponse = controller.createResponse;
+
+ req = {
+ body: {
+ model: 'agent-123',
+ input: 'Hello',
+ stream: false,
+ },
+ user: { id: 'user-123' },
+ config: {
+ endpoints: {
+ agents: { allowedProviders: ['anthropic'] },
+ },
+ },
+ on: jest.fn(),
+ };
+
+ res = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn(),
+ setHeader: jest.fn(),
+ flushHeaders: jest.fn(),
+ end: jest.fn(),
+ write: jest.fn(),
+ };
+ });
+
+ describe('token usage recording - non-streaming', () => {
+ it('should call recordCollectedUsage after successful non-streaming completion', async () => {
+ await createResponse(req, res);
+
+ expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
+ { spendTokens: mockSpendTokens, spendStructuredTokens: mockSpendStructuredTokens },
+ expect.objectContaining({
+ user: 'user-123',
+ conversationId: expect.any(String),
+ collectedUsage: expect.any(Array),
+ context: 'message',
+ }),
+ );
+ });
+
+ it('should pass balance and transactions config to recordCollectedUsage', async () => {
+ mockGetBalanceConfig.mockReturnValue({ enabled: true, startBalance: 2000 });
+ mockGetTransactionsConfig.mockReturnValue({ enabled: true });
+
+ await createResponse(req, res);
+
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
+ expect.any(Object),
+ expect.objectContaining({
+ balance: { enabled: true, startBalance: 2000 },
+ transactions: { enabled: true },
+ }),
+ );
+ });
+
+ it('should pass spendTokens and spendStructuredTokens as dependencies', async () => {
+ await createResponse(req, res);
+
+ const [deps] = mockRecordCollectedUsage.mock.calls[0];
+ expect(deps).toHaveProperty('spendTokens', mockSpendTokens);
+ expect(deps).toHaveProperty('spendStructuredTokens', mockSpendStructuredTokens);
+ });
+
+ it('should include model from primaryConfig in recordCollectedUsage params', async () => {
+ await createResponse(req, res);
+
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
+ expect.any(Object),
+ expect.objectContaining({
+ model: 'claude-3',
+ }),
+ );
+ });
+ });
+
+ describe('token usage recording - streaming', () => {
+ beforeEach(() => {
+ req.body.stream = true;
+
+ const api = require('@librechat/api');
+ api.validateResponseRequest.mockReturnValue({
+ request: { model: 'agent-123', input: 'Hello', stream: true },
+ });
+ });
+
+ it('should call recordCollectedUsage after successful streaming completion', async () => {
+ await createResponse(req, res);
+
+ expect(mockRecordCollectedUsage).toHaveBeenCalledTimes(1);
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
+ { spendTokens: mockSpendTokens, spendStructuredTokens: mockSpendStructuredTokens },
+ expect.objectContaining({
+ user: 'user-123',
+ context: 'message',
+ }),
+ );
+ });
+ });
+
+ describe('collectedUsage population', () => {
+ it('should collect usage from on_chat_model_end events', async () => {
+ const api = require('@librechat/api');
+
+ let capturedOnChatModelEnd;
+ api.createAggregatorEventHandlers.mockImplementation(() => {
+ return {
+ on_message_delta: { handle: jest.fn() },
+ on_reasoning_delta: { handle: jest.fn() },
+ on_run_step: { handle: jest.fn() },
+ on_run_step_delta: { handle: jest.fn() },
+ on_chat_model_end: {
+ handle: jest.fn((event, data) => {
+ if (capturedOnChatModelEnd) {
+ capturedOnChatModelEnd(event, data);
+ }
+ }),
+ },
+ };
+ });
+
+ api.createRun.mockImplementation(async ({ customHandlers }) => {
+ capturedOnChatModelEnd = (event, data) => {
+ customHandlers.on_chat_model_end.handle(event, data);
+ };
+
+ return {
+ processStream: jest.fn().mockImplementation(async () => {
+ customHandlers.on_chat_model_end.handle('on_chat_model_end', {
+ output: {
+ usage_metadata: {
+ input_tokens: 150,
+ output_tokens: 75,
+ model: 'claude-3',
+ },
+ },
+ });
+ }),
+ };
+ });
+
+ await createResponse(req, res);
+
+ expect(mockRecordCollectedUsage).toHaveBeenCalledWith(
+ expect.any(Object),
+ expect.objectContaining({
+ collectedUsage: expect.arrayContaining([
+ expect.objectContaining({
+ input_tokens: 150,
+ output_tokens: 75,
+ }),
+ ]),
+ }),
+ );
+ });
+ });
+});
diff --git a/api/server/controllers/agents/callbacks.js b/api/server/controllers/agents/callbacks.js
index 4742495fc7..0bb935795d 100644
--- a/api/server/controllers/agents/callbacks.js
+++ b/api/server/controllers/agents/callbacks.js
@@ -1,16 +1,13 @@
const { nanoid } = require('nanoid');
-const { sendEvent } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
+const { Constants, EnvVar, GraphEvents, ToolEndHandler } = require('@librechat/agents');
const { Tools, StepTypes, FileContext, ErrorTypes } = require('librechat-data-provider');
const {
- EnvVar,
- Providers,
- GraphEvents,
- getMessageId,
- ToolEndHandler,
- handleToolCalls,
- ChatModelStreamHandler,
-} = require('@librechat/agents');
+ sendEvent,
+ GenerationJobManager,
+ writeAttachmentEvent,
+ createToolExecuteHandler,
+} = require('@librechat/api');
const { processFileCitations } = require('~/server/services/Files/Citations');
const { processCodeOutput } = require('~/server/services/Files/Code/process');
const { loadAuthValues } = require('~/server/services/Tools/credentials');
@@ -51,8 +48,6 @@ class ModelEndHandler {
let errorMessage;
try {
const agentContext = graph.getAgentContext(metadata);
- const isGoogle = agentContext.provider === Providers.GOOGLE;
- const streamingDisabled = !!agentContext.clientOptions?.disableStreaming;
if (data?.output?.additional_kwargs?.stop_reason === 'refusal') {
const info = { ...data.output.additional_kwargs };
errorMessage = JSON.stringify({
@@ -67,21 +62,6 @@ class ModelEndHandler {
});
}
- const toolCalls = data?.output?.tool_calls;
- let hasUnprocessedToolCalls = false;
- if (Array.isArray(toolCalls) && toolCalls.length > 0 && graph?.toolCallStepIds?.has) {
- try {
- hasUnprocessedToolCalls = toolCalls.some(
- (tc) => tc?.id && !graph.toolCallStepIds.has(tc.id),
- );
- } catch {
- hasUnprocessedToolCalls = false;
- }
- }
- if (isGoogle || streamingDisabled || hasUnprocessedToolCalls) {
- await handleToolCalls(toolCalls, metadata, graph);
- }
-
const usage = data?.output?.usage_metadata;
if (!usage) {
return this.finalize(errorMessage);
@@ -92,38 +72,6 @@ class ModelEndHandler {
}
this.collectedUsage.push(usage);
- if (!streamingDisabled) {
- return this.finalize(errorMessage);
- }
- if (!data.output.content) {
- return this.finalize(errorMessage);
- }
- const stepKey = graph.getStepKey(metadata);
- const message_id = getMessageId(stepKey, graph) ?? '';
- if (message_id) {
- await graph.dispatchRunStep(stepKey, {
- type: StepTypes.MESSAGE_CREATION,
- message_creation: {
- message_id,
- },
- });
- }
- const stepId = graph.getStepIdByKey(stepKey);
- const content = data.output.content;
- if (typeof content === 'string') {
- await graph.dispatchMessageDelta(stepId, {
- content: [
- {
- type: 'text',
- text: content,
- },
- ],
- });
- } else if (content.every((c) => c.type?.startsWith('text'))) {
- await graph.dispatchMessageDelta(stepId, {
- content,
- });
- }
} catch (error) {
logger.error('Error handling model end event:', error);
return this.finalize(errorMessage);
@@ -144,17 +92,48 @@ function checkIfLastAgent(last_agent_id, langgraph_node) {
return langgraph_node?.endsWith(last_agent_id);
}
+/**
+ * Helper to emit events either to res (standard mode) or to job emitter (resumable mode).
+ * In Redis mode, awaits the emit to guarantee event ordering (critical for streaming deltas).
+ * @param {ServerResponse} res - The server response object
+ * @param {string | null} streamId - The stream ID for resumable mode, or null for standard mode
+ * @param {Object} eventData - The event data to send
+ * @returns {Promise}
+ */
+async function emitEvent(res, streamId, eventData) {
+ if (streamId) {
+ await GenerationJobManager.emitChunk(streamId, eventData);
+ } else {
+ sendEvent(res, eventData);
+ }
+}
+
+/**
+ * @typedef {Object} ToolExecuteOptions
+ * @property {(toolNames: string[]) => Promise<{loadedTools: StructuredTool[]}>} loadTools - Function to load tools by name
+ * @property {Object} configurable - Configurable context for tool invocation
+ */
+
/**
* Get default handlers for stream events.
* @param {Object} options - The options object.
- * @param {ServerResponse} options.res - The options object.
- * @param {ContentAggregator} options.aggregateContent - The options object.
+ * @param {ServerResponse} options.res - The server response object.
+ * @param {ContentAggregator} options.aggregateContent - Content aggregator function.
* @param {ToolEndCallback} options.toolEndCallback - Callback to use when tool ends.
* @param {Array} options.collectedUsage - The list of collected usage metadata.
+ * @param {string | null} [options.streamId] - The stream ID for resumable mode, or null for standard mode.
+ * @param {ToolExecuteOptions} [options.toolExecuteOptions] - Options for event-driven tool execution.
* @returns {Record} The default handlers.
* @throws {Error} If the request is not found.
*/
-function getDefaultHandlers({ res, aggregateContent, toolEndCallback, collectedUsage }) {
+function getDefaultHandlers({
+ res,
+ aggregateContent,
+ toolEndCallback,
+ collectedUsage,
+ streamId = null,
+ toolExecuteOptions = null,
+}) {
if (!res || !aggregateContent) {
throw new Error(
`[getDefaultHandlers] Missing required options: res: ${!res}, aggregateContent: ${!aggregateContent}`,
@@ -163,7 +142,6 @@ function getDefaultHandlers({ res, aggregateContent, toolEndCallback, collectedU
const handlers = {
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
[GraphEvents.TOOL_END]: new ToolEndHandler(toolEndCallback, logger),
- [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
[GraphEvents.ON_RUN_STEP]: {
/**
* Handle ON_RUN_STEP event.
@@ -171,18 +149,19 @@ function getDefaultHandlers({ res, aggregateContent, toolEndCallback, collectedU
* @param {StreamEventData} data - The event data.
* @param {GraphRunnableConfig['configurable']} [metadata] The runnable metadata.
*/
- handle: (event, data, metadata) => {
+ handle: async (event, data, metadata) => {
+ aggregateContent({ event, data });
if (data?.stepDetails.type === StepTypes.TOOL_CALLS) {
- sendEvent(res, { event, data });
+ await emitEvent(res, streamId, { event, data });
} else if (checkIfLastAgent(metadata?.last_agent_id, metadata?.langgraph_node)) {
- sendEvent(res, { event, data });
+ await emitEvent(res, streamId, { event, data });
} else if (!metadata?.hide_sequential_outputs) {
- sendEvent(res, { event, data });
+ await emitEvent(res, streamId, { event, data });
} else {
const agentName = metadata?.name ?? 'Agent';
const isToolCall = data?.stepDetails.type === StepTypes.TOOL_CALLS;
const action = isToolCall ? 'performing a task...' : 'thinking...';
- sendEvent(res, {
+ await emitEvent(res, streamId, {
event: 'on_agent_update',
data: {
runId: metadata?.run_id,
@@ -190,7 +169,6 @@ function getDefaultHandlers({ res, aggregateContent, toolEndCallback, collectedU
},
});
}
- aggregateContent({ event, data });
},
},
[GraphEvents.ON_RUN_STEP_DELTA]: {
@@ -200,15 +178,15 @@ function getDefaultHandlers({ res, aggregateContent, toolEndCallback, collectedU
* @param {StreamEventData} data - The event data.
* @param {GraphRunnableConfig['configurable']} [metadata] The runnable metadata.
*/
- handle: (event, data, metadata) => {
- if (data?.delta.type === StepTypes.TOOL_CALLS) {
- sendEvent(res, { event, data });
- } else if (checkIfLastAgent(metadata?.last_agent_id, metadata?.langgraph_node)) {
- sendEvent(res, { event, data });
- } else if (!metadata?.hide_sequential_outputs) {
- sendEvent(res, { event, data });
- }
+ handle: async (event, data, metadata) => {
aggregateContent({ event, data });
+ if (data?.delta.type === StepTypes.TOOL_CALLS) {
+ await emitEvent(res, streamId, { event, data });
+ } else if (checkIfLastAgent(metadata?.last_agent_id, metadata?.langgraph_node)) {
+ await emitEvent(res, streamId, { event, data });
+ } else if (!metadata?.hide_sequential_outputs) {
+ await emitEvent(res, streamId, { event, data });
+ }
},
},
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
@@ -218,15 +196,15 @@ function getDefaultHandlers({ res, aggregateContent, toolEndCallback, collectedU
* @param {StreamEventData & { result: ToolEndData }} data - The event data.
* @param {GraphRunnableConfig['configurable']} [metadata] The runnable metadata.
*/
- handle: (event, data, metadata) => {
- if (data?.result != null) {
- sendEvent(res, { event, data });
- } else if (checkIfLastAgent(metadata?.last_agent_id, metadata?.langgraph_node)) {
- sendEvent(res, { event, data });
- } else if (!metadata?.hide_sequential_outputs) {
- sendEvent(res, { event, data });
- }
+ handle: async (event, data, metadata) => {
aggregateContent({ event, data });
+ if (data?.result != null) {
+ await emitEvent(res, streamId, { event, data });
+ } else if (checkIfLastAgent(metadata?.last_agent_id, metadata?.langgraph_node)) {
+ await emitEvent(res, streamId, { event, data });
+ } else if (!metadata?.hide_sequential_outputs) {
+ await emitEvent(res, streamId, { event, data });
+ }
},
},
[GraphEvents.ON_MESSAGE_DELTA]: {
@@ -236,13 +214,13 @@ function getDefaultHandlers({ res, aggregateContent, toolEndCallback, collectedU
* @param {StreamEventData} data - The event data.
* @param {GraphRunnableConfig['configurable']} [metadata] The runnable metadata.
*/
- handle: (event, data, metadata) => {
- if (checkIfLastAgent(metadata?.last_agent_id, metadata?.langgraph_node)) {
- sendEvent(res, { event, data });
- } else if (!metadata?.hide_sequential_outputs) {
- sendEvent(res, { event, data });
- }
+ handle: async (event, data, metadata) => {
aggregateContent({ event, data });
+ if (checkIfLastAgent(metadata?.last_agent_id, metadata?.langgraph_node)) {
+ await emitEvent(res, streamId, { event, data });
+ } else if (!metadata?.hide_sequential_outputs) {
+ await emitEvent(res, streamId, { event, data });
+ }
},
},
[GraphEvents.ON_REASONING_DELTA]: {
@@ -252,29 +230,49 @@ function getDefaultHandlers({ res, aggregateContent, toolEndCallback, collectedU
* @param {StreamEventData} data - The event data.
* @param {GraphRunnableConfig['configurable']} [metadata] The runnable metadata.
*/
- handle: (event, data, metadata) => {
- if (checkIfLastAgent(metadata?.last_agent_id, metadata?.langgraph_node)) {
- sendEvent(res, { event, data });
- } else if (!metadata?.hide_sequential_outputs) {
- sendEvent(res, { event, data });
- }
+ handle: async (event, data, metadata) => {
aggregateContent({ event, data });
+ if (checkIfLastAgent(metadata?.last_agent_id, metadata?.langgraph_node)) {
+ await emitEvent(res, streamId, { event, data });
+ } else if (!metadata?.hide_sequential_outputs) {
+ await emitEvent(res, streamId, { event, data });
+ }
},
},
};
+ if (toolExecuteOptions) {
+ handlers[GraphEvents.ON_TOOL_EXECUTE] = createToolExecuteHandler(toolExecuteOptions);
+ }
+
return handlers;
}
+/**
+ * Helper to write attachment events either to res or to job emitter.
+ * Note: Attachments are not order-sensitive like deltas, so fire-and-forget is acceptable.
+ * @param {ServerResponse} res - The server response object
+ * @param {string | null} streamId - The stream ID for resumable mode, or null for standard mode
+ * @param {Object} attachment - The attachment data
+ */
+function writeAttachment(res, streamId, attachment) {
+ if (streamId) {
+ GenerationJobManager.emitChunk(streamId, { event: 'attachment', data: attachment });
+ } else {
+ res.write(`event: attachment\ndata: ${JSON.stringify(attachment)}\n\n`);
+ }
+}
+
/**
*
* @param {Object} params
* @param {ServerRequest} params.req
* @param {ServerResponse} params.res
* @param {Promise[]} params.artifactPromises
+ * @param {string | null} [params.streamId] - The stream ID for resumable mode, or null for standard mode.
* @returns {ToolEndCallback} The tool end callback.
*/
-function createToolEndCallback({ req, res, artifactPromises }) {
+function createToolEndCallback({ req, res, artifactPromises, streamId = null }) {
/**
* @type {ToolEndCallback}
*/
@@ -302,10 +300,10 @@ function createToolEndCallback({ req, res, artifactPromises }) {
if (!attachment) {
return null;
}
- if (!res.headersSent) {
+ if (!streamId && !res.headersSent) {
return attachment;
}
- res.write(`event: attachment\ndata: ${JSON.stringify(attachment)}\n\n`);
+ writeAttachment(res, streamId, attachment);
return attachment;
})().catch((error) => {
logger.error('Error processing file citations:', error);
@@ -314,8 +312,6 @@ function createToolEndCallback({ req, res, artifactPromises }) {
);
}
- // TODO: a lot of duplicated code in createToolEndCallback
- // we should refactor this to use a helper function in a follow-up PR
if (output.artifact[Tools.ui_resources]) {
artifactPromises.push(
(async () => {
@@ -326,10 +322,10 @@ function createToolEndCallback({ req, res, artifactPromises }) {
conversationId: metadata.thread_id,
[Tools.ui_resources]: output.artifact[Tools.ui_resources].data,
};
- if (!res.headersSent) {
+ if (!streamId && !res.headersSent) {
return attachment;
}
- res.write(`event: attachment\ndata: ${JSON.stringify(attachment)}\n\n`);
+ writeAttachment(res, streamId, attachment);
return attachment;
})().catch((error) => {
logger.error('Error processing artifact content:', error);
@@ -348,10 +344,10 @@ function createToolEndCallback({ req, res, artifactPromises }) {
conversationId: metadata.thread_id,
[Tools.web_search]: { ...output.artifact[Tools.web_search] },
};
- if (!res.headersSent) {
+ if (!streamId && !res.headersSent) {
return attachment;
}
- res.write(`event: attachment\ndata: ${JSON.stringify(attachment)}\n\n`);
+ writeAttachment(res, streamId, attachment);
return attachment;
})().catch((error) => {
logger.error('Error processing artifact content:', error);
@@ -374,7 +370,7 @@ function createToolEndCallback({ req, res, artifactPromises }) {
const { url } = part.image_url;
artifactPromises.push(
(async () => {
- const filename = `${output.name}_${output.tool_call_id}_img_${nanoid()}`;
+ const filename = `${output.name}_img_${nanoid()}`;
const file_id = output.artifact.file_ids?.[i];
const file = await saveBase64Image(url, {
req,
@@ -388,7 +384,7 @@ function createToolEndCallback({ req, res, artifactPromises }) {
toolCallId: output.tool_call_id,
conversationId: metadata.thread_id,
});
- if (!res.headersSent) {
+ if (!streamId && !res.headersSent) {
return fileMetadata;
}
@@ -396,7 +392,7 @@ function createToolEndCallback({ req, res, artifactPromises }) {
return null;
}
- res.write(`event: attachment\ndata: ${JSON.stringify(fileMetadata)}\n\n`);
+ writeAttachment(res, streamId, fileMetadata);
return fileMetadata;
})().catch((error) => {
logger.error('Error processing artifact content:', error);
@@ -407,10 +403,10 @@ function createToolEndCallback({ req, res, artifactPromises }) {
return;
}
- {
- if (output.name !== Tools.execute_code) {
- return;
- }
+ const isCodeTool =
+ output.name === Tools.execute_code || output.name === Constants.PROGRAMMATIC_TOOL_CALLING;
+ if (!isCodeTool) {
+ return;
}
if (!output.artifact.files) {
@@ -435,7 +431,7 @@ function createToolEndCallback({ req, res, artifactPromises }) {
conversationId: metadata.thread_id,
session_id: output.artifact.session_id,
});
- if (!res.headersSent) {
+ if (!streamId && !res.headersSent) {
return fileMetadata;
}
@@ -443,7 +439,225 @@ function createToolEndCallback({ req, res, artifactPromises }) {
return null;
}
- res.write(`event: attachment\ndata: ${JSON.stringify(fileMetadata)}\n\n`);
+ writeAttachment(res, streamId, fileMetadata);
+ return fileMetadata;
+ })().catch((error) => {
+ logger.error('Error processing code output:', error);
+ return null;
+ }),
+ );
+ }
+ };
+}
+
+/**
+ * Helper to write attachment events in Open Responses format (librechat:attachment)
+ * @param {ServerResponse} res - The server response object
+ * @param {Object} tracker - The response tracker with sequence number
+ * @param {Object} attachment - The attachment data
+ * @param {Object} metadata - Additional metadata (messageId, conversationId)
+ */
+function writeResponsesAttachment(res, tracker, attachment, metadata) {
+ const sequenceNumber = tracker.nextSequence();
+ writeAttachmentEvent(res, sequenceNumber, attachment, {
+ messageId: metadata.run_id,
+ conversationId: metadata.thread_id,
+ });
+}
+
+/**
+ * Creates a tool end callback specifically for the Responses API.
+ * Emits attachments as `librechat:attachment` events per the Open Responses extension spec.
+ *
+ * @param {Object} params
+ * @param {ServerRequest} params.req
+ * @param {ServerResponse} params.res
+ * @param {Object} params.tracker - Response tracker with sequence number
+ * @param {Promise[]} params.artifactPromises
+ * @returns {ToolEndCallback} The tool end callback.
+ */
+function createResponsesToolEndCallback({ req, res, tracker, artifactPromises }) {
+ /**
+ * @type {ToolEndCallback}
+ */
+ return async (data, metadata) => {
+ const output = data?.output;
+ if (!output) {
+ return;
+ }
+
+ if (!output.artifact) {
+ return;
+ }
+
+ if (output.artifact[Tools.file_search]) {
+ artifactPromises.push(
+ (async () => {
+ const user = req.user;
+ const attachment = await processFileCitations({
+ user,
+ metadata,
+ appConfig: req.config,
+ toolArtifact: output.artifact,
+ toolCallId: output.tool_call_id,
+ });
+ if (!attachment) {
+ return null;
+ }
+ // For Responses API, emit attachment during streaming
+ if (res.headersSent && !res.writableEnded) {
+ writeResponsesAttachment(res, tracker, attachment, metadata);
+ }
+ return attachment;
+ })().catch((error) => {
+ logger.error('Error processing file citations:', error);
+ return null;
+ }),
+ );
+ }
+
+ if (output.artifact[Tools.ui_resources]) {
+ artifactPromises.push(
+ (async () => {
+ const attachment = {
+ type: Tools.ui_resources,
+ toolCallId: output.tool_call_id,
+ [Tools.ui_resources]: output.artifact[Tools.ui_resources].data,
+ };
+ // For Responses API, always emit attachment during streaming
+ if (res.headersSent && !res.writableEnded) {
+ writeResponsesAttachment(res, tracker, attachment, metadata);
+ }
+ return attachment;
+ })().catch((error) => {
+ logger.error('Error processing artifact content:', error);
+ return null;
+ }),
+ );
+ }
+
+ if (output.artifact[Tools.web_search]) {
+ artifactPromises.push(
+ (async () => {
+ const attachment = {
+ type: Tools.web_search,
+ toolCallId: output.tool_call_id,
+ [Tools.web_search]: { ...output.artifact[Tools.web_search] },
+ };
+ // For Responses API, always emit attachment during streaming
+ if (res.headersSent && !res.writableEnded) {
+ writeResponsesAttachment(res, tracker, attachment, metadata);
+ }
+ return attachment;
+ })().catch((error) => {
+ logger.error('Error processing artifact content:', error);
+ return null;
+ }),
+ );
+ }
+
+ if (output.artifact.content) {
+ /** @type {FormattedContent[]} */
+ const content = output.artifact.content;
+ for (let i = 0; i < content.length; i++) {
+ const part = content[i];
+ if (!part) {
+ continue;
+ }
+ if (part.type !== 'image_url') {
+ continue;
+ }
+ const { url } = part.image_url;
+ artifactPromises.push(
+ (async () => {
+ const filename = `${output.name}_img_${nanoid()}`;
+ const file_id = output.artifact.file_ids?.[i];
+ const file = await saveBase64Image(url, {
+ req,
+ file_id,
+ filename,
+ endpoint: metadata.provider,
+ context: FileContext.image_generation,
+ });
+ const fileMetadata = Object.assign(file, {
+ toolCallId: output.tool_call_id,
+ });
+
+ if (!fileMetadata) {
+ return null;
+ }
+
+ // For Responses API, emit attachment during streaming
+ if (res.headersSent && !res.writableEnded) {
+ const attachment = {
+ file_id: fileMetadata.file_id,
+ filename: fileMetadata.filename,
+ type: fileMetadata.type,
+ url: fileMetadata.filepath,
+ width: fileMetadata.width,
+ height: fileMetadata.height,
+ tool_call_id: output.tool_call_id,
+ };
+ writeResponsesAttachment(res, tracker, attachment, metadata);
+ }
+
+ return fileMetadata;
+ })().catch((error) => {
+ logger.error('Error processing artifact content:', error);
+ return null;
+ }),
+ );
+ }
+ return;
+ }
+
+ const isCodeTool =
+ output.name === Tools.execute_code || output.name === Constants.PROGRAMMATIC_TOOL_CALLING;
+ if (!isCodeTool) {
+ return;
+ }
+
+ if (!output.artifact.files) {
+ return;
+ }
+
+ for (const file of output.artifact.files) {
+ const { id, name } = file;
+ artifactPromises.push(
+ (async () => {
+ const result = await loadAuthValues({
+ userId: req.user.id,
+ authFields: [EnvVar.CODE_API_KEY],
+ });
+ const fileMetadata = await processCodeOutput({
+ req,
+ id,
+ name,
+ apiKey: result[EnvVar.CODE_API_KEY],
+ messageId: metadata.run_id,
+ toolCallId: output.tool_call_id,
+ conversationId: metadata.thread_id,
+ session_id: output.artifact.session_id,
+ });
+
+ if (!fileMetadata) {
+ return null;
+ }
+
+ // For Responses API, emit attachment during streaming
+ if (res.headersSent && !res.writableEnded) {
+ const attachment = {
+ file_id: fileMetadata.file_id,
+ filename: fileMetadata.filename,
+ type: fileMetadata.type,
+ url: fileMetadata.filepath,
+ width: fileMetadata.width,
+ height: fileMetadata.height,
+ tool_call_id: output.tool_call_id,
+ };
+ writeResponsesAttachment(res, tracker, attachment, metadata);
+ }
+
return fileMetadata;
})().catch((error) => {
logger.error('Error processing code output:', error);
@@ -457,4 +671,5 @@ function createToolEndCallback({ req, res, artifactPromises }) {
module.exports = {
getDefaultHandlers,
createToolEndCallback,
+ createResponsesToolEndCallback,
};
diff --git a/api/server/controllers/agents/client.js b/api/server/controllers/agents/client.js
index baa9b7a37a..7aea6d1e8f 100644
--- a/api/server/controllers/agents/client.js
+++ b/api/server/controllers/agents/client.js
@@ -1,19 +1,27 @@
require('events').EventEmitter.defaultMaxListeners = 100;
const { logger } = require('@librechat/data-schemas');
-const { DynamicStructuredTool } = require('@langchain/core/tools');
const { getBufferString, HumanMessage } = require('@langchain/core/messages');
const {
createRun,
Tokenizer,
checkAccess,
- logAxiosError,
+ buildToolSet,
sanitizeTitle,
+ logToolError,
+ payloadParser,
resolveHeaders,
createSafeUser,
+ initializeAgent,
getBalanceConfig,
+ getProviderConfig,
+ omitTitleOptions,
memoryInstructions,
+ applyContextToAgent,
+ createTokenCounter,
+ GenerationJobManager,
getTransactionsConfig,
createMemoryProcessor,
+ createMultiAgentMapper,
filterMalformedContentParts,
} = require('@librechat/api');
const {
@@ -21,9 +29,7 @@ const {
Providers,
TitleMethod,
formatMessage,
- labelContentByAgent,
formatAgentMessages,
- getTokenCountForMessage,
createMetadataAggregator,
} = require('@librechat/agents');
const {
@@ -34,120 +40,18 @@ const {
EModelEndpoint,
PermissionTypes,
isAgentsEndpoint,
- AgentCapabilities,
- bedrockInputSchema,
+ isEphemeralAgentId,
removeNullishValues,
} = require('librechat-data-provider');
-const { initializeAgent } = require('~/server/services/Endpoints/agents/agent');
const { spendTokens, spendStructuredTokens } = require('~/models/spendTokens');
-const { getFormattedMemories, deleteMemory, setMemory } = require('~/models');
const { encodeAndFormat } = require('~/server/services/Files/images/encode');
-const { getProviderConfig } = require('~/server/services/Endpoints');
const { createContextHandlers } = require('~/app/clients/prompts');
-const { checkCapability } = require('~/server/services/Config');
+const { getConvoFiles } = require('~/models/Conversation');
const BaseClient = require('~/app/clients/BaseClient');
const { getRoleByName } = require('~/models/Role');
const { loadAgent } = require('~/models/Agent');
const { getMCPManager } = require('~/config');
-
-const omitTitleOptions = new Set([
- 'stream',
- 'thinking',
- 'streaming',
- 'clientOptions',
- 'thinkingConfig',
- 'thinkingBudget',
- 'includeThoughts',
- 'maxOutputTokens',
- 'additionalModelRequestFields',
-]);
-
-/**
- * @param {ServerRequest} req
- * @param {Agent} agent
- * @param {string} endpoint
- */
-const payloadParser = ({ req, agent, endpoint }) => {
- if (isAgentsEndpoint(endpoint)) {
- return { model: undefined };
- } else if (endpoint === EModelEndpoint.bedrock) {
- const parsedValues = bedrockInputSchema.parse(agent.model_parameters);
- if (parsedValues.thinking == null) {
- parsedValues.thinking = false;
- }
- return parsedValues;
- }
- return req.body.endpointOption.model_parameters;
-};
-
-function createTokenCounter(encoding) {
- return function (message) {
- const countTokens = (text) => Tokenizer.getTokenCount(text, encoding);
- return getTokenCountForMessage(message, countTokens);
- };
-}
-
-function logToolError(graph, error, toolId) {
- logAxiosError({
- error,
- message: `[api/server/controllers/agents/client.js #chatCompletion] Tool Error "${toolId}"`,
- });
-}
-
-/**
- * Applies agent labeling to conversation history when multi-agent patterns are detected.
- * Labels content parts by their originating agent to prevent identity confusion.
- *
- * @param {TMessage[]} orderedMessages - The ordered conversation messages
- * @param {Agent} primaryAgent - The primary agent configuration
- * @param {Map} agentConfigs - Map of additional agent configurations
- * @returns {TMessage[]} Messages with agent labels applied where appropriate
- */
-function applyAgentLabelsToHistory(orderedMessages, primaryAgent, agentConfigs) {
- const shouldLabelByAgent = (primaryAgent.edges?.length ?? 0) > 0 || (agentConfigs?.size ?? 0) > 0;
-
- if (!shouldLabelByAgent) {
- return orderedMessages;
- }
-
- const processedMessages = [];
-
- for (let i = 0; i < orderedMessages.length; i++) {
- const message = orderedMessages[i];
-
- /** @type {Record} */
- const agentNames = { [primaryAgent.id]: primaryAgent.name || 'Assistant' };
-
- if (agentConfigs) {
- for (const [agentId, agentConfig] of agentConfigs.entries()) {
- agentNames[agentId] = agentConfig.name || agentConfig.id;
- }
- }
-
- if (
- !message.isCreatedByUser &&
- message.metadata?.agentIdMap &&
- Array.isArray(message.content)
- ) {
- try {
- const labeledContent = labelContentByAgent(
- message.content,
- message.metadata.agentIdMap,
- agentNames,
- );
-
- processedMessages.push({ ...message, content: labeledContent });
- } catch (error) {
- logger.error('[AgentClient] Error applying agent labels to message:', error);
- processedMessages.push(message);
- }
- } else {
- processedMessages.push(message);
- }
- }
-
- return processedMessages;
-}
+const db = require('~/models');
class AgentClient extends BaseClient {
constructor(options = {}) {
@@ -198,8 +102,6 @@ class AgentClient extends BaseClient {
this.indexTokenCountMap = {};
/** @type {(messages: BaseMessage[]) => Promise} */
this.processMemory;
- /** @type {Record | null} */
- this.agentIdMap = null;
}
/**
@@ -209,9 +111,7 @@ class AgentClient extends BaseClient {
return this.contentParts;
}
- setOptions(options) {
- logger.info('[api/server/controllers/agents/client.js] setOptions', options);
- }
+ setOptions(_options) {}
/**
* `AgentClient` is not opinionated about vision requests, so we don't do anything here
@@ -220,14 +120,9 @@ class AgentClient extends BaseClient {
checkVisionRequest() {}
getSaveOptions() {
- // TODO:
- // would need to be override settings; otherwise, model needs to be undefined
- // model: this.override.model,
- // instructions: this.override.instructions,
- // additional_instructions: this.override.additional_instructions,
let runOptions = {};
try {
- runOptions = payloadParser(this.options);
+ runOptions = payloadParser(this.options) ?? {};
} catch (error) {
logger.error(
'[api/server/controllers/agents/client.js #getSaveOptions] Error parsing options',
@@ -238,14 +133,14 @@ class AgentClient extends BaseClient {
return removeNullishValues(
Object.assign(
{
+ spec: this.options.spec,
+ iconURL: this.options.iconURL,
endpoint: this.options.endpoint,
agent_id: this.options.agent.id,
modelLabel: this.options.modelLabel,
- maxContextTokens: this.options.maxContextTokens,
resendFiles: this.options.resendFiles,
imageDetail: this.options.imageDetail,
- spec: this.options.spec,
- iconURL: this.options.iconURL,
+ maxContextTokens: this.maxContextTokens,
},
// TODO: PARSE OPTIONS BY PROVIDER, MAY CONTAIN SENSITIVE DATA
runOptions,
@@ -253,11 +148,13 @@ class AgentClient extends BaseClient {
);
}
+ /**
+ * Returns build message options. For AgentClient, agent-specific instructions
+ * are retrieved directly from agent objects in buildMessages, so this returns empty.
+ * @returns {Object} Empty options object
+ */
getBuildMessagesOptions() {
- return {
- instructions: this.options.agent.instructions,
- additional_instructions: this.options.agent.additional_instructions,
- };
+ return {};
}
/**
@@ -280,33 +177,43 @@ class AgentClient extends BaseClient {
return files;
}
- async buildMessages(
- messages,
- parentMessageId,
- { instructions = null, additional_instructions = null },
- opts,
- ) {
- let orderedMessages = this.constructor.getMessagesForConversation({
+ async buildMessages(messages, parentMessageId, _buildOptions, opts) {
+ /** Always pass mapMethod; getMessagesForConversation applies it only to messages with addedConvo flag */
+ const orderedMessages = this.constructor.getMessagesForConversation({
messages,
parentMessageId,
summary: this.shouldSummarize,
+ mapMethod: createMultiAgentMapper(this.options.agent, this.agentConfigs),
+ mapCondition: (message) => message.addedConvo === true,
});
- orderedMessages = applyAgentLabelsToHistory(
- orderedMessages,
- this.options.agent,
- this.agentConfigs,
- );
-
let payload;
/** @type {number | undefined} */
let promptTokens;
- /** @type {string} */
- let systemContent = [instructions ?? '', additional_instructions ?? '']
- .filter(Boolean)
- .join('\n')
- .trim();
+ /**
+ * Extract base instructions for all agents (combines instructions + additional_instructions).
+ * This must be done before applying context to preserve the original agent configuration.
+ */
+ const extractBaseInstructions = (agent) => {
+ const baseInstructions = [agent.instructions ?? '', agent.additional_instructions ?? '']
+ .filter(Boolean)
+ .join('\n')
+ .trim();
+ agent.instructions = baseInstructions;
+ return agent;
+ };
+
+ /** Collect all agents for unified processing, extracting base instructions during collection */
+ const allAgents = [
+ { agent: extractBaseInstructions(this.options.agent), agentId: this.options.agent.id },
+ ...(this.agentConfigs?.size > 0
+ ? Array.from(this.agentConfigs.entries()).map(([agentId, agent]) => ({
+ agent: extractBaseInstructions(agent),
+ agentId,
+ }))
+ : []),
+ ];
if (this.options.attachments) {
const attachments = await this.options.attachments;
@@ -341,6 +248,7 @@ class AgentClient extends BaseClient {
assistantName: this.options?.modelLabel,
});
+ /** For non-latest messages, prepend file context directly to message content */
if (message.fileContext && i !== orderedMessages.length - 1) {
if (typeof formattedMessage.content === 'string') {
formattedMessage.content = message.fileContext + '\n' + formattedMessage.content;
@@ -350,8 +258,6 @@ class AgentClient extends BaseClient {
? (textPart.text = message.fileContext + '\n' + textPart.text)
: formattedMessage.content.unshift({ type: 'text', text: message.fileContext });
}
- } else if (message.fileContext && i === orderedMessages.length - 1) {
- systemContent = [systemContent, message.fileContext].join('\n');
}
const needsTokenCount =
@@ -384,46 +290,35 @@ class AgentClient extends BaseClient {
return formattedMessage;
});
+ /**
+ * Build shared run context - applies to ALL agents in the run.
+ * This includes: file context (latest message), augmented prompt (RAG), memory context.
+ */
+ const sharedRunContextParts = [];
+
+ /** File context from the latest message (attachments) */
+ const latestMessage = orderedMessages[orderedMessages.length - 1];
+ if (latestMessage?.fileContext) {
+ sharedRunContextParts.push(latestMessage.fileContext);
+ }
+
+ /** Augmented prompt from RAG/context handlers */
if (this.contextHandlers) {
this.augmentedPrompt = await this.contextHandlers.createContext();
- systemContent = this.augmentedPrompt + systemContent;
- }
-
- // Inject MCP server instructions if available
- const ephemeralAgent = this.options.req.body.ephemeralAgent;
- let mcpServers = [];
-
- // Check for ephemeral agent MCP servers
- if (ephemeralAgent && ephemeralAgent.mcp && ephemeralAgent.mcp.length > 0) {
- mcpServers = ephemeralAgent.mcp;
- }
- // Check for regular agent MCP tools
- else if (this.options.agent && this.options.agent.tools) {
- mcpServers = this.options.agent.tools
- .filter(
- (tool) =>
- tool instanceof DynamicStructuredTool && tool.name.includes(Constants.mcp_delimiter),
- )
- .map((tool) => tool.name.split(Constants.mcp_delimiter).pop())
- .filter(Boolean);
- }
-
- if (mcpServers.length > 0) {
- try {
- const mcpInstructions = await getMCPManager().formatInstructionsForContext(mcpServers);
- if (mcpInstructions) {
- systemContent = [systemContent, mcpInstructions].filter(Boolean).join('\n\n');
- logger.debug('[AgentClient] Injected MCP instructions for servers:', mcpServers);
- }
- } catch (error) {
- logger.error('[AgentClient] Failed to inject MCP instructions:', error);
+ if (this.augmentedPrompt) {
+ sharedRunContextParts.push(this.augmentedPrompt);
}
}
- if (systemContent) {
- this.options.agent.instructions = systemContent;
+ /** Memory context (user preferences/memories) */
+ const withoutKeys = await this.useMemory();
+ if (withoutKeys) {
+ const memoryContext = `${memoryInstructions}\n\n# Existing memory about the user:\n${withoutKeys}`;
+ sharedRunContextParts.push(memoryContext);
}
+ const sharedRunContext = sharedRunContextParts.join('\n\n');
+
/** @type {Record | undefined} */
let tokenCountMap;
@@ -449,14 +344,27 @@ class AgentClient extends BaseClient {
opts.getReqData({ promptTokens });
}
- const withoutKeys = await this.useMemory();
- if (withoutKeys) {
- systemContent += `${memoryInstructions}\n\n# Existing memory about the user:\n${withoutKeys}`;
- }
-
- if (systemContent) {
- this.options.agent.instructions = systemContent;
- }
+ /**
+ * Apply context to all agents.
+ * Each agent gets: shared run context + their own base instructions + their own MCP instructions.
+ *
+ * NOTE: This intentionally mutates agent objects in place. The agentConfigs Map
+ * holds references to config objects that will be passed to the graph runtime.
+ */
+ const ephemeralAgent = this.options.req.body.ephemeralAgent;
+ const mcpManager = getMCPManager();
+ await Promise.all(
+ allAgents.map(({ agent, agentId }) =>
+ applyContextToAgent({
+ agent,
+ agentId,
+ logger,
+ mcpManager,
+ sharedRunContext,
+ ephemeralAgent: agentId === this.options.agent.id ? ephemeralAgent : undefined,
+ }),
+ ),
+ );
return result;
}
@@ -528,6 +436,8 @@ class AgentClient extends BaseClient {
agent_id: memoryConfig.agent.id,
endpoint: EModelEndpoint.agents,
});
+ } else if (memoryConfig.agent?.id != null) {
+ prelimAgent = this.options.agent;
} else if (
memoryConfig.agent?.id == null &&
memoryConfig.agent?.model != null &&
@@ -542,18 +452,32 @@ class AgentClient extends BaseClient {
);
}
- const agent = await initializeAgent({
- req: this.options.req,
- res: this.options.res,
- agent: prelimAgent,
- allowedProviders,
- endpointOption: {
- endpoint:
- prelimAgent.id !== Constants.EPHEMERAL_AGENT_ID
+ if (!prelimAgent) {
+ return;
+ }
+
+ const agent = await initializeAgent(
+ {
+ req: this.options.req,
+ res: this.options.res,
+ agent: prelimAgent,
+ allowedProviders,
+ endpointOption: {
+ endpoint: !isEphemeralAgentId(prelimAgent.id)
? EModelEndpoint.agents
: memoryConfig.agent?.provider,
+ },
},
- });
+ {
+ getConvoFiles,
+ getFiles: db.getFiles,
+ getUserKey: db.getUserKey,
+ updateFilesUsage: db.updateFilesUsage,
+ getUserKeyValues: db.getUserKeyValues,
+ getToolFilesByIds: db.getToolFilesByIds,
+ getCodeGeneratedFiles: db.getCodeGeneratedFiles,
+ },
+ );
if (!agent) {
logger.warn(
@@ -582,17 +506,20 @@ class AgentClient extends BaseClient {
const userId = this.options.req.user.id + '';
const messageId = this.responseMessageId + '';
const conversationId = this.conversationId + '';
+ const streamId = this.options.req?._resumableStreamId || null;
const [withoutKeys, processMemory] = await createMemoryProcessor({
userId,
config,
messageId,
+ streamId,
conversationId,
memoryMethods: {
- setMemory,
- deleteMemory,
- getFormattedMemories,
+ setMemory: db.setMemory,
+ deleteMemory: db.deleteMemory,
+ getFormattedMemories: db.getFormattedMemories,
},
res: this.options.res,
+ user: createSafeUser(this.options.req.user),
});
this.processMemory = processMemory;
@@ -679,9 +606,7 @@ class AgentClient extends BaseClient {
});
const completion = filterMalformedContentParts(this.contentParts);
- const metadata = this.agentIdMap ? { agentIdMap: this.agentIdMap } : undefined;
-
- return { completion, metadata };
+ return { completion };
}
/**
@@ -702,21 +627,37 @@ class AgentClient extends BaseClient {
if (!collectedUsage || !collectedUsage.length) {
return;
}
+ // Use first entry's input_tokens as the base input (represents initial user message context)
+ // Support both OpenAI format (input_token_details) and Anthropic format (cache_*_input_tokens)
+ const firstUsage = collectedUsage[0];
const input_tokens =
- (collectedUsage[0]?.input_tokens || 0) +
- (Number(collectedUsage[0]?.input_token_details?.cache_creation) || 0) +
- (Number(collectedUsage[0]?.input_token_details?.cache_read) || 0);
+ (firstUsage?.input_tokens || 0) +
+ (Number(firstUsage?.input_token_details?.cache_creation) ||
+ Number(firstUsage?.cache_creation_input_tokens) ||
+ 0) +
+ (Number(firstUsage?.input_token_details?.cache_read) ||
+ Number(firstUsage?.cache_read_input_tokens) ||
+ 0);
- let output_tokens = 0;
- let previousTokens = input_tokens; // Start with original input
- for (let i = 0; i < collectedUsage.length; i++) {
- const usage = collectedUsage[i];
+ // Sum output_tokens directly from all entries - works for both sequential and parallel execution
+ // This avoids the incremental calculation that produced negative values for parallel agents
+ let total_output_tokens = 0;
+
+ for (const usage of collectedUsage) {
if (!usage) {
continue;
}
- const cache_creation = Number(usage.input_token_details?.cache_creation) || 0;
- const cache_read = Number(usage.input_token_details?.cache_read) || 0;
+ // Support both OpenAI format (input_token_details) and Anthropic format (cache_*_input_tokens)
+ const cache_creation =
+ Number(usage.input_token_details?.cache_creation) ||
+ Number(usage.cache_creation_input_tokens) ||
+ 0;
+ const cache_read =
+ Number(usage.input_token_details?.cache_read) || Number(usage.cache_read_input_tokens) || 0;
+
+ // Accumulate output tokens for the usage summary
+ total_output_tokens += Number(usage.output_tokens) || 0;
const txMetadata = {
context,
@@ -728,18 +669,6 @@ class AgentClient extends BaseClient {
model: usage.model ?? model ?? this.model ?? this.options.agent.model_parameters.model,
};
- if (i > 0) {
- // Count new tokens generated (input_tokens minus previous accumulated tokens)
- output_tokens +=
- (Number(usage.input_tokens) || 0) + cache_creation + cache_read - previousTokens;
- }
-
- // Add this message's output tokens
- output_tokens += Number(usage.output_tokens) || 0;
-
- // Update previousTokens to include this message's output
- previousTokens += Number(usage.output_tokens) || 0;
-
if (cache_creation > 0 || cache_read > 0) {
spendStructuredTokens(txMetadata, {
promptTokens: {
@@ -769,7 +698,7 @@ class AgentClient extends BaseClient {
this.usage = {
input_tokens,
- output_tokens,
+ output_tokens: total_output_tokens,
};
}
@@ -859,13 +788,13 @@ class AgentClient extends BaseClient {
},
user: createSafeUser(this.options.req.user),
},
- recursionLimit: agentsEConfig?.recursionLimit ?? 25,
+ recursionLimit: agentsEConfig?.recursionLimit ?? 50,
signal: abortController.signal,
streamMode: 'values',
version: 'v2',
};
- const toolSet = new Set((this.options.agent.tools ?? []).map((tool) => tool && tool.name));
+ const toolSet = buildToolSet(this.options.agent);
let { messages: initialMessages, indexTokenCountMap } = formatAgentMessages(
payload,
this.indexTokenCountMap,
@@ -877,12 +806,10 @@ class AgentClient extends BaseClient {
*/
const runAgents = async (messages) => {
const agents = [this.options.agent];
- if (
- this.agentConfigs &&
- this.agentConfigs.size > 0 &&
- ((this.options.agent.edges?.length ?? 0) > 0 ||
- (await checkCapability(this.options.req, AgentCapabilities.chain)))
- ) {
+ // Include additional agents when:
+ // - agentConfigs has agents (from addedConvo parallel execution or agent handoffs)
+ // - Agents without incoming edges become start nodes and run in parallel automatically
+ if (this.agentConfigs && this.agentConfigs.size > 0) {
agents.push(...this.agentConfigs.values());
}
@@ -928,6 +855,7 @@ class AgentClient extends BaseClient {
run = await createRun({
agents,
+ messages,
indexTokenCountMap,
runId: this.responseMessageId,
signal: abortController.signal,
@@ -942,6 +870,12 @@ class AgentClient extends BaseClient {
}
this.run = run;
+
+ const streamId = this.options.req?._resumableStreamId;
+ if (streamId && run.Graph) {
+ GenerationJobManager.setGraph(streamId, run.Graph);
+ }
+
if (userMCPAuthMap != null) {
config.configurable.userMCPAuthMap = userMCPAuthMap;
}
@@ -957,9 +891,10 @@ class AgentClient extends BaseClient {
config.signal = null;
};
+ const hideSequentialOutputs = config.configurable.hide_sequential_outputs;
await runAgents(initialMessages);
/** @deprecated Agent Chain */
- if (config.configurable.hide_sequential_outputs) {
+ if (hideSequentialOutputs) {
this.contentParts = this.contentParts.filter((part, index) => {
// Include parts that are either:
// 1. At or after the finalContentStart index
@@ -972,24 +907,6 @@ class AgentClient extends BaseClient {
);
});
}
-
- try {
- /** Capture agent ID map if we have edges or multiple agents */
- const shouldStoreAgentMap =
- (this.options.agent.edges?.length ?? 0) > 0 || (this.agentConfigs?.size ?? 0) > 0;
- if (shouldStoreAgentMap && run?.Graph) {
- const contentPartAgentMap = run.Graph.getContentPartAgentMap();
- if (contentPartAgentMap && contentPartAgentMap.size > 0) {
- this.agentIdMap = Object.fromEntries(contentPartAgentMap);
- logger.debug('[AgentClient] Captured agent ID map:', {
- totalParts: this.contentParts.length,
- mappedParts: Object.keys(this.agentIdMap).length,
- });
- }
- }
- } catch (error) {
- logger.error('[AgentClient] Error capturing agent ID map:', error);
- }
} catch (err) {
logger.error(
'[api/server/controllers/agents/client.js #sendCompletion] Operation aborted',
@@ -1012,11 +929,20 @@ class AgentClient extends BaseClient {
this.artifactPromises.push(...attachments);
}
- await this.recordCollectedUsage({
- context: 'message',
- balance: balanceConfig,
- transactions: transactionsConfig,
- });
+ /** Skip token spending if aborted - the abort handler (abortMiddleware.js) handles it
+ This prevents double-spending when user aborts via `/api/agents/chat/abort` */
+ const wasAborted = abortController?.signal?.aborted;
+ if (!wasAborted) {
+ await this.recordCollectedUsage({
+ context: 'message',
+ balance: balanceConfig,
+ transactions: transactionsConfig,
+ });
+ } else {
+ logger.debug(
+ '[api/server/controllers/agents/client.js #chatCompletion] Skipping token spending - handled by abort middleware',
+ );
+ }
} catch (err) {
logger.error(
'[api/server/controllers/agents/client.js #chatCompletion] Error in cleanup phase',
@@ -1040,7 +966,15 @@ class AgentClient extends BaseClient {
throw new Error('Run not initialized');
}
const { handleLLMEnd, collected: collectedMetadata } = createMetadataAggregator();
- const { req, res, agent } = this.options;
+ const { req, agent } = this.options;
+
+ if (req?.body?.isTemporary) {
+ logger.debug(
+ `[api/server/controllers/agents/client.js #titleConvo] Skipping title generation for temporary conversation`,
+ );
+ return;
+ }
+
const appConfig = req.config;
let endpoint = agent.endpoint;
@@ -1097,11 +1031,12 @@ class AgentClient extends BaseClient {
const options = await titleProviderConfig.getOptions({
req,
- res,
- optionsOnly: true,
- overrideEndpoint: endpoint,
- overrideModel: clientOptions.model,
- endpointOption: { model_parameters: clientOptions },
+ endpoint,
+ model_parameters: clientOptions,
+ db: {
+ getUserKey: db.getUserKey,
+ getUserKeyValues: db.getUserKeyValues,
+ },
});
let provider = options.provider ?? titleProviderConfig.overrideProvider ?? agent.provider;
diff --git a/api/server/controllers/agents/client.test.js b/api/server/controllers/agents/client.test.js
index 0ce59c5fbc..9dd3567047 100644
--- a/api/server/controllers/agents/client.test.js
+++ b/api/server/controllers/agents/client.test.js
@@ -12,6 +12,17 @@ jest.mock('@librechat/agents', () => ({
jest.mock('@librechat/api', () => ({
...jest.requireActual('@librechat/api'),
+ checkAccess: jest.fn(),
+ initializeAgent: jest.fn(),
+ createMemoryProcessor: jest.fn(),
+}));
+
+jest.mock('~/models/Agent', () => ({
+ loadAgent: jest.fn(),
+}));
+
+jest.mock('~/models/Role', () => ({
+ getRoleByName: jest.fn(),
}));
// Mock getMCPManager
@@ -336,6 +347,25 @@ describe('AgentClient - titleConvo', () => {
expect(client.recordCollectedUsage).not.toHaveBeenCalled();
});
+ it('should skip title generation for temporary chats', async () => {
+ // Set isTemporary to true
+ mockReq.body.isTemporary = true;
+
+ const text = 'Test temporary chat';
+ const abortController = new AbortController();
+
+ const result = await client.titleConvo({ text, abortController });
+
+ // Should return undefined without generating title
+ expect(result).toBeUndefined();
+
+ // generateTitle should NOT have been called
+ expect(mockRun.generateTitle).not.toHaveBeenCalled();
+
+ // recordCollectedUsage should NOT have been called
+ expect(client.recordCollectedUsage).not.toHaveBeenCalled();
+ });
+
it('should skip title generation when titleConvo is false in all config', async () => {
// Set titleConvo to false in "all" config
mockReq.config = {
@@ -1291,8 +1321,8 @@ describe('AgentClient - titleConvo', () => {
expect(client.options.agent.instructions).toContain('# MCP Server Instructions');
expect(client.options.agent.instructions).toContain('Use these tools carefully');
- // Verify the base instructions are also included
- expect(client.options.agent.instructions).toContain('Base instructions');
+ // Verify the base instructions are also included (from agent config, not buildOptions)
+ expect(client.options.agent.instructions).toContain('Base agent instructions');
});
it('should handle MCP instructions with ephemeral agent', async () => {
@@ -1354,8 +1384,8 @@ describe('AgentClient - titleConvo', () => {
additional_instructions: null,
});
- // Verify the instructions still work without MCP content
- expect(client.options.agent.instructions).toBe('Base instructions only');
+ // Verify the instructions still work without MCP content (from agent config, not buildOptions)
+ expect(client.options.agent.instructions).toBe('Base agent instructions');
expect(client.options.agent.instructions).not.toContain('[object Promise]');
});
@@ -1379,8 +1409,8 @@ describe('AgentClient - titleConvo', () => {
additional_instructions: null,
});
- // Should still have base instructions without MCP content
- expect(client.options.agent.instructions).toContain('Base instructions');
+ // Should still have base instructions without MCP content (from agent config, not buildOptions)
+ expect(client.options.agent.instructions).toContain('Base agent instructions');
expect(client.options.agent.instructions).not.toContain('[object Promise]');
});
});
@@ -1611,4 +1641,619 @@ describe('AgentClient - titleConvo', () => {
expect(mockProcessMemory).not.toHaveBeenCalled();
});
});
+
+ describe('getMessagesForConversation - mapMethod and mapCondition', () => {
+ const createMessage = (id, parentId, text, extras = {}) => ({
+ messageId: id,
+ parentMessageId: parentId,
+ text,
+ isCreatedByUser: false,
+ ...extras,
+ });
+
+ it('should apply mapMethod to all messages when mapCondition is not provided', () => {
+ const messages = [
+ createMessage('msg-1', null, 'First message'),
+ createMessage('msg-2', 'msg-1', 'Second message'),
+ createMessage('msg-3', 'msg-2', 'Third message'),
+ ];
+
+ const mapMethod = jest.fn((msg) => ({ ...msg, mapped: true }));
+
+ const result = AgentClient.getMessagesForConversation({
+ messages,
+ parentMessageId: 'msg-3',
+ mapMethod,
+ });
+
+ expect(result).toHaveLength(3);
+ expect(mapMethod).toHaveBeenCalledTimes(3);
+ result.forEach((msg) => {
+ expect(msg.mapped).toBe(true);
+ });
+ });
+
+ it('should apply mapMethod only to messages where mapCondition returns true', () => {
+ const messages = [
+ createMessage('msg-1', null, 'First message', { addedConvo: false }),
+ createMessage('msg-2', 'msg-1', 'Second message', { addedConvo: true }),
+ createMessage('msg-3', 'msg-2', 'Third message', { addedConvo: true }),
+ createMessage('msg-4', 'msg-3', 'Fourth message', { addedConvo: false }),
+ ];
+
+ const mapMethod = jest.fn((msg) => ({ ...msg, mapped: true }));
+ const mapCondition = (msg) => msg.addedConvo === true;
+
+ const result = AgentClient.getMessagesForConversation({
+ messages,
+ parentMessageId: 'msg-4',
+ mapMethod,
+ mapCondition,
+ });
+
+ expect(result).toHaveLength(4);
+ expect(mapMethod).toHaveBeenCalledTimes(2);
+
+ expect(result[0].mapped).toBeUndefined();
+ expect(result[1].mapped).toBe(true);
+ expect(result[2].mapped).toBe(true);
+ expect(result[3].mapped).toBeUndefined();
+ });
+
+ it('should not apply mapMethod when mapCondition returns false for all messages', () => {
+ const messages = [
+ createMessage('msg-1', null, 'First message', { addedConvo: false }),
+ createMessage('msg-2', 'msg-1', 'Second message', { addedConvo: false }),
+ ];
+
+ const mapMethod = jest.fn((msg) => ({ ...msg, mapped: true }));
+ const mapCondition = (msg) => msg.addedConvo === true;
+
+ const result = AgentClient.getMessagesForConversation({
+ messages,
+ parentMessageId: 'msg-2',
+ mapMethod,
+ mapCondition,
+ });
+
+ expect(result).toHaveLength(2);
+ expect(mapMethod).not.toHaveBeenCalled();
+ result.forEach((msg) => {
+ expect(msg.mapped).toBeUndefined();
+ });
+ });
+
+ it('should not call mapMethod when mapMethod is null', () => {
+ const messages = [
+ createMessage('msg-1', null, 'First message'),
+ createMessage('msg-2', 'msg-1', 'Second message'),
+ ];
+
+ const mapCondition = jest.fn(() => true);
+
+ const result = AgentClient.getMessagesForConversation({
+ messages,
+ parentMessageId: 'msg-2',
+ mapMethod: null,
+ mapCondition,
+ });
+
+ expect(result).toHaveLength(2);
+ expect(mapCondition).not.toHaveBeenCalled();
+ });
+
+ it('should handle mapCondition with complex logic', () => {
+ const messages = [
+ createMessage('msg-1', null, 'User message', { isCreatedByUser: true, addedConvo: true }),
+ createMessage('msg-2', 'msg-1', 'Assistant response', { addedConvo: true }),
+ createMessage('msg-3', 'msg-2', 'Another user message', { isCreatedByUser: true }),
+ createMessage('msg-4', 'msg-3', 'Another response', { addedConvo: true }),
+ ];
+
+ const mapMethod = jest.fn((msg) => ({ ...msg, processed: true }));
+ const mapCondition = (msg) => msg.addedConvo === true && !msg.isCreatedByUser;
+
+ const result = AgentClient.getMessagesForConversation({
+ messages,
+ parentMessageId: 'msg-4',
+ mapMethod,
+ mapCondition,
+ });
+
+ expect(result).toHaveLength(4);
+ expect(mapMethod).toHaveBeenCalledTimes(2);
+
+ expect(result[0].processed).toBeUndefined();
+ expect(result[1].processed).toBe(true);
+ expect(result[2].processed).toBeUndefined();
+ expect(result[3].processed).toBe(true);
+ });
+
+ it('should preserve message order after applying mapMethod with mapCondition', () => {
+ const messages = [
+ createMessage('msg-1', null, 'First', { addedConvo: true }),
+ createMessage('msg-2', 'msg-1', 'Second', { addedConvo: false }),
+ createMessage('msg-3', 'msg-2', 'Third', { addedConvo: true }),
+ ];
+
+ const mapMethod = (msg) => ({ ...msg, text: `[MAPPED] ${msg.text}` });
+ const mapCondition = (msg) => msg.addedConvo === true;
+
+ const result = AgentClient.getMessagesForConversation({
+ messages,
+ parentMessageId: 'msg-3',
+ mapMethod,
+ mapCondition,
+ });
+
+ expect(result[0].text).toBe('[MAPPED] First');
+ expect(result[1].text).toBe('Second');
+ expect(result[2].text).toBe('[MAPPED] Third');
+ });
+
+ it('should work with summary option alongside mapMethod and mapCondition', () => {
+ const messages = [
+ createMessage('msg-1', null, 'First', { addedConvo: false }),
+ createMessage('msg-2', 'msg-1', 'Second', {
+ summary: 'Summary of conversation',
+ addedConvo: true,
+ }),
+ createMessage('msg-3', 'msg-2', 'Third', { addedConvo: true }),
+ createMessage('msg-4', 'msg-3', 'Fourth', { addedConvo: false }),
+ ];
+
+ const mapMethod = jest.fn((msg) => ({ ...msg, mapped: true }));
+ const mapCondition = (msg) => msg.addedConvo === true;
+
+ const result = AgentClient.getMessagesForConversation({
+ messages,
+ parentMessageId: 'msg-4',
+ mapMethod,
+ mapCondition,
+ summary: true,
+ });
+
+ /** Traversal stops at msg-2 (has summary), so we get msg-4 -> msg-3 -> msg-2 */
+ expect(result).toHaveLength(3);
+ expect(result[0].text).toBe('Summary of conversation');
+ expect(result[0].role).toBe('system');
+ expect(result[0].mapped).toBe(true);
+ expect(result[1].mapped).toBe(true);
+ expect(result[2].mapped).toBeUndefined();
+ });
+
+ it('should handle empty messages array', () => {
+ const mapMethod = jest.fn();
+ const mapCondition = jest.fn();
+
+ const result = AgentClient.getMessagesForConversation({
+ messages: [],
+ parentMessageId: 'msg-1',
+ mapMethod,
+ mapCondition,
+ });
+
+ expect(result).toHaveLength(0);
+ expect(mapMethod).not.toHaveBeenCalled();
+ expect(mapCondition).not.toHaveBeenCalled();
+ });
+
+ it('should handle undefined mapCondition explicitly', () => {
+ const messages = [
+ createMessage('msg-1', null, 'First'),
+ createMessage('msg-2', 'msg-1', 'Second'),
+ ];
+
+ const mapMethod = jest.fn((msg) => ({ ...msg, mapped: true }));
+
+ const result = AgentClient.getMessagesForConversation({
+ messages,
+ parentMessageId: 'msg-2',
+ mapMethod,
+ mapCondition: undefined,
+ });
+
+ expect(result).toHaveLength(2);
+ expect(mapMethod).toHaveBeenCalledTimes(2);
+ result.forEach((msg) => {
+ expect(msg.mapped).toBe(true);
+ });
+ });
+ });
+
+ describe('buildMessages - memory context for parallel agents', () => {
+ let client;
+ let mockReq;
+ let mockRes;
+ let mockAgent;
+ let mockOptions;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ mockAgent = {
+ id: 'primary-agent',
+ name: 'Primary Agent',
+ endpoint: EModelEndpoint.openAI,
+ provider: EModelEndpoint.openAI,
+ instructions: 'Primary agent instructions',
+ model_parameters: {
+ model: 'gpt-4',
+ },
+ tools: [],
+ };
+
+ mockReq = {
+ user: {
+ id: 'user-123',
+ personalization: {
+ memories: true,
+ },
+ },
+ body: {
+ endpoint: EModelEndpoint.openAI,
+ },
+ config: {
+ memory: {
+ disabled: false,
+ },
+ },
+ };
+
+ mockRes = {};
+
+ mockOptions = {
+ req: mockReq,
+ res: mockRes,
+ agent: mockAgent,
+ endpoint: EModelEndpoint.agents,
+ };
+
+ client = new AgentClient(mockOptions);
+ client.conversationId = 'convo-123';
+ client.responseMessageId = 'response-123';
+ client.shouldSummarize = false;
+ client.maxContextTokens = 4096;
+ });
+
+ it('should pass memory context to parallel agents (addedConvo)', async () => {
+ const memoryContent = 'User prefers dark mode. User is a software developer.';
+ client.useMemory = jest.fn().mockResolvedValue(memoryContent);
+
+ const parallelAgent1 = {
+ id: 'parallel-agent-1',
+ name: 'Parallel Agent 1',
+ instructions: 'Parallel agent 1 instructions',
+ provider: EModelEndpoint.openAI,
+ };
+
+ const parallelAgent2 = {
+ id: 'parallel-agent-2',
+ name: 'Parallel Agent 2',
+ instructions: 'Parallel agent 2 instructions',
+ provider: EModelEndpoint.anthropic,
+ };
+
+ client.agentConfigs = new Map([
+ ['parallel-agent-1', parallelAgent1],
+ ['parallel-agent-2', parallelAgent2],
+ ]);
+
+ const messages = [
+ {
+ messageId: 'msg-1',
+ parentMessageId: null,
+ sender: 'User',
+ text: 'Hello',
+ isCreatedByUser: true,
+ },
+ ];
+
+ await client.buildMessages(messages, null, {
+ instructions: 'Base instructions',
+ additional_instructions: null,
+ });
+
+ expect(client.useMemory).toHaveBeenCalled();
+
+ // Verify primary agent has its configured instructions (not from buildOptions) and memory context
+ expect(client.options.agent.instructions).toContain('Primary agent instructions');
+ expect(client.options.agent.instructions).toContain(memoryContent);
+
+ expect(parallelAgent1.instructions).toContain('Parallel agent 1 instructions');
+ expect(parallelAgent1.instructions).toContain(memoryContent);
+
+ expect(parallelAgent2.instructions).toContain('Parallel agent 2 instructions');
+ expect(parallelAgent2.instructions).toContain(memoryContent);
+ });
+
+ it('should not modify parallel agents when no memory context is available', async () => {
+ client.useMemory = jest.fn().mockResolvedValue(undefined);
+
+ const parallelAgent = {
+ id: 'parallel-agent-1',
+ name: 'Parallel Agent 1',
+ instructions: 'Original parallel instructions',
+ provider: EModelEndpoint.openAI,
+ };
+
+ client.agentConfigs = new Map([['parallel-agent-1', parallelAgent]]);
+
+ const messages = [
+ {
+ messageId: 'msg-1',
+ parentMessageId: null,
+ sender: 'User',
+ text: 'Hello',
+ isCreatedByUser: true,
+ },
+ ];
+
+ await client.buildMessages(messages, null, {
+ instructions: 'Base instructions',
+ additional_instructions: null,
+ });
+
+ expect(parallelAgent.instructions).toBe('Original parallel instructions');
+ });
+
+ it('should handle parallel agents without existing instructions', async () => {
+ const memoryContent = 'User is a data scientist.';
+ client.useMemory = jest.fn().mockResolvedValue(memoryContent);
+
+ const parallelAgentNoInstructions = {
+ id: 'parallel-agent-no-instructions',
+ name: 'Parallel Agent No Instructions',
+ provider: EModelEndpoint.openAI,
+ };
+
+ client.agentConfigs = new Map([
+ ['parallel-agent-no-instructions', parallelAgentNoInstructions],
+ ]);
+
+ const messages = [
+ {
+ messageId: 'msg-1',
+ parentMessageId: null,
+ sender: 'User',
+ text: 'Hello',
+ isCreatedByUser: true,
+ },
+ ];
+
+ await client.buildMessages(messages, null, {
+ instructions: null,
+ additional_instructions: null,
+ });
+
+ expect(parallelAgentNoInstructions.instructions).toContain(memoryContent);
+ });
+
+ it('should not modify agentConfigs when none exist', async () => {
+ const memoryContent = 'User prefers concise responses.';
+ client.useMemory = jest.fn().mockResolvedValue(memoryContent);
+
+ client.agentConfigs = null;
+
+ const messages = [
+ {
+ messageId: 'msg-1',
+ parentMessageId: null,
+ sender: 'User',
+ text: 'Hello',
+ isCreatedByUser: true,
+ },
+ ];
+
+ await expect(
+ client.buildMessages(messages, null, {
+ instructions: 'Base instructions',
+ additional_instructions: null,
+ }),
+ ).resolves.not.toThrow();
+
+ expect(client.options.agent.instructions).toContain(memoryContent);
+ });
+
+ it('should handle empty agentConfigs map', async () => {
+ const memoryContent = 'User likes detailed explanations.';
+ client.useMemory = jest.fn().mockResolvedValue(memoryContent);
+
+ client.agentConfigs = new Map();
+
+ const messages = [
+ {
+ messageId: 'msg-1',
+ parentMessageId: null,
+ sender: 'User',
+ text: 'Hello',
+ isCreatedByUser: true,
+ },
+ ];
+
+ await expect(
+ client.buildMessages(messages, null, {
+ instructions: 'Base instructions',
+ additional_instructions: null,
+ }),
+ ).resolves.not.toThrow();
+
+ expect(client.options.agent.instructions).toContain(memoryContent);
+ });
+ });
+
+ describe('useMemory method - prelimAgent assignment', () => {
+ let client;
+ let mockReq;
+ let mockRes;
+ let mockAgent;
+ let mockOptions;
+ let mockCheckAccess;
+ let mockLoadAgent;
+ let mockInitializeAgent;
+ let mockCreateMemoryProcessor;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ mockAgent = {
+ id: 'agent-123',
+ endpoint: EModelEndpoint.openAI,
+ provider: EModelEndpoint.openAI,
+ instructions: 'Test instructions',
+ model: 'gpt-4',
+ model_parameters: {
+ model: 'gpt-4',
+ },
+ };
+
+ mockReq = {
+ user: {
+ id: 'user-123',
+ personalization: {
+ memories: true,
+ },
+ },
+ config: {
+ memory: {
+ agent: {
+ id: 'agent-123',
+ },
+ },
+ endpoints: {
+ [EModelEndpoint.agents]: {
+ allowedProviders: [EModelEndpoint.openAI],
+ },
+ },
+ },
+ };
+
+ mockRes = {};
+
+ mockOptions = {
+ req: mockReq,
+ res: mockRes,
+ agent: mockAgent,
+ };
+
+ mockCheckAccess = require('@librechat/api').checkAccess;
+ mockLoadAgent = require('~/models/Agent').loadAgent;
+ mockInitializeAgent = require('@librechat/api').initializeAgent;
+ mockCreateMemoryProcessor = require('@librechat/api').createMemoryProcessor;
+ });
+
+ it('should use current agent when memory config agent.id matches current agent id', async () => {
+ mockCheckAccess.mockResolvedValue(true);
+ mockInitializeAgent.mockResolvedValue({
+ ...mockAgent,
+ provider: EModelEndpoint.openAI,
+ });
+ mockCreateMemoryProcessor.mockResolvedValue([undefined, jest.fn()]);
+
+ client = new AgentClient(mockOptions);
+ client.conversationId = 'convo-123';
+ client.responseMessageId = 'response-123';
+
+ await client.useMemory();
+
+ expect(mockLoadAgent).not.toHaveBeenCalled();
+ expect(mockInitializeAgent).toHaveBeenCalledWith(
+ expect.objectContaining({
+ agent: mockAgent,
+ }),
+ expect.any(Object),
+ );
+ });
+
+ it('should load different agent when memory config agent.id differs from current agent id', async () => {
+ const differentAgentId = 'different-agent-456';
+ const differentAgent = {
+ id: differentAgentId,
+ provider: EModelEndpoint.openAI,
+ model: 'gpt-4',
+ instructions: 'Different agent instructions',
+ };
+
+ mockReq.config.memory.agent.id = differentAgentId;
+
+ mockCheckAccess.mockResolvedValue(true);
+ mockLoadAgent.mockResolvedValue(differentAgent);
+ mockInitializeAgent.mockResolvedValue({
+ ...differentAgent,
+ provider: EModelEndpoint.openAI,
+ });
+ mockCreateMemoryProcessor.mockResolvedValue([undefined, jest.fn()]);
+
+ client = new AgentClient(mockOptions);
+ client.conversationId = 'convo-123';
+ client.responseMessageId = 'response-123';
+
+ await client.useMemory();
+
+ expect(mockLoadAgent).toHaveBeenCalledWith(
+ expect.objectContaining({
+ agent_id: differentAgentId,
+ }),
+ );
+ expect(mockInitializeAgent).toHaveBeenCalledWith(
+ expect.objectContaining({
+ agent: differentAgent,
+ }),
+ expect.any(Object),
+ );
+ });
+
+ it('should return early when prelimAgent is undefined (no valid memory agent config)', async () => {
+ mockReq.config.memory = {
+ agent: {},
+ };
+
+ mockCheckAccess.mockResolvedValue(true);
+
+ client = new AgentClient(mockOptions);
+ client.conversationId = 'convo-123';
+ client.responseMessageId = 'response-123';
+
+ const result = await client.useMemory();
+
+ expect(result).toBeUndefined();
+ expect(mockInitializeAgent).not.toHaveBeenCalled();
+ expect(mockCreateMemoryProcessor).not.toHaveBeenCalled();
+ });
+
+ it('should create ephemeral agent when no id but model and provider are specified', async () => {
+ mockReq.config.memory = {
+ agent: {
+ model: 'gpt-4',
+ provider: EModelEndpoint.openAI,
+ },
+ };
+
+ mockCheckAccess.mockResolvedValue(true);
+ mockInitializeAgent.mockResolvedValue({
+ id: Constants.EPHEMERAL_AGENT_ID,
+ model: 'gpt-4',
+ provider: EModelEndpoint.openAI,
+ });
+ mockCreateMemoryProcessor.mockResolvedValue([undefined, jest.fn()]);
+
+ client = new AgentClient(mockOptions);
+ client.conversationId = 'convo-123';
+ client.responseMessageId = 'response-123';
+
+ await client.useMemory();
+
+ expect(mockLoadAgent).not.toHaveBeenCalled();
+ expect(mockInitializeAgent).toHaveBeenCalledWith(
+ expect.objectContaining({
+ agent: expect.objectContaining({
+ id: Constants.EPHEMERAL_AGENT_ID,
+ model: 'gpt-4',
+ provider: EModelEndpoint.openAI,
+ }),
+ }),
+ expect.any(Object),
+ );
+ });
+ });
});
diff --git a/api/server/controllers/agents/openai.js b/api/server/controllers/agents/openai.js
new file mode 100644
index 0000000000..b334580eb1
--- /dev/null
+++ b/api/server/controllers/agents/openai.js
@@ -0,0 +1,701 @@
+const { nanoid } = require('nanoid');
+const { logger } = require('@librechat/data-schemas');
+const { Callback, ToolEndHandler, formatAgentMessages } = require('@librechat/agents');
+const { EModelEndpoint, ResourceType, PermissionBits } = require('librechat-data-provider');
+const {
+ writeSSE,
+ createRun,
+ createChunk,
+ buildToolSet,
+ sendFinalChunk,
+ createSafeUser,
+ validateRequest,
+ initializeAgent,
+ getBalanceConfig,
+ createErrorResponse,
+ recordCollectedUsage,
+ getTransactionsConfig,
+ createToolExecuteHandler,
+ buildNonStreamingResponse,
+ createOpenAIStreamTracker,
+ createOpenAIContentAggregator,
+ isChatCompletionValidationFailure,
+} = require('@librechat/api');
+const { loadAgentTools, loadToolsForExecution } = require('~/server/services/ToolService');
+const { createToolEndCallback } = require('~/server/controllers/agents/callbacks');
+const { findAccessibleResources } = require('~/server/services/PermissionService');
+const { spendTokens, spendStructuredTokens } = require('~/models/spendTokens');
+const { getConvoFiles } = require('~/models/Conversation');
+const { getAgent, getAgents } = require('~/models/Agent');
+const db = require('~/models');
+
+/**
+ * Creates a tool loader function for the agent.
+ * @param {AbortSignal} signal - The abort signal
+ * @param {boolean} [definitionsOnly=true] - When true, returns only serializable
+ * tool definitions without creating full tool instances (for event-driven mode)
+ */
+function createToolLoader(signal, definitionsOnly = true) {
+ return async function loadTools({
+ req,
+ res,
+ tools,
+ model,
+ agentId,
+ provider,
+ tool_options,
+ tool_resources,
+ }) {
+ const agent = { id: agentId, tools, provider, model, tool_options };
+ try {
+ return await loadAgentTools({
+ req,
+ res,
+ agent,
+ signal,
+ tool_resources,
+ definitionsOnly,
+ streamId: null, // No resumable stream for OpenAI compat
+ });
+ } catch (error) {
+ logger.error('Error loading tools for agent ' + agentId, error);
+ }
+ };
+}
+
+/**
+ * Convert content part to internal format
+ * @param {Object} part - Content part
+ * @returns {Object} Converted part
+ */
+function convertContentPart(part) {
+ if (part.type === 'text') {
+ return { type: 'text', text: part.text };
+ }
+ if (part.type === 'image_url') {
+ return { type: 'image_url', image_url: part.image_url };
+ }
+ return part;
+}
+
+/**
+ * Convert OpenAI messages to internal format
+ * @param {Array} messages - OpenAI format messages
+ * @returns {Array} Internal format messages
+ */
+function convertMessages(messages) {
+ return messages.map((msg) => {
+ let content;
+ if (typeof msg.content === 'string') {
+ content = msg.content;
+ } else if (msg.content) {
+ content = msg.content.map(convertContentPart);
+ } else {
+ content = '';
+ }
+
+ return {
+ role: msg.role,
+ content,
+ ...(msg.name && { name: msg.name }),
+ ...(msg.tool_calls && { tool_calls: msg.tool_calls }),
+ ...(msg.tool_call_id && { tool_call_id: msg.tool_call_id }),
+ };
+ });
+}
+
+/**
+ * Send an error response in OpenAI format
+ */
+function sendErrorResponse(res, statusCode, message, type = 'invalid_request_error', code = null) {
+ res.status(statusCode).json(createErrorResponse(message, type, code));
+}
+
+/**
+ * OpenAI-compatible chat completions controller for agents.
+ *
+ * POST /v1/chat/completions
+ *
+ * Request format:
+ * {
+ * "model": "agent_id_here",
+ * "messages": [{"role": "user", "content": "Hello!"}],
+ * "stream": true,
+ * "conversation_id": "optional",
+ * "parent_message_id": "optional"
+ * }
+ */
+const OpenAIChatCompletionController = async (req, res) => {
+ const appConfig = req.config;
+ const requestStartTime = Date.now();
+
+ // Validate request
+ const validation = validateRequest(req.body);
+ if (isChatCompletionValidationFailure(validation)) {
+ return sendErrorResponse(res, 400, validation.error);
+ }
+
+ const request = validation.request;
+ const agentId = request.model;
+
+ // Look up the agent
+ const agent = await getAgent({ id: agentId });
+ if (!agent) {
+ return sendErrorResponse(
+ res,
+ 404,
+ `Agent not found: ${agentId}`,
+ 'invalid_request_error',
+ 'model_not_found',
+ );
+ }
+
+ // Generate IDs
+ const requestId = `chatcmpl-${nanoid()}`;
+ const conversationId = request.conversation_id ?? nanoid();
+ const parentMessageId = request.parent_message_id ?? null;
+ const created = Math.floor(Date.now() / 1000);
+
+ const context = {
+ created,
+ requestId,
+ model: agentId,
+ };
+
+ logger.debug(
+ `[OpenAI API] Request ${requestId} started for agent ${agentId}, stream: ${request.stream}`,
+ );
+
+ // Set up abort controller
+ const abortController = new AbortController();
+
+ // Handle client disconnect
+ req.on('close', () => {
+ if (!abortController.signal.aborted) {
+ abortController.abort();
+ logger.debug('[OpenAI API] Client disconnected, aborting');
+ }
+ });
+
+ try {
+ // Build allowed providers set
+ const allowedProviders = new Set(
+ appConfig?.endpoints?.[EModelEndpoint.agents]?.allowedProviders,
+ );
+
+ // Create tool loader
+ const loadTools = createToolLoader(abortController.signal);
+
+ // Initialize the agent first to check for disableStreaming
+ const endpointOption = {
+ endpoint: agent.provider,
+ model_parameters: agent.model_parameters ?? {},
+ };
+
+ const primaryConfig = await initializeAgent(
+ {
+ req,
+ res,
+ loadTools,
+ requestFiles: [],
+ conversationId,
+ parentMessageId,
+ agent,
+ endpointOption,
+ allowedProviders,
+ isInitialAgent: true,
+ },
+ {
+ getConvoFiles,
+ getFiles: db.getFiles,
+ getUserKey: db.getUserKey,
+ getMessages: db.getMessages,
+ updateFilesUsage: db.updateFilesUsage,
+ getUserKeyValues: db.getUserKeyValues,
+ getUserCodeFiles: db.getUserCodeFiles,
+ getToolFilesByIds: db.getToolFilesByIds,
+ getCodeGeneratedFiles: db.getCodeGeneratedFiles,
+ },
+ );
+
+ // Determine if streaming is enabled (check both request and agent config)
+ const streamingDisabled = !!primaryConfig.model_parameters?.disableStreaming;
+ const isStreaming = request.stream === true && !streamingDisabled;
+
+ // Create tracker for streaming or aggregator for non-streaming
+ const tracker = isStreaming ? createOpenAIStreamTracker() : null;
+ const aggregator = isStreaming ? null : createOpenAIContentAggregator();
+
+ // Set up response for streaming
+ if (isStreaming) {
+ res.setHeader('Content-Type', 'text/event-stream');
+ res.setHeader('Cache-Control', 'no-cache');
+ res.setHeader('Connection', 'keep-alive');
+ res.setHeader('X-Accel-Buffering', 'no');
+ res.flushHeaders();
+
+ // Send initial chunk with role
+ const initialChunk = createChunk(context, { role: 'assistant' });
+ writeSSE(res, initialChunk);
+ }
+
+ // Create handler config for OpenAI streaming (only used when streaming)
+ const handlerConfig = isStreaming
+ ? {
+ res,
+ context,
+ tracker,
+ }
+ : null;
+
+ const collectedUsage = [];
+ /** @type {Promise[]} */
+ const artifactPromises = [];
+
+ const toolEndCallback = createToolEndCallback({ req, res, artifactPromises, streamId: null });
+
+ const toolExecuteOptions = {
+ loadTools: async (toolNames) => {
+ return loadToolsForExecution({
+ req,
+ res,
+ agent,
+ toolNames,
+ signal: abortController.signal,
+ toolRegistry: primaryConfig.toolRegistry,
+ userMCPAuthMap: primaryConfig.userMCPAuthMap,
+ tool_resources: primaryConfig.tool_resources,
+ });
+ },
+ toolEndCallback,
+ };
+
+ const openaiMessages = convertMessages(request.messages);
+
+ const toolSet = buildToolSet(primaryConfig);
+ const { messages: formattedMessages, indexTokenCountMap } = formatAgentMessages(
+ openaiMessages,
+ {},
+ toolSet,
+ );
+
+ /**
+ * Create a simple handler that processes data
+ */
+ const createHandler = (processor) => ({
+ handle: (_event, data) => {
+ if (processor) {
+ processor(data);
+ }
+ },
+ });
+
+ /**
+ * Stream text content in OpenAI format
+ */
+ const streamText = (text) => {
+ if (!text) {
+ return;
+ }
+ if (isStreaming) {
+ tracker.addText();
+ writeSSE(res, createChunk(context, { content: text }));
+ } else {
+ aggregator.addText(text);
+ }
+ };
+
+ /**
+ * Stream reasoning content in OpenAI format (OpenRouter convention)
+ */
+ const streamReasoning = (text) => {
+ if (!text) {
+ return;
+ }
+ if (isStreaming) {
+ tracker.addReasoning();
+ writeSSE(res, createChunk(context, { reasoning: text }));
+ } else {
+ aggregator.addReasoning(text);
+ }
+ };
+
+ // Event handlers for OpenAI-compatible streaming
+ const handlers = {
+ // Text content streaming
+ on_message_delta: createHandler((data) => {
+ const content = data?.delta?.content;
+ if (Array.isArray(content)) {
+ for (const part of content) {
+ if (part.type === 'text' && part.text) {
+ streamText(part.text);
+ }
+ }
+ }
+ }),
+
+ // Reasoning/thinking content streaming
+ on_reasoning_delta: createHandler((data) => {
+ const content = data?.delta?.content;
+ if (Array.isArray(content)) {
+ for (const part of content) {
+ const text = part.think || part.text;
+ if (text) {
+ streamReasoning(text);
+ }
+ }
+ }
+ }),
+
+ // Tool call initiation - streams id and name (from on_run_step)
+ on_run_step: createHandler((data) => {
+ const stepDetails = data?.stepDetails;
+ if (stepDetails?.type === 'tool_calls' && stepDetails.tool_calls) {
+ for (const tc of stepDetails.tool_calls) {
+ const toolIndex = data.index ?? 0;
+ const toolId = tc.id ?? '';
+ const toolName = tc.name ?? '';
+ const toolCall = {
+ id: toolId,
+ type: 'function',
+ function: { name: toolName, arguments: '' },
+ };
+
+ // Track tool call in tracker or aggregator
+ if (isStreaming) {
+ if (!tracker.toolCalls.has(toolIndex)) {
+ tracker.toolCalls.set(toolIndex, toolCall);
+ }
+ // Stream initial tool call chunk (like OpenAI does)
+ writeSSE(
+ res,
+ createChunk(context, {
+ tool_calls: [{ index: toolIndex, ...toolCall }],
+ }),
+ );
+ } else {
+ if (!aggregator.toolCalls.has(toolIndex)) {
+ aggregator.toolCalls.set(toolIndex, toolCall);
+ }
+ }
+ }
+ }
+ }),
+
+ // Tool call argument streaming (from on_run_step_delta)
+ on_run_step_delta: createHandler((data) => {
+ const delta = data?.delta;
+ if (delta?.type === 'tool_calls' && delta.tool_calls) {
+ for (const tc of delta.tool_calls) {
+ const args = tc.args ?? '';
+ if (!args) {
+ continue;
+ }
+
+ const toolIndex = tc.index ?? 0;
+
+ // Update tool call arguments
+ const targetMap = isStreaming ? tracker.toolCalls : aggregator.toolCalls;
+ const tracked = targetMap.get(toolIndex);
+ if (tracked) {
+ tracked.function.arguments += args;
+ }
+
+ // Stream argument delta (only for streaming)
+ if (isStreaming) {
+ writeSSE(
+ res,
+ createChunk(context, {
+ tool_calls: [
+ {
+ index: toolIndex,
+ function: { arguments: args },
+ },
+ ],
+ }),
+ );
+ }
+ }
+ }
+ }),
+
+ // Usage tracking
+ on_chat_model_end: createHandler((data) => {
+ const usage = data?.output?.usage_metadata;
+ if (usage) {
+ collectedUsage.push(usage);
+ const target = isStreaming ? tracker : aggregator;
+ target.usage.promptTokens += usage.input_tokens ?? 0;
+ target.usage.completionTokens += usage.output_tokens ?? 0;
+ }
+ }),
+ on_run_step_completed: createHandler(),
+ // Use proper ToolEndHandler for processing artifacts (images, file citations, code output)
+ on_tool_end: new ToolEndHandler(toolEndCallback, logger),
+ on_chain_stream: createHandler(),
+ on_chain_end: createHandler(),
+ on_agent_update: createHandler(),
+ on_custom_event: createHandler(),
+ // Event-driven tool execution handler
+ on_tool_execute: createToolExecuteHandler(toolExecuteOptions),
+ };
+
+ // Create and run the agent
+ const userId = req.user?.id ?? 'api-user';
+
+ // Extract userMCPAuthMap from primaryConfig (needed for MCP tool connections)
+ const userMCPAuthMap = primaryConfig.userMCPAuthMap;
+
+ const run = await createRun({
+ agents: [primaryConfig],
+ messages: formattedMessages,
+ indexTokenCountMap,
+ runId: requestId,
+ signal: abortController.signal,
+ customHandlers: handlers,
+ requestBody: {
+ messageId: requestId,
+ conversationId,
+ },
+ user: { id: userId },
+ });
+
+ if (!run) {
+ throw new Error('Failed to create agent run');
+ }
+
+ // Process the stream
+ const config = {
+ runName: 'AgentRun',
+ configurable: {
+ thread_id: conversationId,
+ user_id: userId,
+ user: createSafeUser(req.user),
+ ...(userMCPAuthMap != null && { userMCPAuthMap }),
+ },
+ signal: abortController.signal,
+ streamMode: 'values',
+ version: 'v2',
+ };
+
+ await run.processStream({ messages: formattedMessages }, config, {
+ callbacks: {
+ [Callback.TOOL_ERROR]: (graph, error, toolId) => {
+ logger.error(`[OpenAI API] Tool Error "${toolId}"`, error);
+ },
+ },
+ });
+
+ // Record token usage against balance
+ const balanceConfig = getBalanceConfig(appConfig);
+ const transactionsConfig = getTransactionsConfig(appConfig);
+ recordCollectedUsage(
+ { spendTokens, spendStructuredTokens },
+ {
+ user: userId,
+ conversationId,
+ collectedUsage,
+ context: 'message',
+ balance: balanceConfig,
+ transactions: transactionsConfig,
+ model: primaryConfig.model || agent.model_parameters?.model,
+ },
+ ).catch((err) => {
+ logger.error('[OpenAI API] Error recording usage:', err);
+ });
+
+ // Finalize response
+ const duration = Date.now() - requestStartTime;
+ if (isStreaming) {
+ sendFinalChunk(handlerConfig);
+ res.end();
+ logger.debug(`[OpenAI API] Request ${requestId} completed in ${duration}ms (streaming)`);
+
+ // Wait for artifact processing after response ends (non-blocking)
+ if (artifactPromises.length > 0) {
+ Promise.all(artifactPromises).catch((artifactError) => {
+ logger.warn('[OpenAI API] Error processing artifacts:', artifactError);
+ });
+ }
+ } else {
+ // For non-streaming, wait for artifacts before sending response
+ if (artifactPromises.length > 0) {
+ try {
+ await Promise.all(artifactPromises);
+ } catch (artifactError) {
+ logger.warn('[OpenAI API] Error processing artifacts:', artifactError);
+ }
+ }
+
+ // Build usage from aggregated data
+ const usage = {
+ prompt_tokens: aggregator.usage.promptTokens,
+ completion_tokens: aggregator.usage.completionTokens,
+ total_tokens: aggregator.usage.promptTokens + aggregator.usage.completionTokens,
+ };
+
+ if (aggregator.usage.reasoningTokens > 0) {
+ usage.completion_tokens_details = {
+ reasoning_tokens: aggregator.usage.reasoningTokens,
+ };
+ }
+
+ const response = buildNonStreamingResponse(
+ context,
+ aggregator.getText(),
+ aggregator.getReasoning(),
+ aggregator.toolCalls,
+ usage,
+ );
+ res.json(response);
+ logger.debug(`[OpenAI API] Request ${requestId} completed in ${duration}ms (non-streaming)`);
+ }
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : 'An error occurred';
+ logger.error('[OpenAI API] Error:', error);
+
+ // Check if we already started streaming (headers sent)
+ if (res.headersSent) {
+ // Headers already sent, send error in stream
+ const errorChunk = createChunk(context, { content: `\n\nError: ${errorMessage}` }, 'stop');
+ writeSSE(res, errorChunk);
+ writeSSE(res, '[DONE]');
+ res.end();
+ } else {
+ // Forward upstream provider status codes (e.g., Anthropic 400s) instead of masking as 500
+ const statusCode =
+ typeof error?.status === 'number' && error.status >= 400 && error.status < 600
+ ? error.status
+ : 500;
+ const errorType =
+ statusCode >= 400 && statusCode < 500 ? 'invalid_request_error' : 'server_error';
+ sendErrorResponse(res, statusCode, errorMessage, errorType);
+ }
+ }
+};
+
+/**
+ * List available agents as models (filtered by remote access permissions)
+ *
+ * GET /v1/models
+ */
+const ListModelsController = async (req, res) => {
+ try {
+ const userId = req.user?.id;
+ const userRole = req.user?.role;
+
+ if (!userId) {
+ return sendErrorResponse(res, 401, 'Authentication required', 'auth_error');
+ }
+
+ // Find agents the user has remote access to (VIEW permission on REMOTE_AGENT)
+ const accessibleAgentIds = await findAccessibleResources({
+ userId,
+ role: userRole,
+ resourceType: ResourceType.REMOTE_AGENT,
+ requiredPermissions: PermissionBits.VIEW,
+ });
+
+ // Get the accessible agents
+ let agents = [];
+ if (accessibleAgentIds.length > 0) {
+ agents = await getAgents({ _id: { $in: accessibleAgentIds } });
+ }
+
+ const models = agents.map((agent) => ({
+ id: agent.id,
+ object: 'model',
+ created: Math.floor(new Date(agent.createdAt || Date.now()).getTime() / 1000),
+ owned_by: 'librechat',
+ permission: [],
+ root: agent.id,
+ parent: null,
+ // LibreChat extensions
+ name: agent.name,
+ description: agent.description,
+ provider: agent.provider,
+ }));
+
+ res.json({
+ object: 'list',
+ data: models,
+ });
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : 'Failed to list models';
+ logger.error('[OpenAI API] Error listing models:', error);
+ sendErrorResponse(res, 500, errorMessage, 'server_error');
+ }
+};
+
+/**
+ * Get a specific model/agent (with remote access permission check)
+ *
+ * GET /v1/models/:model
+ */
+const GetModelController = async (req, res) => {
+ try {
+ const { model } = req.params;
+ const userId = req.user?.id;
+ const userRole = req.user?.role;
+
+ if (!userId) {
+ return sendErrorResponse(res, 401, 'Authentication required', 'auth_error');
+ }
+
+ const agent = await getAgent({ id: model });
+
+ if (!agent) {
+ return sendErrorResponse(
+ res,
+ 404,
+ `Model not found: ${model}`,
+ 'invalid_request_error',
+ 'model_not_found',
+ );
+ }
+
+ // Check if user has remote access to this agent
+ const accessibleAgentIds = await findAccessibleResources({
+ userId,
+ role: userRole,
+ resourceType: ResourceType.REMOTE_AGENT,
+ requiredPermissions: PermissionBits.VIEW,
+ });
+
+ const hasAccess = accessibleAgentIds.some((id) => id.toString() === agent._id.toString());
+
+ if (!hasAccess) {
+ return sendErrorResponse(
+ res,
+ 403,
+ `No remote access to model: ${model}`,
+ 'permission_error',
+ 'access_denied',
+ );
+ }
+
+ res.json({
+ id: agent.id,
+ object: 'model',
+ created: Math.floor(new Date(agent.createdAt || Date.now()).getTime() / 1000),
+ owned_by: 'librechat',
+ permission: [],
+ root: agent.id,
+ parent: null,
+ // LibreChat extensions
+ name: agent.name,
+ description: agent.description,
+ provider: agent.provider,
+ });
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : 'Failed to get model';
+ logger.error('[OpenAI API] Error getting model:', error);
+ sendErrorResponse(res, 500, errorMessage, 'server_error');
+ }
+};
+
+module.exports = {
+ OpenAIChatCompletionController,
+ ListModelsController,
+ GetModelController,
+};
diff --git a/api/server/controllers/agents/recordCollectedUsage.spec.js b/api/server/controllers/agents/recordCollectedUsage.spec.js
new file mode 100644
index 0000000000..6904f2ed39
--- /dev/null
+++ b/api/server/controllers/agents/recordCollectedUsage.spec.js
@@ -0,0 +1,712 @@
+/**
+ * Tests for AgentClient.recordCollectedUsage
+ *
+ * This is a critical function that handles token spending for agent LLM calls.
+ * It must correctly handle:
+ * - Sequential execution (single agent with tool calls)
+ * - Parallel execution (multiple agents with independent inputs)
+ * - Cache token handling (OpenAI and Anthropic formats)
+ */
+
+const { EModelEndpoint } = require('librechat-data-provider');
+
+// Mock dependencies before requiring the module
+const mockSpendTokens = jest.fn().mockResolvedValue();
+const mockSpendStructuredTokens = jest.fn().mockResolvedValue();
+
+jest.mock('~/models/spendTokens', () => ({
+ spendTokens: (...args) => mockSpendTokens(...args),
+ spendStructuredTokens: (...args) => mockSpendStructuredTokens(...args),
+}));
+
+jest.mock('~/config', () => ({
+ logger: {
+ debug: jest.fn(),
+ error: jest.fn(),
+ warn: jest.fn(),
+ info: jest.fn(),
+ },
+ getMCPManager: jest.fn(() => ({
+ formatInstructionsForContext: jest.fn(),
+ })),
+}));
+
+jest.mock('@librechat/agents', () => ({
+ ...jest.requireActual('@librechat/agents'),
+ createMetadataAggregator: () => ({
+ handleLLMEnd: jest.fn(),
+ collected: [],
+ }),
+}));
+
+const AgentClient = require('./client');
+
+describe('AgentClient - recordCollectedUsage', () => {
+ let client;
+ let mockAgent;
+ let mockOptions;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ mockAgent = {
+ id: 'agent-123',
+ endpoint: EModelEndpoint.openAI,
+ provider: EModelEndpoint.openAI,
+ model_parameters: {
+ model: 'gpt-4',
+ },
+ };
+
+ mockOptions = {
+ req: {
+ user: { id: 'user-123' },
+ body: { model: 'gpt-4', endpoint: EModelEndpoint.openAI },
+ },
+ res: {},
+ agent: mockAgent,
+ endpointTokenConfig: {},
+ };
+
+ client = new AgentClient(mockOptions);
+ client.conversationId = 'convo-123';
+ client.user = 'user-123';
+ });
+
+ describe('basic functionality', () => {
+ it('should return early if collectedUsage is empty', async () => {
+ await client.recordCollectedUsage({
+ collectedUsage: [],
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).not.toHaveBeenCalled();
+ expect(mockSpendStructuredTokens).not.toHaveBeenCalled();
+ expect(client.usage).toBeUndefined();
+ });
+
+ it('should return early if collectedUsage is null', async () => {
+ await client.recordCollectedUsage({
+ collectedUsage: null,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).not.toHaveBeenCalled();
+ expect(client.usage).toBeUndefined();
+ });
+
+ it('should handle single usage entry correctly', async () => {
+ const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' }];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(1);
+ expect(mockSpendTokens).toHaveBeenCalledWith(
+ expect.objectContaining({
+ conversationId: 'convo-123',
+ user: 'user-123',
+ model: 'gpt-4',
+ }),
+ { promptTokens: 100, completionTokens: 50 },
+ );
+ expect(client.usage.input_tokens).toBe(100);
+ expect(client.usage.output_tokens).toBe(50);
+ });
+
+ it('should skip null entries in collectedUsage', async () => {
+ const collectedUsage = [
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ null,
+ { input_tokens: 200, output_tokens: 60, model: 'gpt-4' },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(2);
+ });
+ });
+
+ describe('sequential execution (single agent with tool calls)', () => {
+ it('should calculate tokens correctly for sequential tool calls', async () => {
+ // Sequential flow: output of call N becomes part of input for call N+1
+ // Call 1: input=100, output=50
+ // Call 2: input=150 (100+50), output=30
+ // Call 3: input=180 (150+30), output=20
+ const collectedUsage = [
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ { input_tokens: 150, output_tokens: 30, model: 'gpt-4' },
+ { input_tokens: 180, output_tokens: 20, model: 'gpt-4' },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(3);
+ // Total output should be sum of all output_tokens: 50 + 30 + 20 = 100
+ expect(client.usage.output_tokens).toBe(100);
+ expect(client.usage.input_tokens).toBe(100); // First entry's input
+ });
+ });
+
+ describe('parallel execution (multiple agents)', () => {
+ it('should handle parallel agents with independent input tokens', async () => {
+ // Parallel agents have INDEPENDENT input tokens (not cumulative)
+ // Agent A: input=100, output=50
+ // Agent B: input=80, output=40 (different context, not 100+50)
+ const collectedUsage = [
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ { input_tokens: 80, output_tokens: 40, model: 'gpt-4' },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(2);
+ // Expected total output: 50 + 40 = 90
+ // output_tokens must be positive and should reflect total output
+ expect(client.usage.output_tokens).toBeGreaterThan(0);
+ });
+
+ it('should NOT produce negative output_tokens for parallel execution', async () => {
+ // Critical bug scenario: parallel agents where second agent has LOWER input tokens
+ const collectedUsage = [
+ { input_tokens: 200, output_tokens: 100, model: 'gpt-4' },
+ { input_tokens: 50, output_tokens: 30, model: 'gpt-4' },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ // output_tokens MUST be positive for proper token tracking
+ expect(client.usage.output_tokens).toBeGreaterThan(0);
+ // Correct value should be 100 + 30 = 130
+ });
+
+ it('should calculate correct total output for parallel agents', async () => {
+ // Three parallel agents with independent contexts
+ const collectedUsage = [
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ { input_tokens: 120, output_tokens: 60, model: 'gpt-4-turbo' },
+ { input_tokens: 80, output_tokens: 40, model: 'claude-3' },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(3);
+ // Total output should be 50 + 60 + 40 = 150
+ expect(client.usage.output_tokens).toBe(150);
+ });
+
+ it('should handle worst-case parallel scenario without negative tokens', async () => {
+ // Extreme case: first agent has very high input, subsequent have low
+ const collectedUsage = [
+ { input_tokens: 1000, output_tokens: 500, model: 'gpt-4' },
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ { input_tokens: 50, output_tokens: 25, model: 'gpt-4' },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ // Must be positive, should be 500 + 50 + 25 = 575
+ expect(client.usage.output_tokens).toBeGreaterThan(0);
+ expect(client.usage.output_tokens).toBe(575);
+ });
+ });
+
+ describe('real-world scenarios', () => {
+ it('should correctly sum output tokens for sequential tool calls with growing context', async () => {
+ // Real production data: Claude Opus with multiple tool calls
+ // Context grows as tool results are added, but output_tokens should only count model generations
+ const collectedUsage = [
+ {
+ input_tokens: 31596,
+ output_tokens: 151,
+ total_tokens: 31747,
+ input_token_details: { cache_read: 0, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 35368,
+ output_tokens: 150,
+ total_tokens: 35518,
+ input_token_details: { cache_read: 0, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 58362,
+ output_tokens: 295,
+ total_tokens: 58657,
+ input_token_details: { cache_read: 0, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 112604,
+ output_tokens: 193,
+ total_tokens: 112797,
+ input_token_details: { cache_read: 0, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 257440,
+ output_tokens: 2217,
+ total_tokens: 259657,
+ input_token_details: { cache_read: 0, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ // input_tokens should be first entry's input (initial context)
+ expect(client.usage.input_tokens).toBe(31596);
+
+ // output_tokens should be sum of all model outputs: 151 + 150 + 295 + 193 + 2217 = 3006
+ // NOT the inflated value from incremental calculation (338,559)
+ expect(client.usage.output_tokens).toBe(3006);
+
+ // Verify spendTokens was called for each entry with correct values
+ expect(mockSpendTokens).toHaveBeenCalledTimes(5);
+ expect(mockSpendTokens).toHaveBeenNthCalledWith(
+ 1,
+ expect.objectContaining({ model: 'claude-opus-4-5-20251101' }),
+ { promptTokens: 31596, completionTokens: 151 },
+ );
+ expect(mockSpendTokens).toHaveBeenNthCalledWith(
+ 5,
+ expect.objectContaining({ model: 'claude-opus-4-5-20251101' }),
+ { promptTokens: 257440, completionTokens: 2217 },
+ );
+ });
+
+ it('should handle single followup message correctly', async () => {
+ // Real production data: followup to the above conversation
+ const collectedUsage = [
+ {
+ input_tokens: 263406,
+ output_tokens: 257,
+ total_tokens: 263663,
+ input_token_details: { cache_read: 0, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(client.usage.input_tokens).toBe(263406);
+ expect(client.usage.output_tokens).toBe(257);
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(1);
+ expect(mockSpendTokens).toHaveBeenCalledWith(
+ expect.objectContaining({ model: 'claude-opus-4-5-20251101' }),
+ { promptTokens: 263406, completionTokens: 257 },
+ );
+ });
+
+ it('should ensure output_tokens > 0 check passes for BaseClient.sendMessage', async () => {
+ // This verifies the fix for the duplicate token spending bug
+ // BaseClient.sendMessage checks: if (usage != null && Number(usage[this.outputTokensKey]) > 0)
+ const collectedUsage = [
+ {
+ input_tokens: 31596,
+ output_tokens: 151,
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 35368,
+ output_tokens: 150,
+ model: 'claude-opus-4-5-20251101',
+ },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ const usage = client.getStreamUsage();
+
+ // The check that was failing before the fix
+ expect(usage).not.toBeNull();
+ expect(Number(usage.output_tokens)).toBeGreaterThan(0);
+
+ // Verify correct value
+ expect(usage.output_tokens).toBe(301); // 151 + 150
+ });
+
+ it('should correctly handle cache tokens with multiple tool calls', async () => {
+ // Real production data: Claude Opus with cache tokens (prompt caching)
+ // First entry has cache_creation, subsequent entries have cache_read
+ const collectedUsage = [
+ {
+ input_tokens: 788,
+ output_tokens: 163,
+ total_tokens: 951,
+ input_token_details: { cache_read: 0, cache_creation: 30808 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 3802,
+ output_tokens: 149,
+ total_tokens: 3951,
+ input_token_details: { cache_read: 30808, cache_creation: 768 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 26808,
+ output_tokens: 225,
+ total_tokens: 27033,
+ input_token_details: { cache_read: 31576, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 80912,
+ output_tokens: 204,
+ total_tokens: 81116,
+ input_token_details: { cache_read: 31576, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 136454,
+ output_tokens: 206,
+ total_tokens: 136660,
+ input_token_details: { cache_read: 31576, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 146316,
+ output_tokens: 224,
+ total_tokens: 146540,
+ input_token_details: { cache_read: 31576, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 150402,
+ output_tokens: 1248,
+ total_tokens: 151650,
+ input_token_details: { cache_read: 31576, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 156268,
+ output_tokens: 139,
+ total_tokens: 156407,
+ input_token_details: { cache_read: 31576, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ {
+ input_tokens: 167126,
+ output_tokens: 2961,
+ total_tokens: 170087,
+ input_token_details: { cache_read: 31576, cache_creation: 0 },
+ model: 'claude-opus-4-5-20251101',
+ },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ // input_tokens = first entry's input + cache_creation + cache_read
+ // = 788 + 30808 + 0 = 31596
+ expect(client.usage.input_tokens).toBe(31596);
+
+ // output_tokens = sum of all output_tokens
+ // = 163 + 149 + 225 + 204 + 206 + 224 + 1248 + 139 + 2961 = 5519
+ expect(client.usage.output_tokens).toBe(5519);
+
+ // First 2 entries have cache tokens, should use spendStructuredTokens
+ // Remaining 7 entries have cache_read but no cache_creation, still structured
+ expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(9);
+ expect(mockSpendTokens).toHaveBeenCalledTimes(0);
+
+ // Verify first entry uses structured tokens with cache_creation
+ expect(mockSpendStructuredTokens).toHaveBeenNthCalledWith(
+ 1,
+ expect.objectContaining({ model: 'claude-opus-4-5-20251101' }),
+ {
+ promptTokens: { input: 788, write: 30808, read: 0 },
+ completionTokens: 163,
+ },
+ );
+
+ // Verify second entry uses structured tokens with both cache_creation and cache_read
+ expect(mockSpendStructuredTokens).toHaveBeenNthCalledWith(
+ 2,
+ expect.objectContaining({ model: 'claude-opus-4-5-20251101' }),
+ {
+ promptTokens: { input: 3802, write: 768, read: 30808 },
+ completionTokens: 149,
+ },
+ );
+ });
+ });
+
+ describe('cache token handling', () => {
+ it('should handle OpenAI format cache tokens (input_token_details)', async () => {
+ const collectedUsage = [
+ {
+ input_tokens: 100,
+ output_tokens: 50,
+ model: 'gpt-4',
+ input_token_details: {
+ cache_creation: 20,
+ cache_read: 10,
+ },
+ },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
+ expect(mockSpendStructuredTokens).toHaveBeenCalledWith(
+ expect.objectContaining({ model: 'gpt-4' }),
+ {
+ promptTokens: {
+ input: 100,
+ write: 20,
+ read: 10,
+ },
+ completionTokens: 50,
+ },
+ );
+ });
+
+ it('should handle Anthropic format cache tokens (cache_*_input_tokens)', async () => {
+ const collectedUsage = [
+ {
+ input_tokens: 100,
+ output_tokens: 50,
+ model: 'claude-3',
+ cache_creation_input_tokens: 25,
+ cache_read_input_tokens: 15,
+ },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
+ expect(mockSpendStructuredTokens).toHaveBeenCalledWith(
+ expect.objectContaining({ model: 'claude-3' }),
+ {
+ promptTokens: {
+ input: 100,
+ write: 25,
+ read: 15,
+ },
+ completionTokens: 50,
+ },
+ );
+ });
+
+ it('should use spendTokens for entries without cache tokens', async () => {
+ const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' }];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(1);
+ expect(mockSpendStructuredTokens).not.toHaveBeenCalled();
+ });
+
+ it('should handle mixed cache and non-cache entries', async () => {
+ const collectedUsage = [
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ {
+ input_tokens: 150,
+ output_tokens: 30,
+ model: 'gpt-4',
+ input_token_details: { cache_creation: 10, cache_read: 5 },
+ },
+ { input_tokens: 200, output_tokens: 20, model: 'gpt-4' },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(2);
+ expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
+ });
+
+ it('should include cache tokens in total input calculation', async () => {
+ const collectedUsage = [
+ {
+ input_tokens: 100,
+ output_tokens: 50,
+ model: 'gpt-4',
+ input_token_details: {
+ cache_creation: 20,
+ cache_read: 10,
+ },
+ },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ // Total input should include cache tokens: 100 + 20 + 10 = 130
+ expect(client.usage.input_tokens).toBe(130);
+ });
+ });
+
+ describe('model fallback', () => {
+ it('should use usage.model when available', async () => {
+ const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4-turbo' }];
+
+ await client.recordCollectedUsage({
+ model: 'fallback-model',
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledWith(
+ expect.objectContaining({ model: 'gpt-4-turbo' }),
+ expect.any(Object),
+ );
+ });
+
+ it('should fallback to param model when usage.model is missing', async () => {
+ const collectedUsage = [{ input_tokens: 100, output_tokens: 50 }];
+
+ await client.recordCollectedUsage({
+ model: 'param-model',
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledWith(
+ expect.objectContaining({ model: 'param-model' }),
+ expect.any(Object),
+ );
+ });
+
+ it('should fallback to client.model when param model is missing', async () => {
+ client.model = 'client-model';
+ const collectedUsage = [{ input_tokens: 100, output_tokens: 50 }];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledWith(
+ expect.objectContaining({ model: 'client-model' }),
+ expect.any(Object),
+ );
+ });
+
+ it('should fallback to agent model_parameters.model as last resort', async () => {
+ const collectedUsage = [{ input_tokens: 100, output_tokens: 50 }];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledWith(
+ expect.objectContaining({ model: 'gpt-4' }),
+ expect.any(Object),
+ );
+ });
+ });
+
+ describe('getStreamUsage integration', () => {
+ it('should return the usage object set by recordCollectedUsage', async () => {
+ const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' }];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ const usage = client.getStreamUsage();
+ expect(usage).toEqual({
+ input_tokens: 100,
+ output_tokens: 50,
+ });
+ });
+
+ it('should return undefined before recordCollectedUsage is called', () => {
+ const usage = client.getStreamUsage();
+ expect(usage).toBeUndefined();
+ });
+
+ it('should have output_tokens > 0 for BaseClient.sendMessage check', async () => {
+ // This test verifies the usage will pass the check in BaseClient.sendMessage:
+ // if (usage != null && Number(usage[this.outputTokensKey]) > 0)
+ const collectedUsage = [
+ { input_tokens: 200, output_tokens: 100, model: 'gpt-4' },
+ { input_tokens: 50, output_tokens: 30, model: 'gpt-4' },
+ ];
+
+ await client.recordCollectedUsage({
+ collectedUsage,
+ balance: { enabled: true },
+ transactions: { enabled: true },
+ });
+
+ const usage = client.getStreamUsage();
+ expect(usage).not.toBeNull();
+ expect(Number(usage.output_tokens)).toBeGreaterThan(0);
+ });
+ });
+});
diff --git a/api/server/controllers/agents/request.js b/api/server/controllers/agents/request.js
index faf3905349..dea5400036 100644
--- a/api/server/controllers/agents/request.js
+++ b/api/server/controllers/agents/request.js
@@ -1,16 +1,17 @@
const { logger } = require('@librechat/data-schemas');
-const { Constants } = require('librechat-data-provider');
+const { Constants, ViolationTypes } = require('librechat-data-provider');
const {
sendEvent,
- sanitizeFileForTransmit,
+ getViolationInfo,
+ buildMessageFiles,
+ GenerationJobManager,
+ decrementPendingRequest,
sanitizeMessageForTransmit,
+ checkAndIncrementPendingRequest,
} = require('@librechat/api');
-const {
- handleAbortError,
- createAbortController,
- cleanupAbortController,
-} = require('~/server/middleware');
const { disposeClient, clientRegistry, requestDataMap } = require('~/server/cleanup');
+const { handleAbortError } = require('~/server/middleware');
+const { logViolation } = require('~/cache');
const { saveMessage } = require('~/models');
function createCloseHandler(abortController) {
@@ -31,12 +32,16 @@ function createCloseHandler(abortController) {
};
}
-const AgentController = async (req, res, next, initializeClient, addTitle) => {
- let {
+/**
+ * Resumable Agent Controller - Generation runs independently of HTTP connection.
+ * Returns streamId immediately, client subscribes separately via SSE.
+ */
+const ResumableAgentController = async (req, res, next, initializeClient, addTitle) => {
+ const {
text,
isRegenerate,
endpointOption,
- conversationId,
+ conversationId: reqConversationId,
isContinued = false,
editedContent = null,
parentMessageId = null,
@@ -44,18 +49,410 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
responseMessageId: editedResponseMessageId = null,
} = req.body;
- let sender;
- let abortKey;
+ const userId = req.user.id;
+
+ const { allowed, pendingRequests, limit } = await checkAndIncrementPendingRequest(userId);
+ if (!allowed) {
+ const violationInfo = getViolationInfo(pendingRequests, limit);
+ await logViolation(req, res, ViolationTypes.CONCURRENT, violationInfo, violationInfo.score);
+ return res.status(429).json(violationInfo);
+ }
+
+ // Generate conversationId upfront if not provided - streamId === conversationId always
+ // Treat "new" as a placeholder that needs a real UUID (frontend may send "new" for new convos)
+ const conversationId =
+ !reqConversationId || reqConversationId === 'new' ? crypto.randomUUID() : reqConversationId;
+ const streamId = conversationId;
+
+ let client = null;
+
+ try {
+ logger.debug(`[ResumableAgentController] Creating job`, {
+ streamId,
+ conversationId,
+ reqConversationId,
+ userId,
+ });
+
+ const job = await GenerationJobManager.createJob(streamId, userId, conversationId);
+ const jobCreatedAt = job.createdAt; // Capture creation time to detect job replacement
+ req._resumableStreamId = streamId;
+
+ // Send JSON response IMMEDIATELY so client can connect to SSE stream
+ // This is critical: tool loading (MCP OAuth) may emit events that the client needs to receive
+ res.json({ streamId, conversationId, status: 'started' });
+
+ // Note: We no longer use res.on('close') to abort since we send JSON immediately.
+ // The response closes normally after res.json(), which is not an abort condition.
+ // Abort handling is done through GenerationJobManager via the SSE stream connection.
+
+ // Track if partial response was already saved to avoid duplicates
+ let partialResponseSaved = false;
+
+ /**
+ * Listen for all subscribers leaving to save partial response.
+ * This ensures the response is saved to DB even if all clients disconnect
+ * while generation continues.
+ *
+ * Note: The messageId used here falls back to `${userMessage.messageId}_` if the
+ * actual response messageId isn't available yet. The final response save will
+ * overwrite this with the complete response using the same messageId pattern.
+ */
+ job.emitter.on('allSubscribersLeft', async (aggregatedContent) => {
+ if (partialResponseSaved || !aggregatedContent || aggregatedContent.length === 0) {
+ return;
+ }
+
+ const resumeState = await GenerationJobManager.getResumeState(streamId);
+ if (!resumeState?.userMessage) {
+ logger.debug('[ResumableAgentController] No user message to save partial response for');
+ return;
+ }
+
+ partialResponseSaved = true;
+ const responseConversationId = resumeState.conversationId || conversationId;
+
+ try {
+ const partialMessage = {
+ messageId: resumeState.responseMessageId || `${resumeState.userMessage.messageId}_`,
+ conversationId: responseConversationId,
+ parentMessageId: resumeState.userMessage.messageId,
+ sender: client?.sender ?? 'AI',
+ content: aggregatedContent,
+ unfinished: true,
+ error: false,
+ isCreatedByUser: false,
+ user: userId,
+ endpoint: endpointOption.endpoint,
+ model: endpointOption.modelOptions?.model || endpointOption.model_parameters?.model,
+ };
+
+ if (req.body?.agent_id) {
+ partialMessage.agent_id = req.body.agent_id;
+ }
+
+ await saveMessage(req, partialMessage, {
+ context: 'api/server/controllers/agents/request.js - partial response on disconnect',
+ });
+
+ logger.debug(
+ `[ResumableAgentController] Saved partial response for ${streamId}, content parts: ${aggregatedContent.length}`,
+ );
+ } catch (error) {
+ logger.error('[ResumableAgentController] Error saving partial response:', error);
+ // Reset flag so we can try again if subscribers reconnect and leave again
+ partialResponseSaved = false;
+ }
+ });
+
+ /** @type {{ client: TAgentClient; userMCPAuthMap?: Record> }} */
+ const result = await initializeClient({
+ req,
+ res,
+ endpointOption,
+ // Use the job's abort controller signal - allows abort via GenerationJobManager.abortJob()
+ signal: job.abortController.signal,
+ });
+
+ if (job.abortController.signal.aborted) {
+ GenerationJobManager.completeJob(streamId, 'Request aborted during initialization');
+ await decrementPendingRequest(userId);
+ return;
+ }
+
+ client = result.client;
+
+ if (client?.sender) {
+ GenerationJobManager.updateMetadata(streamId, { sender: client.sender });
+ }
+
+ // Store reference to client's contentParts - graph will be set when run is created
+ if (client?.contentParts) {
+ GenerationJobManager.setContentParts(streamId, client.contentParts);
+ }
+
+ let userMessage;
+
+ const getReqData = (data = {}) => {
+ if (data.userMessage) {
+ userMessage = data.userMessage;
+ }
+ // conversationId is pre-generated, no need to update from callback
+ };
+
+ // Start background generation - readyPromise resolves immediately now
+ // (sync mechanism handles late subscribers)
+ const startGeneration = async () => {
+ try {
+ // Short timeout as safety net - promise should already be resolved
+ await Promise.race([job.readyPromise, new Promise((resolve) => setTimeout(resolve, 100))]);
+ } catch (waitError) {
+ logger.warn(
+ `[ResumableAgentController] Error waiting for subscriber: ${waitError.message}`,
+ );
+ }
+
+ try {
+ const onStart = (userMsg, respMsgId, _isNewConvo) => {
+ userMessage = userMsg;
+
+ // Store userMessage and responseMessageId upfront for resume capability
+ GenerationJobManager.updateMetadata(streamId, {
+ responseMessageId: respMsgId,
+ userMessage: {
+ messageId: userMsg.messageId,
+ parentMessageId: userMsg.parentMessageId,
+ conversationId: userMsg.conversationId,
+ text: userMsg.text,
+ },
+ });
+
+ GenerationJobManager.emitChunk(streamId, {
+ created: true,
+ message: userMessage,
+ streamId,
+ });
+ };
+
+ const messageOptions = {
+ user: userId,
+ onStart,
+ getReqData,
+ isContinued,
+ isRegenerate,
+ editedContent,
+ conversationId,
+ parentMessageId,
+ abortController: job.abortController,
+ overrideParentMessageId,
+ isEdited: !!editedContent,
+ userMCPAuthMap: result.userMCPAuthMap,
+ responseMessageId: editedResponseMessageId,
+ progressOptions: {
+ res: {
+ write: () => true,
+ end: () => {},
+ headersSent: false,
+ writableEnded: false,
+ },
+ },
+ };
+
+ const response = await client.sendMessage(text, messageOptions);
+
+ const messageId = response.messageId;
+ const endpoint = endpointOption.endpoint;
+ response.endpoint = endpoint;
+
+ const databasePromise = response.databasePromise;
+ delete response.databasePromise;
+
+ const { conversation: convoData = {} } = await databasePromise;
+ const conversation = { ...convoData };
+ conversation.title =
+ conversation && !conversation.title ? null : conversation?.title || 'New Chat';
+
+ if (req.body.files && Array.isArray(client.options.attachments)) {
+ const files = buildMessageFiles(req.body.files, client.options.attachments);
+ if (files.length > 0) {
+ userMessage.files = files;
+ }
+ delete userMessage.image_urls;
+ }
+
+ // Check abort state BEFORE calling completeJob (which triggers abort signal for cleanup)
+ const wasAbortedBeforeComplete = job.abortController.signal.aborted;
+ const isNewConvo = !reqConversationId || reqConversationId === 'new';
+ const shouldGenerateTitle =
+ addTitle &&
+ parentMessageId === Constants.NO_PARENT &&
+ isNewConvo &&
+ !wasAbortedBeforeComplete;
+
+ // Save user message BEFORE sending final event to avoid race condition
+ // where client refetch happens before database is updated
+ if (!client.skipSaveUserMessage && userMessage) {
+ await saveMessage(req, userMessage, {
+ context: 'api/server/controllers/agents/request.js - resumable user message',
+ });
+ }
+
+ // CRITICAL: Save response message BEFORE emitting final event.
+ // This prevents race conditions where the client sends a follow-up message
+ // before the response is saved to the database, causing orphaned parentMessageIds.
+ if (client.savedMessageIds && !client.savedMessageIds.has(messageId)) {
+ await saveMessage(
+ req,
+ { ...response, user: userId, unfinished: wasAbortedBeforeComplete },
+ { context: 'api/server/controllers/agents/request.js - resumable response end' },
+ );
+ }
+
+ // Check if our job was replaced by a new request before emitting
+ // This prevents stale requests from emitting events to newer jobs
+ const currentJob = await GenerationJobManager.getJob(streamId);
+ const jobWasReplaced = !currentJob || currentJob.createdAt !== jobCreatedAt;
+
+ if (jobWasReplaced) {
+ logger.debug(`[ResumableAgentController] Skipping FINAL emit - job was replaced`, {
+ streamId,
+ originalCreatedAt: jobCreatedAt,
+ currentCreatedAt: currentJob?.createdAt,
+ });
+ // Still decrement pending request since we incremented at start
+ await decrementPendingRequest(userId);
+ return;
+ }
+
+ if (!wasAbortedBeforeComplete) {
+ const finalEvent = {
+ final: true,
+ conversation,
+ title: conversation.title,
+ requestMessage: sanitizeMessageForTransmit(userMessage),
+ responseMessage: { ...response },
+ };
+
+ logger.debug(`[ResumableAgentController] Emitting FINAL event`, {
+ streamId,
+ wasAbortedBeforeComplete,
+ userMessageId: userMessage?.messageId,
+ responseMessageId: response?.messageId,
+ conversationId: conversation?.conversationId,
+ });
+
+ await GenerationJobManager.emitDone(streamId, finalEvent);
+ GenerationJobManager.completeJob(streamId);
+ await decrementPendingRequest(userId);
+ } else {
+ const finalEvent = {
+ final: true,
+ conversation,
+ title: conversation.title,
+ requestMessage: sanitizeMessageForTransmit(userMessage),
+ responseMessage: { ...response, unfinished: true },
+ };
+
+ logger.debug(`[ResumableAgentController] Emitting ABORTED FINAL event`, {
+ streamId,
+ wasAbortedBeforeComplete,
+ userMessageId: userMessage?.messageId,
+ responseMessageId: response?.messageId,
+ conversationId: conversation?.conversationId,
+ });
+
+ await GenerationJobManager.emitDone(streamId, finalEvent);
+ GenerationJobManager.completeJob(streamId, 'Request aborted');
+ await decrementPendingRequest(userId);
+ }
+
+ if (shouldGenerateTitle) {
+ addTitle(req, {
+ text,
+ response: { ...response },
+ client,
+ })
+ .catch((err) => {
+ logger.error('[ResumableAgentController] Error in title generation', err);
+ })
+ .finally(() => {
+ if (client) {
+ disposeClient(client);
+ }
+ });
+ } else {
+ if (client) {
+ disposeClient(client);
+ }
+ }
+ } catch (error) {
+ // Check if this was an abort (not a real error)
+ const wasAborted = job.abortController.signal.aborted || error.message?.includes('abort');
+
+ if (wasAborted) {
+ logger.debug(`[ResumableAgentController] Generation aborted for ${streamId}`);
+ // abortJob already handled emitDone and completeJob
+ } else {
+ logger.error(`[ResumableAgentController] Generation error for ${streamId}:`, error);
+ await GenerationJobManager.emitError(streamId, error.message || 'Generation failed');
+ GenerationJobManager.completeJob(streamId, error.message);
+ }
+
+ await decrementPendingRequest(userId);
+
+ if (client) {
+ disposeClient(client);
+ }
+
+ // Don't continue to title generation after error/abort
+ return;
+ }
+ };
+
+ // Start generation and handle any unhandled errors
+ startGeneration().catch(async (err) => {
+ logger.error(
+ `[ResumableAgentController] Unhandled error in background generation: ${err.message}`,
+ );
+ GenerationJobManager.completeJob(streamId, err.message);
+ await decrementPendingRequest(userId);
+ });
+ } catch (error) {
+ logger.error('[ResumableAgentController] Initialization error:', error);
+ if (!res.headersSent) {
+ res.status(500).json({ error: error.message || 'Failed to start generation' });
+ } else {
+ // JSON already sent, emit error to stream so client can receive it
+ await GenerationJobManager.emitError(streamId, error.message || 'Failed to start generation');
+ }
+ GenerationJobManager.completeJob(streamId, error.message);
+ await decrementPendingRequest(userId);
+ if (client) {
+ disposeClient(client);
+ }
+ }
+};
+
+/**
+ * Agent Controller - Routes to ResumableAgentController for all requests.
+ * The legacy non-resumable path is kept below but no longer used by default.
+ */
+const AgentController = async (req, res, next, initializeClient, addTitle) => {
+ return ResumableAgentController(req, res, next, initializeClient, addTitle);
+};
+
+/**
+ * Legacy Non-resumable Agent Controller - Uses GenerationJobManager for abort handling.
+ * Response is streamed directly to client via res, but abort state is managed centrally.
+ * @deprecated Use ResumableAgentController instead
+ */
+const _LegacyAgentController = async (req, res, next, initializeClient, addTitle) => {
+ const {
+ text,
+ isRegenerate,
+ endpointOption,
+ conversationId: reqConversationId,
+ isContinued = false,
+ editedContent = null,
+ parentMessageId = null,
+ overrideParentMessageId = null,
+ responseMessageId: editedResponseMessageId = null,
+ } = req.body;
+
+ // Generate conversationId upfront if not provided - streamId === conversationId always
+ // Treat "new" as a placeholder that needs a real UUID (frontend may send "new" for new convos)
+ const conversationId =
+ !reqConversationId || reqConversationId === 'new' ? crypto.randomUUID() : reqConversationId;
+ const streamId = conversationId;
+
let userMessage;
- let promptTokens;
let userMessageId;
let responseMessageId;
- let userMessagePromise;
- let getAbortData;
let client = null;
let cleanupHandlers = [];
- const newConvo = !conversationId;
+ // Match the same logic used for conversationId generation above
+ const isNewConvo = !reqConversationId || reqConversationId === 'new';
const userId = req.user.id;
// Create handler to avoid capturing the entire parent scope
@@ -64,24 +461,20 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
if (key === 'userMessage') {
userMessage = data[key];
userMessageId = data[key].messageId;
- } else if (key === 'userMessagePromise') {
- userMessagePromise = data[key];
} else if (key === 'responseMessageId') {
responseMessageId = data[key];
} else if (key === 'promptTokens') {
- promptTokens = data[key];
+ // Update job metadata with prompt tokens for abort handling
+ GenerationJobManager.updateMetadata(streamId, { promptTokens: data[key] });
} else if (key === 'sender') {
- sender = data[key];
- } else if (key === 'abortKey') {
- abortKey = data[key];
- } else if (!conversationId && key === 'conversationId') {
- conversationId = data[key];
+ GenerationJobManager.updateMetadata(streamId, { sender: data[key] });
}
+ // conversationId is pre-generated, no need to update from callback
}
};
// Create a function to handle final cleanup
- const performCleanup = () => {
+ const performCleanup = async () => {
logger.debug('[AgentController] Performing cleanup');
if (Array.isArray(cleanupHandlers)) {
for (const handler of cleanupHandlers) {
@@ -95,10 +488,10 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
}
}
- // Clean up abort controller
- if (abortKey) {
- logger.debug('[AgentController] Cleaning up abort controller');
- cleanupAbortController(abortKey);
+ // Complete the job in GenerationJobManager
+ if (streamId) {
+ logger.debug('[AgentController] Completing job in GenerationJobManager');
+ await GenerationJobManager.completeJob(streamId);
}
// Dispose client properly
@@ -110,11 +503,7 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
client = null;
getReqData = null;
userMessage = null;
- getAbortData = null;
- endpointOption.agent = null;
- endpointOption = null;
cleanupHandlers = null;
- userMessagePromise = null;
// Clear request data map
if (requestDataMap.has(req)) {
@@ -136,6 +525,7 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
}
};
cleanupHandlers.push(removePrelimHandler);
+
/** @type {{ client: TAgentClient; userMCPAuthMap?: Record> }} */
const result = await initializeClient({
req,
@@ -143,6 +533,7 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
endpointOption,
signal: prelimAbortController.signal,
});
+
if (prelimAbortController.signal?.aborted) {
prelimAbortController = null;
throw new Error('Request was aborted before initialization could complete');
@@ -161,28 +552,24 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
// Store request data in WeakMap keyed by req object
requestDataMap.set(req, { client });
- // Use WeakRef to allow GC but still access content if it exists
- const contentRef = new WeakRef(client.contentParts || []);
+ // Create job in GenerationJobManager for abort handling
+ // streamId === conversationId (pre-generated above)
+ const job = await GenerationJobManager.createJob(streamId, userId, conversationId);
- // Minimize closure scope - only capture small primitives and WeakRef
- getAbortData = () => {
- // Dereference WeakRef each time
- const content = contentRef.deref();
+ // Store endpoint metadata for abort handling
+ GenerationJobManager.updateMetadata(streamId, {
+ endpoint: endpointOption.endpoint,
+ iconURL: endpointOption.iconURL,
+ model: endpointOption.modelOptions?.model || endpointOption.model_parameters?.model,
+ sender: client?.sender,
+ });
- return {
- sender,
- content: content || [],
- userMessage,
- promptTokens,
- conversationId,
- userMessagePromise,
- messageId: responseMessageId,
- parentMessageId: overrideParentMessageId ?? userMessageId,
- };
- };
+ // Store content parts reference for abort
+ if (client?.contentParts) {
+ GenerationJobManager.setContentParts(streamId, client.contentParts);
+ }
- const { abortController, onStart } = createAbortController(req, res, getAbortData, getReqData);
- const closeHandler = createCloseHandler(abortController);
+ const closeHandler = createCloseHandler(job.abortController);
res.on('close', closeHandler);
cleanupHandlers.push(() => {
try {
@@ -192,6 +579,27 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
}
});
+ /**
+ * onStart callback - stores user message and response ID for abort handling
+ */
+ const onStart = (userMsg, respMsgId, _isNewConvo) => {
+ sendEvent(res, { message: userMsg, created: true });
+ userMessage = userMsg;
+ userMessageId = userMsg.messageId;
+ responseMessageId = respMsgId;
+
+ // Store metadata for abort handling (conversationId is pre-generated)
+ GenerationJobManager.updateMetadata(streamId, {
+ responseMessageId: respMsgId,
+ userMessage: {
+ messageId: userMsg.messageId,
+ parentMessageId: userMsg.parentMessageId,
+ conversationId,
+ text: userMsg.text,
+ },
+ });
+ };
+
const messageOptions = {
user: userId,
onStart,
@@ -201,7 +609,7 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
editedContent,
conversationId,
parentMessageId,
- abortController,
+ abortController: job.abortController,
overrideParentMessageId,
isEdited: !!editedContent,
userMCPAuthMap: result.userMCPAuthMap,
@@ -228,20 +636,16 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
conversation.title =
conversation && !conversation.title ? null : conversation?.title || 'New Chat';
- // Process files if needed (sanitize to remove large text fields before transmission)
- if (req.body.files && client.options?.attachments) {
- userMessage.files = [];
- const messageFiles = new Set(req.body.files.map((file) => file.file_id));
- for (const attachment of client.options.attachments) {
- if (messageFiles.has(attachment.file_id)) {
- userMessage.files.push(sanitizeFileForTransmit(attachment));
- }
+ if (req.body.files && Array.isArray(client.options.attachments)) {
+ const files = buildMessageFiles(req.body.files, client.options.attachments);
+ if (files.length > 0) {
+ userMessage.files = files;
}
delete userMessage.image_urls;
}
// Only send if not aborted
- if (!abortController.signal.aborted) {
+ if (!job.abortController.signal.aborted) {
// Create a new response object with minimal copies
const finalResponse = { ...response };
@@ -292,7 +696,7 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
}
// Add title if needed - extract minimal data
- if (addTitle && parentMessageId === Constants.NO_PARENT && newConvo) {
+ if (addTitle && parentMessageId === Constants.NO_PARENT && isNewConvo) {
addTitle(req, {
text,
response: { ...response },
@@ -315,7 +719,7 @@ const AgentController = async (req, res, next, initializeClient, addTitle) => {
// Handle error without capturing much scope
handleAbortError(res, req, error, {
conversationId,
- sender,
+ sender: client?.sender,
messageId: responseMessageId,
parentMessageId: overrideParentMessageId ?? userMessageId ?? parentMessageId,
userMessageId,
diff --git a/api/server/controllers/agents/responses.js b/api/server/controllers/agents/responses.js
new file mode 100644
index 0000000000..afdb96be9f
--- /dev/null
+++ b/api/server/controllers/agents/responses.js
@@ -0,0 +1,889 @@
+const { nanoid } = require('nanoid');
+const { v4: uuidv4 } = require('uuid');
+const { logger } = require('@librechat/data-schemas');
+const { Callback, ToolEndHandler, formatAgentMessages } = require('@librechat/agents');
+const { EModelEndpoint, ResourceType, PermissionBits } = require('librechat-data-provider');
+const {
+ createRun,
+ buildToolSet,
+ createSafeUser,
+ initializeAgent,
+ getBalanceConfig,
+ recordCollectedUsage,
+ getTransactionsConfig,
+ createToolExecuteHandler,
+ // Responses API
+ writeDone,
+ buildResponse,
+ generateResponseId,
+ isValidationFailure,
+ emitResponseCreated,
+ createResponseContext,
+ createResponseTracker,
+ setupStreamingResponse,
+ emitResponseInProgress,
+ convertInputToMessages,
+ validateResponseRequest,
+ buildAggregatedResponse,
+ createResponseAggregator,
+ sendResponsesErrorResponse,
+ createResponsesEventHandlers,
+ createAggregatorEventHandlers,
+} = require('@librechat/api');
+const {
+ createResponsesToolEndCallback,
+ createToolEndCallback,
+} = require('~/server/controllers/agents/callbacks');
+const { loadAgentTools, loadToolsForExecution } = require('~/server/services/ToolService');
+const { findAccessibleResources } = require('~/server/services/PermissionService');
+const { getConvoFiles, saveConvo, getConvo } = require('~/models/Conversation');
+const { spendTokens, spendStructuredTokens } = require('~/models/spendTokens');
+const { getAgent, getAgents } = require('~/models/Agent');
+const db = require('~/models');
+
+/** @type {import('@librechat/api').AppConfig | null} */
+let appConfig = null;
+
+/**
+ * Set the app config for the controller
+ * @param {import('@librechat/api').AppConfig} config
+ */
+function setAppConfig(config) {
+ appConfig = config;
+}
+
+/**
+ * Creates a tool loader function for the agent.
+ * @param {AbortSignal} signal - The abort signal
+ * @param {boolean} [definitionsOnly=true] - When true, returns only serializable
+ * tool definitions without creating full tool instances (for event-driven mode)
+ */
+function createToolLoader(signal, definitionsOnly = true) {
+ return async function loadTools({
+ req,
+ res,
+ tools,
+ model,
+ agentId,
+ provider,
+ tool_options,
+ tool_resources,
+ }) {
+ const agent = { id: agentId, tools, provider, model, tool_options };
+ try {
+ return await loadAgentTools({
+ req,
+ res,
+ agent,
+ signal,
+ tool_resources,
+ definitionsOnly,
+ streamId: null,
+ });
+ } catch (error) {
+ logger.error('Error loading tools for agent ' + agentId, error);
+ }
+ };
+}
+
+/**
+ * Convert Open Responses input items to internal messages
+ * @param {import('@librechat/api').InputItem[]} input
+ * @returns {Array} Internal messages
+ */
+function convertToInternalMessages(input) {
+ return convertInputToMessages(input);
+}
+
+/**
+ * Load messages from a previous response/conversation
+ * @param {string} conversationId - The conversation/response ID
+ * @param {string} userId - The user ID
+ * @returns {Promise} Messages from the conversation
+ */
+async function loadPreviousMessages(conversationId, userId) {
+ try {
+ const messages = await db.getMessages({ conversationId, user: userId });
+ if (!messages || messages.length === 0) {
+ return [];
+ }
+
+ // Convert stored messages to internal format
+ return messages.map((msg) => {
+ const internalMsg = {
+ role: msg.isCreatedByUser ? 'user' : 'assistant',
+ content: '',
+ messageId: msg.messageId,
+ };
+
+ // Handle content - could be string or array
+ if (typeof msg.text === 'string') {
+ internalMsg.content = msg.text;
+ } else if (Array.isArray(msg.content)) {
+ // Handle content parts
+ internalMsg.content = msg.content;
+ } else if (msg.text) {
+ internalMsg.content = String(msg.text);
+ }
+
+ return internalMsg;
+ });
+ } catch (error) {
+ logger.error('[Responses API] Error loading previous messages:', error);
+ return [];
+ }
+}
+
+/**
+ * Save input messages to database
+ * @param {import('express').Request} req
+ * @param {string} conversationId
+ * @param {Array} inputMessages - Internal format messages
+ * @param {string} agentId
+ * @returns {Promise}
+ */
+async function saveInputMessages(req, conversationId, inputMessages, agentId) {
+ for (const msg of inputMessages) {
+ if (msg.role === 'user') {
+ await db.saveMessage(
+ req,
+ {
+ messageId: msg.messageId || nanoid(),
+ conversationId,
+ parentMessageId: null,
+ isCreatedByUser: true,
+ text: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),
+ sender: 'User',
+ endpoint: EModelEndpoint.agents,
+ model: agentId,
+ },
+ { context: 'Responses API - save user input' },
+ );
+ }
+ }
+}
+
+/**
+ * Save response output to database
+ * @param {import('express').Request} req
+ * @param {string} conversationId
+ * @param {string} responseId
+ * @param {import('@librechat/api').Response} response
+ * @param {string} agentId
+ * @returns {Promise}
+ */
+async function saveResponseOutput(req, conversationId, responseId, response, agentId) {
+ // Extract text content from output items
+ let responseText = '';
+ for (const item of response.output) {
+ if (item.type === 'message' && item.content) {
+ for (const part of item.content) {
+ if (part.type === 'output_text' && part.text) {
+ responseText += part.text;
+ }
+ }
+ }
+ }
+
+ // Save the assistant message
+ await db.saveMessage(
+ req,
+ {
+ messageId: responseId,
+ conversationId,
+ parentMessageId: null,
+ isCreatedByUser: false,
+ text: responseText,
+ sender: 'Agent',
+ endpoint: EModelEndpoint.agents,
+ model: agentId,
+ finish_reason: response.status === 'completed' ? 'stop' : response.status,
+ tokenCount: response.usage?.output_tokens,
+ },
+ { context: 'Responses API - save assistant response' },
+ );
+}
+
+/**
+ * Save or update conversation
+ * @param {import('express').Request} req
+ * @param {string} conversationId
+ * @param {string} agentId
+ * @param {object} agent
+ * @returns {Promise}
+ */
+async function saveConversation(req, conversationId, agentId, agent) {
+ await saveConvo(
+ req,
+ {
+ conversationId,
+ endpoint: EModelEndpoint.agents,
+ agentId,
+ title: agent?.name || 'Open Responses Conversation',
+ model: agent?.model,
+ },
+ { context: 'Responses API - save conversation' },
+ );
+}
+
+/**
+ * Convert stored messages to Open Responses output format
+ * @param {Array} messages - Stored messages
+ * @returns {Array} Output items
+ */
+function convertMessagesToOutputItems(messages) {
+ const output = [];
+
+ for (const msg of messages) {
+ if (!msg.isCreatedByUser) {
+ output.push({
+ type: 'message',
+ id: msg.messageId,
+ role: 'assistant',
+ status: 'completed',
+ content: [
+ {
+ type: 'output_text',
+ text: msg.text || '',
+ annotations: [],
+ },
+ ],
+ });
+ }
+ }
+
+ return output;
+}
+
+/**
+ * Create Response - POST /v1/responses
+ *
+ * Creates a model response following the Open Responses API specification.
+ * Supports both streaming and non-streaming responses.
+ *
+ * @param {import('express').Request} req
+ * @param {import('express').Response} res
+ */
+const createResponse = async (req, res) => {
+ const requestStartTime = Date.now();
+
+ // Validate request
+ const validation = validateResponseRequest(req.body);
+ if (isValidationFailure(validation)) {
+ return sendResponsesErrorResponse(res, 400, validation.error);
+ }
+
+ const request = validation.request;
+ const agentId = request.model;
+ const isStreaming = request.stream === true;
+
+ // Look up the agent
+ const agent = await getAgent({ id: agentId });
+ if (!agent) {
+ return sendResponsesErrorResponse(
+ res,
+ 404,
+ `Agent not found: ${agentId}`,
+ 'not_found',
+ 'model_not_found',
+ );
+ }
+
+ // Generate IDs
+ const responseId = generateResponseId();
+ const conversationId = request.previous_response_id ?? uuidv4();
+ const parentMessageId = null;
+
+ // Create response context
+ const context = createResponseContext(request, responseId);
+
+ logger.debug(
+ `[Responses API] Request ${responseId} started for agent ${agentId}, stream: ${isStreaming}`,
+ );
+
+ // Set up abort controller
+ const abortController = new AbortController();
+
+ // Handle client disconnect
+ req.on('close', () => {
+ if (!abortController.signal.aborted) {
+ abortController.abort();
+ logger.debug('[Responses API] Client disconnected, aborting');
+ }
+ });
+
+ try {
+ // Build allowed providers set
+ const allowedProviders = new Set(
+ appConfig?.endpoints?.[EModelEndpoint.agents]?.allowedProviders,
+ );
+
+ // Create tool loader
+ const loadTools = createToolLoader(abortController.signal);
+
+ // Initialize the agent first to check for disableStreaming
+ const endpointOption = {
+ endpoint: agent.provider,
+ model_parameters: agent.model_parameters ?? {},
+ };
+
+ const primaryConfig = await initializeAgent(
+ {
+ req,
+ res,
+ loadTools,
+ requestFiles: [],
+ conversationId,
+ parentMessageId,
+ agent,
+ endpointOption,
+ allowedProviders,
+ isInitialAgent: true,
+ },
+ {
+ getConvoFiles,
+ getFiles: db.getFiles,
+ getUserKey: db.getUserKey,
+ getMessages: db.getMessages,
+ updateFilesUsage: db.updateFilesUsage,
+ getUserKeyValues: db.getUserKeyValues,
+ getUserCodeFiles: db.getUserCodeFiles,
+ getToolFilesByIds: db.getToolFilesByIds,
+ getCodeGeneratedFiles: db.getCodeGeneratedFiles,
+ },
+ );
+
+ // Determine if streaming is enabled (check both request and agent config)
+ const streamingDisabled = !!primaryConfig.model_parameters?.disableStreaming;
+ const actuallyStreaming = isStreaming && !streamingDisabled;
+
+ // Load previous messages if previous_response_id is provided
+ let previousMessages = [];
+ if (request.previous_response_id) {
+ const userId = req.user?.id ?? 'api-user';
+ previousMessages = await loadPreviousMessages(request.previous_response_id, userId);
+ }
+
+ // Convert input to internal messages
+ const inputMessages = convertToInternalMessages(
+ typeof request.input === 'string' ? request.input : request.input,
+ );
+
+ // Merge previous messages with new input
+ const allMessages = [...previousMessages, ...inputMessages];
+
+ const toolSet = buildToolSet(primaryConfig);
+ const { messages: formattedMessages, indexTokenCountMap } = formatAgentMessages(
+ allMessages,
+ {},
+ toolSet,
+ );
+
+ // Create tracker for streaming or aggregator for non-streaming
+ const tracker = actuallyStreaming ? createResponseTracker() : null;
+ const aggregator = actuallyStreaming ? null : createResponseAggregator();
+
+ // Set up response for streaming
+ if (actuallyStreaming) {
+ setupStreamingResponse(res);
+
+ // Create handler config
+ const handlerConfig = {
+ res,
+ context,
+ tracker,
+ };
+
+ // Emit response.created then response.in_progress per Open Responses spec
+ emitResponseCreated(handlerConfig);
+ emitResponseInProgress(handlerConfig);
+
+ // Create event handlers
+ const { handlers: responsesHandlers, finalizeStream } =
+ createResponsesEventHandlers(handlerConfig);
+
+ // Collect usage for balance tracking
+ const collectedUsage = [];
+
+ // Artifact promises for processing tool outputs
+ /** @type {Promise[]} */
+ const artifactPromises = [];
+ // Use Responses API-specific callback that emits librechat:attachment events
+ const toolEndCallback = createResponsesToolEndCallback({
+ req,
+ res,
+ tracker,
+ artifactPromises,
+ });
+
+ // Create tool execute options for event-driven tool execution
+ const toolExecuteOptions = {
+ loadTools: async (toolNames) => {
+ return loadToolsForExecution({
+ req,
+ res,
+ agent,
+ toolNames,
+ signal: abortController.signal,
+ toolRegistry: primaryConfig.toolRegistry,
+ userMCPAuthMap: primaryConfig.userMCPAuthMap,
+ tool_resources: primaryConfig.tool_resources,
+ });
+ },
+ toolEndCallback,
+ };
+
+ // Combine handlers
+ const handlers = {
+ on_message_delta: responsesHandlers.on_message_delta,
+ on_reasoning_delta: responsesHandlers.on_reasoning_delta,
+ on_run_step: responsesHandlers.on_run_step,
+ on_run_step_delta: responsesHandlers.on_run_step_delta,
+ on_chat_model_end: {
+ handle: (event, data) => {
+ responsesHandlers.on_chat_model_end.handle(event, data);
+ const usage = data?.output?.usage_metadata;
+ if (usage) {
+ collectedUsage.push(usage);
+ }
+ },
+ },
+ on_tool_end: new ToolEndHandler(toolEndCallback, logger),
+ on_run_step_completed: { handle: () => {} },
+ on_chain_stream: { handle: () => {} },
+ on_chain_end: { handle: () => {} },
+ on_agent_update: { handle: () => {} },
+ on_custom_event: { handle: () => {} },
+ on_tool_execute: createToolExecuteHandler(toolExecuteOptions),
+ };
+
+ // Create and run the agent
+ const userId = req.user?.id ?? 'api-user';
+ const userMCPAuthMap = primaryConfig.userMCPAuthMap;
+
+ const run = await createRun({
+ agents: [primaryConfig],
+ messages: formattedMessages,
+ indexTokenCountMap,
+ runId: responseId,
+ signal: abortController.signal,
+ customHandlers: handlers,
+ requestBody: {
+ messageId: responseId,
+ conversationId,
+ },
+ user: { id: userId },
+ });
+
+ if (!run) {
+ throw new Error('Failed to create agent run');
+ }
+
+ // Process the stream
+ const config = {
+ runName: 'AgentRun',
+ configurable: {
+ thread_id: conversationId,
+ user_id: userId,
+ user: createSafeUser(req.user),
+ ...(userMCPAuthMap != null && { userMCPAuthMap }),
+ },
+ signal: abortController.signal,
+ streamMode: 'values',
+ version: 'v2',
+ };
+
+ await run.processStream({ messages: formattedMessages }, config, {
+ callbacks: {
+ [Callback.TOOL_ERROR]: (graph, error, toolId) => {
+ logger.error(`[Responses API] Tool Error "${toolId}"`, error);
+ },
+ },
+ });
+
+ // Record token usage against balance
+ const balanceConfig = getBalanceConfig(req.config);
+ const transactionsConfig = getTransactionsConfig(req.config);
+ recordCollectedUsage(
+ { spendTokens, spendStructuredTokens },
+ {
+ user: userId,
+ conversationId,
+ collectedUsage,
+ context: 'message',
+ balance: balanceConfig,
+ transactions: transactionsConfig,
+ model: primaryConfig.model || agent.model_parameters?.model,
+ },
+ ).catch((err) => {
+ logger.error('[Responses API] Error recording usage:', err);
+ });
+
+ // Finalize the stream
+ finalizeStream();
+ res.end();
+
+ const duration = Date.now() - requestStartTime;
+ logger.debug(`[Responses API] Request ${responseId} completed in ${duration}ms (streaming)`);
+
+ // Save to database if store: true
+ if (request.store === true) {
+ try {
+ // Save conversation
+ await saveConversation(req, conversationId, agentId, agent);
+
+ // Save input messages
+ await saveInputMessages(req, conversationId, inputMessages, agentId);
+
+ // Build response for saving (use tracker with buildResponse for streaming)
+ const finalResponse = buildResponse(context, tracker, 'completed');
+ await saveResponseOutput(req, conversationId, responseId, finalResponse, agentId);
+
+ logger.debug(
+ `[Responses API] Stored response ${responseId} in conversation ${conversationId}`,
+ );
+ } catch (saveError) {
+ logger.error('[Responses API] Error saving response:', saveError);
+ // Don't fail the request if saving fails
+ }
+ }
+
+ // Wait for artifact processing after response ends (non-blocking)
+ if (artifactPromises.length > 0) {
+ Promise.all(artifactPromises).catch((artifactError) => {
+ logger.warn('[Responses API] Error processing artifacts:', artifactError);
+ });
+ }
+ } else {
+ const aggregatorHandlers = createAggregatorEventHandlers(aggregator);
+
+ // Collect usage for balance tracking
+ const collectedUsage = [];
+
+ /** @type {Promise[]} */
+ const artifactPromises = [];
+ const toolEndCallback = createToolEndCallback({ req, res, artifactPromises, streamId: null });
+
+ const toolExecuteOptions = {
+ loadTools: async (toolNames) => {
+ return loadToolsForExecution({
+ req,
+ res,
+ agent,
+ toolNames,
+ signal: abortController.signal,
+ toolRegistry: primaryConfig.toolRegistry,
+ userMCPAuthMap: primaryConfig.userMCPAuthMap,
+ tool_resources: primaryConfig.tool_resources,
+ });
+ },
+ toolEndCallback,
+ };
+
+ const handlers = {
+ on_message_delta: aggregatorHandlers.on_message_delta,
+ on_reasoning_delta: aggregatorHandlers.on_reasoning_delta,
+ on_run_step: aggregatorHandlers.on_run_step,
+ on_run_step_delta: aggregatorHandlers.on_run_step_delta,
+ on_chat_model_end: {
+ handle: (event, data) => {
+ aggregatorHandlers.on_chat_model_end.handle(event, data);
+ const usage = data?.output?.usage_metadata;
+ if (usage) {
+ collectedUsage.push(usage);
+ }
+ },
+ },
+ on_tool_end: new ToolEndHandler(toolEndCallback, logger),
+ on_run_step_completed: { handle: () => {} },
+ on_chain_stream: { handle: () => {} },
+ on_chain_end: { handle: () => {} },
+ on_agent_update: { handle: () => {} },
+ on_custom_event: { handle: () => {} },
+ on_tool_execute: createToolExecuteHandler(toolExecuteOptions),
+ };
+
+ const userId = req.user?.id ?? 'api-user';
+ const userMCPAuthMap = primaryConfig.userMCPAuthMap;
+
+ const run = await createRun({
+ agents: [primaryConfig],
+ messages: formattedMessages,
+ indexTokenCountMap,
+ runId: responseId,
+ signal: abortController.signal,
+ customHandlers: handlers,
+ requestBody: {
+ messageId: responseId,
+ conversationId,
+ },
+ user: { id: userId },
+ });
+
+ if (!run) {
+ throw new Error('Failed to create agent run');
+ }
+
+ const config = {
+ runName: 'AgentRun',
+ configurable: {
+ thread_id: conversationId,
+ user_id: userId,
+ user: createSafeUser(req.user),
+ ...(userMCPAuthMap != null && { userMCPAuthMap }),
+ },
+ signal: abortController.signal,
+ streamMode: 'values',
+ version: 'v2',
+ };
+
+ await run.processStream({ messages: formattedMessages }, config, {
+ callbacks: {
+ [Callback.TOOL_ERROR]: (graph, error, toolId) => {
+ logger.error(`[Responses API] Tool Error "${toolId}"`, error);
+ },
+ },
+ });
+
+ // Record token usage against balance
+ const balanceConfig = getBalanceConfig(req.config);
+ const transactionsConfig = getTransactionsConfig(req.config);
+ recordCollectedUsage(
+ { spendTokens, spendStructuredTokens },
+ {
+ user: userId,
+ conversationId,
+ collectedUsage,
+ context: 'message',
+ balance: balanceConfig,
+ transactions: transactionsConfig,
+ model: primaryConfig.model || agent.model_parameters?.model,
+ },
+ ).catch((err) => {
+ logger.error('[Responses API] Error recording usage:', err);
+ });
+
+ if (artifactPromises.length > 0) {
+ try {
+ await Promise.all(artifactPromises);
+ } catch (artifactError) {
+ logger.warn('[Responses API] Error processing artifacts:', artifactError);
+ }
+ }
+
+ const response = buildAggregatedResponse(context, aggregator);
+
+ if (request.store === true) {
+ try {
+ await saveConversation(req, conversationId, agentId, agent);
+
+ await saveInputMessages(req, conversationId, inputMessages, agentId);
+
+ await saveResponseOutput(req, conversationId, responseId, response, agentId);
+
+ logger.debug(
+ `[Responses API] Stored response ${responseId} in conversation ${conversationId}`,
+ );
+ } catch (saveError) {
+ logger.error('[Responses API] Error saving response:', saveError);
+ // Don't fail the request if saving fails
+ }
+ }
+
+ res.json(response);
+
+ const duration = Date.now() - requestStartTime;
+ logger.debug(
+ `[Responses API] Request ${responseId} completed in ${duration}ms (non-streaming)`,
+ );
+ }
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : 'An error occurred';
+ logger.error('[Responses API] Error:', error);
+
+ // Check if we already started streaming (headers sent)
+ if (res.headersSent) {
+ // Headers already sent, write error event and close
+ writeDone(res);
+ res.end();
+ } else {
+ // Forward upstream provider status codes (e.g., Anthropic 400s) instead of masking as 500
+ const statusCode =
+ typeof error?.status === 'number' && error.status >= 400 && error.status < 600
+ ? error.status
+ : 500;
+ const errorType = statusCode >= 400 && statusCode < 500 ? 'invalid_request' : 'server_error';
+ sendResponsesErrorResponse(res, statusCode, errorMessage, errorType);
+ }
+ }
+};
+
+/**
+ * List available agents as models - GET /v1/models (also works with /v1/responses/models)
+ *
+ * Returns a list of available agents the user has remote access to.
+ *
+ * @param {import('express').Request} req
+ * @param {import('express').Response} res
+ */
+const listModels = async (req, res) => {
+ try {
+ const userId = req.user?.id;
+ const userRole = req.user?.role;
+
+ if (!userId) {
+ return sendResponsesErrorResponse(res, 401, 'Authentication required', 'auth_error');
+ }
+
+ // Find agents the user has remote access to (VIEW permission on REMOTE_AGENT)
+ const accessibleAgentIds = await findAccessibleResources({
+ userId,
+ role: userRole,
+ resourceType: ResourceType.REMOTE_AGENT,
+ requiredPermissions: PermissionBits.VIEW,
+ });
+
+ // Get the accessible agents
+ let agents = [];
+ if (accessibleAgentIds.length > 0) {
+ agents = await getAgents({ _id: { $in: accessibleAgentIds } });
+ }
+
+ // Convert to models format
+ const models = agents.map((agent) => ({
+ id: agent.id,
+ object: 'model',
+ created: Math.floor(new Date(agent.createdAt).getTime() / 1000),
+ owned_by: agent.author ?? 'librechat',
+ // Additional metadata
+ name: agent.name,
+ description: agent.description,
+ provider: agent.provider,
+ }));
+
+ res.json({
+ object: 'list',
+ data: models,
+ });
+ } catch (error) {
+ logger.error('[Responses API] Error listing models:', error);
+ sendResponsesErrorResponse(
+ res,
+ 500,
+ error instanceof Error ? error.message : 'Failed to list models',
+ 'server_error',
+ );
+ }
+};
+
+/**
+ * Get Response - GET /v1/responses/:id
+ *
+ * Retrieves a stored response by its ID.
+ * The response ID maps to a conversationId in LibreChat's storage.
+ *
+ * @param {import('express').Request} req
+ * @param {import('express').Response} res
+ */
+const getResponse = async (req, res) => {
+ try {
+ const responseId = req.params.id;
+ const userId = req.user?.id;
+
+ if (!responseId) {
+ return sendResponsesErrorResponse(res, 400, 'Response ID is required');
+ }
+
+ // The responseId could be either the response ID or the conversation ID
+ // Try to find a conversation with this ID
+ const conversation = await getConvo(userId, responseId);
+
+ if (!conversation) {
+ return sendResponsesErrorResponse(
+ res,
+ 404,
+ `Response not found: ${responseId}`,
+ 'not_found',
+ 'response_not_found',
+ );
+ }
+
+ // Load messages for this conversation
+ const messages = await db.getMessages({ conversationId: responseId, user: userId });
+
+ if (!messages || messages.length === 0) {
+ return sendResponsesErrorResponse(
+ res,
+ 404,
+ `No messages found for response: ${responseId}`,
+ 'not_found',
+ 'response_not_found',
+ );
+ }
+
+ // Convert messages to Open Responses output format
+ const output = convertMessagesToOutputItems(messages);
+
+ // Find the last assistant message for usage info
+ const lastAssistantMessage = messages.filter((m) => !m.isCreatedByUser).pop();
+
+ // Build the response object
+ const response = {
+ id: responseId,
+ object: 'response',
+ created_at: Math.floor(new Date(conversation.createdAt || Date.now()).getTime() / 1000),
+ completed_at: Math.floor(new Date(conversation.updatedAt || Date.now()).getTime() / 1000),
+ status: 'completed',
+ incomplete_details: null,
+ model: conversation.agentId || conversation.model || 'unknown',
+ previous_response_id: null,
+ instructions: null,
+ output,
+ error: null,
+ tools: [],
+ tool_choice: 'auto',
+ truncation: 'disabled',
+ parallel_tool_calls: true,
+ text: { format: { type: 'text' } },
+ temperature: 1,
+ top_p: 1,
+ presence_penalty: 0,
+ frequency_penalty: 0,
+ top_logprobs: null,
+ reasoning: null,
+ user: userId,
+ usage: lastAssistantMessage?.tokenCount
+ ? {
+ input_tokens: 0,
+ output_tokens: lastAssistantMessage.tokenCount,
+ total_tokens: lastAssistantMessage.tokenCount,
+ }
+ : null,
+ max_output_tokens: null,
+ max_tool_calls: null,
+ store: true,
+ background: false,
+ service_tier: 'default',
+ metadata: {},
+ safety_identifier: null,
+ prompt_cache_key: null,
+ };
+
+ res.json(response);
+ } catch (error) {
+ logger.error('[Responses API] Error getting response:', error);
+ sendResponsesErrorResponse(
+ res,
+ 500,
+ error instanceof Error ? error.message : 'Failed to get response',
+ 'server_error',
+ );
+ }
+};
+
+module.exports = {
+ createResponse,
+ getResponse,
+ listModels,
+ setAppConfig,
+};
diff --git a/api/server/controllers/agents/v1.js b/api/server/controllers/agents/v1.js
index b7b2dbf367..a2c0d55186 100644
--- a/api/server/controllers/agents/v1.js
+++ b/api/server/controllers/agents/v1.js
@@ -5,11 +5,15 @@ const { logger } = require('@librechat/data-schemas');
const {
agentCreateSchema,
agentUpdateSchema,
+ refreshListAvatars,
mergeAgentOcrConversion,
+ MAX_AVATAR_REFRESH_AGENTS,
convertOcrToContextInPlace,
} = require('@librechat/api');
const {
+ Time,
Tools,
+ CacheKeys,
Constants,
FileSources,
ResourceType,
@@ -19,8 +23,6 @@ const {
PermissionBits,
actionDelimiter,
removeNullishValues,
- CacheKeys,
- Time,
} = require('librechat-data-provider');
const {
getListAgentsByAccess,
@@ -38,14 +40,13 @@ const {
grantPermission,
} = require('~/server/services/PermissionService');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
+const { getCategoriesWithCounts, deleteFileByFilter } = require('~/models');
const { resizeAvatar } = require('~/server/services/Files/images/avatar');
const { getFileStrategy } = require('~/server/utils/getFileStrategy');
const { refreshS3Url } = require('~/server/services/Files/S3/crud');
const { filterFile } = require('~/server/services/Files/process');
const { updateAction, getActions } = require('~/models/Action');
const { getCachedTools } = require('~/server/services/Config');
-const { deleteFileByFilter } = require('~/models/File');
-const { getCategoriesWithCounts } = require('~/models');
const { getLogStores } = require('~/cache');
const systemTools = {
@@ -57,46 +58,6 @@ const systemTools = {
const MAX_SEARCH_LEN = 100;
const escapeRegex = (str = '') => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
-/**
- * Opportunistically refreshes S3-backed avatars for agent list responses.
- * Only list responses are refreshed because they're the highest-traffic surface and
- * the avatar URLs have a short-lived TTL. The refresh is cached per-user for 30 minutes
- * via {@link CacheKeys.S3_EXPIRY_INTERVAL} so we refresh once per interval at most.
- * @param {Array} agents - Agents being enriched with S3-backed avatars
- * @param {string} userId - User identifier used for the cache refresh key
- */
-const refreshListAvatars = async (agents, userId) => {
- if (!agents?.length) {
- return;
- }
-
- const cache = getLogStores(CacheKeys.S3_EXPIRY_INTERVAL);
- const refreshKey = `${userId}:agents_list`;
- const alreadyChecked = await cache.get(refreshKey);
- if (alreadyChecked) {
- return;
- }
-
- await Promise.all(
- agents.map(async (agent) => {
- if (agent?.avatar?.source !== FileSources.s3 || !agent?.avatar?.filepath) {
- return;
- }
-
- try {
- const newPath = await refreshS3Url(agent.avatar);
- if (newPath && newPath !== agent.avatar.filepath) {
- agent.avatar = { ...agent.avatar, filepath: newPath };
- }
- } catch (err) {
- logger.debug('[/Agents] Avatar refresh error for list item', err);
- }
- }),
- );
-
- await cache.set(refreshKey, true, Time.THIRTY_MINUTES);
-};
-
/**
* Creates an Agent.
* @route POST /Agents
@@ -110,13 +71,17 @@ const createAgentHandler = async (req, res) => {
const validatedData = agentCreateSchema.parse(req.body);
const { tools = [], ...agentData } = removeNullishValues(validatedData);
+ if (agentData.model_parameters && typeof agentData.model_parameters === 'object') {
+ agentData.model_parameters = removeNullishValues(agentData.model_parameters, true);
+ }
+
const { id: userId } = req.user;
agentData.id = `agent_${nanoid()}`;
agentData.author = userId;
agentData.tools = [];
- const availableTools = await getCachedTools();
+ const availableTools = (await getCachedTools()) ?? {};
for (const tool of tools) {
if (availableTools[tool]) {
agentData.tools.push(tool);
@@ -129,16 +94,25 @@ const createAgentHandler = async (req, res) => {
const agent = await createAgent(agentData);
- // Automatically grant owner permissions to the creator
try {
- await grantPermission({
- principalType: PrincipalType.USER,
- principalId: userId,
- resourceType: ResourceType.AGENT,
- resourceId: agent._id,
- accessRoleId: AccessRoleIds.AGENT_OWNER,
- grantedBy: userId,
- });
+ await Promise.all([
+ grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_OWNER,
+ grantedBy: userId,
+ }),
+ grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.REMOTE_AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.REMOTE_AGENT_OWNER,
+ grantedBy: userId,
+ }),
+ ]);
logger.debug(
`[createAgent] Granted owner permissions to user ${userId} for agent ${agent.id}`,
);
@@ -260,6 +234,11 @@ const updateAgentHandler = async (req, res) => {
// Preserve explicit null for avatar to allow resetting the avatar
const { avatar: avatarField, _id, ...rest } = validatedData;
const updateData = removeNullishValues(rest);
+
+ if (updateData.model_parameters && typeof updateData.model_parameters === 'object') {
+ updateData.model_parameters = removeNullishValues(updateData.model_parameters, true);
+ }
+
if (avatarField === null) {
updateData.avatar = avatarField;
}
@@ -426,16 +405,25 @@ const duplicateAgentHandler = async (req, res) => {
newAgentData.actions = agentActions;
const newAgent = await createAgent(newAgentData);
- // Automatically grant owner permissions to the duplicator
try {
- await grantPermission({
- principalType: PrincipalType.USER,
- principalId: userId,
- resourceType: ResourceType.AGENT,
- resourceId: newAgent._id,
- accessRoleId: AccessRoleIds.AGENT_OWNER,
- grantedBy: userId,
- });
+ await Promise.all([
+ grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.AGENT,
+ resourceId: newAgent._id,
+ accessRoleId: AccessRoleIds.AGENT_OWNER,
+ grantedBy: userId,
+ }),
+ grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.REMOTE_AGENT,
+ resourceId: newAgent._id,
+ accessRoleId: AccessRoleIds.REMOTE_AGENT_OWNER,
+ grantedBy: userId,
+ }),
+ ]);
logger.debug(
`[duplicateAgent] Granted owner permissions to user ${userId} for duplicated agent ${newAgent.id}`,
);
@@ -536,6 +524,38 @@ const getListAgentsHandler = async (req, res) => {
requiredPermissions: PermissionBits.VIEW,
});
+ /**
+ * Refresh all S3 avatars for this user's accessible agent set (not only the current page)
+ * This addresses page-size limits preventing refresh of agents beyond the first page
+ */
+ const cache = getLogStores(CacheKeys.S3_EXPIRY_INTERVAL);
+ const refreshKey = `${userId}:agents_avatar_refresh`;
+ let cachedRefresh = await cache.get(refreshKey);
+ const isValidCachedRefresh =
+ cachedRefresh != null && typeof cachedRefresh === 'object' && cachedRefresh.urlCache != null;
+ if (!isValidCachedRefresh) {
+ try {
+ const fullList = await getListAgentsByAccess({
+ accessibleIds,
+ otherParams: {},
+ limit: MAX_AVATAR_REFRESH_AGENTS,
+ after: null,
+ });
+ const { urlCache } = await refreshListAvatars({
+ agents: fullList?.data ?? [],
+ userId,
+ refreshS3Url,
+ updateAgent,
+ });
+ cachedRefresh = { urlCache };
+ await cache.set(refreshKey, cachedRefresh, Time.THIRTY_MINUTES);
+ } catch (err) {
+ logger.error('[/Agents] Error refreshing avatars for full list: %o', err);
+ }
+ } else {
+ logger.debug('[/Agents] S3 avatar refresh already checked, skipping');
+ }
+
// Use the new ACL-aware function
const data = await getListAgentsByAccess({
accessibleIds,
@@ -551,11 +571,20 @@ const getListAgentsHandler = async (req, res) => {
const publicSet = new Set(publiclyAccessibleIds.map((oid) => oid.toString()));
+ const urlCache = cachedRefresh?.urlCache;
data.data = agents.map((agent) => {
try {
if (agent?._id && publicSet.has(agent._id.toString())) {
agent.isPublic = true;
}
+ if (
+ urlCache &&
+ agent?.id &&
+ agent?.avatar?.source === FileSources.s3 &&
+ urlCache[agent.id]
+ ) {
+ agent.avatar = { ...agent.avatar, filepath: urlCache[agent.id] };
+ }
} catch (e) {
// Silently ignore mapping errors
void e;
@@ -563,15 +592,9 @@ const getListAgentsHandler = async (req, res) => {
return agent;
});
- // Opportunistically refresh S3 avatar URLs for list results with caching
- try {
- await refreshListAvatars(data.data, req.user.id);
- } catch (err) {
- logger.debug('[/Agents] Skipping avatar refresh for list', err);
- }
return res.json(data);
} catch (error) {
- logger.error('[/Agents] Error listing Agents', error);
+ logger.error('[/Agents] Error listing Agents: %o', error);
res.status(500).json({ error: error.message });
}
};
@@ -647,6 +670,14 @@ const uploadAgentAvatarHandler = async (req, res) => {
const updatedAgent = await updateAgent({ id: agent_id }, data, {
updatingUserId: req.user.id,
});
+
+ try {
+ const avatarCache = getLogStores(CacheKeys.S3_EXPIRY_INTERVAL);
+ await avatarCache.delete(`${req.user.id}:agents_avatar_refresh`);
+ } catch (cacheErr) {
+ logger.error('[/:agent_id/avatar] Error invalidating avatar refresh cache', cacheErr);
+ }
+
res.status(201).json(updatedAgent);
} catch (error) {
const message = 'An error occurred while updating the Agent Avatar';
diff --git a/api/server/controllers/agents/v1.spec.js b/api/server/controllers/agents/v1.spec.js
index bfdee7eb79..ce68cc241f 100644
--- a/api/server/controllers/agents/v1.spec.js
+++ b/api/server/controllers/agents/v1.spec.js
@@ -1,8 +1,9 @@
const mongoose = require('mongoose');
-const { v4: uuidv4 } = require('uuid');
const { nanoid } = require('nanoid');
-const { MongoMemoryServer } = require('mongodb-memory-server');
+const { v4: uuidv4 } = require('uuid');
const { agentSchema } = require('@librechat/data-schemas');
+const { FileSources } = require('librechat-data-provider');
+const { MongoMemoryServer } = require('mongodb-memory-server');
// Only mock the dependencies that are not database-related
jest.mock('~/server/services/Config', () => ({
@@ -54,6 +55,16 @@ jest.mock('~/models', () => ({
getCategoriesWithCounts: jest.fn(),
}));
+// Mock cache for S3 avatar refresh tests
+const mockCache = {
+ get: jest.fn(),
+ set: jest.fn(),
+ delete: jest.fn(),
+};
+jest.mock('~/cache', () => ({
+ getLogStores: jest.fn(() => mockCache),
+}));
+
const {
createAgent: createAgentHandler,
updateAgent: updateAgentHandler,
@@ -65,6 +76,8 @@ const {
findPubliclyAccessibleResources,
} = require('~/server/services/PermissionService');
+const { refreshS3Url } = require('~/server/services/Files/S3/crud');
+
/**
* @type {import('mongoose').Model}
*/
@@ -357,6 +370,46 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
});
});
+ test('should remove empty strings from model_parameters (Issue Fix)', async () => {
+ // This tests the fix for empty strings being sent to API instead of being omitted
+ // When a user clears a numeric field (like max_tokens), it should be removed, not sent as ""
+ const dataWithEmptyModelParams = {
+ provider: 'azureOpenAI',
+ model: 'gpt-4',
+ name: 'Agent with Empty Model Params',
+ model_parameters: {
+ temperature: 0.7, // Valid number - should be preserved
+ max_tokens: '', // Empty string - should be removed
+ maxContextTokens: '', // Empty string - should be removed
+ topP: 0, // Zero value - should be preserved (not treated as empty)
+ frequency_penalty: '', // Empty string - should be removed
+ },
+ };
+
+ mockReq.body = dataWithEmptyModelParams;
+
+ await createAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.status).toHaveBeenCalledWith(201);
+
+ const createdAgent = mockRes.json.mock.calls[0][0];
+ expect(createdAgent.model_parameters).toBeDefined();
+ // Valid numbers should be preserved
+ expect(createdAgent.model_parameters.temperature).toBe(0.7);
+ expect(createdAgent.model_parameters.topP).toBe(0);
+ // Empty strings should be removed
+ expect(createdAgent.model_parameters.max_tokens).toBeUndefined();
+ expect(createdAgent.model_parameters.maxContextTokens).toBeUndefined();
+ expect(createdAgent.model_parameters.frequency_penalty).toBeUndefined();
+
+ // Verify in database
+ const agentInDb = await Agent.findOne({ id: createdAgent.id });
+ expect(agentInDb.model_parameters.temperature).toBe(0.7);
+ expect(agentInDb.model_parameters.topP).toBe(0);
+ expect(agentInDb.model_parameters.max_tokens).toBeUndefined();
+ expect(agentInDb.model_parameters.maxContextTokens).toBeUndefined();
+ });
+
test('should handle invalid avatar format', async () => {
const dataWithInvalidAvatar = {
provider: 'openai',
@@ -539,6 +592,49 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
expect(updatedAgent.tool_resources.invalid_tool).toBeUndefined();
});
+ test('should remove empty strings from model_parameters during update (Issue Fix)', async () => {
+ // First create an agent with valid model_parameters
+ await Agent.updateOne(
+ { id: existingAgentId },
+ {
+ model_parameters: {
+ temperature: 0.5,
+ max_tokens: 1000,
+ maxContextTokens: 2000,
+ },
+ },
+ );
+
+ mockReq.user.id = existingAgentAuthorId.toString();
+ mockReq.params.id = existingAgentId;
+ // Simulate user clearing the fields (sends empty strings)
+ mockReq.body = {
+ model_parameters: {
+ temperature: 0.7, // Change to new value
+ max_tokens: '', // Clear this field (should be removed, not sent as "")
+ maxContextTokens: '', // Clear this field (should be removed, not sent as "")
+ },
+ };
+
+ await updateAgentHandler(mockReq, mockRes);
+
+ expect(mockRes.json).toHaveBeenCalled();
+
+ const updatedAgent = mockRes.json.mock.calls[0][0];
+ expect(updatedAgent.model_parameters).toBeDefined();
+ // Valid number should be updated
+ expect(updatedAgent.model_parameters.temperature).toBe(0.7);
+ // Empty strings should be removed, not sent as ""
+ expect(updatedAgent.model_parameters.max_tokens).toBeUndefined();
+ expect(updatedAgent.model_parameters.maxContextTokens).toBeUndefined();
+
+ // Verify in database
+ const agentInDb = await Agent.findOne({ id: existingAgentId });
+ expect(agentInDb.model_parameters.temperature).toBe(0.7);
+ expect(agentInDb.model_parameters.max_tokens).toBeUndefined();
+ expect(agentInDb.model_parameters.maxContextTokens).toBeUndefined();
+ });
+
test('should return 404 for non-existent agent', async () => {
mockReq.user.id = existingAgentAuthorId.toString();
mockReq.params.id = `agent_${uuidv4()}`; // Non-existent ID
@@ -1124,4 +1220,431 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
expect(response.data[0].is_promoted).toBe(true);
});
});
+
+ describe('S3 Avatar Refresh', () => {
+ let userA, userB;
+ let agentWithS3Avatar, agentWithLocalAvatar, agentOwnedByOther;
+
+ beforeEach(async () => {
+ await Agent.deleteMany({});
+ jest.clearAllMocks();
+
+ // Reset cache mock
+ mockCache.get.mockResolvedValue(false);
+ mockCache.set.mockResolvedValue(undefined);
+
+ userA = new mongoose.Types.ObjectId();
+ userB = new mongoose.Types.ObjectId();
+
+ // Create agent with S3 avatar owned by userA
+ agentWithS3Avatar = await Agent.create({
+ id: `agent_${nanoid(12)}`,
+ name: 'Agent with S3 Avatar',
+ description: 'Has S3 avatar',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: userA,
+ avatar: {
+ source: FileSources.s3,
+ filepath: 'old-s3-path.jpg',
+ },
+ versions: [
+ {
+ name: 'Agent with S3 Avatar',
+ description: 'Has S3 avatar',
+ provider: 'openai',
+ model: 'gpt-4',
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ },
+ ],
+ });
+
+ // Create agent with local avatar owned by userA
+ agentWithLocalAvatar = await Agent.create({
+ id: `agent_${nanoid(12)}`,
+ name: 'Agent with Local Avatar',
+ description: 'Has local avatar',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: userA,
+ avatar: {
+ source: 'local',
+ filepath: 'local-path.jpg',
+ },
+ versions: [
+ {
+ name: 'Agent with Local Avatar',
+ description: 'Has local avatar',
+ provider: 'openai',
+ model: 'gpt-4',
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ },
+ ],
+ });
+
+ // Create agent with S3 avatar owned by userB
+ agentOwnedByOther = await Agent.create({
+ id: `agent_${nanoid(12)}`,
+ name: 'Agent Owned By Other',
+ description: 'Owned by userB',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: userB,
+ avatar: {
+ source: FileSources.s3,
+ filepath: 'other-s3-path.jpg',
+ },
+ versions: [
+ {
+ name: 'Agent Owned By Other',
+ description: 'Owned by userB',
+ provider: 'openai',
+ model: 'gpt-4',
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ },
+ ],
+ });
+ });
+
+ test('should skip avatar refresh if cache hit', async () => {
+ mockCache.get.mockResolvedValue({ urlCache: {} });
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ // Should not call refreshS3Url when cache hit
+ expect(refreshS3Url).not.toHaveBeenCalled();
+ });
+
+ test('should refresh and persist S3 avatars on cache miss', async () => {
+ mockCache.get.mockResolvedValue(false);
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+ refreshS3Url.mockResolvedValue('new-s3-path.jpg');
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ // Verify S3 URL was refreshed
+ expect(refreshS3Url).toHaveBeenCalled();
+
+ // Verify cache was set with urlCache map, not a plain boolean
+ expect(mockCache.set).toHaveBeenCalledWith(
+ expect.any(String),
+ expect.objectContaining({ urlCache: expect.any(Object) }),
+ expect.any(Number),
+ );
+
+ // Verify response was returned
+ expect(mockRes.json).toHaveBeenCalled();
+ });
+
+ test('should refresh avatars for all accessible agents (VIEW permission)', async () => {
+ mockCache.get.mockResolvedValue(false);
+ // User A has access to both their own agent and userB's agent
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id, agentOwnedByOther._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+ refreshS3Url.mockResolvedValue('new-path.jpg');
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ // Should be called for both agents - any user with VIEW access can refresh
+ expect(refreshS3Url).toHaveBeenCalledTimes(2);
+ });
+
+ test('should skip non-S3 avatars', async () => {
+ mockCache.get.mockResolvedValue(false);
+ findAccessibleResources.mockResolvedValue([agentWithLocalAvatar._id, agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+ refreshS3Url.mockResolvedValue('new-path.jpg');
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ // Should only be called for S3 avatar agent
+ expect(refreshS3Url).toHaveBeenCalledTimes(1);
+ });
+
+ test('should not update if S3 URL unchanged', async () => {
+ mockCache.get.mockResolvedValue(false);
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+ // Return the same path - no update needed
+ refreshS3Url.mockResolvedValue('old-s3-path.jpg');
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ // Verify refreshS3Url was called
+ expect(refreshS3Url).toHaveBeenCalled();
+
+ // Response should still be returned
+ expect(mockRes.json).toHaveBeenCalled();
+ });
+
+ test('should handle S3 refresh errors gracefully', async () => {
+ mockCache.get.mockResolvedValue(false);
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+ refreshS3Url.mockRejectedValue(new Error('S3 error'));
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ // Should not throw - handles error gracefully
+ await expect(getListAgentsHandler(mockReq, mockRes)).resolves.not.toThrow();
+
+ // Response should still be returned
+ expect(mockRes.json).toHaveBeenCalled();
+ });
+
+ test('should process agents in batches', async () => {
+ mockCache.get.mockResolvedValue(false);
+
+ // Create 25 agents (should be processed in batches of 20)
+ const manyAgents = [];
+ for (let i = 0; i < 25; i++) {
+ const agent = await Agent.create({
+ id: `agent_${nanoid(12)}`,
+ name: `Agent ${i}`,
+ description: `Agent ${i} description`,
+ provider: 'openai',
+ model: 'gpt-4',
+ author: userA,
+ avatar: {
+ source: FileSources.s3,
+ filepath: `path${i}.jpg`,
+ },
+ versions: [
+ {
+ name: `Agent ${i}`,
+ description: `Agent ${i} description`,
+ provider: 'openai',
+ model: 'gpt-4',
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ },
+ ],
+ });
+ manyAgents.push(agent);
+ }
+
+ const allAgentIds = manyAgents.map((a) => a._id);
+ findAccessibleResources.mockResolvedValue(allAgentIds);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+ refreshS3Url.mockImplementation((avatar) =>
+ Promise.resolve(avatar.filepath.replace('.jpg', '-new.jpg')),
+ );
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ // All 25 should be processed
+ expect(refreshS3Url).toHaveBeenCalledTimes(25);
+ });
+
+ test('should skip agents without id or author', async () => {
+ mockCache.get.mockResolvedValue(false);
+
+ // Create agent without proper id field (edge case)
+ const agentWithoutId = await Agent.create({
+ id: `agent_${nanoid(12)}`,
+ name: 'Agent without ID field',
+ description: 'Testing',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: userA,
+ avatar: {
+ source: FileSources.s3,
+ filepath: 'test-path.jpg',
+ },
+ versions: [
+ {
+ name: 'Agent without ID field',
+ description: 'Testing',
+ provider: 'openai',
+ model: 'gpt-4',
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ },
+ ],
+ });
+
+ findAccessibleResources.mockResolvedValue([agentWithoutId._id, agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+ refreshS3Url.mockResolvedValue('new-path.jpg');
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ // Should still complete without errors
+ expect(mockRes.json).toHaveBeenCalled();
+ });
+
+ test('should use MAX_AVATAR_REFRESH_AGENTS limit for full list query', async () => {
+ mockCache.get.mockResolvedValue(false);
+ findAccessibleResources.mockResolvedValue([]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ // Verify that the handler completed successfully
+ expect(mockRes.json).toHaveBeenCalled();
+ });
+
+ test('should treat legacy boolean cache entry as a miss and run refresh', async () => {
+ // Simulate a cache entry written by the pre-fix code
+ mockCache.get.mockResolvedValue(true);
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+ refreshS3Url.mockResolvedValue('new-s3-path.jpg');
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ // Boolean true fails the shape guard, so refresh must run
+ expect(refreshS3Url).toHaveBeenCalled();
+ // Cache is overwritten with the proper format
+ expect(mockCache.set).toHaveBeenCalledWith(
+ expect.any(String),
+ expect.objectContaining({ urlCache: expect.any(Object) }),
+ expect.any(Number),
+ );
+ });
+
+ test('should apply cached urlCache filepath to paginated response on cache hit', async () => {
+ const agentId = agentWithS3Avatar.id;
+ const cachedUrl = 'cached-presigned-url.jpg';
+
+ mockCache.get.mockResolvedValue({ urlCache: { [agentId]: cachedUrl } });
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ expect(refreshS3Url).not.toHaveBeenCalled();
+
+ const responseData = mockRes.json.mock.calls[0][0];
+ const agent = responseData.data.find((a) => a.id === agentId);
+ // Cached URL is served, not the stale DB value 'old-s3-path.jpg'
+ expect(agent.avatar.filepath).toBe(cachedUrl);
+ });
+
+ test('should preserve DB filepath for agents absent from urlCache on cache hit', async () => {
+ mockCache.get.mockResolvedValue({ urlCache: {} });
+ findAccessibleResources.mockResolvedValue([agentWithS3Avatar._id]);
+ findPubliclyAccessibleResources.mockResolvedValue([]);
+
+ const mockReq = {
+ user: { id: userA.toString(), role: 'USER' },
+ query: {},
+ };
+ const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+ };
+
+ await getListAgentsHandler(mockReq, mockRes);
+
+ expect(refreshS3Url).not.toHaveBeenCalled();
+
+ const responseData = mockRes.json.mock.calls[0][0];
+ const agent = responseData.data.find((a) => a.id === agentWithS3Avatar.id);
+ expect(agent.avatar.filepath).toBe('old-s3-path.jpg');
+ });
+ });
});
diff --git a/api/server/controllers/assistants/chatV1.js b/api/server/controllers/assistants/chatV1.js
index 91759bed37..804594d0bf 100644
--- a/api/server/controllers/assistants/chatV1.js
+++ b/api/server/controllers/assistants/chatV1.js
@@ -7,6 +7,7 @@ const {
Constants,
RunStatus,
CacheKeys,
+ VisionModes,
ContentTypes,
EModelEndpoint,
ViolationTypes,
@@ -25,6 +26,7 @@ const {
const { runAssistant, createOnTextProgress } = require('~/server/services/AssistantService');
const validateAuthor = require('~/server/middleware/assistants/validateAuthor');
const { formatMessage, createVisionPrompt } = require('~/app/clients/prompts');
+const { encodeAndFormat } = require('~/server/services/Files/images/encode');
const { createRun, StreamRunManager } = require('~/server/services/Runs');
const { addTitle } = require('~/server/services/Endpoints/assistants');
const { createRunBody } = require('~/server/services/createRunBody');
@@ -64,7 +66,7 @@ const chatV1 = async (req, res) => {
clientTimestamp,
} = req.body;
- /** @type {OpenAIClient} */
+ /** @type {OpenAI} */
let openai;
/** @type {string|undefined} - the current thread id */
let thread_id = _thread_id;
@@ -285,11 +287,10 @@ const chatV1 = async (req, res) => {
});
};
- const { openai: _openai, client } = await getOpenAIClient({
+ const { openai: _openai } = await getOpenAIClient({
req,
res,
endpointOption,
- initAppClient: true,
});
openai = _openai;
@@ -364,7 +365,15 @@ const chatV1 = async (req, res) => {
role: 'user',
content: '',
};
- const files = await client.addImageURLs(visionMessage, attachments);
+ const { files, image_urls } = await encodeAndFormat(
+ req,
+ attachments,
+ {
+ endpoint: EModelEndpoint.assistants,
+ },
+ VisionModes.generative,
+ );
+ visionMessage.image_urls = image_urls.length ? image_urls : undefined;
if (!visionMessage.image_urls?.length) {
return;
}
@@ -609,7 +618,6 @@ const chatV1 = async (req, res) => {
text,
responseText: response.text,
conversationId,
- client,
});
}
diff --git a/api/server/controllers/assistants/chatV2.js b/api/server/controllers/assistants/chatV2.js
index 2dcfef2846..414681d6dc 100644
--- a/api/server/controllers/assistants/chatV2.js
+++ b/api/server/controllers/assistants/chatV2.js
@@ -61,7 +61,7 @@ const chatV2 = async (req, res) => {
clientTimestamp,
} = req.body;
- /** @type {OpenAIClient} */
+ /** @type {OpenAI} */
let openai;
/** @type {string|undefined} - the current thread id */
let thread_id = _thread_id;
@@ -160,11 +160,10 @@ const chatV2 = async (req, res) => {
});
};
- const { openai: _openai, client } = await getOpenAIClient({
+ const { openai: _openai } = await getOpenAIClient({
req,
res,
endpointOption,
- initAppClient: true,
});
openai = _openai;
@@ -453,7 +452,6 @@ const chatV2 = async (req, res) => {
text,
responseText: response.text,
conversationId,
- client,
});
}
diff --git a/api/server/controllers/assistants/helpers.js b/api/server/controllers/assistants/helpers.js
index 418fd45808..9183680f1e 100644
--- a/api/server/controllers/assistants/helpers.js
+++ b/api/server/controllers/assistants/helpers.js
@@ -63,7 +63,7 @@ const _listAssistants = async ({ req, res, version, query }) => {
* @returns {Promise>} A promise that resolves to the response from the `openai.beta.assistants.list` method call.
*/
const listAllAssistants = async ({ req, res, version, query }) => {
- /** @type {{ openai: OpenAIClient }} */
+ /** @type {{ openai: OpenAI }} */
const { openai } = await getOpenAIClient({ req, res, version });
const allAssistants = [];
@@ -138,6 +138,7 @@ const listAssistantsForAzure = async ({ req, res, version, azureConfig = {}, que
/* The specified model is only necessary to
fetch assistants for the shared instance */
+ req.body = req.body || {}; // Express 5: req.body is undefined instead of {} when no body parser runs
req.body.model = currentModelTuples[0][0];
promises.push(listAllAssistants({ req, res, version, query }));
}
@@ -181,10 +182,10 @@ const listAssistantsForAzure = async ({ req, res, version, azureConfig = {}, que
* @param {TEndpointOption} params.endpointOption - The endpoint options.
* @param {boolean} params.initAppClient - Whether to initialize the app client.
* @param {string} params.overrideEndpoint - The endpoint to override.
- * @returns {Promise<{ openai: OpenAIClient, openAIApiKey: string; client: import('~/app/clients/OpenAIClient') }>} - The initialized OpenAI client.
+ * @returns {Promise<{ openai: OpenAI, openAIApiKey: string }>} - The initialized OpenAI SDK client.
*/
async function getOpenAIClient({ req, res, endpointOption, initAppClient, overrideEndpoint }) {
- let endpoint = overrideEndpoint ?? req.body.endpoint ?? req.query.endpoint;
+ let endpoint = overrideEndpoint ?? req.body?.endpoint ?? req.query?.endpoint;
const version = await getCurrentVersion(req, endpoint);
if (!endpoint) {
throw new Error(`[${req.baseUrl}] Endpoint is required`);
diff --git a/api/server/controllers/assistants/v1.js b/api/server/controllers/assistants/v1.js
index e2fbbe5b34..5d13d30334 100644
--- a/api/server/controllers/assistants/v1.js
+++ b/api/server/controllers/assistants/v1.js
@@ -9,7 +9,7 @@ const { updateAssistantDoc, getAssistants } = require('~/models/Assistant');
const { getOpenAIClient, fetchAssistants } = require('./helpers');
const { getCachedTools } = require('~/server/services/Config');
const { manifestToolMap } = require('~/app/clients/tools');
-const { deleteFileByFilter } = require('~/models/File');
+const { deleteFileByFilter } = require('~/models');
/**
* Create an assistant.
@@ -31,7 +31,7 @@ const createAssistant = async (req, res) => {
delete assistantData.conversation_starters;
delete assistantData.append_current_datetime;
- const toolDefinitions = await getCachedTools();
+ const toolDefinitions = (await getCachedTools()) ?? {};
assistantData.tools = tools
.map((tool) => {
@@ -136,7 +136,7 @@ const patchAssistant = async (req, res) => {
...updateData
} = req.body;
- const toolDefinitions = await getCachedTools();
+ const toolDefinitions = (await getCachedTools()) ?? {};
updateData.tools = (updateData.tools ?? [])
.map((tool) => {
@@ -259,7 +259,7 @@ function filterAssistantDocs({ documents, userId, assistantsConfig = {} }) {
const getAssistantDocuments = async (req, res) => {
try {
const appConfig = req.config;
- const endpoint = req.query;
+ const endpoint = req.query?.endpoint;
const assistantsConfig = appConfig.endpoints?.[endpoint];
const documents = await getAssistants(
{},
diff --git a/api/server/controllers/assistants/v2.js b/api/server/controllers/assistants/v2.js
index 278dd13021..b9c5cd709f 100644
--- a/api/server/controllers/assistants/v2.js
+++ b/api/server/controllers/assistants/v2.js
@@ -28,7 +28,7 @@ const createAssistant = async (req, res) => {
delete assistantData.conversation_starters;
delete assistantData.append_current_datetime;
- const toolDefinitions = await getCachedTools();
+ const toolDefinitions = (await getCachedTools()) ?? {};
assistantData.tools = tools
.map((tool) => {
@@ -125,7 +125,7 @@ const updateAssistant = async ({ req, openai, assistant_id, updateData }) => {
let hasFileSearch = false;
for (const tool of updateData.tools ?? []) {
- const toolDefinitions = await getCachedTools();
+ const toolDefinitions = (await getCachedTools()) ?? {};
let actualTool = typeof tool === 'string' ? toolDefinitions[tool] : tool;
if (!actualTool && manifestToolMap[tool] && manifestToolMap[tool].toolkit === true) {
diff --git a/api/server/controllers/auth/LogoutController.js b/api/server/controllers/auth/LogoutController.js
index 02d3d0302d..0b3cf262b8 100644
--- a/api/server/controllers/auth/LogoutController.js
+++ b/api/server/controllers/auth/LogoutController.js
@@ -5,15 +5,29 @@ const { logoutUser } = require('~/server/services/AuthService');
const { getOpenIdConfig } = require('~/strategies');
const logoutController = async (req, res) => {
- const refreshToken = req.headers.cookie ? cookies.parse(req.headers.cookie).refreshToken : null;
+ const parsedCookies = req.headers.cookie ? cookies.parse(req.headers.cookie) : {};
+ const isOpenIdUser = req.user?.openidId != null && req.user?.provider === 'openid';
+
+ /** For OpenID users, read refresh token from session; for others, use cookie */
+ let refreshToken;
+ if (isOpenIdUser && req.session?.openidTokens) {
+ refreshToken = req.session.openidTokens.refreshToken;
+ delete req.session.openidTokens;
+ }
+ refreshToken = refreshToken || parsedCookies.refreshToken;
+
try {
const logout = await logoutUser(req, refreshToken);
const { status, message } = logout;
+
res.clearCookie('refreshToken');
+ res.clearCookie('openid_access_token');
+ res.clearCookie('openid_id_token');
+ res.clearCookie('openid_user_id');
res.clearCookie('token_provider');
const response = { message };
if (
- req.user.openidId != null &&
+ isOpenIdUser &&
isEnabled(process.env.OPENID_USE_END_SESSION_ENDPOINT) &&
process.env.OPENID_ISSUER
) {
@@ -27,7 +41,12 @@ const logoutController = async (req, res) => {
? openIdConfig.serverMetadata().end_session_endpoint
: null;
if (endSessionEndpoint) {
- response.redirect = endSessionEndpoint;
+ const endSessionUrl = new URL(endSessionEndpoint);
+ /** Redirect back to app's login page after IdP logout */
+ const postLogoutRedirectUri =
+ process.env.OPENID_POST_LOGOUT_REDIRECT_URI || `${process.env.DOMAIN_CLIENT}/login`;
+ endSessionUrl.searchParams.set('post_logout_redirect_uri', postLogoutRedirectUri);
+ response.redirect = endSessionUrl.toString();
} else {
logger.warn(
'[logoutController] end_session_endpoint not found in OpenID issuer metadata. Please verify that the issuer is correct.',
diff --git a/api/server/controllers/auth/oauth.js b/api/server/controllers/auth/oauth.js
new file mode 100644
index 0000000000..80c2ced002
--- /dev/null
+++ b/api/server/controllers/auth/oauth.js
@@ -0,0 +1,79 @@
+const { CacheKeys } = require('librechat-data-provider');
+const { logger, DEFAULT_SESSION_EXPIRY } = require('@librechat/data-schemas');
+const {
+ isEnabled,
+ getAdminPanelUrl,
+ isAdminPanelRedirect,
+ generateAdminExchangeCode,
+} = require('@librechat/api');
+const { syncUserEntraGroupMemberships } = require('~/server/services/PermissionService');
+const { setAuthTokens, setOpenIDAuthTokens } = require('~/server/services/AuthService');
+const getLogStores = require('~/cache/getLogStores');
+const { checkBan } = require('~/server/middleware');
+const { generateToken } = require('~/models');
+
+const domains = {
+ client: process.env.DOMAIN_CLIENT,
+ server: process.env.DOMAIN_SERVER,
+};
+
+function createOAuthHandler(redirectUri = domains.client) {
+ /**
+ * A handler to process OAuth authentication results.
+ * @type {Function}
+ * @param {ServerRequest} req - Express request object.
+ * @param {ServerResponse} res - Express response object.
+ * @param {NextFunction} next - Express next middleware function.
+ */
+ return async (req, res, next) => {
+ try {
+ if (res.headersSent) {
+ return;
+ }
+
+ await checkBan(req, res);
+ if (req.banned) {
+ return;
+ }
+
+ /** Check if this is an admin panel redirect (cross-origin) */
+ if (isAdminPanelRedirect(redirectUri, getAdminPanelUrl(), domains.client)) {
+ /** For admin panel, generate exchange code instead of setting cookies */
+ const cache = getLogStores(CacheKeys.ADMIN_OAUTH_EXCHANGE);
+ const sessionExpiry = Number(process.env.SESSION_EXPIRY) || DEFAULT_SESSION_EXPIRY;
+ const token = await generateToken(req.user, sessionExpiry);
+
+ /** Get refresh token from tokenset for OpenID users */
+ const refreshToken =
+ req.user.tokenset?.refresh_token || req.user.federatedTokens?.refresh_token;
+
+ const exchangeCode = await generateAdminExchangeCode(cache, req.user, token, refreshToken);
+
+ const callbackUrl = new URL(redirectUri);
+ callbackUrl.searchParams.set('code', exchangeCode);
+ logger.info(`[OAuth] Admin panel redirect with exchange code for user: ${req.user.email}`);
+ return res.redirect(callbackUrl.toString());
+ }
+
+ /** Standard OAuth flow - set cookies and redirect */
+ if (
+ req.user &&
+ req.user.provider == 'openid' &&
+ isEnabled(process.env.OPENID_REUSE_TOKENS) === true
+ ) {
+ await syncUserEntraGroupMemberships(req.user, req.user.tokenset.access_token);
+ setOpenIDAuthTokens(req.user.tokenset, req, res, req.user._id.toString());
+ } else {
+ await setAuthTokens(req.user._id, res);
+ }
+ res.redirect(redirectUri);
+ } catch (err) {
+ logger.error('Error in setting authentication tokens:', err);
+ next(err);
+ }
+ };
+}
+
+module.exports = {
+ createOAuthHandler,
+};
diff --git a/api/server/controllers/mcp.js b/api/server/controllers/mcp.js
index 5bc6f8f23c..e5dfff61ca 100644
--- a/api/server/controllers/mcp.js
+++ b/api/server/controllers/mcp.js
@@ -1,16 +1,58 @@
/**
* MCP Tools Controller
* Handles MCP-specific tool endpoints, decoupled from regular LibreChat tools
+ *
+ * @import { MCPServerRegistry } from '@librechat/api'
+ * @import { MCPServerDocument } from 'librechat-data-provider'
*/
const { logger } = require('@librechat/data-schemas');
-const { Constants } = require('librechat-data-provider');
const {
- cacheMCPServerTools,
- getMCPServerTools,
- getAppConfig,
-} = require('~/server/services/Config');
-const { getMCPManager } = require('~/config');
-const { mcpServersRegistry } = require('@librechat/api');
+ isMCPDomainNotAllowedError,
+ isMCPInspectionFailedError,
+ MCPErrorCodes,
+} = require('@librechat/api');
+const { Constants, MCPServerUserInputSchema } = require('librechat-data-provider');
+const { cacheMCPServerTools, getMCPServerTools } = require('~/server/services/Config');
+const { getMCPManager, getMCPServersRegistry } = require('~/config');
+
+/**
+ * Handles MCP-specific errors and sends appropriate HTTP responses.
+ * @param {Error} error - The error to handle
+ * @param {import('express').Response} res - Express response object
+ * @returns {import('express').Response | null} Response if handled, null if not an MCP error
+ */
+function handleMCPError(error, res) {
+ if (isMCPDomainNotAllowedError(error)) {
+ return res.status(error.statusCode).json({
+ error: error.code,
+ message: error.message,
+ });
+ }
+
+ if (isMCPInspectionFailedError(error)) {
+ return res.status(error.statusCode).json({
+ error: error.code,
+ message: error.message,
+ });
+ }
+
+ // Fallback for legacy string-based error handling (backwards compatibility)
+ if (error.message?.startsWith(MCPErrorCodes.DOMAIN_NOT_ALLOWED)) {
+ return res.status(403).json({
+ error: MCPErrorCodes.DOMAIN_NOT_ALLOWED,
+ message: error.message.replace(/^MCP_DOMAIN_NOT_ALLOWED\s*:\s*/i, ''),
+ });
+ }
+
+ if (error.message?.startsWith(MCPErrorCodes.INSPECTION_FAILED)) {
+ return res.status(400).json({
+ error: MCPErrorCodes.INSPECTION_FAILED,
+ message: error.message,
+ });
+ }
+
+ return null;
+}
/**
* Get all MCP tools available to the user
@@ -23,13 +65,14 @@ const getMCPTools = async (req, res) => {
return res.status(401).json({ message: 'Unauthorized' });
}
- const appConfig = req.config ?? (await getAppConfig({ role: req.user?.role }));
- if (!appConfig?.mcpConfig) {
+ const mcpConfig = await getMCPServersRegistry().getAllServerConfigs(userId);
+ const configuredServers = mcpConfig ? Object.keys(mcpConfig) : [];
+
+ if (!mcpConfig || Object.keys(mcpConfig).length == 0) {
return res.status(200).json({ servers: {} });
}
const mcpManager = getMCPManager();
- const configuredServers = Object.keys(appConfig.mcpConfig);
const mcpServers = {};
const cachePromises = configuredServers.map((serverName) =>
@@ -71,8 +114,8 @@ const getMCPTools = async (req, res) => {
const serverTools = serverToolsMap.get(serverName);
// Get server config once
- const serverConfig = appConfig.mcpConfig[serverName];
- const rawServerConfig = await mcpServersRegistry.getServerConfig(serverName, userId);
+ const serverConfig = mcpConfig[serverName];
+ const rawServerConfig = await getMCPServersRegistry().getServerConfig(serverName, userId);
// Initialize server object with all server-level data
const server = {
@@ -127,7 +170,142 @@ const getMCPTools = async (req, res) => {
res.status(500).json({ message: error.message });
}
};
+/**
+ * Get all MCP servers with permissions
+ * @route GET /api/mcp/servers
+ */
+const getMCPServersList = async (req, res) => {
+ try {
+ const userId = req.user?.id;
+ if (!userId) {
+ return res.status(401).json({ message: 'Unauthorized' });
+ }
+
+ // 2. Get all server configs from registry (YAML + DB)
+ const serverConfigs = await getMCPServersRegistry().getAllServerConfigs(userId);
+
+ return res.json(serverConfigs);
+ } catch (error) {
+ logger.error('[getMCPServersList]', error);
+ res.status(500).json({ error: error.message });
+ }
+};
+
+/**
+ * Create MCP server
+ * @route POST /api/mcp/servers
+ */
+const createMCPServerController = async (req, res) => {
+ try {
+ const userId = req.user?.id;
+ const { config } = req.body;
+
+ const validation = MCPServerUserInputSchema.safeParse(config);
+ if (!validation.success) {
+ return res.status(400).json({
+ message: 'Invalid configuration',
+ errors: validation.error.errors,
+ });
+ }
+ const result = await getMCPServersRegistry().addServer(
+ 'temp_server_name',
+ validation.data,
+ 'DB',
+ userId,
+ );
+ res.status(201).json({
+ serverName: result.serverName,
+ ...result.config,
+ });
+ } catch (error) {
+ logger.error('[createMCPServer]', error);
+ const mcpErrorResponse = handleMCPError(error, res);
+ if (mcpErrorResponse) {
+ return mcpErrorResponse;
+ }
+ res.status(500).json({ message: error.message });
+ }
+};
+
+/**
+ * Get MCP server by ID
+ */
+const getMCPServerById = async (req, res) => {
+ try {
+ const userId = req.user?.id;
+ const { serverName } = req.params;
+ if (!serverName) {
+ return res.status(400).json({ message: 'Server name is required' });
+ }
+ const parsedConfig = await getMCPServersRegistry().getServerConfig(serverName, userId);
+
+ if (!parsedConfig) {
+ return res.status(404).json({ message: 'MCP server not found' });
+ }
+
+ res.status(200).json(parsedConfig);
+ } catch (error) {
+ logger.error('[getMCPServerById]', error);
+ res.status(500).json({ message: error.message });
+ }
+};
+
+/**
+ * Update MCP server
+ * @route PATCH /api/mcp/servers/:serverName
+ */
+const updateMCPServerController = async (req, res) => {
+ try {
+ const userId = req.user?.id;
+ const { serverName } = req.params;
+ const { config } = req.body;
+
+ const validation = MCPServerUserInputSchema.safeParse(config);
+ if (!validation.success) {
+ return res.status(400).json({
+ message: 'Invalid configuration',
+ errors: validation.error.errors,
+ });
+ }
+ const parsedConfig = await getMCPServersRegistry().updateServer(
+ serverName,
+ validation.data,
+ 'DB',
+ userId,
+ );
+
+ res.status(200).json(parsedConfig);
+ } catch (error) {
+ logger.error('[updateMCPServer]', error);
+ const mcpErrorResponse = handleMCPError(error, res);
+ if (mcpErrorResponse) {
+ return mcpErrorResponse;
+ }
+ res.status(500).json({ message: error.message });
+ }
+};
+
+/**
+ * Delete MCP server
+ * @route DELETE /api/mcp/servers/:serverName
+ */
+const deleteMCPServerController = async (req, res) => {
+ try {
+ const userId = req.user?.id;
+ const { serverName } = req.params;
+ await getMCPServersRegistry().removeServer(serverName, 'DB', userId);
+ res.status(200).json({ message: 'MCP server deleted successfully' });
+ } catch (error) {
+ logger.error('[deleteMCPServer]', error);
+ res.status(500).json({ message: error.message });
+ }
+};
module.exports = {
getMCPTools,
+ getMCPServersList,
+ createMCPServerController,
+ getMCPServerById,
+ updateMCPServerController,
+ deleteMCPServerController,
};
diff --git a/api/server/experimental.js b/api/server/experimental.js
index 0ceb58de22..4a457abf61 100644
--- a/api/server/experimental.js
+++ b/api/server/experimental.js
@@ -246,7 +246,22 @@ if (cluster.isMaster) {
app.use(noIndex);
app.use(express.json({ limit: '3mb' }));
app.use(express.urlencoded({ extended: true, limit: '3mb' }));
+
app.use(handleJsonParseError);
+
+ /**
+ * Express 5 Compatibility: Make req.query writable for mongoSanitize
+ * In Express 5, req.query is read-only by default, but express-mongo-sanitize needs to modify it
+ */
+ app.use((req, _res, next) => {
+ Object.defineProperty(req, 'query', {
+ ...Object.getOwnPropertyDescriptor(req, 'query'),
+ value: req.query,
+ writable: true,
+ });
+ next();
+ });
+
app.use(mongoSanitize());
app.use(cors());
app.use(cookieParser());
@@ -284,9 +299,9 @@ if (cluster.isMaster) {
app.use('/api/auth', routes.auth);
app.use('/api/actions', routes.actions);
app.use('/api/keys', routes.keys);
+ app.use('/api/api-keys', routes.apiKeys);
app.use('/api/user', routes.user);
app.use('/api/search', routes.search);
- app.use('/api/edit', routes.edit);
app.use('/api/messages', routes.messages);
app.use('/api/convos', routes.convos);
app.use('/api/presets', routes.presets);
@@ -329,7 +344,12 @@ if (cluster.isMaster) {
});
/** Start listening on shared port (cluster will distribute connections) */
- app.listen(port, host, async () => {
+ app.listen(port, host, async (err) => {
+ if (err) {
+ logger.error(`Worker ${process.pid} failed to start server:`, err);
+ process.exit(1);
+ }
+
logger.info(
`Worker ${process.pid} started: Server listening at http://${
host == '0.0.0.0' ? 'localhost' : host
diff --git a/api/server/index.js b/api/server/index.js
index 767847c286..2aff26ceaf 100644
--- a/api/server/index.js
+++ b/api/server/index.js
@@ -13,8 +13,11 @@ const mongoSanitize = require('express-mongo-sanitize');
const {
isEnabled,
ErrorController,
+ memoryDiagnostics,
performStartupChecks,
handleJsonParseError,
+ GenerationJobManager,
+ createStreamServices,
initializeFileStorage,
} = require('@librechat/api');
const { connectDb, indexSync } = require('~/db');
@@ -83,6 +86,20 @@ const startServer = async () => {
app.use(express.json({ limit: '3mb' }));
app.use(express.urlencoded({ extended: true, limit: '3mb' }));
app.use(handleJsonParseError);
+
+ /**
+ * Express 5 Compatibility: Make req.query writable for mongoSanitize
+ * In Express 5, req.query is read-only by default, but express-mongo-sanitize needs to modify it
+ */
+ app.use((req, _res, next) => {
+ Object.defineProperty(req, 'query', {
+ ...Object.getOwnPropertyDescriptor(req, 'query'),
+ value: req.query,
+ writable: true,
+ });
+ next();
+ });
+
app.use(mongoSanitize());
app.use(cors());
app.use(cookieParser());
@@ -118,11 +135,12 @@ const startServer = async () => {
app.use('/oauth', routes.oauth);
/* API Endpoints */
app.use('/api/auth', routes.auth);
+ app.use('/api/admin', routes.adminAuth);
app.use('/api/actions', routes.actions);
app.use('/api/keys', routes.keys);
+ app.use('/api/api-keys', routes.apiKeys);
app.use('/api/user', routes.user);
app.use('/api/search', routes.search);
- app.use('/api/edit', routes.edit);
app.use('/api/messages', routes.messages);
app.use('/api/convos', routes.convos);
app.use('/api/presets', routes.presets);
@@ -131,7 +149,6 @@ const startServer = async () => {
app.use('/api/endpoints', routes.endpoints);
app.use('/api/balance', routes.balance);
app.use('/api/models', routes.models);
- app.use('/api/plugins', routes.plugins);
app.use('/api/config', routes.config);
app.use('/api/assistants', routes.assistants);
app.use('/api/files', await routes.files.initialize());
@@ -163,7 +180,12 @@ const startServer = async () => {
res.send(updatedIndexHtml);
});
- app.listen(port, host, async () => {
+ app.listen(port, host, async (err) => {
+ if (err) {
+ logger.error('Failed to start server:', err);
+ process.exit(1);
+ }
+
if (host === '0.0.0.0') {
logger.info(
`Server listening on all interfaces at port ${port}. Use http://localhost:${port} to access it`,
@@ -175,6 +197,16 @@ const startServer = async () => {
await initializeMCPs();
await initializeOAuthReconnectManager();
await checkMigrations();
+
+ // Configure stream services (auto-detects Redis from USE_REDIS env var)
+ const streamServices = createStreamServices();
+ GenerationJobManager.configure(streamServices);
+ GenerationJobManager.initialize();
+
+ const inspectFlags = process.execArgv.some((arg) => arg.startsWith('--inspect'));
+ if (inspectFlags || isEnabled(process.env.MEM_DIAG)) {
+ memoryDiagnostics.start();
+ }
});
};
@@ -225,6 +257,15 @@ process.on('uncaughtException', (err) => {
return;
}
+ if (isEnabled(process.env.CONTINUE_ON_UNCAUGHT_EXCEPTION)) {
+ logger.error('Unhandled error encountered. The app will continue running.', {
+ name: err?.name,
+ message: err?.message,
+ stack: err?.stack,
+ });
+ return;
+ }
+
process.exit(1);
});
diff --git a/api/server/index.spec.js b/api/server/index.spec.js
index 4dcd34687e..c73c605518 100644
--- a/api/server/index.spec.js
+++ b/api/server/index.spec.js
@@ -25,6 +25,13 @@ jest.mock('~/app/clients/tools', () => ({
toolkits: [],
}));
+jest.mock('~/config', () => ({
+ createMCPServersRegistry: jest.fn(),
+ createMCPManager: jest.fn().mockResolvedValue({
+ getAppToolFunctions: jest.fn().mockResolvedValue({}),
+ }),
+}));
+
describe('Server Configuration', () => {
// Increase the default timeout to allow for Mongo cleanup
jest.setTimeout(30_000);
diff --git a/api/server/middleware/abortControllers.js b/api/server/middleware/abortControllers.js
deleted file mode 100644
index 31acbfe389..0000000000
--- a/api/server/middleware/abortControllers.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// abortControllers.js
-module.exports = new Map();
diff --git a/api/server/middleware/abortMiddleware.js b/api/server/middleware/abortMiddleware.js
index 1f762ca808..d07a09682d 100644
--- a/api/server/middleware/abortMiddleware.js
+++ b/api/server/middleware/abortMiddleware.js
@@ -1,124 +1,188 @@
const { logger } = require('@librechat/data-schemas');
-const { countTokens, isEnabled, sendEvent, sanitizeMessageForTransmit } = require('@librechat/api');
-const { isAssistantsEndpoint, ErrorTypes, Constants } = require('librechat-data-provider');
+const {
+ countTokens,
+ isEnabled,
+ sendEvent,
+ GenerationJobManager,
+ sanitizeMessageForTransmit,
+} = require('@librechat/api');
+const { isAssistantsEndpoint, ErrorTypes } = require('librechat-data-provider');
+const { spendTokens, spendStructuredTokens } = require('~/models/spendTokens');
const { truncateText, smartTruncateText } = require('~/app/clients/prompts');
const clearPendingReq = require('~/cache/clearPendingReq');
const { sendError } = require('~/server/middleware/error');
-const { spendTokens } = require('~/models/spendTokens');
-const abortControllers = require('./abortControllers');
const { saveMessage, getConvo } = require('~/models');
const { abortRun } = require('./abortRun');
-const abortDataMap = new WeakMap();
-
/**
- * @param {string} abortKey
- * @returns {boolean}
+ * Spend tokens for all models from collected usage.
+ * This handles both sequential and parallel agent execution.
+ *
+ * IMPORTANT: After spending, this function clears the collectedUsage array
+ * to prevent double-spending. The array is shared with AgentClient.collectedUsage,
+ * so clearing it here prevents the finally block from also spending tokens.
+ *
+ * @param {Object} params
+ * @param {string} params.userId - User ID
+ * @param {string} params.conversationId - Conversation ID
+ * @param {Array} params.collectedUsage - Usage metadata from all models
+ * @param {string} [params.fallbackModel] - Fallback model name if not in usage
*/
-function cleanupAbortController(abortKey) {
- if (!abortControllers.has(abortKey)) {
- return false;
+async function spendCollectedUsage({ userId, conversationId, collectedUsage, fallbackModel }) {
+ if (!collectedUsage || collectedUsage.length === 0) {
+ return;
}
- const { abortController } = abortControllers.get(abortKey);
+ const spendPromises = [];
- if (!abortController) {
- abortControllers.delete(abortKey);
- return true;
- }
-
- // 1. Check if this controller has any composed signals and clean them up
- try {
- // This creates a temporary composed signal to use for cleanup
- const composedSignal = AbortSignal.any([abortController.signal]);
-
- // Get all event types - in practice, AbortSignal typically only uses 'abort'
- const eventTypes = ['abort'];
-
- // First, execute a dummy listener removal to handle potential composed signals
- for (const eventType of eventTypes) {
- const dummyHandler = () => {};
- composedSignal.addEventListener(eventType, dummyHandler);
- composedSignal.removeEventListener(eventType, dummyHandler);
-
- const listeners = composedSignal.listeners?.(eventType) || [];
- for (const listener of listeners) {
- composedSignal.removeEventListener(eventType, listener);
- }
+ for (const usage of collectedUsage) {
+ if (!usage) {
+ continue;
}
- } catch (e) {
- logger.debug(`Error cleaning up composed signals: ${e}`);
+
+ // Support both OpenAI format (input_token_details) and Anthropic format (cache_*_input_tokens)
+ const cache_creation =
+ Number(usage.input_token_details?.cache_creation) ||
+ Number(usage.cache_creation_input_tokens) ||
+ 0;
+ const cache_read =
+ Number(usage.input_token_details?.cache_read) || Number(usage.cache_read_input_tokens) || 0;
+
+ const txMetadata = {
+ context: 'abort',
+ conversationId,
+ user: userId,
+ model: usage.model ?? fallbackModel,
+ };
+
+ if (cache_creation > 0 || cache_read > 0) {
+ spendPromises.push(
+ spendStructuredTokens(txMetadata, {
+ promptTokens: {
+ input: usage.input_tokens,
+ write: cache_creation,
+ read: cache_read,
+ },
+ completionTokens: usage.output_tokens,
+ }).catch((err) => {
+ logger.error('[abortMiddleware] Error spending structured tokens for abort', err);
+ }),
+ );
+ continue;
+ }
+
+ spendPromises.push(
+ spendTokens(txMetadata, {
+ promptTokens: usage.input_tokens,
+ completionTokens: usage.output_tokens,
+ }).catch((err) => {
+ logger.error('[abortMiddleware] Error spending tokens for abort', err);
+ }),
+ );
}
- // 2. Abort the controller if not already aborted
- if (!abortController.signal.aborted) {
- abortController.abort();
- }
+ // Wait for all token spending to complete
+ await Promise.all(spendPromises);
- // 3. Remove from registry
- abortControllers.delete(abortKey);
-
- // 4. Clean up any data stored in the WeakMap
- if (abortDataMap.has(abortController)) {
- abortDataMap.delete(abortController);
- }
-
- // 5. Clean up function references on the controller
- if (abortController.getAbortData) {
- abortController.getAbortData = null;
- }
-
- if (abortController.abortCompletion) {
- abortController.abortCompletion = null;
- }
-
- return true;
+ // Clear the array to prevent double-spending from the AgentClient finally block.
+ // The collectedUsage array is shared by reference with AgentClient.collectedUsage,
+ // so clearing it here ensures recordCollectedUsage() sees an empty array and returns early.
+ collectedUsage.length = 0;
}
/**
- * @param {string} abortKey
- * @returns {function(): void}
+ * Abort an active message generation.
+ * Uses GenerationJobManager for all agent requests.
+ * Since streamId === conversationId, we can directly abort by conversationId.
*/
-function createCleanUpHandler(abortKey) {
- return function () {
- try {
- cleanupAbortController(abortKey);
- } catch {
- // Ignore cleanup errors
- }
- };
-}
-
async function abortMessage(req, res) {
- let { abortKey, endpoint } = req.body;
+ const { abortKey, endpoint } = req.body;
if (isAssistantsEndpoint(endpoint)) {
return await abortRun(req, res);
}
const conversationId = abortKey?.split(':')?.[0] ?? req.user.id;
+ const userId = req.user.id;
- if (!abortControllers.has(abortKey) && abortControllers.has(conversationId)) {
- abortKey = conversationId;
+ // Use GenerationJobManager to abort the job (streamId === conversationId)
+ const abortResult = await GenerationJobManager.abortJob(conversationId);
+
+ if (!abortResult.success) {
+ if (!res.headersSent) {
+ return res.status(204).send({ message: 'Request not found' });
+ }
+ return;
}
- if (!abortControllers.has(abortKey) && !res.headersSent) {
- return res.status(204).send({ message: 'Request not found' });
+ const { jobData, content, text, collectedUsage } = abortResult;
+
+ const completionTokens = await countTokens(text);
+ const promptTokens = jobData?.promptTokens ?? 0;
+
+ const responseMessage = {
+ messageId: jobData?.responseMessageId,
+ parentMessageId: jobData?.userMessage?.messageId,
+ conversationId: jobData?.conversationId,
+ content,
+ text,
+ sender: jobData?.sender ?? 'AI',
+ finish_reason: 'incomplete',
+ endpoint: jobData?.endpoint,
+ iconURL: jobData?.iconURL,
+ model: jobData?.model,
+ unfinished: false,
+ error: false,
+ isCreatedByUser: false,
+ tokenCount: completionTokens,
+ };
+
+ // Spend tokens for ALL models from collectedUsage (handles parallel agents/addedConvo)
+ if (collectedUsage && collectedUsage.length > 0) {
+ await spendCollectedUsage({
+ userId,
+ conversationId: jobData?.conversationId,
+ collectedUsage,
+ fallbackModel: jobData?.model,
+ });
+ } else {
+ // Fallback: no collected usage, use text-based token counting for primary model only
+ await spendTokens(
+ { ...responseMessage, context: 'incomplete', user: userId },
+ { promptTokens, completionTokens },
+ );
}
- const { abortController } = abortControllers.get(abortKey) ?? {};
- if (!abortController) {
- return res.status(204).send({ message: 'Request not found' });
- }
-
- const finalEvent = await abortController.abortCompletion?.();
- logger.debug(
- `[abortMessage] ID: ${req.user.id} | ${req.user.email} | Aborted request: ` +
- JSON.stringify({ abortKey }),
+ await saveMessage(
+ req,
+ { ...responseMessage, user: userId },
+ { context: 'api/server/middleware/abortMiddleware.js' },
);
- cleanupAbortController(abortKey);
- if (res.headersSent && finalEvent) {
+ // Get conversation for title
+ const conversation = await getConvo(userId, conversationId);
+
+ const finalEvent = {
+ title: conversation && !conversation.title ? null : conversation?.title || 'New Chat',
+ final: true,
+ conversation,
+ requestMessage: jobData?.userMessage
+ ? sanitizeMessageForTransmit({
+ messageId: jobData.userMessage.messageId,
+ parentMessageId: jobData.userMessage.parentMessageId,
+ conversationId: jobData.userMessage.conversationId,
+ text: jobData.userMessage.text,
+ isCreatedByUser: true,
+ })
+ : null,
+ responseMessage,
+ };
+
+ logger.debug(
+ `[abortMessage] ID: ${userId} | ${req.user.email} | Aborted request: ${conversationId}`,
+ );
+
+ if (res.headersSent) {
return sendEvent(res, finalEvent);
}
@@ -139,171 +203,13 @@ const handleAbort = function () {
};
};
-const createAbortController = (req, res, getAbortData, getReqData) => {
- const abortController = new AbortController();
- const { endpointOption } = req.body;
-
- // Store minimal data in WeakMap to avoid circular references
- abortDataMap.set(abortController, {
- getAbortDataFn: getAbortData,
- userId: req.user.id,
- endpoint: endpointOption.endpoint,
- iconURL: endpointOption.iconURL,
- model: endpointOption.modelOptions?.model || endpointOption.model_parameters?.model,
- });
-
- // Replace the direct function reference with a wrapper that uses WeakMap
- abortController.getAbortData = function () {
- const data = abortDataMap.get(this);
- if (!data || typeof data.getAbortDataFn !== 'function') {
- return {};
- }
-
- try {
- const result = data.getAbortDataFn();
-
- // Create a copy without circular references
- const cleanResult = { ...result };
-
- // If userMessagePromise exists, break its reference to client
- if (
- cleanResult.userMessagePromise &&
- typeof cleanResult.userMessagePromise.then === 'function'
- ) {
- // Create a new promise that fulfills with the same result but doesn't reference the original
- const originalPromise = cleanResult.userMessagePromise;
- cleanResult.userMessagePromise = new Promise((resolve, reject) => {
- originalPromise.then(
- (result) => resolve({ ...result }),
- (error) => reject(error),
- );
- });
- }
-
- return cleanResult;
- } catch (err) {
- logger.error('[abortController.getAbortData] Error:', err);
- return {};
- }
- };
-
- /**
- * @param {TMessage} userMessage
- * @param {string} responseMessageId
- * @param {boolean} [isNewConvo]
- */
- const onStart = (userMessage, responseMessageId, isNewConvo) => {
- sendEvent(res, { message: userMessage, created: true });
-
- const prelimAbortKey = userMessage?.conversationId ?? req.user.id;
- const abortKey = isNewConvo
- ? `${prelimAbortKey}${Constants.COMMON_DIVIDER}${Constants.NEW_CONVO}`
- : prelimAbortKey;
- getReqData({ abortKey });
- const prevRequest = abortControllers.get(abortKey);
- const { overrideUserMessageId } = req?.body ?? {};
-
- if (overrideUserMessageId != null && prevRequest && prevRequest?.abortController) {
- const data = prevRequest.abortController.getAbortData();
- getReqData({ userMessage: data?.userMessage });
- const addedAbortKey = `${abortKey}:${responseMessageId}`;
-
- // Store minimal options
- const minimalOptions = {
- endpoint: endpointOption.endpoint,
- iconURL: endpointOption.iconURL,
- model: endpointOption.modelOptions?.model || endpointOption.model_parameters?.model,
- };
-
- abortControllers.set(addedAbortKey, { abortController, ...minimalOptions });
- const cleanupHandler = createCleanUpHandler(addedAbortKey);
- res.on('finish', cleanupHandler);
- return;
- }
-
- // Store minimal options
- const minimalOptions = {
- endpoint: endpointOption.endpoint,
- iconURL: endpointOption.iconURL,
- model: endpointOption.modelOptions?.model || endpointOption.model_parameters?.model,
- };
-
- abortControllers.set(abortKey, { abortController, ...minimalOptions });
- const cleanupHandler = createCleanUpHandler(abortKey);
- res.on('finish', cleanupHandler);
- };
-
- // Define abortCompletion without capturing the entire parent scope
- abortController.abortCompletion = async function () {
- this.abort();
-
- // Get data from WeakMap
- const ctrlData = abortDataMap.get(this);
- if (!ctrlData || !ctrlData.getAbortDataFn) {
- return { final: true, conversation: {}, title: 'New Chat' };
- }
-
- // Get abort data using stored function
- const { conversationId, userMessage, userMessagePromise, promptTokens, ...responseData } =
- ctrlData.getAbortDataFn();
-
- const completionTokens = await countTokens(responseData?.text ?? '');
- const user = ctrlData.userId;
-
- const responseMessage = {
- ...responseData,
- conversationId,
- finish_reason: 'incomplete',
- endpoint: ctrlData.endpoint,
- iconURL: ctrlData.iconURL,
- model: ctrlData.modelOptions?.model ?? ctrlData.model_parameters?.model,
- unfinished: false,
- error: false,
- isCreatedByUser: false,
- tokenCount: completionTokens,
- };
-
- await spendTokens(
- { ...responseMessage, context: 'incomplete', user },
- { promptTokens, completionTokens },
- );
-
- await saveMessage(
- req,
- { ...responseMessage, user },
- { context: 'api/server/middleware/abortMiddleware.js' },
- );
-
- let conversation;
- if (userMessagePromise) {
- const resolved = await userMessagePromise;
- conversation = resolved?.conversation;
- // Break reference to promise
- resolved.conversation = null;
- }
-
- if (!conversation) {
- conversation = await getConvo(user, conversationId);
- }
-
- return {
- title: conversation && !conversation.title ? null : conversation?.title || 'New Chat',
- final: true,
- conversation,
- requestMessage: sanitizeMessageForTransmit(userMessage),
- responseMessage: responseMessage,
- };
- };
-
- return { abortController, onStart };
-};
-
/**
+ * Handle abort errors during generation.
* @param {ServerResponse} res
* @param {ServerRequest} req
* @param {Error | unknown} error
* @param {Partial & { partialText?: string }} data
- * @returns { Promise }
+ * @returns {Promise}
*/
const handleAbortError = async (res, req, error, data) => {
if (error?.message?.includes('base64')) {
@@ -368,8 +274,7 @@ const handleAbortError = async (res, req, error, data) => {
};
}
- const callback = createCleanUpHandler(conversationId);
- await sendError(req, res, options, callback);
+ await sendError(req, res, options);
};
if (partialText && partialText.length > 5) {
@@ -387,6 +292,4 @@ const handleAbortError = async (res, req, error, data) => {
module.exports = {
handleAbort,
handleAbortError,
- createAbortController,
- cleanupAbortController,
};
diff --git a/api/server/middleware/abortMiddleware.spec.js b/api/server/middleware/abortMiddleware.spec.js
new file mode 100644
index 0000000000..93f2ce558b
--- /dev/null
+++ b/api/server/middleware/abortMiddleware.spec.js
@@ -0,0 +1,428 @@
+/**
+ * Tests for abortMiddleware - spendCollectedUsage function
+ *
+ * This tests the token spending logic for abort scenarios,
+ * particularly for parallel agents (addedConvo) where multiple
+ * models need their tokens spent.
+ */
+
+const mockSpendTokens = jest.fn().mockResolvedValue();
+const mockSpendStructuredTokens = jest.fn().mockResolvedValue();
+
+jest.mock('~/models/spendTokens', () => ({
+ spendTokens: (...args) => mockSpendTokens(...args),
+ spendStructuredTokens: (...args) => mockSpendStructuredTokens(...args),
+}));
+
+jest.mock('@librechat/data-schemas', () => ({
+ logger: {
+ debug: jest.fn(),
+ error: jest.fn(),
+ warn: jest.fn(),
+ info: jest.fn(),
+ },
+}));
+
+jest.mock('@librechat/api', () => ({
+ countTokens: jest.fn().mockResolvedValue(100),
+ isEnabled: jest.fn().mockReturnValue(false),
+ sendEvent: jest.fn(),
+ GenerationJobManager: {
+ abortJob: jest.fn(),
+ },
+ sanitizeMessageForTransmit: jest.fn((msg) => msg),
+}));
+
+jest.mock('librechat-data-provider', () => ({
+ isAssistantsEndpoint: jest.fn().mockReturnValue(false),
+ ErrorTypes: { INVALID_REQUEST: 'INVALID_REQUEST', NO_SYSTEM_MESSAGES: 'NO_SYSTEM_MESSAGES' },
+}));
+
+jest.mock('~/app/clients/prompts', () => ({
+ truncateText: jest.fn((text) => text),
+ smartTruncateText: jest.fn((text) => text),
+}));
+
+jest.mock('~/cache/clearPendingReq', () => jest.fn().mockResolvedValue());
+
+jest.mock('~/server/middleware/error', () => ({
+ sendError: jest.fn(),
+}));
+
+jest.mock('~/models', () => ({
+ saveMessage: jest.fn().mockResolvedValue(),
+ getConvo: jest.fn().mockResolvedValue({ title: 'Test Chat' }),
+}));
+
+jest.mock('./abortRun', () => ({
+ abortRun: jest.fn(),
+}));
+
+// Import the module after mocks are set up
+// We need to extract the spendCollectedUsage function for testing
+// Since it's not exported, we'll test it through the handleAbort flow
+
+describe('abortMiddleware - spendCollectedUsage', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('spendCollectedUsage logic', () => {
+ // Since spendCollectedUsage is not exported, we test the logic directly
+ // by replicating the function here for unit testing
+
+ const spendCollectedUsage = async ({
+ userId,
+ conversationId,
+ collectedUsage,
+ fallbackModel,
+ }) => {
+ if (!collectedUsage || collectedUsage.length === 0) {
+ return;
+ }
+
+ const spendPromises = [];
+
+ for (const usage of collectedUsage) {
+ if (!usage) {
+ continue;
+ }
+
+ const cache_creation =
+ Number(usage.input_token_details?.cache_creation) ||
+ Number(usage.cache_creation_input_tokens) ||
+ 0;
+ const cache_read =
+ Number(usage.input_token_details?.cache_read) ||
+ Number(usage.cache_read_input_tokens) ||
+ 0;
+
+ const txMetadata = {
+ context: 'abort',
+ conversationId,
+ user: userId,
+ model: usage.model ?? fallbackModel,
+ };
+
+ if (cache_creation > 0 || cache_read > 0) {
+ spendPromises.push(
+ mockSpendStructuredTokens(txMetadata, {
+ promptTokens: {
+ input: usage.input_tokens,
+ write: cache_creation,
+ read: cache_read,
+ },
+ completionTokens: usage.output_tokens,
+ }).catch(() => {
+ // Log error but don't throw
+ }),
+ );
+ continue;
+ }
+
+ spendPromises.push(
+ mockSpendTokens(txMetadata, {
+ promptTokens: usage.input_tokens,
+ completionTokens: usage.output_tokens,
+ }).catch(() => {
+ // Log error but don't throw
+ }),
+ );
+ }
+
+ // Wait for all token spending to complete
+ await Promise.all(spendPromises);
+
+ // Clear the array to prevent double-spending
+ collectedUsage.length = 0;
+ };
+
+ it('should return early if collectedUsage is empty', async () => {
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage: [],
+ fallbackModel: 'gpt-4',
+ });
+
+ expect(mockSpendTokens).not.toHaveBeenCalled();
+ expect(mockSpendStructuredTokens).not.toHaveBeenCalled();
+ });
+
+ it('should return early if collectedUsage is null', async () => {
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage: null,
+ fallbackModel: 'gpt-4',
+ });
+
+ expect(mockSpendTokens).not.toHaveBeenCalled();
+ expect(mockSpendStructuredTokens).not.toHaveBeenCalled();
+ });
+
+ it('should skip null entries in collectedUsage', async () => {
+ const collectedUsage = [
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ null,
+ { input_tokens: 200, output_tokens: 60, model: 'gpt-4' },
+ ];
+
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ fallbackModel: 'gpt-4',
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(2);
+ });
+
+ it('should spend tokens for single model', async () => {
+ const collectedUsage = [{ input_tokens: 100, output_tokens: 50, model: 'gpt-4' }];
+
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ fallbackModel: 'gpt-4',
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(1);
+ expect(mockSpendTokens).toHaveBeenCalledWith(
+ expect.objectContaining({
+ context: 'abort',
+ conversationId: 'convo-123',
+ user: 'user-123',
+ model: 'gpt-4',
+ }),
+ { promptTokens: 100, completionTokens: 50 },
+ );
+ });
+
+ it('should spend tokens for multiple models (parallel agents)', async () => {
+ const collectedUsage = [
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ { input_tokens: 80, output_tokens: 40, model: 'claude-3' },
+ { input_tokens: 120, output_tokens: 60, model: 'gemini-pro' },
+ ];
+
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ fallbackModel: 'gpt-4',
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(3);
+
+ // Verify each model was called
+ expect(mockSpendTokens).toHaveBeenNthCalledWith(
+ 1,
+ expect.objectContaining({ model: 'gpt-4' }),
+ { promptTokens: 100, completionTokens: 50 },
+ );
+ expect(mockSpendTokens).toHaveBeenNthCalledWith(
+ 2,
+ expect.objectContaining({ model: 'claude-3' }),
+ { promptTokens: 80, completionTokens: 40 },
+ );
+ expect(mockSpendTokens).toHaveBeenNthCalledWith(
+ 3,
+ expect.objectContaining({ model: 'gemini-pro' }),
+ { promptTokens: 120, completionTokens: 60 },
+ );
+ });
+
+ it('should use fallbackModel when usage.model is missing', async () => {
+ const collectedUsage = [{ input_tokens: 100, output_tokens: 50 }];
+
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ fallbackModel: 'fallback-model',
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledWith(
+ expect.objectContaining({ model: 'fallback-model' }),
+ expect.any(Object),
+ );
+ });
+
+ it('should use spendStructuredTokens for OpenAI format cache tokens', async () => {
+ const collectedUsage = [
+ {
+ input_tokens: 100,
+ output_tokens: 50,
+ model: 'gpt-4',
+ input_token_details: {
+ cache_creation: 20,
+ cache_read: 10,
+ },
+ },
+ ];
+
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ fallbackModel: 'gpt-4',
+ });
+
+ expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
+ expect(mockSpendTokens).not.toHaveBeenCalled();
+ expect(mockSpendStructuredTokens).toHaveBeenCalledWith(
+ expect.objectContaining({ model: 'gpt-4', context: 'abort' }),
+ {
+ promptTokens: {
+ input: 100,
+ write: 20,
+ read: 10,
+ },
+ completionTokens: 50,
+ },
+ );
+ });
+
+ it('should use spendStructuredTokens for Anthropic format cache tokens', async () => {
+ const collectedUsage = [
+ {
+ input_tokens: 100,
+ output_tokens: 50,
+ model: 'claude-3',
+ cache_creation_input_tokens: 25,
+ cache_read_input_tokens: 15,
+ },
+ ];
+
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ fallbackModel: 'claude-3',
+ });
+
+ expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
+ expect(mockSpendTokens).not.toHaveBeenCalled();
+ expect(mockSpendStructuredTokens).toHaveBeenCalledWith(
+ expect.objectContaining({ model: 'claude-3' }),
+ {
+ promptTokens: {
+ input: 100,
+ write: 25,
+ read: 15,
+ },
+ completionTokens: 50,
+ },
+ );
+ });
+
+ it('should handle mixed cache and non-cache entries', async () => {
+ const collectedUsage = [
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ {
+ input_tokens: 150,
+ output_tokens: 30,
+ model: 'claude-3',
+ cache_creation_input_tokens: 20,
+ cache_read_input_tokens: 10,
+ },
+ { input_tokens: 200, output_tokens: 20, model: 'gemini-pro' },
+ ];
+
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ fallbackModel: 'gpt-4',
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(2);
+ expect(mockSpendStructuredTokens).toHaveBeenCalledTimes(1);
+ });
+
+ it('should handle real-world parallel agent abort scenario', async () => {
+ // Simulates: Primary agent (gemini) + addedConvo agent (gpt-5) aborted mid-stream
+ const collectedUsage = [
+ { input_tokens: 31596, output_tokens: 151, model: 'gemini-3-flash-preview' },
+ { input_tokens: 28000, output_tokens: 120, model: 'gpt-5.2' },
+ ];
+
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ fallbackModel: 'gemini-3-flash-preview',
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(2);
+
+ // Primary model
+ expect(mockSpendTokens).toHaveBeenNthCalledWith(
+ 1,
+ expect.objectContaining({ model: 'gemini-3-flash-preview' }),
+ { promptTokens: 31596, completionTokens: 151 },
+ );
+
+ // Parallel model (addedConvo)
+ expect(mockSpendTokens).toHaveBeenNthCalledWith(
+ 2,
+ expect.objectContaining({ model: 'gpt-5.2' }),
+ { promptTokens: 28000, completionTokens: 120 },
+ );
+ });
+
+ it('should clear collectedUsage array after spending to prevent double-spending', async () => {
+ // This tests the race condition fix: after abort middleware spends tokens,
+ // the collectedUsage array is cleared so AgentClient.recordCollectedUsage()
+ // (which shares the same array reference) sees an empty array and returns early.
+ const collectedUsage = [
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ { input_tokens: 80, output_tokens: 40, model: 'claude-3' },
+ ];
+
+ expect(collectedUsage.length).toBe(2);
+
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ fallbackModel: 'gpt-4',
+ });
+
+ expect(mockSpendTokens).toHaveBeenCalledTimes(2);
+
+ // The array should be cleared after spending
+ expect(collectedUsage.length).toBe(0);
+ });
+
+ it('should await all token spending operations before clearing array', async () => {
+ // Ensure we don't clear the array before spending completes
+ let spendCallCount = 0;
+ mockSpendTokens.mockImplementation(async () => {
+ spendCallCount++;
+ // Simulate async delay
+ await new Promise((resolve) => setTimeout(resolve, 10));
+ });
+
+ const collectedUsage = [
+ { input_tokens: 100, output_tokens: 50, model: 'gpt-4' },
+ { input_tokens: 80, output_tokens: 40, model: 'claude-3' },
+ ];
+
+ await spendCollectedUsage({
+ userId: 'user-123',
+ conversationId: 'convo-123',
+ collectedUsage,
+ fallbackModel: 'gpt-4',
+ });
+
+ // Both spend calls should have completed
+ expect(spendCallCount).toBe(2);
+
+ // Array should be cleared after awaiting
+ expect(collectedUsage.length).toBe(0);
+ });
+ });
+});
diff --git a/api/server/middleware/abortRun.js b/api/server/middleware/abortRun.js
index dd50d7bf94..44375f5024 100644
--- a/api/server/middleware/abortRun.js
+++ b/api/server/middleware/abortRun.js
@@ -16,6 +16,7 @@ async function abortRun(req, res) {
const conversation = await getConvo(req.user.id, conversationId);
if (conversation?.model) {
+ req.body = req.body || {}; // Express 5: ensure req.body exists
req.body.model = conversation.model;
}
diff --git a/api/server/middleware/accessResources/canAccessAgentFromBody.js b/api/server/middleware/accessResources/canAccessAgentFromBody.js
index e2b20d4886..f8112af14d 100644
--- a/api/server/middleware/accessResources/canAccessAgentFromBody.js
+++ b/api/server/middleware/accessResources/canAccessAgentFromBody.js
@@ -1,5 +1,10 @@
const { logger } = require('@librechat/data-schemas');
-const { Constants, isAgentsEndpoint, ResourceType } = require('librechat-data-provider');
+const {
+ Constants,
+ ResourceType,
+ isAgentsEndpoint,
+ isEphemeralAgentId,
+} = require('librechat-data-provider');
const { canAccessResource } = require('./canAccessResource');
const { getAgent } = require('~/models/Agent');
@@ -13,7 +18,8 @@ const { getAgent } = require('~/models/Agent');
*/
const resolveAgentIdFromBody = async (agentCustomId) => {
// Handle ephemeral agents - they don't need permission checks
- if (agentCustomId === Constants.EPHEMERAL_AGENT_ID) {
+ // Real agent IDs always start with "agent_", so anything else is ephemeral
+ if (isEphemeralAgentId(agentCustomId)) {
return null; // No permission check needed for ephemeral agents
}
@@ -62,7 +68,8 @@ const canAccessAgentFromBody = (options) => {
}
// Skip permission checks for ephemeral agents
- if (agentId === Constants.EPHEMERAL_AGENT_ID) {
+ // Real agent IDs always start with "agent_", so anything else is ephemeral
+ if (isEphemeralAgentId(agentId)) {
return next();
}
diff --git a/api/server/middleware/accessResources/canAccessAgentResource.spec.js b/api/server/middleware/accessResources/canAccessAgentResource.spec.js
index e3dca73bd2..1106390e72 100644
--- a/api/server/middleware/accessResources/canAccessAgentResource.spec.js
+++ b/api/server/middleware/accessResources/canAccessAgentResource.spec.js
@@ -29,7 +29,7 @@ describe('canAccessAgentResource middleware', () => {
AGENTS: {
USE: true,
CREATE: true,
- SHARED_GLOBAL: false,
+ SHARE: true,
},
},
});
diff --git a/api/server/middleware/accessResources/canAccessMCPServerResource.js b/api/server/middleware/accessResources/canAccessMCPServerResource.js
new file mode 100644
index 0000000000..85d479c712
--- /dev/null
+++ b/api/server/middleware/accessResources/canAccessMCPServerResource.js
@@ -0,0 +1,61 @@
+const { ResourceType } = require('librechat-data-provider');
+const { canAccessResource } = require('./canAccessResource');
+const { findMCPServerByServerName } = require('~/models');
+
+/**
+ * MCP Server name resolver function
+ * Resolves MCP server name (e.g., "my-mcp-server") to MongoDB ObjectId
+ *
+ * @param {string} serverName - Server name from route parameter
+ * @returns {Promise} MCP server document with _id field, or null if not found
+ */
+const resolveMCPServerName = async (serverName) => {
+ return await findMCPServerByServerName(serverName);
+};
+
+/**
+ * MCP Server-specific middleware factory that creates middleware to check MCP server access permissions.
+ * This middleware extends the generic canAccessResource to handle MCP server custom ID resolution.
+ *
+ * @param {Object} options - Configuration options
+ * @param {number} options.requiredPermission - The permission bit required (1=view, 2=edit, 4=delete, 8=share)
+ * @param {string} [options.resourceIdParam='serverName'] - The name of the route parameter containing the MCP server custom ID
+ * @returns {Function} Express middleware function
+ *
+ * @example
+ * // Basic usage for viewing MCP servers
+ * router.get('/servers/:serverName',
+ * canAccessMCPServerResource({ requiredPermission: 1 }),
+ * getMCPServer
+ * );
+ *
+ * @example
+ * // Custom resource ID parameter and edit permission
+ * router.patch('/servers/:id',
+ * canAccessMCPServerResource({
+ * requiredPermission: 2,
+ * resourceIdParam: 'id'
+ * }),
+ * updateMCPServer
+ * );
+ */
+const canAccessMCPServerResource = (options) => {
+ const { requiredPermission, resourceIdParam = 'serverName' } = options;
+
+ if (!requiredPermission || typeof requiredPermission !== 'number') {
+ throw new Error(
+ 'canAccessMCPServerResource: requiredPermission is required and must be a number',
+ );
+ }
+
+ return canAccessResource({
+ resourceType: ResourceType.MCPSERVER,
+ requiredPermission,
+ resourceIdParam,
+ idResolver: resolveMCPServerName,
+ });
+};
+
+module.exports = {
+ canAccessMCPServerResource,
+};
diff --git a/api/server/middleware/accessResources/canAccessMCPServerResource.spec.js b/api/server/middleware/accessResources/canAccessMCPServerResource.spec.js
new file mode 100644
index 0000000000..77508be2d1
--- /dev/null
+++ b/api/server/middleware/accessResources/canAccessMCPServerResource.spec.js
@@ -0,0 +1,627 @@
+const mongoose = require('mongoose');
+const { ResourceType, PrincipalType, PrincipalModel } = require('librechat-data-provider');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+const { canAccessMCPServerResource } = require('./canAccessMCPServerResource');
+const { User, Role, AclEntry } = require('~/db/models');
+const { createMCPServer } = require('~/models');
+
+describe('canAccessMCPServerResource middleware', () => {
+ let mongoServer;
+ let req, res, next;
+ let testUser;
+
+ beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ const mongoUri = mongoServer.getUri();
+ await mongoose.connect(mongoUri);
+ });
+
+ afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+ });
+
+ beforeEach(async () => {
+ await mongoose.connection.dropDatabase();
+ await Role.create({
+ name: 'test-role',
+ permissions: {
+ MCP_SERVERS: {
+ USE: true,
+ CREATE: true,
+ SHARE: true,
+ },
+ },
+ });
+
+ // Create a test user
+ testUser = await User.create({
+ email: 'test@example.com',
+ name: 'Test User',
+ username: 'testuser',
+ role: 'test-role',
+ });
+
+ req = {
+ user: { id: testUser._id, role: testUser.role },
+ params: {},
+ };
+ res = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn(),
+ };
+ next = jest.fn();
+
+ jest.clearAllMocks();
+ });
+
+ describe('middleware factory', () => {
+ test('should throw error if requiredPermission is not provided', () => {
+ expect(() => canAccessMCPServerResource({})).toThrow(
+ 'canAccessMCPServerResource: requiredPermission is required and must be a number',
+ );
+ });
+
+ test('should throw error if requiredPermission is not a number', () => {
+ expect(() => canAccessMCPServerResource({ requiredPermission: '1' })).toThrow(
+ 'canAccessMCPServerResource: requiredPermission is required and must be a number',
+ );
+ });
+
+ test('should throw error if requiredPermission is null', () => {
+ expect(() => canAccessMCPServerResource({ requiredPermission: null })).toThrow(
+ 'canAccessMCPServerResource: requiredPermission is required and must be a number',
+ );
+ });
+
+ test('should create middleware with default resourceIdParam (serverName)', () => {
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 });
+ expect(typeof middleware).toBe('function');
+ expect(middleware.length).toBe(3); // Express middleware signature
+ });
+
+ test('should create middleware with custom resourceIdParam', () => {
+ const middleware = canAccessMCPServerResource({
+ requiredPermission: 2,
+ resourceIdParam: 'mcpId',
+ });
+ expect(typeof middleware).toBe('function');
+ expect(middleware.length).toBe(3);
+ });
+ });
+
+ describe('permission checking with real MCP servers', () => {
+ test('should allow access when user is the MCP server author', async () => {
+ // Create an MCP server owned by the test user
+ const mcpServer = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp',
+ title: 'Test MCP Server',
+ },
+ author: testUser._id,
+ });
+
+ // Create ACL entry for the author (owner permissions)
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer._id,
+ permBits: 15, // All permissions (1+2+4+8)
+ grantedBy: testUser._id,
+ });
+
+ req.params.serverName = mcpServer.serverName;
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 }); // VIEW permission
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+
+ test('should deny access when user is not the author and has no ACL entry', async () => {
+ // Create an MCP server owned by a different user
+ const otherUser = await User.create({
+ email: 'other@example.com',
+ name: 'Other User',
+ username: 'otheruser',
+ role: 'test-role',
+ });
+
+ const mcpServer = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp',
+ title: 'Other User MCP Server',
+ },
+ author: otherUser._id,
+ });
+
+ // Create ACL entry for the other user (owner)
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: otherUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer._id,
+ permBits: 15, // All permissions
+ grantedBy: otherUser._id,
+ });
+
+ req.params.serverName = mcpServer.serverName;
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 }); // VIEW permission
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Forbidden',
+ message: 'Insufficient permissions to access this mcpServer',
+ });
+ });
+
+ test('should allow access when user has ACL entry with sufficient permissions', async () => {
+ // Create an MCP server owned by a different user
+ const otherUser = await User.create({
+ email: 'other2@example.com',
+ name: 'Other User 2',
+ username: 'otheruser2',
+ role: 'test-role',
+ });
+
+ const mcpServer = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp',
+ title: 'Shared MCP Server',
+ },
+ author: otherUser._id,
+ });
+
+ // Create ACL entry granting view permission to test user
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer._id,
+ permBits: 1, // VIEW permission
+ grantedBy: otherUser._id,
+ });
+
+ req.params.serverName = mcpServer.serverName;
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 }); // VIEW permission
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+
+ test('should deny access when ACL permissions are insufficient', async () => {
+ // Create an MCP server owned by a different user
+ const otherUser = await User.create({
+ email: 'other3@example.com',
+ name: 'Other User 3',
+ username: 'otheruser3',
+ role: 'test-role',
+ });
+
+ const mcpServer = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp',
+ title: 'Limited Access MCP Server',
+ },
+ author: otherUser._id,
+ });
+
+ // Create ACL entry granting only view permission
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer._id,
+ permBits: 1, // VIEW permission only
+ grantedBy: otherUser._id,
+ });
+
+ req.params.serverName = mcpServer.serverName;
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 2 }); // EDIT permission required
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(403);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Forbidden',
+ message: 'Insufficient permissions to access this mcpServer',
+ });
+ });
+
+ test('should handle non-existent MCP server', async () => {
+ req.params.serverName = 'non-existent-mcp-server';
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(404);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Not Found',
+ message: 'mcpServer not found',
+ });
+ });
+
+ test('should use custom resourceIdParam', async () => {
+ const mcpServer = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp',
+ title: 'Custom Param MCP Server',
+ },
+ author: testUser._id,
+ });
+
+ // Create ACL entry for the author
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer._id,
+ permBits: 15, // All permissions
+ grantedBy: testUser._id,
+ });
+
+ req.params.mcpId = mcpServer.serverName; // Using custom param name
+
+ const middleware = canAccessMCPServerResource({
+ requiredPermission: 1,
+ resourceIdParam: 'mcpId',
+ });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('permission levels', () => {
+ let mcpServer;
+
+ beforeEach(async () => {
+ mcpServer = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp',
+ title: 'Permission Test MCP Server',
+ },
+ author: testUser._id,
+ });
+
+ // Create ACL entry with all permissions for the owner
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer._id,
+ permBits: 15, // All permissions (1+2+4+8)
+ grantedBy: testUser._id,
+ });
+
+ req.params.serverName = mcpServer.serverName;
+ });
+
+ test('should support view permission (1)', async () => {
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 });
+ await middleware(req, res, next);
+ expect(next).toHaveBeenCalled();
+ });
+
+ test('should support edit permission (2)', async () => {
+ const middleware = canAccessMCPServerResource({ requiredPermission: 2 });
+ await middleware(req, res, next);
+ expect(next).toHaveBeenCalled();
+ });
+
+ test('should support delete permission (4)', async () => {
+ const middleware = canAccessMCPServerResource({ requiredPermission: 4 });
+ await middleware(req, res, next);
+ expect(next).toHaveBeenCalled();
+ });
+
+ test('should support share permission (8)', async () => {
+ const middleware = canAccessMCPServerResource({ requiredPermission: 8 });
+ await middleware(req, res, next);
+ expect(next).toHaveBeenCalled();
+ });
+
+ test('should support combined permissions', async () => {
+ const viewAndEdit = 1 | 2; // 3
+ const middleware = canAccessMCPServerResource({ requiredPermission: viewAndEdit });
+ await middleware(req, res, next);
+ expect(next).toHaveBeenCalled();
+ });
+ });
+
+ describe('integration with resolveMCPServerId', () => {
+ test('should resolve serverName to MongoDB ObjectId correctly', async () => {
+ const mcpServer = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp',
+ title: 'Integration Test MCP Server',
+ },
+ author: testUser._id,
+ });
+
+ // Create ACL entry for the author
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer._id,
+ permBits: 15, // All permissions
+ grantedBy: testUser._id,
+ });
+
+ req.params.serverName = mcpServer.serverName;
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ // Verify that req.resourceAccess was set correctly
+ expect(req.resourceAccess).toBeDefined();
+ expect(req.resourceAccess.resourceType).toBe(ResourceType.MCPSERVER);
+ expect(req.resourceAccess.resourceId.toString()).toBe(mcpServer._id.toString());
+ expect(req.resourceAccess.customResourceId).toBe(mcpServer.serverName);
+ });
+
+ test('should work with MCP server CRUD operations', async () => {
+ // Create MCP server
+ const mcpServer = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp',
+ title: 'CRUD Test MCP Server',
+ description: 'Testing integration',
+ },
+ author: testUser._id,
+ });
+
+ // Create ACL entry for the author
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer._id,
+ permBits: 15, // All permissions
+ grantedBy: testUser._id,
+ });
+
+ req.params.serverName = mcpServer.serverName;
+
+ // Test view access
+ const viewMiddleware = canAccessMCPServerResource({ requiredPermission: 1 });
+ await viewMiddleware(req, res, next);
+ expect(next).toHaveBeenCalled();
+ jest.clearAllMocks();
+
+ // Update the MCP server
+ const { updateMCPServer } = require('~/models');
+ await updateMCPServer(mcpServer.serverName, {
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp',
+ title: 'CRUD Test MCP Server',
+ description: 'Updated description',
+ },
+ });
+
+ // Test edit access
+ const editMiddleware = canAccessMCPServerResource({ requiredPermission: 2 });
+ await editMiddleware(req, res, next);
+ expect(next).toHaveBeenCalled();
+ });
+
+ test('should handle stdio type MCP server', async () => {
+ const mcpServer = await createMCPServer({
+ config: {
+ type: 'stdio',
+ command: 'node',
+ args: ['server.js'],
+ title: 'Stdio MCP Server',
+ },
+ author: testUser._id,
+ });
+
+ // Create ACL entry for the author
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer._id,
+ permBits: 15,
+ grantedBy: testUser._id,
+ });
+
+ req.params.serverName = mcpServer.serverName;
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(req.resourceAccess.resourceInfo.config.type).toBe('stdio');
+ });
+ });
+
+ describe('authentication and authorization edge cases', () => {
+ test('should return 400 when serverName parameter is missing', async () => {
+ // Don't set req.params.serverName
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(400);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Bad Request',
+ message: 'serverName is required',
+ });
+ });
+
+ test('should return 401 when user is not authenticated', async () => {
+ req.user = null;
+ req.params.serverName = 'some-server';
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Unauthorized',
+ message: 'Authentication required',
+ });
+ });
+
+ test('should return 401 when user id is missing', async () => {
+ req.user = { role: 'test-role' }; // No id
+ req.params.serverName = 'some-server';
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(401);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Unauthorized',
+ message: 'Authentication required',
+ });
+ });
+
+ test('should allow admin users to bypass permission checks', async () => {
+ const { SystemRoles } = require('librechat-data-provider');
+
+ // Create an MCP server owned by another user
+ const otherUser = await User.create({
+ email: 'owner@example.com',
+ name: 'Owner User',
+ username: 'owneruser',
+ role: 'test-role',
+ });
+
+ const mcpServer = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp',
+ title: 'Admin Test MCP Server',
+ },
+ author: otherUser._id,
+ });
+
+ // Set user as admin
+ req.user = { id: testUser._id, role: SystemRoles.ADMIN };
+ req.params.serverName = mcpServer.serverName;
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 4 }); // DELETE permission
+ await middleware(req, res, next);
+
+ expect(next).toHaveBeenCalled();
+ expect(res.status).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('error handling', () => {
+ test('should handle server returning null gracefully (treated as not found)', async () => {
+ // When an MCP server is not found, findMCPServerByServerName returns null
+ // which the middleware correctly handles as a 404
+ req.params.serverName = 'definitely-non-existent-server';
+
+ const middleware = canAccessMCPServerResource({ requiredPermission: 1 });
+ await middleware(req, res, next);
+
+ expect(next).not.toHaveBeenCalled();
+ expect(res.status).toHaveBeenCalledWith(404);
+ expect(res.json).toHaveBeenCalledWith({
+ error: 'Not Found',
+ message: 'mcpServer not found',
+ });
+ });
+ });
+
+ describe('multiple servers with same title', () => {
+ test('should handle MCP servers with auto-generated suffixes', async () => {
+ // Create multiple servers with the same title (will have different serverNames)
+ const mcpServer1 = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp1',
+ title: 'Duplicate Title',
+ },
+ author: testUser._id,
+ });
+
+ const mcpServer2 = await createMCPServer({
+ config: {
+ type: 'sse',
+ url: 'https://example.com/mcp2',
+ title: 'Duplicate Title',
+ },
+ author: testUser._id,
+ });
+
+ // Create ACL entries for both
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer1._id,
+ permBits: 15,
+ grantedBy: testUser._id,
+ });
+
+ await AclEntry.create({
+ principalType: PrincipalType.USER,
+ principalId: testUser._id,
+ principalModel: PrincipalModel.USER,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: mcpServer2._id,
+ permBits: 15,
+ grantedBy: testUser._id,
+ });
+
+ // Verify they have different serverNames
+ expect(mcpServer1.serverName).toBe('duplicate-title');
+ expect(mcpServer2.serverName).toBe('duplicate-title-2');
+
+ // Test access to first server
+ req.params.serverName = mcpServer1.serverName;
+ const middleware1 = canAccessMCPServerResource({ requiredPermission: 1 });
+ await middleware1(req, res, next);
+ expect(next).toHaveBeenCalled();
+ expect(req.resourceAccess.resourceId.toString()).toBe(mcpServer1._id.toString());
+
+ jest.clearAllMocks();
+
+ // Test access to second server
+ req.params.serverName = mcpServer2.serverName;
+ const middleware2 = canAccessMCPServerResource({ requiredPermission: 1 });
+ await middleware2(req, res, next);
+ expect(next).toHaveBeenCalled();
+ expect(req.resourceAccess.resourceId.toString()).toBe(mcpServer2._id.toString());
+ });
+ });
+});
diff --git a/api/server/middleware/accessResources/fileAccess.js b/api/server/middleware/accessResources/fileAccess.js
index b26a512f5f..25d41e7c02 100644
--- a/api/server/middleware/accessResources/fileAccess.js
+++ b/api/server/middleware/accessResources/fileAccess.js
@@ -2,7 +2,7 @@ const { logger } = require('@librechat/data-schemas');
const { PermissionBits, hasPermissions, ResourceType } = require('librechat-data-provider');
const { getEffectivePermissions } = require('~/server/services/PermissionService');
const { getAgents } = require('~/models/Agent');
-const { getFiles } = require('~/models/File');
+const { getFiles } = require('~/models');
/**
* Checks if user has access to a file through agent permissions
diff --git a/api/server/middleware/accessResources/fileAccess.spec.js b/api/server/middleware/accessResources/fileAccess.spec.js
index 6e741ac34e..cc0d57ac48 100644
--- a/api/server/middleware/accessResources/fileAccess.spec.js
+++ b/api/server/middleware/accessResources/fileAccess.spec.js
@@ -4,7 +4,7 @@ const { MongoMemoryServer } = require('mongodb-memory-server');
const { fileAccess } = require('./fileAccess');
const { User, Role, AclEntry } = require('~/db/models');
const { createAgent } = require('~/models/Agent');
-const { createFile } = require('~/models/File');
+const { createFile } = require('~/models');
describe('fileAccess middleware', () => {
let mongoServer;
@@ -32,7 +32,7 @@ describe('fileAccess middleware', () => {
AGENTS: {
USE: true,
CREATE: true,
- SHARED_GLOBAL: false,
+ SHARE: true,
},
},
});
diff --git a/api/server/middleware/accessResources/index.js b/api/server/middleware/accessResources/index.js
index e1c5def829..838834919a 100644
--- a/api/server/middleware/accessResources/index.js
+++ b/api/server/middleware/accessResources/index.js
@@ -3,6 +3,7 @@ const { canAccessAgentResource } = require('./canAccessAgentResource');
const { canAccessAgentFromBody } = require('./canAccessAgentFromBody');
const { canAccessPromptViaGroup } = require('./canAccessPromptViaGroup');
const { canAccessPromptGroupResource } = require('./canAccessPromptGroupResource');
+const { canAccessMCPServerResource } = require('./canAccessMCPServerResource');
module.exports = {
canAccessResource,
@@ -10,4 +11,5 @@ module.exports = {
canAccessAgentFromBody,
canAccessPromptViaGroup,
canAccessPromptGroupResource,
+ canAccessMCPServerResource,
};
diff --git a/api/server/middleware/buildEndpointOption.js b/api/server/middleware/buildEndpointOption.js
index 7b19f7a3d4..64ed8e7466 100644
--- a/api/server/middleware/buildEndpointOption.js
+++ b/api/server/middleware/buildEndpointOption.js
@@ -5,38 +5,45 @@ const {
EModelEndpoint,
isAgentsEndpoint,
parseCompactConvo,
+ getDefaultParamsEndpoint,
} = require('librechat-data-provider');
const azureAssistants = require('~/server/services/Endpoints/azureAssistants');
const assistants = require('~/server/services/Endpoints/assistants');
-const { processFiles } = require('~/server/services/Files/process');
-const anthropic = require('~/server/services/Endpoints/anthropic');
-const bedrock = require('~/server/services/Endpoints/bedrock');
-const openAI = require('~/server/services/Endpoints/openAI');
+const { getEndpointsConfig } = require('~/server/services/Config');
const agents = require('~/server/services/Endpoints/agents');
-const custom = require('~/server/services/Endpoints/custom');
-const google = require('~/server/services/Endpoints/google');
+const { updateFilesUsage } = require('~/models');
const buildFunction = {
- [EModelEndpoint.openAI]: openAI.buildOptions,
- [EModelEndpoint.google]: google.buildOptions,
- [EModelEndpoint.custom]: custom.buildOptions,
[EModelEndpoint.agents]: agents.buildOptions,
- [EModelEndpoint.bedrock]: bedrock.buildOptions,
- [EModelEndpoint.azureOpenAI]: openAI.buildOptions,
- [EModelEndpoint.anthropic]: anthropic.buildOptions,
[EModelEndpoint.assistants]: assistants.buildOptions,
[EModelEndpoint.azureAssistants]: azureAssistants.buildOptions,
};
async function buildEndpointOption(req, res, next) {
const { endpoint, endpointType } = req.body;
+
+ let endpointsConfig;
+ try {
+ endpointsConfig = await getEndpointsConfig(req);
+ } catch (error) {
+ logger.error('Error fetching endpoints config in buildEndpointOption', error);
+ }
+
+ const defaultParamsEndpoint = getDefaultParamsEndpoint(endpointsConfig, endpoint);
+
let parsedBody;
try {
- parsedBody = parseCompactConvo({ endpoint, endpointType, conversation: req.body });
+ parsedBody = parseCompactConvo({
+ endpoint,
+ endpointType,
+ conversation: req.body,
+ defaultParamsEndpoint,
+ });
} catch (error) {
- logger.warn(
- `Error parsing conversation for endpoint ${endpoint}${error?.message ? `: ${error.message}` : ''}`,
- );
+ logger.error(`Error parsing compact conversation for endpoint ${endpoint}`, error);
+ logger.debug({
+ 'Error parsing compact conversation': { endpoint, endpointType, conversation: req.body },
+ });
return handleError(res, { text: 'Error parsing conversation' });
}
@@ -65,6 +72,7 @@ async function buildEndpointOption(req, res, next) {
endpoint,
endpointType,
conversation: currentModelSpec.preset,
+ defaultParamsEndpoint,
});
if (currentModelSpec.iconURL != null && currentModelSpec.iconURL !== '') {
parsedBody.iconURL = currentModelSpec.iconURL;
@@ -89,10 +97,11 @@ async function buildEndpointOption(req, res, next) {
: buildFunction[endpointType ?? endpoint];
// TODO: use object params
+ req.body = req.body || {}; // Express 5: ensure req.body exists
req.body.endpointOption = await builder(endpoint, parsedBody, endpointType);
if (req.body.files && !isAgents) {
- req.body.endpointOption.attachments = processFiles(req.body.files);
+ req.body.endpointOption.attachments = updateFilesUsage(req.body.files);
}
next();
diff --git a/api/server/middleware/buildEndpointOption.spec.js b/api/server/middleware/buildEndpointOption.spec.js
new file mode 100644
index 0000000000..eab5e2666b
--- /dev/null
+++ b/api/server/middleware/buildEndpointOption.spec.js
@@ -0,0 +1,237 @@
+/**
+ * Wrap parseCompactConvo: the REAL function runs, but jest can observe
+ * calls and return values. Must be declared before require('./buildEndpointOption')
+ * so the destructured reference in the middleware captures the wrapper.
+ */
+jest.mock('librechat-data-provider', () => {
+ const actual = jest.requireActual('librechat-data-provider');
+ return {
+ ...actual,
+ parseCompactConvo: jest.fn((...args) => actual.parseCompactConvo(...args)),
+ };
+});
+
+const { EModelEndpoint, parseCompactConvo } = require('librechat-data-provider');
+
+const mockBuildOptions = jest.fn((_endpoint, parsedBody) => ({
+ ...parsedBody,
+ endpoint: _endpoint,
+}));
+
+jest.mock('~/server/services/Endpoints/azureAssistants', () => ({
+ buildOptions: mockBuildOptions,
+}));
+jest.mock('~/server/services/Endpoints/assistants', () => ({
+ buildOptions: mockBuildOptions,
+}));
+jest.mock('~/server/services/Endpoints/agents', () => ({
+ buildOptions: mockBuildOptions,
+}));
+
+jest.mock('~/models', () => ({
+ updateFilesUsage: jest.fn(),
+}));
+
+const mockGetEndpointsConfig = jest.fn();
+jest.mock('~/server/services/Config', () => ({
+ getEndpointsConfig: (...args) => mockGetEndpointsConfig(...args),
+}));
+
+jest.mock('@librechat/api', () => ({
+ handleError: jest.fn(),
+}));
+
+const buildEndpointOption = require('./buildEndpointOption');
+
+const createReq = (body, config = {}) => ({
+ body,
+ config,
+ baseUrl: '/api/chat',
+});
+
+const createRes = () => ({
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnThis(),
+});
+
+describe('buildEndpointOption - defaultParamsEndpoint parsing', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should pass defaultParamsEndpoint to parseCompactConvo and preserve maxOutputTokens', async () => {
+ mockGetEndpointsConfig.mockResolvedValue({
+ AnthropicClaude: {
+ type: EModelEndpoint.custom,
+ customParams: {
+ defaultParamsEndpoint: EModelEndpoint.anthropic,
+ },
+ },
+ });
+
+ const req = createReq(
+ {
+ endpoint: 'AnthropicClaude',
+ endpointType: EModelEndpoint.custom,
+ model: 'anthropic/claude-opus-4.5',
+ temperature: 0.7,
+ maxOutputTokens: 8192,
+ topP: 0.9,
+ maxContextTokens: 50000,
+ },
+ { modelSpecs: null },
+ );
+
+ await buildEndpointOption(req, createRes(), jest.fn());
+
+ expect(parseCompactConvo).toHaveBeenCalledWith(
+ expect.objectContaining({
+ defaultParamsEndpoint: EModelEndpoint.anthropic,
+ }),
+ );
+
+ const parsedResult = parseCompactConvo.mock.results[0].value;
+ expect(parsedResult.maxOutputTokens).toBe(8192);
+ expect(parsedResult.topP).toBe(0.9);
+ expect(parsedResult.temperature).toBe(0.7);
+ expect(parsedResult.maxContextTokens).toBe(50000);
+ });
+
+ it('should strip maxOutputTokens when no defaultParamsEndpoint is configured', async () => {
+ mockGetEndpointsConfig.mockResolvedValue({
+ MyOpenRouter: {
+ type: EModelEndpoint.custom,
+ },
+ });
+
+ const req = createReq(
+ {
+ endpoint: 'MyOpenRouter',
+ endpointType: EModelEndpoint.custom,
+ model: 'gpt-4o',
+ temperature: 0.7,
+ maxOutputTokens: 8192,
+ max_tokens: 4096,
+ },
+ { modelSpecs: null },
+ );
+
+ await buildEndpointOption(req, createRes(), jest.fn());
+
+ expect(parseCompactConvo).toHaveBeenCalledWith(
+ expect.objectContaining({
+ defaultParamsEndpoint: undefined,
+ }),
+ );
+
+ const parsedResult = parseCompactConvo.mock.results[0].value;
+ expect(parsedResult.maxOutputTokens).toBeUndefined();
+ expect(parsedResult.max_tokens).toBe(4096);
+ expect(parsedResult.temperature).toBe(0.7);
+ });
+
+ it('should strip bedrock region from custom endpoint without defaultParamsEndpoint', async () => {
+ mockGetEndpointsConfig.mockResolvedValue({
+ MyEndpoint: {
+ type: EModelEndpoint.custom,
+ },
+ });
+
+ const req = createReq(
+ {
+ endpoint: 'MyEndpoint',
+ endpointType: EModelEndpoint.custom,
+ model: 'gpt-4o',
+ temperature: 0.7,
+ region: 'us-east-1',
+ },
+ { modelSpecs: null },
+ );
+
+ await buildEndpointOption(req, createRes(), jest.fn());
+
+ const parsedResult = parseCompactConvo.mock.results[0].value;
+ expect(parsedResult.region).toBeUndefined();
+ expect(parsedResult.temperature).toBe(0.7);
+ });
+
+ it('should pass defaultParamsEndpoint when re-parsing enforced model spec', async () => {
+ mockGetEndpointsConfig.mockResolvedValue({
+ AnthropicClaude: {
+ type: EModelEndpoint.custom,
+ customParams: {
+ defaultParamsEndpoint: EModelEndpoint.anthropic,
+ },
+ },
+ });
+
+ const modelSpec = {
+ name: 'claude-opus-4.5',
+ preset: {
+ endpoint: 'AnthropicClaude',
+ endpointType: EModelEndpoint.custom,
+ model: 'anthropic/claude-opus-4.5',
+ temperature: 0.7,
+ maxOutputTokens: 8192,
+ maxContextTokens: 50000,
+ },
+ };
+
+ const req = createReq(
+ {
+ endpoint: 'AnthropicClaude',
+ endpointType: EModelEndpoint.custom,
+ spec: 'claude-opus-4.5',
+ model: 'anthropic/claude-opus-4.5',
+ },
+ {
+ modelSpecs: {
+ enforce: true,
+ list: [modelSpec],
+ },
+ },
+ );
+
+ await buildEndpointOption(req, createRes(), jest.fn());
+
+ const enforcedCall = parseCompactConvo.mock.calls[1];
+ expect(enforcedCall[0]).toEqual(
+ expect.objectContaining({
+ defaultParamsEndpoint: EModelEndpoint.anthropic,
+ }),
+ );
+
+ const enforcedResult = parseCompactConvo.mock.results[1].value;
+ expect(enforcedResult.maxOutputTokens).toBe(8192);
+ expect(enforcedResult.temperature).toBe(0.7);
+ expect(enforcedResult.maxContextTokens).toBe(50000);
+ });
+
+ it('should fall back to OpenAI schema when getEndpointsConfig fails', async () => {
+ mockGetEndpointsConfig.mockRejectedValue(new Error('Config unavailable'));
+
+ const req = createReq(
+ {
+ endpoint: 'AnthropicClaude',
+ endpointType: EModelEndpoint.custom,
+ model: 'anthropic/claude-opus-4.5',
+ temperature: 0.7,
+ maxOutputTokens: 8192,
+ max_tokens: 4096,
+ },
+ { modelSpecs: null },
+ );
+
+ await buildEndpointOption(req, createRes(), jest.fn());
+
+ expect(parseCompactConvo).toHaveBeenCalledWith(
+ expect.objectContaining({
+ defaultParamsEndpoint: undefined,
+ }),
+ );
+
+ const parsedResult = parseCompactConvo.mock.results[0].value;
+ expect(parsedResult.maxOutputTokens).toBeUndefined();
+ expect(parsedResult.max_tokens).toBe(4096);
+ });
+});
diff --git a/api/server/middleware/checkBan.js b/api/server/middleware/checkBan.js
index b8e680cb94..79804a84e1 100644
--- a/api/server/middleware/checkBan.js
+++ b/api/server/middleware/checkBan.js
@@ -19,14 +19,14 @@ const message = 'Your account has been temporarily banned due to violations of o
* @param {Object} req - Express Request object.
* @param {Object} res - Express Response object.
*
- * @returns {Promise} - Returns a Promise which when resolved sends a response status of 403 with a specific message if request is not of api/ask or api/edit types. If it is, calls `denyRequest()` function.
+ * @returns {Promise} - Returns a Promise which when resolved sends a response status of 403 with a specific message if request is not of api/agents/chat. If it is, calls `denyRequest()` function.
*/
const banResponse = async (req, res) => {
const ua = uap(req.headers['user-agent']);
- const { baseUrl } = req;
+ const { baseUrl, originalUrl } = req;
if (!ua.browser.name) {
return res.status(403).json({ message });
- } else if (baseUrl === '/api/ask' || baseUrl === '/api/edit') {
+ } else if (baseUrl === '/api/agents' && originalUrl.startsWith('/api/agents/chat')) {
return await denyRequest(req, res, { type: ViolationTypes.BAN });
}
diff --git a/api/server/middleware/checkSharePublicAccess.js b/api/server/middleware/checkSharePublicAccess.js
new file mode 100644
index 0000000000..0e95b9f6f8
--- /dev/null
+++ b/api/server/middleware/checkSharePublicAccess.js
@@ -0,0 +1,85 @@
+const { logger } = require('@librechat/data-schemas');
+const { ResourceType, PermissionTypes, Permissions } = require('librechat-data-provider');
+const { getRoleByName } = require('~/models/Role');
+
+/**
+ * Maps resource types to their corresponding permission types
+ */
+const resourceToPermissionType = {
+ [ResourceType.AGENT]: PermissionTypes.AGENTS,
+ [ResourceType.PROMPTGROUP]: PermissionTypes.PROMPTS,
+ [ResourceType.MCPSERVER]: PermissionTypes.MCP_SERVERS,
+ [ResourceType.REMOTE_AGENT]: PermissionTypes.REMOTE_AGENTS,
+};
+
+/**
+ * Middleware to check if user has SHARE_PUBLIC permission for a resource type
+ * Only enforced when request body contains `public: true`
+ * @param {import('express').Request} req - Express request
+ * @param {import('express').Response} res - Express response
+ * @param {import('express').NextFunction} next - Express next function
+ */
+const checkSharePublicAccess = async (req, res, next) => {
+ try {
+ const { public: isPublic } = req.body;
+
+ // Only check if trying to enable public sharing
+ if (!isPublic) {
+ return next();
+ }
+
+ const user = req.user;
+ if (!user || !user.role) {
+ return res.status(401).json({
+ error: 'Unauthorized',
+ message: 'Authentication required',
+ });
+ }
+
+ const { resourceType } = req.params;
+ const permissionType = resourceToPermissionType[resourceType];
+
+ if (!permissionType) {
+ return res.status(400).json({
+ error: 'Bad Request',
+ message: `Unsupported resource type for public sharing: ${resourceType}`,
+ });
+ }
+
+ const role = await getRoleByName(user.role);
+ if (!role || !role.permissions) {
+ return res.status(403).json({
+ error: 'Forbidden',
+ message: 'No permissions configured for user role',
+ });
+ }
+
+ const resourcePerms = role.permissions[permissionType] || {};
+ const canSharePublic = resourcePerms[Permissions.SHARE_PUBLIC] === true;
+
+ if (!canSharePublic) {
+ logger.warn(
+ `[checkSharePublicAccess][${user.id}] User denied SHARE_PUBLIC for ${resourceType}`,
+ );
+ return res.status(403).json({
+ error: 'Forbidden',
+ message: `You do not have permission to share ${resourceType} resources publicly`,
+ });
+ }
+
+ next();
+ } catch (error) {
+ logger.error(
+ `[checkSharePublicAccess][${req.user?.id}] Error checking SHARE_PUBLIC permission`,
+ error,
+ );
+ return res.status(500).json({
+ error: 'Internal Server Error',
+ message: 'Failed to check public sharing permissions',
+ });
+ }
+};
+
+module.exports = {
+ checkSharePublicAccess,
+};
diff --git a/api/server/middleware/checkSharePublicAccess.spec.js b/api/server/middleware/checkSharePublicAccess.spec.js
new file mode 100644
index 0000000000..c73e71693b
--- /dev/null
+++ b/api/server/middleware/checkSharePublicAccess.spec.js
@@ -0,0 +1,164 @@
+const { ResourceType, PermissionTypes, Permissions } = require('librechat-data-provider');
+const { checkSharePublicAccess } = require('./checkSharePublicAccess');
+const { getRoleByName } = require('~/models/Role');
+
+jest.mock('~/models/Role');
+
+describe('checkSharePublicAccess middleware', () => {
+ let mockReq;
+ let mockRes;
+ let mockNext;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockReq = {
+ user: { id: 'user123', role: 'USER' },
+ params: { resourceType: ResourceType.AGENT },
+ body: {},
+ };
+ mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn(),
+ };
+ mockNext = jest.fn();
+ });
+
+ it('should call next() when public is not true', async () => {
+ mockReq.body = { public: false };
+
+ await checkSharePublicAccess(mockReq, mockRes, mockNext);
+
+ expect(mockNext).toHaveBeenCalled();
+ expect(mockRes.status).not.toHaveBeenCalled();
+ });
+
+ it('should call next() when public is undefined', async () => {
+ mockReq.body = { updated: [] };
+
+ await checkSharePublicAccess(mockReq, mockRes, mockNext);
+
+ expect(mockNext).toHaveBeenCalled();
+ expect(mockRes.status).not.toHaveBeenCalled();
+ });
+
+ it('should return 401 when user is not authenticated', async () => {
+ mockReq.body = { public: true };
+ mockReq.user = null;
+
+ await checkSharePublicAccess(mockReq, mockRes, mockNext);
+
+ expect(mockRes.status).toHaveBeenCalledWith(401);
+ expect(mockRes.json).toHaveBeenCalledWith({
+ error: 'Unauthorized',
+ message: 'Authentication required',
+ });
+ expect(mockNext).not.toHaveBeenCalled();
+ });
+
+ it('should return 403 when user role has no SHARE_PUBLIC permission for agents', async () => {
+ mockReq.body = { public: true };
+ mockReq.params = { resourceType: ResourceType.AGENT };
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.AGENTS]: {
+ [Permissions.SHARE]: true,
+ [Permissions.SHARE_PUBLIC]: false,
+ },
+ },
+ });
+
+ await checkSharePublicAccess(mockReq, mockRes, mockNext);
+
+ expect(mockRes.status).toHaveBeenCalledWith(403);
+ expect(mockRes.json).toHaveBeenCalledWith({
+ error: 'Forbidden',
+ message: `You do not have permission to share ${ResourceType.AGENT} resources publicly`,
+ });
+ expect(mockNext).not.toHaveBeenCalled();
+ });
+
+ it('should call next() when user has SHARE_PUBLIC permission for agents', async () => {
+ mockReq.body = { public: true };
+ mockReq.params = { resourceType: ResourceType.AGENT };
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.AGENTS]: {
+ [Permissions.SHARE]: true,
+ [Permissions.SHARE_PUBLIC]: true,
+ },
+ },
+ });
+
+ await checkSharePublicAccess(mockReq, mockRes, mockNext);
+
+ expect(mockNext).toHaveBeenCalled();
+ expect(mockRes.status).not.toHaveBeenCalled();
+ });
+
+ it('should check prompts permission for promptgroup resource type', async () => {
+ mockReq.body = { public: true };
+ mockReq.params = { resourceType: ResourceType.PROMPTGROUP };
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.PROMPTS]: {
+ [Permissions.SHARE_PUBLIC]: true,
+ },
+ },
+ });
+
+ await checkSharePublicAccess(mockReq, mockRes, mockNext);
+
+ expect(mockNext).toHaveBeenCalled();
+ });
+
+ it('should check mcp_servers permission for mcpserver resource type', async () => {
+ mockReq.body = { public: true };
+ mockReq.params = { resourceType: ResourceType.MCPSERVER };
+ getRoleByName.mockResolvedValue({
+ permissions: {
+ [PermissionTypes.MCP_SERVERS]: {
+ [Permissions.SHARE_PUBLIC]: true,
+ },
+ },
+ });
+
+ await checkSharePublicAccess(mockReq, mockRes, mockNext);
+
+ expect(mockNext).toHaveBeenCalled();
+ });
+
+ it('should return 400 for unsupported resource type', async () => {
+ mockReq.body = { public: true };
+ mockReq.params = { resourceType: 'unsupported' };
+
+ await checkSharePublicAccess(mockReq, mockRes, mockNext);
+
+ expect(mockRes.status).toHaveBeenCalledWith(400);
+ expect(mockRes.json).toHaveBeenCalledWith({
+ error: 'Bad Request',
+ message: 'Unsupported resource type for public sharing: unsupported',
+ });
+ });
+
+ it('should return 403 when role has no permissions object', async () => {
+ mockReq.body = { public: true };
+ getRoleByName.mockResolvedValue({ permissions: null });
+
+ await checkSharePublicAccess(mockReq, mockRes, mockNext);
+
+ expect(mockRes.status).toHaveBeenCalledWith(403);
+ });
+
+ it('should return 500 on error', async () => {
+ mockReq.body = { public: true };
+ getRoleByName.mockRejectedValue(new Error('Database error'));
+
+ await checkSharePublicAccess(mockReq, mockRes, mockNext);
+
+ expect(mockRes.status).toHaveBeenCalledWith(500);
+ expect(mockRes.json).toHaveBeenCalledWith({
+ error: 'Internal Server Error',
+ message: 'Failed to check public sharing permissions',
+ });
+ });
+});
diff --git a/api/server/middleware/concurrentLimiter.js b/api/server/middleware/concurrentLimiter.js
deleted file mode 100644
index 96885e2fd4..0000000000
--- a/api/server/middleware/concurrentLimiter.js
+++ /dev/null
@@ -1,76 +0,0 @@
-const { isEnabled } = require('@librechat/api');
-const { Time, CacheKeys, ViolationTypes } = require('librechat-data-provider');
-const clearPendingReq = require('~/cache/clearPendingReq');
-const { logViolation, getLogStores } = require('~/cache');
-const denyRequest = require('./denyRequest');
-
-const {
- USE_REDIS,
- CONCURRENT_MESSAGE_MAX = 1,
- CONCURRENT_VIOLATION_SCORE: score,
-} = process.env ?? {};
-
-/**
- * Middleware to limit concurrent requests for a user.
- *
- * This middleware checks if a user has exceeded a specified concurrent request limit.
- * If the user exceeds the limit, an error is returned. If the user is within the limit,
- * their request count is incremented. After the request is processed, the count is decremented.
- * If the `cache` store is not available, the middleware will skip its logic.
- *
- * @function
- * @param {Object} req - Express request object containing user information.
- * @param {Object} res - Express response object.
- * @param {import('express').NextFunction} next - Next middleware function.
- * @throws {Error} Throws an error if the user exceeds the concurrent request limit.
- */
-const concurrentLimiter = async (req, res, next) => {
- const namespace = CacheKeys.PENDING_REQ;
- const cache = getLogStores(namespace);
- if (!cache) {
- return next();
- }
-
- if (Object.keys(req?.body ?? {}).length === 1 && req?.body?.abortKey) {
- return next();
- }
-
- const userId = req.user?.id ?? req.user?._id ?? '';
- const limit = Math.max(CONCURRENT_MESSAGE_MAX, 1);
- const type = ViolationTypes.CONCURRENT;
-
- const key = `${isEnabled(USE_REDIS) ? namespace : ''}:${userId}`;
- const pendingRequests = +((await cache.get(key)) ?? 0);
-
- if (pendingRequests >= limit) {
- const errorMessage = {
- type,
- limit,
- pendingRequests,
- };
-
- await logViolation(req, res, type, errorMessage, score);
- return await denyRequest(req, res, errorMessage);
- } else {
- await cache.set(key, pendingRequests + 1, Time.ONE_MINUTE);
- }
-
- // Ensure the requests are removed from the store once the request is done
- let cleared = false;
- const cleanUp = async () => {
- if (cleared) {
- return;
- }
- cleared = true;
- await clearPendingReq({ userId, cache });
- };
-
- if (pendingRequests < limit) {
- res.on('finish', cleanUp);
- res.on('close', cleanUp);
- }
-
- next();
-};
-
-module.exports = concurrentLimiter;
diff --git a/api/server/middleware/index.js b/api/server/middleware/index.js
index 55ee465674..64b9fb1618 100644
--- a/api/server/middleware/index.js
+++ b/api/server/middleware/index.js
@@ -3,8 +3,6 @@ const validateRegistration = require('./validateRegistration');
const buildEndpointOption = require('./buildEndpointOption');
const validateMessageReq = require('./validateMessageReq');
const checkDomainAllowed = require('./checkDomainAllowed');
-const concurrentLimiter = require('./concurrentLimiter');
-const validateEndpoint = require('./validateEndpoint');
const requireLocalAuth = require('./requireLocalAuth');
const canDeleteAccount = require('./canDeleteAccount');
const accessResources = require('./accessResources');
@@ -42,9 +40,7 @@ module.exports = {
requireLdapAuth,
requireLocalAuth,
canDeleteAccount,
- validateEndpoint,
configMiddleware,
- concurrentLimiter,
checkDomainAllowed,
validateMessageReq,
buildEndpointOption,
diff --git a/api/server/middleware/requireJwtAuth.js b/api/server/middleware/requireJwtAuth.js
index ed83c4773e..16b107aefc 100644
--- a/api/server/middleware/requireJwtAuth.js
+++ b/api/server/middleware/requireJwtAuth.js
@@ -7,16 +7,13 @@ const { isEnabled } = require('@librechat/api');
* Switches between JWT and OpenID authentication based on cookies and environment settings
*/
const requireJwtAuth = (req, res, next) => {
- // Check if token provider is specified in cookies
const cookieHeader = req.headers.cookie;
const tokenProvider = cookieHeader ? cookies.parse(cookieHeader).token_provider : null;
- // Use OpenID authentication if token provider is OpenID and OPENID_REUSE_TOKENS is enabled
if (tokenProvider === 'openid' && isEnabled(process.env.OPENID_REUSE_TOKENS)) {
return passport.authenticate('openidJwt', { session: false })(req, res, next);
}
- // Default to standard JWT authentication
return passport.authenticate('jwt', { session: false })(req, res, next);
};
diff --git a/api/server/middleware/roles/access.spec.js b/api/server/middleware/roles/access.spec.js
index fe8d77a4f5..9de840819d 100644
--- a/api/server/middleware/roles/access.spec.js
+++ b/api/server/middleware/roles/access.spec.js
@@ -51,9 +51,9 @@ describe('Access Middleware', () => {
permissions: {
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true },
[PermissionTypes.PROMPTS]: {
- [Permissions.SHARED_GLOBAL]: false,
[Permissions.USE]: true,
[Permissions.CREATE]: true,
+ [Permissions.SHARE]: true,
},
[PermissionTypes.MEMORIES]: {
[Permissions.USE]: true,
@@ -65,7 +65,7 @@ describe('Access Middleware', () => {
[PermissionTypes.AGENTS]: {
[Permissions.USE]: true,
[Permissions.CREATE]: false,
- [Permissions.SHARED_GLOBAL]: false,
+ [Permissions.SHARE]: false,
},
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true },
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
@@ -79,9 +79,9 @@ describe('Access Middleware', () => {
permissions: {
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true },
[PermissionTypes.PROMPTS]: {
- [Permissions.SHARED_GLOBAL]: true,
[Permissions.USE]: true,
[Permissions.CREATE]: true,
+ [Permissions.SHARE]: true,
},
[PermissionTypes.MEMORIES]: {
[Permissions.USE]: true,
@@ -93,7 +93,7 @@ describe('Access Middleware', () => {
[PermissionTypes.AGENTS]: {
[Permissions.USE]: true,
[Permissions.CREATE]: true,
- [Permissions.SHARED_GLOBAL]: true,
+ [Permissions.SHARE]: true,
},
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true },
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
@@ -110,7 +110,7 @@ describe('Access Middleware', () => {
[PermissionTypes.AGENTS]: {
[Permissions.USE]: false,
[Permissions.CREATE]: false,
- [Permissions.SHARED_GLOBAL]: false,
+ [Permissions.SHARE]: false,
},
// Has permissions for other types
[PermissionTypes.PROMPTS]: {
@@ -241,7 +241,7 @@ describe('Access Middleware', () => {
req: {},
user: { id: 'admin123', role: 'admin' },
permissionType: PermissionTypes.AGENTS,
- permissions: [Permissions.SHARED_GLOBAL],
+ permissions: [Permissions.SHARE],
getRoleByName,
});
expect(shareResult).toBe(true);
@@ -318,7 +318,7 @@ describe('Access Middleware', () => {
const middleware = generateCheckAccess({
permissionType: PermissionTypes.AGENTS,
- permissions: [Permissions.USE, Permissions.CREATE, Permissions.SHARED_GLOBAL],
+ permissions: [Permissions.USE, Permissions.CREATE, Permissions.SHARE],
getRoleByName,
});
await middleware(req, res, next);
@@ -349,7 +349,7 @@ describe('Access Middleware', () => {
[PermissionTypes.AGENTS]: {
[Permissions.USE]: false,
[Permissions.CREATE]: false,
- [Permissions.SHARED_GLOBAL]: false,
+ [Permissions.SHARE]: false,
},
},
});
diff --git a/api/server/middleware/validate/convoAccess.js b/api/server/middleware/validate/convoAccess.js
index ffee70ae61..127bfdc530 100644
--- a/api/server/middleware/validate/convoAccess.js
+++ b/api/server/middleware/validate/convoAccess.js
@@ -6,6 +6,15 @@ const { logViolation, getLogStores } = require('~/cache');
const { USE_REDIS, CONVO_ACCESS_VIOLATION_SCORE: score = 0 } = process.env ?? {};
+/**
+ * Helper function to get conversationId from different request body structures.
+ * @param {Object} body - The request body.
+ * @returns {string|undefined} The conversationId.
+ */
+const getConversationId = (body) => {
+ return body.conversationId ?? body.arg?.conversationId;
+};
+
/**
* Middleware to validate user's authorization for a conversation.
*
@@ -24,7 +33,7 @@ const validateConvoAccess = async (req, res, next) => {
const namespace = ViolationTypes.CONVO_ACCESS;
const cache = getLogStores(namespace);
- const conversationId = req.body.conversationId;
+ const conversationId = getConversationId(req.body);
if (!conversationId || conversationId === Constants.NEW_CONVO) {
return next();
diff --git a/api/server/middleware/validateEndpoint.js b/api/server/middleware/validateEndpoint.js
deleted file mode 100644
index 51cf14bf09..0000000000
--- a/api/server/middleware/validateEndpoint.js
+++ /dev/null
@@ -1,20 +0,0 @@
-const { handleError } = require('@librechat/api');
-
-function validateEndpoint(req, res, next) {
- const { endpoint: _endpoint, endpointType } = req.body;
- const endpoint = endpointType ?? _endpoint;
-
- if (!req.body.text || req.body.text.length === 0) {
- return handleError(res, { text: 'Prompt empty or too short' });
- }
-
- const pathEndpoint = req.baseUrl.split('/')[3];
-
- if (endpoint !== pathEndpoint) {
- return handleError(res, { text: 'Illegal request: Endpoint mismatch' });
- }
-
- next();
-}
-
-module.exports = validateEndpoint;
diff --git a/api/server/middleware/validateImageRequest.js b/api/server/middleware/validateImageRequest.js
index b74ed7225e..4d954d07c4 100644
--- a/api/server/middleware/validateImageRequest.js
+++ b/api/server/middleware/validateImageRequest.js
@@ -68,17 +68,11 @@ function createValidateImageRequest(secureImageLinks) {
}
const parsedCookies = cookies.parse(cookieHeader);
- const refreshToken = parsedCookies.refreshToken;
-
- if (!refreshToken) {
- logger.warn('[validateImageRequest] Token not provided');
- return res.status(401).send('Unauthorized');
- }
-
const tokenProvider = parsedCookies.token_provider;
let userIdForPath;
if (tokenProvider === 'openid' && isEnabled(process.env.OPENID_REUSE_TOKENS)) {
+ /** For OpenID users with OPENID_REUSE_TOKENS, use openid_user_id cookie */
const openidUserId = parsedCookies.openid_user_id;
if (!openidUserId) {
logger.warn('[validateImageRequest] No OpenID user ID cookie found');
@@ -92,6 +86,17 @@ function createValidateImageRequest(secureImageLinks) {
}
userIdForPath = validationResult.userId;
} else {
+ /**
+ * For non-OpenID users (or OpenID without REUSE_TOKENS), use refreshToken from cookies.
+ * These users authenticate via setAuthTokens() which stores refreshToken in cookies.
+ */
+ const refreshToken = parsedCookies.refreshToken;
+
+ if (!refreshToken) {
+ logger.warn('[validateImageRequest] Token not provided');
+ return res.status(401).send('Unauthorized');
+ }
+
const validationResult = validateToken(refreshToken);
if (!validationResult.valid) {
logger.warn(`[validateImageRequest] ${validationResult.error}`);
diff --git a/api/server/routes/__tests__/config.spec.js b/api/server/routes/__tests__/config.spec.js
index 054e4726f0..7d7d3ea13a 100644
--- a/api/server/routes/__tests__/config.spec.js
+++ b/api/server/routes/__tests__/config.spec.js
@@ -43,7 +43,6 @@ afterEach(() => {
//TODO: This works/passes locally but http request tests fail with 404 in CI. Need to figure out why.
-// eslint-disable-next-line jest/no-disabled-tests
describe.skip('GET /', () => {
it('should return 200 and the correct body', async () => {
process.env.APP_TITLE = 'Test Title';
diff --git a/api/server/routes/__tests__/convos.spec.js b/api/server/routes/__tests__/convos.spec.js
index e1f9469bef..931ef006d0 100644
--- a/api/server/routes/__tests__/convos.spec.js
+++ b/api/server/routes/__tests__/convos.spec.js
@@ -59,6 +59,7 @@ jest.mock('~/server/middleware', () => ({
forkUserLimiter: (req, res, next) => next(),
})),
configMiddleware: (req, res, next) => next(),
+ validateConvoAccess: (req, res, next) => next(),
}));
jest.mock('~/server/utils/import/fork', () => ({
@@ -108,7 +109,7 @@ describe('Convos Routes', () => {
let app;
let convosRouter;
const { deleteAllSharedLinks, deleteConvoSharedLink } = require('~/models');
- const { deleteConvos } = require('~/models/Conversation');
+ const { deleteConvos, saveConvo } = require('~/models/Conversation');
const { deleteToolCalls } = require('~/models/ToolCall');
beforeAll(() => {
@@ -384,6 +385,40 @@ describe('Convos Routes', () => {
expect(deleteConvoSharedLink).not.toHaveBeenCalled();
});
+ it('should return 400 when request body is empty (DoS prevention)', async () => {
+ const response = await request(app).delete('/api/convos').send({});
+
+ expect(response.status).toBe(400);
+ expect(response.body).toEqual({ error: 'no parameters provided' });
+ expect(deleteConvos).not.toHaveBeenCalled();
+ });
+
+ it('should return 400 when arg is null (DoS prevention)', async () => {
+ const response = await request(app).delete('/api/convos').send({ arg: null });
+
+ expect(response.status).toBe(400);
+ expect(response.body).toEqual({ error: 'no parameters provided' });
+ expect(deleteConvos).not.toHaveBeenCalled();
+ });
+
+ it('should return 400 when arg is undefined (DoS prevention)', async () => {
+ const response = await request(app).delete('/api/convos').send({ arg: undefined });
+
+ expect(response.status).toBe(400);
+ expect(response.body).toEqual({ error: 'no parameters provided' });
+ expect(deleteConvos).not.toHaveBeenCalled();
+ });
+
+ it('should return 400 when request body is null (DoS prevention)', async () => {
+ const response = await request(app)
+ .delete('/api/convos')
+ .set('Content-Type', 'application/json')
+ .send('null');
+
+ expect(response.status).toBe(400);
+ expect(deleteConvos).not.toHaveBeenCalled();
+ });
+
it('should return 500 if deleteConvoSharedLink fails', async () => {
const mockConversationId = 'conv-error';
@@ -460,6 +495,138 @@ describe('Convos Routes', () => {
expect(deleteConvoSharedLink).toHaveBeenCalledAfter(deleteConvos);
});
});
+
+ describe('POST /archive', () => {
+ it('should archive a conversation successfully', async () => {
+ const mockConversationId = 'conv-123';
+ const mockArchivedConvo = {
+ conversationId: mockConversationId,
+ title: 'Test Conversation',
+ isArchived: true,
+ user: 'test-user-123',
+ };
+
+ saveConvo.mockResolvedValue(mockArchivedConvo);
+
+ const response = await request(app)
+ .post('/api/convos/archive')
+ .send({
+ arg: {
+ conversationId: mockConversationId,
+ isArchived: true,
+ },
+ });
+
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual(mockArchivedConvo);
+ expect(saveConvo).toHaveBeenCalledWith(
+ expect.objectContaining({ user: { id: 'test-user-123' } }),
+ { conversationId: mockConversationId, isArchived: true },
+ { context: `POST /api/convos/archive ${mockConversationId}` },
+ );
+ });
+
+ it('should unarchive a conversation successfully', async () => {
+ const mockConversationId = 'conv-456';
+ const mockUnarchivedConvo = {
+ conversationId: mockConversationId,
+ title: 'Unarchived Conversation',
+ isArchived: false,
+ user: 'test-user-123',
+ };
+
+ saveConvo.mockResolvedValue(mockUnarchivedConvo);
+
+ const response = await request(app)
+ .post('/api/convos/archive')
+ .send({
+ arg: {
+ conversationId: mockConversationId,
+ isArchived: false,
+ },
+ });
+
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual(mockUnarchivedConvo);
+ expect(saveConvo).toHaveBeenCalledWith(
+ expect.objectContaining({ user: { id: 'test-user-123' } }),
+ { conversationId: mockConversationId, isArchived: false },
+ { context: `POST /api/convos/archive ${mockConversationId}` },
+ );
+ });
+
+ it('should return 400 when conversationId is missing', async () => {
+ const response = await request(app)
+ .post('/api/convos/archive')
+ .send({
+ arg: {
+ isArchived: true,
+ },
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body).toEqual({ error: 'conversationId is required' });
+ expect(saveConvo).not.toHaveBeenCalled();
+ });
+
+ it('should return 400 when isArchived is not a boolean', async () => {
+ const response = await request(app)
+ .post('/api/convos/archive')
+ .send({
+ arg: {
+ conversationId: 'conv-123',
+ isArchived: 'true',
+ },
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body).toEqual({ error: 'isArchived must be a boolean' });
+ expect(saveConvo).not.toHaveBeenCalled();
+ });
+
+ it('should return 400 when isArchived is undefined', async () => {
+ const response = await request(app)
+ .post('/api/convos/archive')
+ .send({
+ arg: {
+ conversationId: 'conv-123',
+ },
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body).toEqual({ error: 'isArchived must be a boolean' });
+ expect(saveConvo).not.toHaveBeenCalled();
+ });
+
+ it('should return 500 when saveConvo fails', async () => {
+ const mockConversationId = 'conv-error';
+ saveConvo.mockRejectedValue(new Error('Database error'));
+
+ const response = await request(app)
+ .post('/api/convos/archive')
+ .send({
+ arg: {
+ conversationId: mockConversationId,
+ isArchived: true,
+ },
+ });
+
+ expect(response.status).toBe(500);
+ expect(response.text).toBe('Error archiving conversation');
+
+ const { logger } = require('@librechat/data-schemas');
+ expect(logger.error).toHaveBeenCalledWith('Error archiving conversation', expect.any(Error));
+ });
+
+ it('should handle empty arg object', async () => {
+ const response = await request(app).post('/api/convos/archive').send({
+ arg: {},
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body).toEqual({ error: 'conversationId is required' });
+ });
+ });
});
/**
diff --git a/api/server/routes/__tests__/keys.spec.js b/api/server/routes/__tests__/keys.spec.js
new file mode 100644
index 0000000000..0c96dd3bcb
--- /dev/null
+++ b/api/server/routes/__tests__/keys.spec.js
@@ -0,0 +1,174 @@
+const express = require('express');
+const request = require('supertest');
+
+jest.mock('~/models', () => ({
+ updateUserKey: jest.fn(),
+ deleteUserKey: jest.fn(),
+ getUserKeyExpiry: jest.fn(),
+}));
+
+jest.mock('~/server/middleware/requireJwtAuth', () => (req, res, next) => next());
+
+jest.mock('~/server/middleware', () => ({
+ requireJwtAuth: (req, res, next) => next(),
+}));
+
+describe('Keys Routes', () => {
+ let app;
+ const { updateUserKey, deleteUserKey, getUserKeyExpiry } = require('~/models');
+
+ beforeAll(() => {
+ const keysRouter = require('../keys');
+
+ app = express();
+ app.use(express.json());
+
+ app.use((req, res, next) => {
+ req.user = { id: 'test-user-123' };
+ next();
+ });
+
+ app.use('/api/keys', keysRouter);
+ });
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('PUT /', () => {
+ it('should update a user key with the authenticated user ID', async () => {
+ updateUserKey.mockResolvedValue({});
+
+ const response = await request(app)
+ .put('/api/keys')
+ .send({ name: 'openAI', value: 'sk-test-key-123', expiresAt: '2026-12-31' });
+
+ expect(response.status).toBe(201);
+ expect(updateUserKey).toHaveBeenCalledWith({
+ userId: 'test-user-123',
+ name: 'openAI',
+ value: 'sk-test-key-123',
+ expiresAt: '2026-12-31',
+ });
+ expect(updateUserKey).toHaveBeenCalledTimes(1);
+ });
+
+ it('should not allow userId override via request body (IDOR prevention)', async () => {
+ updateUserKey.mockResolvedValue({});
+
+ const response = await request(app).put('/api/keys').send({
+ userId: 'attacker-injected-id',
+ name: 'openAI',
+ value: 'sk-attacker-key',
+ });
+
+ expect(response.status).toBe(201);
+ expect(updateUserKey).toHaveBeenCalledWith({
+ userId: 'test-user-123',
+ name: 'openAI',
+ value: 'sk-attacker-key',
+ expiresAt: undefined,
+ });
+ });
+
+ it('should ignore extraneous fields from request body', async () => {
+ updateUserKey.mockResolvedValue({});
+
+ const response = await request(app).put('/api/keys').send({
+ name: 'openAI',
+ value: 'sk-test-key',
+ expiresAt: '2026-12-31',
+ _id: 'injected-mongo-id',
+ __v: 99,
+ extra: 'should-be-ignored',
+ });
+
+ expect(response.status).toBe(201);
+ expect(updateUserKey).toHaveBeenCalledWith({
+ userId: 'test-user-123',
+ name: 'openAI',
+ value: 'sk-test-key',
+ expiresAt: '2026-12-31',
+ });
+ });
+
+ it('should handle missing optional fields', async () => {
+ updateUserKey.mockResolvedValue({});
+
+ const response = await request(app)
+ .put('/api/keys')
+ .send({ name: 'anthropic', value: 'sk-ant-key' });
+
+ expect(response.status).toBe(201);
+ expect(updateUserKey).toHaveBeenCalledWith({
+ userId: 'test-user-123',
+ name: 'anthropic',
+ value: 'sk-ant-key',
+ expiresAt: undefined,
+ });
+ });
+
+ it('should return 400 when request body is null', async () => {
+ const response = await request(app)
+ .put('/api/keys')
+ .set('Content-Type', 'application/json')
+ .send('null');
+
+ expect(response.status).toBe(400);
+ expect(updateUserKey).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('DELETE /:name', () => {
+ it('should delete a user key by name', async () => {
+ deleteUserKey.mockResolvedValue({});
+
+ const response = await request(app).delete('/api/keys/openAI');
+
+ expect(response.status).toBe(204);
+ expect(deleteUserKey).toHaveBeenCalledWith({
+ userId: 'test-user-123',
+ name: 'openAI',
+ });
+ expect(deleteUserKey).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('DELETE /', () => {
+ it('should delete all keys when all=true', async () => {
+ deleteUserKey.mockResolvedValue({});
+
+ const response = await request(app).delete('/api/keys?all=true');
+
+ expect(response.status).toBe(204);
+ expect(deleteUserKey).toHaveBeenCalledWith({
+ userId: 'test-user-123',
+ all: true,
+ });
+ });
+
+ it('should return 400 when all query param is not true', async () => {
+ const response = await request(app).delete('/api/keys');
+
+ expect(response.status).toBe(400);
+ expect(response.body).toEqual({ error: 'Specify either all=true to delete.' });
+ expect(deleteUserKey).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('GET /', () => {
+ it('should return key expiry for a given key name', async () => {
+ const mockExpiry = { expiresAt: '2026-12-31' };
+ getUserKeyExpiry.mockResolvedValue(mockExpiry);
+
+ const response = await request(app).get('/api/keys?name=openAI');
+
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual(mockExpiry);
+ expect(getUserKeyExpiry).toHaveBeenCalledWith({
+ userId: 'test-user-123',
+ name: 'openAI',
+ });
+ });
+ });
+});
diff --git a/api/server/routes/__tests__/mcp.spec.js b/api/server/routes/__tests__/mcp.spec.js
index ae87a6d900..e87fcf8f15 100644
--- a/api/server/routes/__tests__/mcp.spec.js
+++ b/api/server/routes/__tests__/mcp.spec.js
@@ -1,25 +1,58 @@
+const crypto = require('crypto');
const express = require('express');
const request = require('supertest');
const mongoose = require('mongoose');
+const cookieParser = require('cookie-parser');
+const { getBasePath } = require('@librechat/api');
const { MongoMemoryServer } = require('mongodb-memory-server');
-jest.mock('@librechat/api', () => ({
- ...jest.requireActual('@librechat/api'),
- MCPOAuthHandler: {
- initiateOAuthFlow: jest.fn(),
- getFlowState: jest.fn(),
- completeOAuthFlow: jest.fn(),
- generateFlowId: jest.fn(),
- },
- MCPTokenStorage: {
- storeTokens: jest.fn(),
- },
- getUserMCPAuthMap: jest.fn(),
- mcpServersRegistry: {
- getServerConfig: jest.fn(),
- getOAuthServers: jest.fn(),
- },
-}));
+function generateTestCsrfToken(flowId) {
+ return crypto
+ .createHmac('sha256', process.env.JWT_SECRET)
+ .update(flowId)
+ .digest('hex')
+ .slice(0, 32);
+}
+
+const mockRegistryInstance = {
+ getServerConfig: jest.fn(),
+ getOAuthServers: jest.fn(),
+ getAllServerConfigs: jest.fn(),
+ addServer: jest.fn(),
+ updateServer: jest.fn(),
+ removeServer: jest.fn(),
+};
+
+jest.mock('@librechat/api', () => {
+ const actual = jest.requireActual('@librechat/api');
+ return {
+ ...actual,
+ MCPOAuthHandler: {
+ initiateOAuthFlow: jest.fn(),
+ getFlowState: jest.fn(),
+ completeOAuthFlow: jest.fn(),
+ generateFlowId: jest.fn(),
+ },
+ MCPTokenStorage: {
+ storeTokens: jest.fn(),
+ getClientInfoAndMetadata: jest.fn(),
+ getTokens: jest.fn(),
+ deleteUserTokens: jest.fn(),
+ },
+ getUserMCPAuthMap: jest.fn(),
+ generateCheckAccess: jest.fn(() => (req, res, next) => next()),
+ MCPServersRegistry: {
+ getInstance: () => mockRegistryInstance,
+ },
+ // Error handling utilities (from @librechat/api mcp/errors)
+ isMCPDomainNotAllowedError: (error) => error?.code === 'MCP_DOMAIN_NOT_ALLOWED',
+ isMCPInspectionFailedError: (error) => error?.code === 'MCP_INSPECTION_FAILED',
+ MCPErrorCodes: {
+ DOMAIN_NOT_ALLOWED: 'MCP_DOMAIN_NOT_ALLOWED',
+ INSPECTION_FAILED: 'MCP_INSPECTION_FAILED',
+ },
+ };
+});
jest.mock('@librechat/data-schemas', () => ({
logger: {
@@ -38,6 +71,9 @@ jest.mock('@librechat/data-schemas', () => ({
findById: jest.fn(),
},
})),
+ createMethods: jest.fn(() => ({
+ findUser: jest.fn(),
+ })),
}));
jest.mock('~/models', () => ({
@@ -46,6 +82,7 @@ jest.mock('~/models', () => ({
createToken: jest.fn(),
deleteTokens: jest.fn(),
findPluginAuthsByKeys: jest.fn(),
+ getRoleByName: jest.fn(),
}));
jest.mock('~/server/services/Config', () => ({
@@ -71,6 +108,8 @@ jest.mock('~/server/services/PluginService', () => ({
jest.mock('~/config', () => ({
getMCPManager: jest.fn(),
getFlowStateManager: jest.fn(),
+ getOAuthReconnectionManager: jest.fn(),
+ getMCPServersRegistry: jest.fn(() => mockRegistryInstance),
}));
jest.mock('~/cache', () => ({
@@ -79,6 +118,7 @@ jest.mock('~/cache', () => ({
jest.mock('~/server/middleware', () => ({
requireJwtAuth: (req, res, next) => next(),
+ canAccessMCPServerResource: () => (req, res, next) => next(),
}));
jest.mock('~/server/services/Tools/mcp', () => ({
@@ -100,6 +140,7 @@ describe('MCP Routes', () => {
app = express();
app.use(express.json());
+ app.use(cookieParser());
app.use((req, res, next) => {
req.user = { id: 'test-user-id' };
@@ -119,7 +160,7 @@ describe('MCP Routes', () => {
});
describe('GET /:serverName/oauth/initiate', () => {
- const { MCPOAuthHandler, mcpServersRegistry } = require('@librechat/api');
+ const { MCPOAuthHandler } = require('@librechat/api');
const { getLogStores } = require('~/cache');
it('should initiate OAuth flow successfully', async () => {
@@ -134,16 +175,16 @@ describe('MCP Routes', () => {
getLogStores.mockReturnValue({});
require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
- mcpServersRegistry.getServerConfig.mockResolvedValue({});
+ mockRegistryInstance.getServerConfig.mockResolvedValue({});
MCPOAuthHandler.initiateOAuthFlow.mockResolvedValue({
authorizationUrl: 'https://oauth.example.com/auth',
- flowId: 'test-flow-id',
+ flowId: 'test-user-id:test-server',
});
const response = await request(app).get('/api/mcp/test-server/oauth/initiate').query({
userId: 'test-user-id',
- flowId: 'test-flow-id',
+ flowId: 'test-user-id:test-server',
});
expect(response.status).toBe(302);
@@ -160,7 +201,7 @@ describe('MCP Routes', () => {
it('should return 403 when userId does not match authenticated user', async () => {
const response = await request(app).get('/api/mcp/test-server/oauth/initiate').query({
userId: 'different-user-id',
- flowId: 'test-flow-id',
+ flowId: 'test-user-id:test-server',
});
expect(response.status).toBe(403);
@@ -198,7 +239,7 @@ describe('MCP Routes', () => {
const response = await request(app).get('/api/mcp/test-server/oauth/initiate').query({
userId: 'test-user-id',
- flowId: 'test-flow-id',
+ flowId: 'test-user-id:test-server',
});
expect(response.status).toBe(400);
@@ -215,7 +256,7 @@ describe('MCP Routes', () => {
const response = await request(app).get('/api/mcp/test-server/oauth/initiate').query({
userId: 'test-user-id',
- flowId: 'test-flow-id',
+ flowId: 'test-user-id:test-server',
});
expect(response.status).toBe(500);
@@ -225,7 +266,7 @@ describe('MCP Routes', () => {
it('should return 400 when flow state metadata is null', async () => {
const mockFlowManager = {
getFlowState: jest.fn().mockResolvedValue({
- id: 'test-flow-id',
+ id: 'test-user-id:test-server',
metadata: null,
}),
};
@@ -235,7 +276,7 @@ describe('MCP Routes', () => {
const response = await request(app).get('/api/mcp/test-server/oauth/initiate').query({
userId: 'test-user-id',
- flowId: 'test-flow-id',
+ flowId: 'test-user-id:test-server',
});
expect(response.status).toBe(400);
@@ -250,45 +291,84 @@ describe('MCP Routes', () => {
it('should redirect to error page when OAuth error is received', async () => {
const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
error: 'access_denied',
- state: 'test-flow-id',
+ state: 'test-user-id:test-server',
});
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/error?error=access_denied');
+ expect(response.headers.location).toBe(`${basePath}/oauth/error?error=access_denied`);
});
it('should redirect to error page when code is missing', async () => {
const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
- state: 'test-flow-id',
+ state: 'test-user-id:test-server',
});
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/error?error=missing_code');
+ expect(response.headers.location).toBe(`${basePath}/oauth/error?error=missing_code`);
});
it('should redirect to error page when state is missing', async () => {
const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
code: 'test-auth-code',
});
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/error?error=missing_state');
+ expect(response.headers.location).toBe(`${basePath}/oauth/error?error=missing_state`);
+ });
+
+ it('should redirect to error page when CSRF cookie is missing', async () => {
+ const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
+ code: 'test-auth-code',
+ state: 'test-user-id:test-server',
+ });
+ const basePath = getBasePath();
+
+ expect(response.status).toBe(302);
+ expect(response.headers.location).toBe(
+ `${basePath}/oauth/error?error=csrf_validation_failed`,
+ );
+ });
+
+ it('should redirect to error page when CSRF cookie does not match state', async () => {
+ const csrfToken = generateTestCsrfToken('different-flow-id');
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
+ .query({
+ code: 'test-auth-code',
+ state: 'test-user-id:test-server',
+ });
+ const basePath = getBasePath();
+
+ expect(response.status).toBe(302);
+ expect(response.headers.location).toBe(
+ `${basePath}/oauth/error?error=csrf_validation_failed`,
+ );
});
it('should redirect to error page when flow state is not found', async () => {
MCPOAuthHandler.getFlowState.mockResolvedValue(null);
+ const flowId = 'invalid-flow:id';
+ const csrfToken = generateTestCsrfToken(flowId);
- const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
- code: 'test-auth-code',
- state: 'invalid-flow-id',
- });
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
+ .query({
+ code: 'test-auth-code',
+ state: flowId,
+ });
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/error?error=invalid_state');
+ expect(response.headers.location).toBe(`${basePath}/oauth/error?error=invalid_state`);
});
it('should handle OAuth callback successfully', async () => {
- const { mcpServersRegistry } = require('@librechat/api');
+ // mockRegistryInstance is defined at the top of the file
const mockFlowManager = {
getFlowState: jest.fn().mockResolvedValue({ status: 'PENDING' }),
completeFlow: jest.fn().mockResolvedValue(),
@@ -309,7 +389,7 @@ describe('MCP Routes', () => {
MCPOAuthHandler.getFlowState.mockResolvedValue(mockFlowState);
MCPOAuthHandler.completeOAuthFlow.mockResolvedValue(mockTokens);
MCPTokenStorage.storeTokens.mockResolvedValue();
- mcpServersRegistry.getServerConfig.mockResolvedValue({});
+ mockRegistryInstance.getServerConfig.mockResolvedValue({});
getLogStores.mockReturnValue({});
require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
@@ -335,15 +415,22 @@ describe('MCP Routes', () => {
});
setCachedTools.mockResolvedValue();
- const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
- code: 'test-auth-code',
- state: 'test-flow-id',
- });
+ const flowId = 'test-user-id:test-server';
+ const csrfToken = generateTestCsrfToken(flowId);
+
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
+ .query({
+ code: 'test-auth-code',
+ state: flowId,
+ });
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/success?serverName=test-server');
+ expect(response.headers.location).toBe(`${basePath}/oauth/success?serverName=test-server`);
expect(MCPOAuthHandler.completeOAuthFlow).toHaveBeenCalledWith(
- 'test-flow-id',
+ flowId,
'test-auth-code',
mockFlowManager,
{},
@@ -365,23 +452,32 @@ describe('MCP Routes', () => {
'mcp_oauth',
mockTokens,
);
- expect(mockFlowManager.deleteFlow).toHaveBeenCalledWith('test-flow-id', 'mcp_get_tokens');
+ expect(mockFlowManager.deleteFlow).toHaveBeenCalledWith(
+ 'test-user-id:test-server',
+ 'mcp_get_tokens',
+ );
});
it('should redirect to error page when callback processing fails', async () => {
MCPOAuthHandler.getFlowState.mockRejectedValue(new Error('Callback error'));
+ const flowId = 'test-user-id:test-server';
+ const csrfToken = generateTestCsrfToken(flowId);
- const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
- code: 'test-auth-code',
- state: 'test-flow-id',
- });
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
+ .query({
+ code: 'test-auth-code',
+ state: flowId,
+ });
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/error?error=callback_failed');
+ expect(response.headers.location).toBe(`${basePath}/oauth/error?error=callback_failed`);
});
it('should handle system-level OAuth completion', async () => {
- const { mcpServersRegistry } = require('@librechat/api');
+ // mockRegistryInstance is defined at the top of the file
const mockFlowManager = {
getFlowState: jest.fn().mockResolvedValue({ status: 'PENDING' }),
completeFlow: jest.fn().mockResolvedValue(),
@@ -402,22 +498,29 @@ describe('MCP Routes', () => {
MCPOAuthHandler.getFlowState.mockResolvedValue(mockFlowState);
MCPOAuthHandler.completeOAuthFlow.mockResolvedValue(mockTokens);
MCPTokenStorage.storeTokens.mockResolvedValue();
- mcpServersRegistry.getServerConfig.mockResolvedValue({});
+ mockRegistryInstance.getServerConfig.mockResolvedValue({});
getLogStores.mockReturnValue({});
require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
- const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
- code: 'test-auth-code',
- state: 'test-flow-id',
- });
+ const flowId = 'test-user-id:test-server';
+ const csrfToken = generateTestCsrfToken(flowId);
+
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
+ .query({
+ code: 'test-auth-code',
+ state: flowId,
+ });
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/success?serverName=test-server');
- expect(mockFlowManager.deleteFlow).toHaveBeenCalledWith('test-flow-id', 'mcp_get_tokens');
+ expect(response.headers.location).toBe(`${basePath}/oauth/success?serverName=test-server`);
+ expect(mockFlowManager.deleteFlow).toHaveBeenCalledWith(flowId, 'mcp_get_tokens');
});
it('should handle reconnection failure after OAuth', async () => {
- const { mcpServersRegistry } = require('@librechat/api');
+ // mockRegistryInstance is defined at the top of the file
const mockFlowManager = {
getFlowState: jest.fn().mockResolvedValue({ status: 'PENDING' }),
completeFlow: jest.fn().mockResolvedValue(),
@@ -438,7 +541,7 @@ describe('MCP Routes', () => {
MCPOAuthHandler.getFlowState.mockResolvedValue(mockFlowState);
MCPOAuthHandler.completeOAuthFlow.mockResolvedValue(mockTokens);
MCPTokenStorage.storeTokens.mockResolvedValue();
- mcpServersRegistry.getServerConfig.mockResolvedValue({});
+ mockRegistryInstance.getServerConfig.mockResolvedValue({});
getLogStores.mockReturnValue({});
require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
@@ -451,19 +554,26 @@ describe('MCP Routes', () => {
getCachedTools.mockResolvedValue({});
setCachedTools.mockResolvedValue();
- const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
- code: 'test-auth-code',
- state: 'test-flow-id',
- });
+ const flowId = 'test-user-id:test-server';
+ const csrfToken = generateTestCsrfToken(flowId);
+
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
+ .query({
+ code: 'test-auth-code',
+ state: flowId,
+ });
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/success?serverName=test-server');
+ expect(response.headers.location).toBe(`${basePath}/oauth/success?serverName=test-server`);
expect(MCPTokenStorage.storeTokens).toHaveBeenCalled();
- expect(mockFlowManager.deleteFlow).toHaveBeenCalledWith('test-flow-id', 'mcp_get_tokens');
+ expect(mockFlowManager.deleteFlow).toHaveBeenCalledWith(flowId, 'mcp_get_tokens');
});
it('should redirect to error page if token storage fails', async () => {
- const { mcpServersRegistry } = require('@librechat/api');
+ // mockRegistryInstance is defined at the top of the file
const mockFlowManager = {
completeFlow: jest.fn().mockResolvedValue(),
deleteFlow: jest.fn().mockResolvedValue(true),
@@ -483,7 +593,7 @@ describe('MCP Routes', () => {
MCPOAuthHandler.getFlowState.mockResolvedValue(mockFlowState);
MCPOAuthHandler.completeOAuthFlow.mockResolvedValue(mockTokens);
MCPTokenStorage.storeTokens.mockRejectedValue(new Error('store failed'));
- mcpServersRegistry.getServerConfig.mockResolvedValue({});
+ mockRegistryInstance.getServerConfig.mockResolvedValue({});
getLogStores.mockReturnValue({});
require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
@@ -492,18 +602,25 @@ describe('MCP Routes', () => {
};
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
- const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
- code: 'test-auth-code',
- state: 'test-flow-id',
- });
+ const flowId = 'test-user-id:test-server';
+ const csrfToken = generateTestCsrfToken(flowId);
+
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
+ .query({
+ code: 'test-auth-code',
+ state: flowId,
+ });
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/error?error=callback_failed');
+ expect(response.headers.location).toBe(`${basePath}/oauth/error?error=callback_failed`);
expect(mockMcpManager.getUserConnection).not.toHaveBeenCalled();
});
it('should use original flow state credentials when storing tokens', async () => {
- const { mcpServersRegistry } = require('@librechat/api');
+ // mockRegistryInstance is defined at the top of the file
const mockFlowManager = {
getFlowState: jest.fn(),
completeFlow: jest.fn().mockResolvedValue(),
@@ -535,7 +652,7 @@ describe('MCP Routes', () => {
MCPOAuthHandler.getFlowState.mockResolvedValue(flowState);
MCPOAuthHandler.completeOAuthFlow.mockResolvedValue(mockTokens);
MCPTokenStorage.storeTokens.mockResolvedValue();
- mcpServersRegistry.getServerConfig.mockResolvedValue({});
+ mockRegistryInstance.getServerConfig.mockResolvedValue({});
getLogStores.mockReturnValue({});
require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
@@ -550,21 +667,27 @@ describe('MCP Routes', () => {
clearReconnection: jest.fn(),
});
- const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
- code: 'test-auth-code',
- state: 'test-flow-id',
- });
+ const flowId = 'test-user-id:test-server';
+ const csrfToken = generateTestCsrfToken(flowId);
+
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
+ .query({
+ code: 'test-auth-code',
+ state: flowId,
+ });
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/success?serverName=test-server');
+ expect(response.headers.location).toBe(`${basePath}/oauth/success?serverName=test-server`);
- // Verify storeTokens was called with ORIGINAL flow state credentials
expect(MCPTokenStorage.storeTokens).toHaveBeenCalledWith(
expect.objectContaining({
userId: 'test-user-id',
serverName: 'test-server',
tokens: mockTokens,
- clientInfo: clientInfo, // Uses original flow state, not any "updated" credentials
+ clientInfo: clientInfo,
metadata: flowState.metadata,
}),
);
@@ -591,15 +714,21 @@ describe('MCP Routes', () => {
getLogStores.mockReturnValue({});
require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
- const response = await request(app).get('/api/mcp/test-server/oauth/callback').query({
- code: 'test-auth-code',
- state: 'test-flow-id',
- });
+ const flowId = 'test-user-id:test-server';
+ const csrfToken = generateTestCsrfToken(flowId);
+
+ const response = await request(app)
+ .get('/api/mcp/test-server/oauth/callback')
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
+ .query({
+ code: 'test-auth-code',
+ state: flowId,
+ });
+ const basePath = getBasePath();
expect(response.status).toBe(302);
- expect(response.headers.location).toBe('/oauth/success?serverName=test-server');
+ expect(response.headers.location).toBe(`${basePath}/oauth/success?serverName=test-server`);
- // Verify completeOAuthFlow was NOT called (prevented duplicate)
expect(MCPOAuthHandler.completeOAuthFlow).not.toHaveBeenCalled();
expect(MCPTokenStorage.storeTokens).not.toHaveBeenCalled();
});
@@ -714,7 +843,7 @@ describe('MCP Routes', () => {
getLogStores.mockReturnValue({});
require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
- const response = await request(app).get('/api/mcp/oauth/status/test-flow-id');
+ const response = await request(app).get('/api/mcp/oauth/status/test-user-id:test-server');
expect(response.status).toBe(200);
expect(response.body).toEqual({
@@ -725,6 +854,13 @@ describe('MCP Routes', () => {
});
});
+ it('should return 403 when flowId does not match authenticated user', async () => {
+ const response = await request(app).get('/api/mcp/oauth/status/other-user-id:test-server');
+
+ expect(response.status).toBe(403);
+ expect(response.body).toEqual({ error: 'Access denied' });
+ });
+
it('should return 404 when flow is not found', async () => {
const mockFlowManager = {
getFlowState: jest.fn().mockResolvedValue(null),
@@ -733,7 +869,7 @@ describe('MCP Routes', () => {
getLogStores.mockReturnValue({});
require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
- const response = await request(app).get('/api/mcp/oauth/status/non-existent-flow');
+ const response = await request(app).get('/api/mcp/oauth/status/test-user-id:non-existent');
expect(response.status).toBe(404);
expect(response.body).toEqual({ error: 'Flow not found' });
@@ -747,7 +883,7 @@ describe('MCP Routes', () => {
getLogStores.mockReturnValue({});
require('~/config').getFlowStateManager.mockReturnValue(mockFlowManager);
- const response = await request(app).get('/api/mcp/oauth/status/error-flow-id');
+ const response = await request(app).get('/api/mcp/oauth/status/test-user-id:error-server');
expect(response.status).toBe(500);
expect(response.body).toEqual({ error: 'Failed to get flow status' });
@@ -836,14 +972,14 @@ describe('MCP Routes', () => {
});
describe('POST /:serverName/reinitialize', () => {
- const { mcpServersRegistry } = require('@librechat/api');
+ // mockRegistryInstance is defined at the top of the file
it('should return 404 when server is not found in configuration', async () => {
const mockMcpManager = {
disconnectUserConnection: jest.fn().mockResolvedValue(),
};
- mcpServersRegistry.getServerConfig.mockResolvedValue(null);
+ mockRegistryInstance.getServerConfig.mockResolvedValue(null);
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
require('~/config').getFlowStateManager.mockReturnValue({});
require('~/cache').getLogStores.mockReturnValue({});
@@ -868,7 +1004,7 @@ describe('MCP Routes', () => {
}),
};
- mcpServersRegistry.getServerConfig.mockResolvedValue({
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
customUserVars: {},
});
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
@@ -901,7 +1037,7 @@ describe('MCP Routes', () => {
getUserConnection: jest.fn().mockRejectedValue(new Error('Connection failed')),
};
- mcpServersRegistry.getServerConfig.mockResolvedValue({});
+ mockRegistryInstance.getServerConfig.mockResolvedValue({});
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
require('~/config').getFlowStateManager.mockReturnValue({});
require('~/cache').getLogStores.mockReturnValue({});
@@ -920,7 +1056,7 @@ describe('MCP Routes', () => {
disconnectUserConnection: jest.fn(),
};
- mcpServersRegistry.getServerConfig.mockImplementation(() => {
+ mockRegistryInstance.getServerConfig.mockImplementation(() => {
throw new Error('Config loading failed');
});
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
@@ -959,7 +1095,9 @@ describe('MCP Routes', () => {
getUserConnection: jest.fn().mockResolvedValue(mockUserConnection),
};
- mcpServersRegistry.getServerConfig.mockResolvedValue({ endpoint: 'http://test-server.com' });
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
+ endpoint: 'http://test-server.com',
+ });
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
require('~/config').getFlowStateManager.mockReturnValue({});
require('~/cache').getLogStores.mockReturnValue({});
@@ -1004,7 +1142,7 @@ describe('MCP Routes', () => {
getUserConnection: jest.fn().mockResolvedValue(mockUserConnection),
};
- mcpServersRegistry.getServerConfig.mockResolvedValue({
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
endpoint: 'http://test-server.com',
customUserVars: {
API_KEY: 'some-env-var',
@@ -1214,12 +1352,12 @@ describe('MCP Routes', () => {
describe('GET /:serverName/auth-values', () => {
const { getUserPluginAuthValue } = require('~/server/services/PluginService');
- const { mcpServersRegistry } = require('@librechat/api');
+ // mockRegistryInstance is defined at the top of the file
it('should return auth value flags for server', async () => {
const mockMcpManager = {};
- mcpServersRegistry.getServerConfig.mockResolvedValue({
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
customUserVars: {
API_KEY: 'some-env-var',
SECRET_TOKEN: 'another-env-var',
@@ -1246,7 +1384,7 @@ describe('MCP Routes', () => {
it('should return 404 when server is not found in configuration', async () => {
const mockMcpManager = {};
- mcpServersRegistry.getServerConfig.mockResolvedValue(null);
+ mockRegistryInstance.getServerConfig.mockResolvedValue(null);
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
const response = await request(app).get('/api/mcp/non-existent-server/auth-values');
@@ -1260,7 +1398,7 @@ describe('MCP Routes', () => {
it('should handle errors when checking auth values', async () => {
const mockMcpManager = {};
- mcpServersRegistry.getServerConfig.mockResolvedValue({
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
customUserVars: {
API_KEY: 'some-env-var',
},
@@ -1283,7 +1421,7 @@ describe('MCP Routes', () => {
it('should return 500 when auth values check throws unexpected error', async () => {
const mockMcpManager = {};
- mcpServersRegistry.getServerConfig.mockImplementation(() => {
+ mockRegistryInstance.getServerConfig.mockImplementation(() => {
throw new Error('Config loading failed');
});
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
@@ -1297,7 +1435,7 @@ describe('MCP Routes', () => {
it('should handle customUserVars that is not an object', async () => {
const mockMcpManager = {};
- mcpServersRegistry.getServerConfig.mockResolvedValue({
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
customUserVars: 'not-an-object',
});
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
@@ -1326,13 +1464,13 @@ describe('MCP Routes', () => {
describe('GET /:serverName/oauth/callback - Edge Cases', () => {
it('should handle OAuth callback without toolFlowId (falsy toolFlowId)', async () => {
- const { MCPOAuthHandler, MCPTokenStorage, mcpServersRegistry } = require('@librechat/api');
+ const { MCPOAuthHandler, MCPTokenStorage } = require('@librechat/api');
const mockTokens = {
access_token: 'edge-access-token',
refresh_token: 'edge-refresh-token',
};
MCPOAuthHandler.getFlowState = jest.fn().mockResolvedValue({
- id: 'test-flow-id',
+ id: 'test-user-id:test-server',
userId: 'test-user-id',
metadata: {
serverUrl: 'https://example.com',
@@ -1344,7 +1482,7 @@ describe('MCP Routes', () => {
});
MCPOAuthHandler.completeOAuthFlow = jest.fn().mockResolvedValue(mockTokens);
MCPTokenStorage.storeTokens.mockResolvedValue();
- mcpServersRegistry.getServerConfig.mockResolvedValue({});
+ mockRegistryInstance.getServerConfig.mockResolvedValue({});
const mockFlowManager = {
getFlowState: jest.fn().mockResolvedValue({ status: 'PENDING' }),
@@ -1360,18 +1498,24 @@ describe('MCP Routes', () => {
};
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
+ const flowId = 'test-user-id:test-server';
+ const csrfToken = generateTestCsrfToken(flowId);
+
const response = await request(app)
- .get('/api/mcp/test-server/oauth/callback?code=test-code&state=test-flow-id')
+ .get(`/api/mcp/test-server/oauth/callback?code=test-code&state=${flowId}`)
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
.expect(302);
+ const basePath = getBasePath();
+
expect(mockFlowManager.completeFlow).not.toHaveBeenCalled();
- expect(response.headers.location).toContain('/oauth/success');
+ expect(response.headers.location).toContain(`${basePath}/oauth/success`);
});
it('should handle null cached tools in OAuth callback (triggers || {} fallback)', async () => {
const { getCachedTools } = require('~/server/services/Config');
getCachedTools.mockResolvedValue(null);
- const { MCPOAuthHandler, MCPTokenStorage, mcpServersRegistry } = require('@librechat/api');
+ const { MCPOAuthHandler, MCPTokenStorage } = require('@librechat/api');
const mockTokens = {
access_token: 'edge-access-token',
refresh_token: 'edge-refresh-token',
@@ -1379,7 +1523,7 @@ describe('MCP Routes', () => {
const mockFlowManager = {
getFlowState: jest.fn().mockResolvedValue({
- id: 'test-flow-id',
+ id: 'test-user-id:test-server',
userId: 'test-user-id',
metadata: { serverUrl: 'https://example.com', oauth: {} },
clientInfo: {},
@@ -1397,7 +1541,7 @@ describe('MCP Routes', () => {
});
MCPOAuthHandler.completeOAuthFlow.mockResolvedValue(mockTokens);
MCPTokenStorage.storeTokens.mockResolvedValue();
- mcpServersRegistry.getServerConfig.mockResolvedValue({});
+ mockRegistryInstance.getServerConfig.mockResolvedValue({});
const mockMcpManager = {
getUserConnection: jest.fn().mockResolvedValue({
@@ -1408,11 +1552,291 @@ describe('MCP Routes', () => {
};
require('~/config').getMCPManager.mockReturnValue(mockMcpManager);
+ const flowId = 'test-user-id:test-server';
+ const csrfToken = generateTestCsrfToken(flowId);
+
const response = await request(app)
- .get('/api/mcp/test-server/oauth/callback?code=test-code&state=test-flow-id')
+ .get(`/api/mcp/test-server/oauth/callback?code=test-code&state=${flowId}`)
+ .set('Cookie', [`oauth_csrf=${csrfToken}`])
.expect(302);
- expect(response.headers.location).toContain('/oauth/success');
+ const basePath = getBasePath();
+
+ expect(response.headers.location).toContain(`${basePath}/oauth/success`);
+ });
+ });
+
+ describe('GET /servers', () => {
+ // mockRegistryInstance is defined at the top of the file
+
+ it('should return all server configs for authenticated user', async () => {
+ const mockServerConfigs = {
+ 'server-1': {
+ endpoint: 'http://server1.com',
+ name: 'Server 1',
+ },
+ 'server-2': {
+ endpoint: 'http://server2.com',
+ name: 'Server 2',
+ },
+ };
+
+ mockRegistryInstance.getAllServerConfigs.mockResolvedValue(mockServerConfigs);
+
+ const response = await request(app).get('/api/mcp/servers');
+
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual(mockServerConfigs);
+ expect(mockRegistryInstance.getAllServerConfigs).toHaveBeenCalledWith('test-user-id');
+ });
+
+ it('should return empty object when no servers are configured', async () => {
+ mockRegistryInstance.getAllServerConfigs.mockResolvedValue({});
+
+ const response = await request(app).get('/api/mcp/servers');
+
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual({});
+ });
+
+ it('should return 401 when user is not authenticated', async () => {
+ const unauthApp = express();
+ unauthApp.use(express.json());
+ unauthApp.use((req, _res, next) => {
+ req.user = null;
+ next();
+ });
+ unauthApp.use('/api/mcp', mcpRouter);
+
+ const response = await request(unauthApp).get('/api/mcp/servers');
+
+ expect(response.status).toBe(401);
+ expect(response.body).toEqual({ message: 'Unauthorized' });
+ });
+
+ it('should return 500 when server config retrieval fails', async () => {
+ mockRegistryInstance.getAllServerConfigs.mockRejectedValue(new Error('Database error'));
+
+ const response = await request(app).get('/api/mcp/servers');
+
+ expect(response.status).toBe(500);
+ expect(response.body).toEqual({ error: 'Database error' });
+ });
+ });
+
+ describe('POST /servers', () => {
+ it('should create MCP server with valid SSE config', async () => {
+ const validConfig = {
+ type: 'sse',
+ url: 'https://mcp-server.example.com/sse',
+ title: 'Test SSE Server',
+ description: 'A test SSE server',
+ };
+
+ mockRegistryInstance.addServer.mockResolvedValue({
+ serverName: 'test-sse-server',
+ config: validConfig,
+ });
+
+ const response = await request(app).post('/api/mcp/servers').send({ config: validConfig });
+
+ expect(response.status).toBe(201);
+ expect(response.body).toEqual({
+ serverName: 'test-sse-server',
+ ...validConfig,
+ });
+ expect(mockRegistryInstance.addServer).toHaveBeenCalledWith(
+ 'temp_server_name',
+ expect.objectContaining({
+ type: 'sse',
+ url: 'https://mcp-server.example.com/sse',
+ }),
+ 'DB',
+ 'test-user-id',
+ );
+ });
+
+ it('should reject stdio config for security reasons', async () => {
+ const stdioConfig = {
+ type: 'stdio',
+ command: 'node',
+ args: ['server.js'],
+ title: 'Test Stdio Server',
+ };
+
+ const response = await request(app).post('/api/mcp/servers').send({ config: stdioConfig });
+
+ // Stdio transport is not allowed via API - only admins can configure it via YAML
+ expect(response.status).toBe(400);
+ expect(response.body.message).toBe('Invalid configuration');
+ });
+
+ it('should return 400 for invalid configuration', async () => {
+ const invalidConfig = {
+ type: 'sse',
+ // Missing required 'url' field
+ title: 'Invalid Server',
+ };
+
+ const response = await request(app).post('/api/mcp/servers').send({ config: invalidConfig });
+
+ expect(response.status).toBe(400);
+ expect(response.body.message).toBe('Invalid configuration');
+ expect(response.body.errors).toBeDefined();
+ });
+
+ it('should return 400 for SSE config with invalid URL protocol', async () => {
+ const invalidConfig = {
+ type: 'sse',
+ url: 'ws://invalid-protocol.example.com/sse',
+ title: 'Invalid Protocol Server',
+ };
+
+ const response = await request(app).post('/api/mcp/servers').send({ config: invalidConfig });
+
+ expect(response.status).toBe(400);
+ expect(response.body.message).toBe('Invalid configuration');
+ });
+
+ it('should return 500 when registry throws error', async () => {
+ const validConfig = {
+ type: 'sse',
+ url: 'https://mcp-server.example.com/sse',
+ title: 'Test Server',
+ };
+
+ mockRegistryInstance.addServer.mockRejectedValue(new Error('Database connection failed'));
+
+ const response = await request(app).post('/api/mcp/servers').send({ config: validConfig });
+
+ expect(response.status).toBe(500);
+ expect(response.body).toEqual({ message: 'Database connection failed' });
+ });
+ });
+
+ describe('GET /servers/:serverName', () => {
+ it('should return server config when found', async () => {
+ const mockConfig = {
+ type: 'sse',
+ url: 'https://mcp-server.example.com/sse',
+ title: 'Test Server',
+ };
+
+ mockRegistryInstance.getServerConfig.mockResolvedValue(mockConfig);
+
+ const response = await request(app).get('/api/mcp/servers/test-server');
+
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual(mockConfig);
+ expect(mockRegistryInstance.getServerConfig).toHaveBeenCalledWith(
+ 'test-server',
+ 'test-user-id',
+ );
+ });
+
+ it('should return 404 when server not found', async () => {
+ mockRegistryInstance.getServerConfig.mockResolvedValue(null);
+
+ const response = await request(app).get('/api/mcp/servers/non-existent-server');
+
+ expect(response.status).toBe(404);
+ expect(response.body).toEqual({ message: 'MCP server not found' });
+ });
+
+ it('should return 500 when registry throws error', async () => {
+ mockRegistryInstance.getServerConfig.mockRejectedValue(new Error('Database error'));
+
+ const response = await request(app).get('/api/mcp/servers/error-server');
+
+ expect(response.status).toBe(500);
+ expect(response.body).toEqual({ message: 'Database error' });
+ });
+ });
+
+ describe('PATCH /servers/:serverName', () => {
+ it('should update server with valid config', async () => {
+ const updatedConfig = {
+ type: 'sse',
+ url: 'https://updated-mcp-server.example.com/sse',
+ title: 'Updated Server',
+ description: 'Updated description',
+ };
+
+ mockRegistryInstance.updateServer.mockResolvedValue(updatedConfig);
+
+ const response = await request(app)
+ .patch('/api/mcp/servers/test-server')
+ .send({ config: updatedConfig });
+
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual(updatedConfig);
+ expect(mockRegistryInstance.updateServer).toHaveBeenCalledWith(
+ 'test-server',
+ expect.objectContaining({
+ type: 'sse',
+ url: 'https://updated-mcp-server.example.com/sse',
+ }),
+ 'DB',
+ 'test-user-id',
+ );
+ });
+
+ it('should return 400 for invalid configuration', async () => {
+ const invalidConfig = {
+ type: 'sse',
+ // Missing required 'url' field
+ title: 'Invalid Update',
+ };
+
+ const response = await request(app)
+ .patch('/api/mcp/servers/test-server')
+ .send({ config: invalidConfig });
+
+ expect(response.status).toBe(400);
+ expect(response.body.message).toBe('Invalid configuration');
+ expect(response.body.errors).toBeDefined();
+ });
+
+ it('should return 500 when registry throws error', async () => {
+ const validConfig = {
+ type: 'sse',
+ url: 'https://mcp-server.example.com/sse',
+ title: 'Test Server',
+ };
+
+ mockRegistryInstance.updateServer.mockRejectedValue(new Error('Update failed'));
+
+ const response = await request(app)
+ .patch('/api/mcp/servers/test-server')
+ .send({ config: validConfig });
+
+ expect(response.status).toBe(500);
+ expect(response.body).toEqual({ message: 'Update failed' });
+ });
+ });
+
+ describe('DELETE /servers/:serverName', () => {
+ it('should delete server successfully', async () => {
+ mockRegistryInstance.removeServer.mockResolvedValue(undefined);
+
+ const response = await request(app).delete('/api/mcp/servers/test-server');
+
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual({ message: 'MCP server deleted successfully' });
+ expect(mockRegistryInstance.removeServer).toHaveBeenCalledWith(
+ 'test-server',
+ 'DB',
+ 'test-user-id',
+ );
+ });
+
+ it('should return 500 when registry throws error', async () => {
+ mockRegistryInstance.removeServer.mockRejectedValue(new Error('Deletion failed'));
+
+ const response = await request(app).delete('/api/mcp/servers/error-server');
+
+ expect(response.status).toBe(500);
+ expect(response.body).toEqual({ message: 'Deletion failed' });
});
});
});
diff --git a/api/server/routes/accessPermissions.js b/api/server/routes/accessPermissions.js
index 532f3bc50c..45afec133b 100644
--- a/api/server/routes/accessPermissions.js
+++ b/api/server/routes/accessPermissions.js
@@ -2,6 +2,7 @@ const express = require('express');
const { ResourceType, PermissionBits } = require('librechat-data-provider');
const {
getUserEffectivePermissions,
+ getAllEffectivePermissions,
updateResourcePermissions,
getResourcePermissions,
getResourceRoles,
@@ -9,6 +10,8 @@ const {
} = require('~/server/controllers/PermissionsController');
const { requireJwtAuth, checkBan, uaParser, canAccessResource } = require('~/server/middleware');
const { checkPeoplePickerAccess } = require('~/server/middleware/checkPeoplePickerAccess');
+const { checkSharePublicAccess } = require('~/server/middleware/checkSharePublicAccess');
+const { findMCPServerByObjectId } = require('~/models');
const router = express.Router();
@@ -34,48 +37,82 @@ router.get('/search-principals', checkPeoplePickerAccess, searchPrincipals);
*/
router.get('/:resourceType/roles', getResourceRoles);
+/**
+ * Middleware factory to check resource access for permission-related operations.
+ * SECURITY: Users must have SHARE permission to view or modify resource permissions.
+ * @param {string} requiredPermission - The permission bit required (e.g., SHARE)
+ * @returns Express middleware function
+ */
+const checkResourcePermissionAccess = (requiredPermission) => (req, res, next) => {
+ const { resourceType } = req.params;
+ let middleware;
+
+ if (resourceType === ResourceType.AGENT) {
+ middleware = canAccessResource({
+ resourceType: ResourceType.AGENT,
+ requiredPermission,
+ resourceIdParam: 'resourceId',
+ });
+ } else if (resourceType === ResourceType.REMOTE_AGENT) {
+ middleware = canAccessResource({
+ resourceType: ResourceType.REMOTE_AGENT,
+ requiredPermission,
+ resourceIdParam: 'resourceId',
+ });
+ } else if (resourceType === ResourceType.PROMPTGROUP) {
+ middleware = canAccessResource({
+ resourceType: ResourceType.PROMPTGROUP,
+ requiredPermission,
+ resourceIdParam: 'resourceId',
+ });
+ } else if (resourceType === ResourceType.MCPSERVER) {
+ middleware = canAccessResource({
+ resourceType: ResourceType.MCPSERVER,
+ requiredPermission,
+ resourceIdParam: 'resourceId',
+ idResolver: findMCPServerByObjectId,
+ });
+ } else {
+ return res.status(400).json({
+ error: 'Bad Request',
+ message: `Unsupported resource type: ${resourceType}`,
+ });
+ }
+
+ // Execute the middleware
+ middleware(req, res, next);
+};
+
/**
* GET /api/permissions/{resourceType}/{resourceId}
* Get all permissions for a specific resource
+ * SECURITY: Requires SHARE permission to view resource permissions
*/
-router.get('/:resourceType/:resourceId', getResourcePermissions);
+router.get(
+ '/:resourceType/:resourceId',
+ checkResourcePermissionAccess(PermissionBits.SHARE),
+ getResourcePermissions,
+);
/**
* PUT /api/permissions/{resourceType}/{resourceId}
* Bulk update permissions for a specific resource
+ * SECURITY: Requires SHARE permission to modify resource permissions
+ * SECURITY: Requires SHARE_PUBLIC permission to enable public sharing
*/
router.put(
'/:resourceType/:resourceId',
- // Use middleware that dynamically handles resource type and permissions
- (req, res, next) => {
- const { resourceType } = req.params;
- let middleware;
-
- if (resourceType === ResourceType.AGENT) {
- middleware = canAccessResource({
- resourceType: ResourceType.AGENT,
- requiredPermission: PermissionBits.SHARE,
- resourceIdParam: 'resourceId',
- });
- } else if (resourceType === ResourceType.PROMPTGROUP) {
- middleware = canAccessResource({
- resourceType: ResourceType.PROMPTGROUP,
- requiredPermission: PermissionBits.SHARE,
- resourceIdParam: 'resourceId',
- });
- } else {
- return res.status(400).json({
- error: 'Bad Request',
- message: `Unsupported resource type: ${resourceType}`,
- });
- }
-
- // Execute the middleware
- middleware(req, res, next);
- },
+ checkResourcePermissionAccess(PermissionBits.SHARE),
+ checkSharePublicAccess,
updateResourcePermissions,
);
+/**
+ * GET /api/permissions/{resourceType}/effective/all
+ * Get user's effective permissions for all accessible resources of a type
+ */
+router.get('/:resourceType/effective/all', getAllEffectivePermissions);
+
/**
* GET /api/permissions/{resourceType}/{resourceId}/effective
* Get user's effective permissions for a specific resource
diff --git a/api/server/routes/accessPermissions.test.js b/api/server/routes/accessPermissions.test.js
new file mode 100644
index 0000000000..81c21c8667
--- /dev/null
+++ b/api/server/routes/accessPermissions.test.js
@@ -0,0 +1,228 @@
+const express = require('express');
+const request = require('supertest');
+const mongoose = require('mongoose');
+const { v4: uuidv4 } = require('uuid');
+const { createMethods } = require('@librechat/data-schemas');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+const { ResourceType, PermissionBits } = require('librechat-data-provider');
+const { createAgent } = require('~/models/Agent');
+
+/**
+ * Mock the PermissionsController to isolate route testing
+ */
+jest.mock('~/server/controllers/PermissionsController', () => ({
+ getUserEffectivePermissions: jest.fn((req, res) => res.json({ permissions: [] })),
+ getAllEffectivePermissions: jest.fn((req, res) => res.json({ permissions: [] })),
+ updateResourcePermissions: jest.fn((req, res) => res.json({ success: true })),
+ getResourcePermissions: jest.fn((req, res) =>
+ res.json({
+ resourceType: req.params.resourceType,
+ resourceId: req.params.resourceId,
+ principals: [],
+ public: false,
+ }),
+ ),
+ getResourceRoles: jest.fn((req, res) => res.json({ roles: [] })),
+ searchPrincipals: jest.fn((req, res) => res.json({ principals: [] })),
+}));
+
+jest.mock('~/server/middleware/checkPeoplePickerAccess', () => ({
+ checkPeoplePickerAccess: jest.fn((req, res, next) => next()),
+}));
+
+// Import actual middleware to get canAccessResource
+const { canAccessResource } = require('~/server/middleware');
+const { findMCPServerByObjectId } = require('~/models');
+
+/**
+ * Security Tests for SBA-ADV-20251203-02
+ *
+ * These tests verify that users cannot query or modify agent permissions
+ * without proper SHARE permission.
+ */
+describe('Access Permissions Routes - Security Tests (SBA-ADV-20251203-02)', () => {
+ let app;
+ let mongoServer;
+ let authorId;
+ let attackerId;
+ let agentId;
+ let methods;
+ let User;
+ let modelsToCleanup = [];
+
+ beforeAll(async () => {
+ mongoServer = await MongoMemoryServer.create();
+ const mongoUri = mongoServer.getUri();
+ await mongoose.connect(mongoUri);
+
+ // Initialize models
+ const { createModels } = require('@librechat/data-schemas');
+ const models = createModels(mongoose);
+ modelsToCleanup = Object.keys(models);
+ Object.assign(mongoose.models, models);
+
+ methods = createMethods(mongoose);
+ User = models.User;
+
+ await methods.seedDefaultRoles();
+ });
+
+ afterAll(async () => {
+ const collections = mongoose.connection.collections;
+ for (const key in collections) {
+ await collections[key].deleteMany({});
+ }
+ for (const modelName of modelsToCleanup) {
+ delete mongoose.models[modelName];
+ }
+ await mongoose.disconnect();
+ await mongoServer.stop();
+ });
+
+ beforeEach(async () => {
+ // Clear all collections
+ const collections = mongoose.connection.collections;
+ for (const key in collections) {
+ await collections[key].deleteMany({});
+ }
+ await methods.seedDefaultRoles();
+
+ // Create author (owner of the agent)
+ authorId = new mongoose.Types.ObjectId().toString();
+ await User.create({
+ _id: authorId,
+ name: 'Agent Owner',
+ email: 'owner@example.com',
+ username: 'owner@example.com',
+ provider: 'local',
+ });
+
+ // Create attacker (should not have access)
+ attackerId = new mongoose.Types.ObjectId().toString();
+ await User.create({
+ _id: attackerId,
+ name: 'Attacker',
+ email: 'attacker@example.com',
+ username: 'attacker@example.com',
+ provider: 'local',
+ });
+
+ // Create private agent owned by author
+ const customAgentId = `agent_${uuidv4().replace(/-/g, '').substring(0, 20)}`;
+ await createAgent({
+ id: customAgentId,
+ name: 'Private Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+ agentId = customAgentId;
+
+ // Create Express app with attacker as current user
+ app = express();
+ app.use(express.json());
+
+ // Mock authentication middleware - attacker is the current user
+ app.use((req, res, next) => {
+ req.user = { id: attackerId, role: 'USER' };
+ req.app = { locals: {} };
+ next();
+ });
+
+ // Middleware factory for permission access check (mirrors actual implementation)
+ const checkResourcePermissionAccess = (requiredPermission) => (req, res, next) => {
+ const { resourceType } = req.params;
+ let middleware;
+
+ if (resourceType === ResourceType.AGENT) {
+ middleware = canAccessResource({
+ resourceType: ResourceType.AGENT,
+ requiredPermission,
+ resourceIdParam: 'resourceId',
+ });
+ } else if (resourceType === ResourceType.PROMPTGROUP) {
+ middleware = canAccessResource({
+ resourceType: ResourceType.PROMPTGROUP,
+ requiredPermission,
+ resourceIdParam: 'resourceId',
+ });
+ } else if (resourceType === ResourceType.MCPSERVER) {
+ middleware = canAccessResource({
+ resourceType: ResourceType.MCPSERVER,
+ requiredPermission,
+ resourceIdParam: 'resourceId',
+ idResolver: findMCPServerByObjectId,
+ });
+ } else {
+ return res.status(400).json({
+ error: 'Bad Request',
+ message: `Unsupported resource type: ${resourceType}`,
+ });
+ }
+
+ middleware(req, res, next);
+ };
+
+ // GET route with access control (THE FIX)
+ app.get(
+ '/permissions/:resourceType/:resourceId',
+ checkResourcePermissionAccess(PermissionBits.SHARE),
+ (req, res) =>
+ res.json({
+ resourceType: req.params.resourceType,
+ resourceId: req.params.resourceId,
+ principals: [],
+ public: false,
+ }),
+ );
+
+ // PUT route with access control
+ app.put(
+ '/permissions/:resourceType/:resourceId',
+ checkResourcePermissionAccess(PermissionBits.SHARE),
+ (req, res) => res.json({ success: true }),
+ );
+ });
+
+ describe('GET /permissions/:resourceType/:resourceId', () => {
+ it('should deny permission query for user without access (main vulnerability test)', async () => {
+ /**
+ * SECURITY TEST: This is the core test for SBA-ADV-20251203-02
+ *
+ * Before the fix, any authenticated user could query permissions for
+ * any agent by just knowing the agent ID, exposing information about
+ * who has access to private agents.
+ *
+ * After the fix, users must have SHARE permission to view permissions.
+ */
+ const response = await request(app)
+ .get(`/permissions/agent/${agentId}`)
+ .set('Content-Type', 'application/json');
+
+ // Should be denied - attacker has no permission on the agent
+ expect(response.status).toBe(403);
+ expect(response.body.error).toBe('Forbidden');
+ });
+
+ it('should return 400 for unsupported resource type', async () => {
+ const response = await request(app)
+ .get(`/permissions/unsupported/${agentId}`)
+ .set('Content-Type', 'application/json');
+
+ expect(response.status).toBe(400);
+ expect(response.body.message).toContain('Unsupported resource type');
+ });
+ });
+
+ describe('PUT /permissions/:resourceType/:resourceId', () => {
+ it('should deny permission update for user without access', async () => {
+ const response = await request(app)
+ .put(`/permissions/agent/${agentId}`)
+ .set('Content-Type', 'application/json')
+ .send({ principals: [] });
+
+ expect(response.status).toBe(403);
+ expect(response.body.error).toBe('Forbidden');
+ });
+ });
+});
diff --git a/api/server/routes/actions.js b/api/server/routes/actions.js
index 9f94f617ce..806edc66cc 100644
--- a/api/server/routes/actions.js
+++ b/api/server/routes/actions.js
@@ -1,14 +1,47 @@
const express = require('express');
const jwt = require('jsonwebtoken');
-const { getAccessToken } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { CacheKeys } = require('librechat-data-provider');
+const {
+ getBasePath,
+ getAccessToken,
+ setOAuthSession,
+ validateOAuthCsrf,
+ OAUTH_CSRF_COOKIE,
+ setOAuthCsrfCookie,
+ validateOAuthSession,
+ OAUTH_SESSION_COOKIE,
+} = require('@librechat/api');
const { findToken, updateToken, createToken } = require('~/models');
+const { requireJwtAuth } = require('~/server/middleware');
const { getFlowStateManager } = require('~/config');
const { getLogStores } = require('~/cache');
const router = express.Router();
const JWT_SECRET = process.env.JWT_SECRET;
+const OAUTH_CSRF_COOKIE_PATH = '/api/actions';
+
+/**
+ * Sets a CSRF cookie binding the action OAuth flow to the current browser session.
+ * Must be called before the user opens the IdP authorization URL.
+ *
+ * @route POST /actions/:action_id/oauth/bind
+ */
+router.post('/:action_id/oauth/bind', requireJwtAuth, setOAuthSession, async (req, res) => {
+ try {
+ const { action_id } = req.params;
+ const user = req.user;
+ if (!user?.id) {
+ return res.status(401).json({ error: 'User not authenticated' });
+ }
+ const flowId = `${user.id}:${action_id}`;
+ setOAuthCsrfCookie(res, flowId, OAUTH_CSRF_COOKIE_PATH);
+ res.json({ success: true });
+ } catch (error) {
+ logger.error('[Action OAuth] Failed to set CSRF binding cookie', error);
+ res.status(500).json({ error: 'Failed to bind OAuth flow' });
+ }
+});
/**
* Handles the OAuth callback and exchanges the authorization code for tokens.
@@ -24,6 +57,7 @@ router.get('/:action_id/oauth/callback', async (req, res) => {
const { code, state } = req.query;
const flowsCache = getLogStores(CacheKeys.FLOWS);
const flowManager = getFlowStateManager(flowsCache);
+ const basePath = getBasePath();
let identifier = action_id;
try {
let decodedState;
@@ -32,19 +66,34 @@ router.get('/:action_id/oauth/callback', async (req, res) => {
} catch (err) {
logger.error('Error verifying state parameter:', err);
await flowManager.failFlow(identifier, 'oauth', 'Invalid or expired state parameter');
- return res.redirect('/oauth/error?error=invalid_state');
+ return res.redirect(`${basePath}/oauth/error?error=invalid_state`);
}
if (decodedState.action_id !== action_id) {
await flowManager.failFlow(identifier, 'oauth', 'Mismatched action ID in state parameter');
- return res.redirect('/oauth/error?error=invalid_state');
+ return res.redirect(`${basePath}/oauth/error?error=invalid_state`);
}
if (!decodedState.user) {
await flowManager.failFlow(identifier, 'oauth', 'Invalid user ID in state parameter');
- return res.redirect('/oauth/error?error=invalid_state');
+ return res.redirect(`${basePath}/oauth/error?error=invalid_state`);
}
+
identifier = `${decodedState.user}:${action_id}`;
+
+ if (
+ !validateOAuthCsrf(req, res, identifier, OAUTH_CSRF_COOKIE_PATH) &&
+ !validateOAuthSession(req, decodedState.user)
+ ) {
+ logger.error('[Action OAuth] CSRF validation failed: no valid CSRF or session cookie', {
+ identifier,
+ hasCsrfCookie: !!req.cookies?.[OAUTH_CSRF_COOKIE],
+ hasSessionCookie: !!req.cookies?.[OAUTH_SESSION_COOKIE],
+ });
+ await flowManager.failFlow(identifier, 'oauth', 'CSRF validation failed');
+ return res.redirect(`${basePath}/oauth/error?error=csrf_validation_failed`);
+ }
+
const flowState = await flowManager.getFlowState(identifier, 'oauth');
if (!flowState) {
throw new Error('OAuth flow not found');
@@ -70,14 +119,13 @@ router.get('/:action_id/oauth/callback', async (req, res) => {
);
await flowManager.completeFlow(identifier, 'oauth', tokenData);
- /** Redirect to React success page */
const serverName = flowState.metadata?.action_name || `Action ${action_id}`;
- const redirectUrl = `/oauth/success?serverName=${encodeURIComponent(serverName)}`;
+ const redirectUrl = `${basePath}/oauth/success?serverName=${encodeURIComponent(serverName)}`;
res.redirect(redirectUrl);
} catch (error) {
logger.error('Error in OAuth callback:', error);
await flowManager.failFlow(identifier, 'oauth', error);
- res.redirect('/oauth/error?error=callback_failed');
+ res.redirect(`${basePath}/oauth/error?error=callback_failed`);
}
});
diff --git a/api/server/routes/admin/auth.js b/api/server/routes/admin/auth.js
new file mode 100644
index 0000000000..291b5eaaf8
--- /dev/null
+++ b/api/server/routes/admin/auth.js
@@ -0,0 +1,127 @@
+const express = require('express');
+const passport = require('passport');
+const { randomState } = require('openid-client');
+const { logger } = require('@librechat/data-schemas');
+const { CacheKeys } = require('librechat-data-provider');
+const {
+ requireAdmin,
+ getAdminPanelUrl,
+ exchangeAdminCode,
+ createSetBalanceConfig,
+} = require('@librechat/api');
+const { loginController } = require('~/server/controllers/auth/LoginController');
+const { createOAuthHandler } = require('~/server/controllers/auth/oauth');
+const { getAppConfig } = require('~/server/services/Config');
+const getLogStores = require('~/cache/getLogStores');
+const { getOpenIdConfig } = require('~/strategies');
+const middleware = require('~/server/middleware');
+const { Balance } = require('~/db/models');
+
+const setBalanceConfig = createSetBalanceConfig({
+ getAppConfig,
+ Balance,
+});
+
+const router = express.Router();
+
+router.post(
+ '/login/local',
+ middleware.logHeaders,
+ middleware.loginLimiter,
+ middleware.checkBan,
+ middleware.requireLocalAuth,
+ requireAdmin,
+ setBalanceConfig,
+ loginController,
+);
+
+router.get('/verify', middleware.requireJwtAuth, requireAdmin, (req, res) => {
+ const { password: _p, totpSecret: _t, __v, ...user } = req.user;
+ user.id = user._id.toString();
+ res.status(200).json({ user });
+});
+
+router.get('/oauth/openid/check', (req, res) => {
+ const openidConfig = getOpenIdConfig();
+ if (!openidConfig) {
+ return res.status(404).json({
+ error: 'OpenID configuration not found',
+ error_code: 'OPENID_NOT_CONFIGURED',
+ });
+ }
+ res.status(200).json({ message: 'OpenID check successful' });
+});
+
+router.get('/oauth/openid', (req, res, next) => {
+ return passport.authenticate('openidAdmin', {
+ session: false,
+ state: randomState(),
+ })(req, res, next);
+});
+
+router.get(
+ '/oauth/openid/callback',
+ passport.authenticate('openidAdmin', {
+ failureRedirect: `${getAdminPanelUrl()}/auth/openid/callback?error=auth_failed&error_description=Authentication+failed`,
+ failureMessage: true,
+ session: false,
+ }),
+ requireAdmin,
+ setBalanceConfig,
+ middleware.checkDomainAllowed,
+ createOAuthHandler(`${getAdminPanelUrl()}/auth/openid/callback`),
+);
+
+/** Regex pattern for valid exchange codes: 64 hex characters */
+const EXCHANGE_CODE_PATTERN = /^[a-f0-9]{64}$/i;
+
+/**
+ * Exchange OAuth authorization code for tokens.
+ * This endpoint is called server-to-server by the admin panel.
+ * The code is one-time-use and expires in 30 seconds.
+ *
+ * POST /api/admin/oauth/exchange
+ * Body: { code: string }
+ * Response: { token: string, refreshToken: string, user: object }
+ */
+router.post('/oauth/exchange', middleware.loginLimiter, async (req, res) => {
+ try {
+ const { code } = req.body;
+
+ if (!code) {
+ logger.warn('[admin/oauth/exchange] Missing authorization code');
+ return res.status(400).json({
+ error: 'Missing authorization code',
+ error_code: 'MISSING_CODE',
+ });
+ }
+
+ if (typeof code !== 'string' || !EXCHANGE_CODE_PATTERN.test(code)) {
+ logger.warn('[admin/oauth/exchange] Invalid authorization code format');
+ return res.status(400).json({
+ error: 'Invalid authorization code format',
+ error_code: 'INVALID_CODE_FORMAT',
+ });
+ }
+
+ const cache = getLogStores(CacheKeys.ADMIN_OAUTH_EXCHANGE);
+ const result = await exchangeAdminCode(cache, code);
+
+ if (!result) {
+ return res.status(401).json({
+ error: 'Invalid or expired authorization code',
+ error_code: 'INVALID_OR_EXPIRED_CODE',
+ });
+ }
+
+ res.json(result);
+ } catch (error) {
+ logger.error('[admin/oauth/exchange] Error:', error);
+ res.status(500).json({
+ error: 'Internal server error',
+ error_code: 'INTERNAL_ERROR',
+ });
+ }
+});
+
+module.exports = router;
diff --git a/api/server/routes/agents/__tests__/abort.spec.js b/api/server/routes/agents/__tests__/abort.spec.js
new file mode 100644
index 0000000000..442665d973
--- /dev/null
+++ b/api/server/routes/agents/__tests__/abort.spec.js
@@ -0,0 +1,303 @@
+/**
+ * Tests for the agent abort endpoint
+ *
+ * Tests the following fixes from PR #11462:
+ * 1. Authorization check - only job owner can abort
+ * 2. Early abort handling - skip save when no responseMessageId
+ * 3. Partial response saving - save message before returning
+ */
+
+const express = require('express');
+const request = require('supertest');
+
+const mockLogger = {
+ debug: jest.fn(),
+ warn: jest.fn(),
+ error: jest.fn(),
+ info: jest.fn(),
+};
+
+const mockGenerationJobManager = {
+ getJob: jest.fn(),
+ abortJob: jest.fn(),
+ getActiveJobIdsForUser: jest.fn(),
+};
+
+const mockSaveMessage = jest.fn();
+
+jest.mock('@librechat/data-schemas', () => ({
+ ...jest.requireActual('@librechat/data-schemas'),
+ logger: mockLogger,
+}));
+
+jest.mock('@librechat/api', () => ({
+ ...jest.requireActual('@librechat/api'),
+ isEnabled: jest.fn().mockReturnValue(false),
+ GenerationJobManager: mockGenerationJobManager,
+}));
+
+jest.mock('~/models', () => ({
+ saveMessage: (...args) => mockSaveMessage(...args),
+}));
+
+jest.mock('~/server/middleware', () => ({
+ uaParser: (req, res, next) => next(),
+ checkBan: (req, res, next) => next(),
+ requireJwtAuth: (req, res, next) => {
+ req.user = { id: 'test-user-123' };
+ next();
+ },
+ messageIpLimiter: (req, res, next) => next(),
+ configMiddleware: (req, res, next) => next(),
+ messageUserLimiter: (req, res, next) => next(),
+}));
+
+// Mock the chat module - needs to be a router
+jest.mock('~/server/routes/agents/chat', () => require('express').Router());
+
+// Mock the v1 module - v1 is directly used as middleware
+jest.mock('~/server/routes/agents/v1', () => ({
+ v1: require('express').Router(),
+}));
+
+// Import after mocks
+const agentRoutes = require('~/server/routes/agents/index');
+
+describe('Agent Abort Endpoint', () => {
+ let app;
+
+ beforeAll(() => {
+ app = express();
+ app.use(express.json());
+ app.use('/api/agents', agentRoutes);
+ });
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('POST /chat/abort', () => {
+ describe('Authorization', () => {
+ it("should return 403 when user tries to abort another user's job", async () => {
+ const jobStreamId = 'test-stream-123';
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ metadata: { userId: 'other-user-456' },
+ });
+
+ const response = await request(app)
+ .post('/api/agents/chat/abort')
+ .send({ conversationId: jobStreamId });
+
+ expect(response.status).toBe(403);
+ expect(response.body).toEqual({ error: 'Unauthorized' });
+ expect(mockLogger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('Unauthorized abort attempt'),
+ );
+ expect(mockGenerationJobManager.abortJob).not.toHaveBeenCalled();
+ });
+
+ it('should allow abort when user owns the job', async () => {
+ const jobStreamId = 'test-stream-123';
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ metadata: { userId: 'test-user-123' },
+ });
+
+ mockGenerationJobManager.abortJob.mockResolvedValue({
+ success: true,
+ jobData: null,
+ content: [],
+ text: '',
+ });
+
+ const response = await request(app)
+ .post('/api/agents/chat/abort')
+ .send({ conversationId: jobStreamId });
+
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual({ success: true, aborted: jobStreamId });
+ expect(mockGenerationJobManager.abortJob).toHaveBeenCalledWith(jobStreamId);
+ });
+
+ it('should allow abort when job has no userId metadata (backwards compatibility)', async () => {
+ const jobStreamId = 'test-stream-123';
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ metadata: {},
+ });
+
+ mockGenerationJobManager.abortJob.mockResolvedValue({
+ success: true,
+ jobData: null,
+ content: [],
+ text: '',
+ });
+
+ const response = await request(app)
+ .post('/api/agents/chat/abort')
+ .send({ conversationId: jobStreamId });
+
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual({ success: true, aborted: jobStreamId });
+ });
+ });
+
+ describe('Early Abort Handling', () => {
+ it('should skip message saving when responseMessageId is missing (early abort)', async () => {
+ const jobStreamId = 'test-stream-123';
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ metadata: { userId: 'test-user-123' },
+ });
+
+ mockGenerationJobManager.abortJob.mockResolvedValue({
+ success: true,
+ jobData: {
+ userMessage: { messageId: 'user-msg-123' },
+ // No responseMessageId - early abort before generation started
+ conversationId: jobStreamId,
+ },
+ content: [],
+ text: '',
+ });
+
+ const response = await request(app)
+ .post('/api/agents/chat/abort')
+ .send({ conversationId: jobStreamId });
+
+ expect(response.status).toBe(200);
+ expect(mockSaveMessage).not.toHaveBeenCalled();
+ });
+
+ it('should skip message saving when userMessage is missing', async () => {
+ const jobStreamId = 'test-stream-123';
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ metadata: { userId: 'test-user-123' },
+ });
+
+ mockGenerationJobManager.abortJob.mockResolvedValue({
+ success: true,
+ jobData: {
+ // No userMessage
+ responseMessageId: 'response-msg-123',
+ conversationId: jobStreamId,
+ },
+ content: [],
+ text: '',
+ });
+
+ const response = await request(app)
+ .post('/api/agents/chat/abort')
+ .send({ conversationId: jobStreamId });
+
+ expect(response.status).toBe(200);
+ expect(mockSaveMessage).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('Partial Response Saving', () => {
+ it('should save partial response when both userMessage and responseMessageId exist', async () => {
+ const jobStreamId = 'test-stream-123';
+ const userMessageId = 'user-msg-123';
+ const responseMessageId = 'response-msg-456';
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ metadata: { userId: 'test-user-123' },
+ });
+
+ mockGenerationJobManager.abortJob.mockResolvedValue({
+ success: true,
+ jobData: {
+ userMessage: { messageId: userMessageId },
+ responseMessageId,
+ conversationId: jobStreamId,
+ sender: 'TestAgent',
+ endpoint: 'anthropic',
+ model: 'claude-3',
+ },
+ content: [{ type: 'text', text: 'Partial response...' }],
+ text: 'Partial response...',
+ });
+
+ mockSaveMessage.mockResolvedValue();
+
+ const response = await request(app)
+ .post('/api/agents/chat/abort')
+ .send({ conversationId: jobStreamId });
+
+ expect(response.status).toBe(200);
+ expect(mockSaveMessage).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.objectContaining({
+ messageId: responseMessageId,
+ parentMessageId: userMessageId,
+ conversationId: jobStreamId,
+ content: [{ type: 'text', text: 'Partial response...' }],
+ text: 'Partial response...',
+ sender: 'TestAgent',
+ endpoint: 'anthropic',
+ model: 'claude-3',
+ unfinished: true,
+ error: false,
+ isCreatedByUser: false,
+ user: 'test-user-123',
+ }),
+ expect.objectContaining({
+ context: 'api/server/routes/agents/index.js - abort endpoint',
+ }),
+ );
+ });
+
+ it('should handle saveMessage errors gracefully', async () => {
+ const jobStreamId = 'test-stream-123';
+
+ mockGenerationJobManager.getJob.mockResolvedValue({
+ metadata: { userId: 'test-user-123' },
+ });
+
+ mockGenerationJobManager.abortJob.mockResolvedValue({
+ success: true,
+ jobData: {
+ userMessage: { messageId: 'user-msg-123' },
+ responseMessageId: 'response-msg-456',
+ conversationId: jobStreamId,
+ },
+ content: [],
+ text: '',
+ });
+
+ mockSaveMessage.mockRejectedValue(new Error('Database error'));
+
+ const response = await request(app)
+ .post('/api/agents/chat/abort')
+ .send({ conversationId: jobStreamId });
+
+ // Should still return success even if save fails
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual({ success: true, aborted: jobStreamId });
+ expect(mockLogger.error).toHaveBeenCalledWith(
+ expect.stringContaining('Failed to save partial response'),
+ );
+ });
+ });
+
+ describe('Job Not Found', () => {
+ it('should return 404 when job is not found', async () => {
+ mockGenerationJobManager.getJob.mockResolvedValue(null);
+ mockGenerationJobManager.getActiveJobIdsForUser.mockResolvedValue([]);
+
+ const response = await request(app)
+ .post('/api/agents/chat/abort')
+ .send({ conversationId: 'non-existent-job' });
+
+ expect(response.status).toBe(404);
+ expect(response.body).toEqual({
+ error: 'Job not found',
+ streamId: 'non-existent-job',
+ });
+ });
+ });
+ });
+});
diff --git a/api/server/routes/agents/__tests__/responses.spec.js b/api/server/routes/agents/__tests__/responses.spec.js
new file mode 100644
index 0000000000..4d83219b84
--- /dev/null
+++ b/api/server/routes/agents/__tests__/responses.spec.js
@@ -0,0 +1,1125 @@
+/**
+ * Open Responses API Integration Tests
+ *
+ * Tests the /v1/responses endpoint against the Open Responses specification
+ * compliance tests. Uses real Anthropic API for LLM calls.
+ *
+ * @see https://openresponses.org/specification
+ * @see https://github.com/openresponses/openresponses/blob/main/src/lib/compliance-tests.ts
+ */
+
+// Load environment variables from root .env file for API keys
+require('dotenv').config({ path: require('path').resolve(__dirname, '../../../../../.env') });
+
+const originalEnv = {
+ CREDS_KEY: process.env.CREDS_KEY,
+ CREDS_IV: process.env.CREDS_IV,
+};
+
+process.env.CREDS_KEY = '0123456789abcdef0123456789abcdef';
+process.env.CREDS_IV = '0123456789abcdef';
+
+/** Skip tests if ANTHROPIC_API_KEY is not available */
+const SKIP_INTEGRATION_TESTS = !process.env.ANTHROPIC_API_KEY;
+if (SKIP_INTEGRATION_TESTS) {
+ console.warn('ANTHROPIC_API_KEY not found - skipping integration tests');
+}
+
+jest.mock('meilisearch', () => ({
+ MeiliSearch: jest.fn().mockImplementation(() => ({
+ getIndex: jest.fn().mockRejectedValue(new Error('mocked')),
+ index: jest.fn().mockReturnValue({
+ getRawInfo: jest.fn().mockResolvedValue({ primaryKey: 'id' }),
+ updateSettings: jest.fn().mockResolvedValue({}),
+ addDocuments: jest.fn().mockResolvedValue({}),
+ updateDocuments: jest.fn().mockResolvedValue({}),
+ deleteDocument: jest.fn().mockResolvedValue({}),
+ }),
+ })),
+}));
+
+jest.mock('~/server/services/Config', () => ({
+ loadCustomConfig: jest.fn(() => Promise.resolve({})),
+ getAppConfig: jest.fn().mockResolvedValue({
+ paths: {
+ uploads: '/tmp',
+ dist: '/tmp/dist',
+ fonts: '/tmp/fonts',
+ assets: '/tmp/assets',
+ },
+ fileStrategy: 'local',
+ imageOutputType: 'PNG',
+ endpoints: {
+ agents: {
+ allowedProviders: ['anthropic', 'openAI'],
+ },
+ },
+ }),
+ setCachedTools: jest.fn(),
+ getCachedTools: jest.fn(),
+ getMCPServerTools: jest.fn().mockReturnValue([]),
+}));
+
+jest.mock('~/app/clients/tools', () => ({
+ createOpenAIImageTools: jest.fn(() => []),
+ createYouTubeTools: jest.fn(() => []),
+ manifestToolMap: {},
+ toolkits: [],
+}));
+
+jest.mock('~/config', () => ({
+ createMCPServersRegistry: jest.fn(),
+ createMCPManager: jest.fn().mockResolvedValue({
+ getAppToolFunctions: jest.fn().mockResolvedValue({}),
+ }),
+}));
+
+const express = require('express');
+const request = require('supertest');
+const mongoose = require('mongoose');
+const { v4: uuidv4 } = require('uuid');
+const { MongoMemoryServer } = require('mongodb-memory-server');
+const { hashToken, getRandomValues, createModels } = require('@librechat/data-schemas');
+const {
+ SystemRoles,
+ ResourceType,
+ AccessRoleIds,
+ PrincipalType,
+ PrincipalModel,
+ PermissionBits,
+ EModelEndpoint,
+} = require('librechat-data-provider');
+
+/** @type {import('mongoose').Model} */
+let Agent;
+/** @type {import('mongoose').Model} */
+let AgentApiKey;
+/** @type {import('mongoose').Model} */
+let User;
+/** @type {import('mongoose').Model} */
+let AclEntry;
+/** @type {import('mongoose').Model} */
+let AccessRole;
+
+/**
+ * Parse SSE stream into events
+ * @param {string} text - Raw SSE text
+ * @returns {Array<{event: string, data: unknown}>}
+ */
+function parseSSEEvents(text) {
+ const events = [];
+ const lines = text.split('\n');
+
+ let currentEvent = '';
+ let currentData = '';
+
+ for (const line of lines) {
+ if (line.startsWith('event:')) {
+ currentEvent = line.slice(6).trim();
+ } else if (line.startsWith('data:')) {
+ currentData = line.slice(5).trim();
+ } else if (line === '' && currentData) {
+ if (currentData === '[DONE]') {
+ events.push({ event: 'done', data: '[DONE]' });
+ } else {
+ try {
+ const parsed = JSON.parse(currentData);
+ events.push({
+ event: currentEvent || parsed.type || 'unknown',
+ data: parsed,
+ });
+ } catch {
+ // Skip unparseable data
+ }
+ }
+ currentEvent = '';
+ currentData = '';
+ }
+ }
+
+ return events;
+}
+
+/**
+ * Valid streaming event types per Open Responses specification
+ * @see https://github.com/openresponses/openresponses/blob/main/src/lib/sse-parser.ts
+ */
+const VALID_STREAMING_EVENT_TYPES = new Set([
+ // Standard Open Responses events
+ 'response.created',
+ 'response.queued',
+ 'response.in_progress',
+ 'response.completed',
+ 'response.failed',
+ 'response.incomplete',
+ 'response.output_item.added',
+ 'response.output_item.done',
+ 'response.content_part.added',
+ 'response.content_part.done',
+ 'response.output_text.delta',
+ 'response.output_text.done',
+ 'response.refusal.delta',
+ 'response.refusal.done',
+ 'response.function_call_arguments.delta',
+ 'response.function_call_arguments.done',
+ 'response.reasoning_summary_part.added',
+ 'response.reasoning_summary_part.done',
+ 'response.reasoning.delta',
+ 'response.reasoning.done',
+ 'response.reasoning_summary_text.delta',
+ 'response.reasoning_summary_text.done',
+ 'response.output_text.annotation.added',
+ 'error',
+ // LibreChat extension events (prefixed per Open Responses spec)
+ // @see https://openresponses.org/specification#extending-streaming-events
+ 'librechat:attachment',
+]);
+
+/**
+ * Validate a streaming event against Open Responses spec
+ * @param {Object} event - Parsed event with data
+ * @returns {string[]} Array of validation errors
+ */
+function validateStreamingEvent(event) {
+ const errors = [];
+ const data = event.data;
+
+ if (!data || typeof data !== 'object') {
+ return errors; // Skip non-object data (e.g., [DONE])
+ }
+
+ const eventType = data.type;
+
+ // Check event type is valid
+ if (!VALID_STREAMING_EVENT_TYPES.has(eventType)) {
+ errors.push(`Invalid event type: ${eventType}`);
+ return errors;
+ }
+
+ // Validate required fields based on event type
+ switch (eventType) {
+ case 'response.output_text.delta':
+ if (typeof data.sequence_number !== 'number') {
+ errors.push('response.output_text.delta: missing sequence_number');
+ }
+ if (typeof data.item_id !== 'string') {
+ errors.push('response.output_text.delta: missing item_id');
+ }
+ if (typeof data.output_index !== 'number') {
+ errors.push('response.output_text.delta: missing output_index');
+ }
+ if (typeof data.content_index !== 'number') {
+ errors.push('response.output_text.delta: missing content_index');
+ }
+ if (typeof data.delta !== 'string') {
+ errors.push('response.output_text.delta: missing delta');
+ }
+ if (!Array.isArray(data.logprobs)) {
+ errors.push('response.output_text.delta: missing logprobs array');
+ }
+ break;
+
+ case 'response.output_text.done':
+ if (typeof data.sequence_number !== 'number') {
+ errors.push('response.output_text.done: missing sequence_number');
+ }
+ if (typeof data.item_id !== 'string') {
+ errors.push('response.output_text.done: missing item_id');
+ }
+ if (typeof data.output_index !== 'number') {
+ errors.push('response.output_text.done: missing output_index');
+ }
+ if (typeof data.content_index !== 'number') {
+ errors.push('response.output_text.done: missing content_index');
+ }
+ if (typeof data.text !== 'string') {
+ errors.push('response.output_text.done: missing text');
+ }
+ if (!Array.isArray(data.logprobs)) {
+ errors.push('response.output_text.done: missing logprobs array');
+ }
+ break;
+
+ case 'response.reasoning.delta':
+ if (typeof data.sequence_number !== 'number') {
+ errors.push('response.reasoning.delta: missing sequence_number');
+ }
+ if (typeof data.item_id !== 'string') {
+ errors.push('response.reasoning.delta: missing item_id');
+ }
+ if (typeof data.output_index !== 'number') {
+ errors.push('response.reasoning.delta: missing output_index');
+ }
+ if (typeof data.content_index !== 'number') {
+ errors.push('response.reasoning.delta: missing content_index');
+ }
+ if (typeof data.delta !== 'string') {
+ errors.push('response.reasoning.delta: missing delta');
+ }
+ break;
+
+ case 'response.reasoning.done':
+ if (typeof data.sequence_number !== 'number') {
+ errors.push('response.reasoning.done: missing sequence_number');
+ }
+ if (typeof data.item_id !== 'string') {
+ errors.push('response.reasoning.done: missing item_id');
+ }
+ if (typeof data.output_index !== 'number') {
+ errors.push('response.reasoning.done: missing output_index');
+ }
+ if (typeof data.content_index !== 'number') {
+ errors.push('response.reasoning.done: missing content_index');
+ }
+ if (typeof data.text !== 'string') {
+ errors.push('response.reasoning.done: missing text');
+ }
+ break;
+
+ case 'response.in_progress':
+ case 'response.completed':
+ case 'response.failed':
+ if (!data.response || typeof data.response !== 'object') {
+ errors.push(`${eventType}: missing response object`);
+ }
+ break;
+
+ case 'response.output_item.added':
+ case 'response.output_item.done':
+ if (typeof data.output_index !== 'number') {
+ errors.push(`${eventType}: missing output_index`);
+ }
+ if (!data.item || typeof data.item !== 'object') {
+ errors.push(`${eventType}: missing item object`);
+ }
+ break;
+ }
+
+ return errors;
+}
+
+/**
+ * Validate all streaming events and return errors
+ * @param {Array} events - Array of parsed events
+ * @returns {string[]} Array of all validation errors
+ */
+function validateAllStreamingEvents(events) {
+ const allErrors = [];
+ for (const event of events) {
+ const errors = validateStreamingEvent(event);
+ allErrors.push(...errors);
+ }
+ return allErrors;
+}
+
+/**
+ * Create a test agent with Anthropic provider
+ * @param {Object} overrides
+ * @returns {Promise}
+ */
+async function createTestAgent(overrides = {}) {
+ const timestamp = new Date();
+ const agentData = {
+ id: `agent_${uuidv4().replace(/-/g, '').substring(0, 21)}`,
+ name: 'Test Anthropic Agent',
+ description: 'An agent for testing Open Responses API',
+ instructions: 'You are a helpful assistant. Be concise.',
+ provider: EModelEndpoint.anthropic,
+ model: 'claude-sonnet-4-5-20250929',
+ author: new mongoose.Types.ObjectId(),
+ tools: [],
+ model_parameters: {},
+ ...overrides,
+ };
+
+ const versionData = { ...agentData };
+ delete versionData.author;
+
+ const initialAgentData = {
+ ...agentData,
+ versions: [
+ {
+ ...versionData,
+ createdAt: timestamp,
+ updatedAt: timestamp,
+ },
+ ],
+ category: 'general',
+ };
+
+ return (await Agent.create(initialAgentData)).toObject();
+}
+
+/**
+ * Create an agent with extended thinking enabled
+ * @param {Object} overrides
+ * @returns {Promise}
+ */
+async function createThinkingAgent(overrides = {}) {
+ return createTestAgent({
+ name: 'Test Thinking Agent',
+ description: 'An agent with extended thinking enabled',
+ model_parameters: {
+ thinking: {
+ type: 'enabled',
+ budget_tokens: 5000,
+ },
+ },
+ ...overrides,
+ });
+}
+
+const describeWithApiKey = SKIP_INTEGRATION_TESTS ? describe.skip : describe;
+
+describeWithApiKey('Open Responses API Integration Tests', () => {
+ // Increase timeout for real API calls
+ jest.setTimeout(120000);
+
+ let mongoServer;
+ let app;
+ let testAgent;
+ let thinkingAgent;
+ let testUser;
+ let testApiKey; // The raw API key for Authorization header
+
+ afterAll(() => {
+ process.env.CREDS_KEY = originalEnv.CREDS_KEY;
+ process.env.CREDS_IV = originalEnv.CREDS_IV;
+ });
+
+ beforeAll(async () => {
+ // Start MongoDB Memory Server
+ mongoServer = await MongoMemoryServer.create();
+ const mongoUri = mongoServer.getUri();
+
+ // Connect to MongoDB
+ await mongoose.connect(mongoUri);
+
+ // Register all models
+ const models = createModels(mongoose);
+
+ // Get models
+ Agent = models.Agent;
+ AgentApiKey = models.AgentApiKey;
+ User = models.User;
+ AclEntry = models.AclEntry;
+ AccessRole = models.AccessRole;
+
+ // Create minimal Express app with just the responses routes
+ app = express();
+ app.use(express.json());
+
+ // Mount the responses routes
+ const responsesRoutes = require('~/server/routes/agents/responses');
+ app.use('/api/agents/v1/responses', responsesRoutes);
+
+ // Create test user
+ testUser = await User.create({
+ name: 'Test API User',
+ username: 'testapiuser',
+ email: 'testapiuser@test.com',
+ emailVerified: true,
+ provider: 'local',
+ role: SystemRoles.ADMIN,
+ });
+
+ // Create REMOTE_AGENT access roles (if they don't exist)
+ const existingRoles = await AccessRole.find({
+ accessRoleId: {
+ $in: [
+ AccessRoleIds.REMOTE_AGENT_VIEWER,
+ AccessRoleIds.REMOTE_AGENT_EDITOR,
+ AccessRoleIds.REMOTE_AGENT_OWNER,
+ ],
+ },
+ });
+
+ if (existingRoles.length === 0) {
+ await AccessRole.create([
+ {
+ accessRoleId: AccessRoleIds.REMOTE_AGENT_VIEWER,
+ name: 'API Viewer',
+ description: 'Can query the agent via API',
+ resourceType: ResourceType.REMOTE_AGENT,
+ permBits: PermissionBits.VIEW,
+ },
+ {
+ accessRoleId: AccessRoleIds.REMOTE_AGENT_EDITOR,
+ name: 'API Editor',
+ description: 'Can view and modify the agent via API',
+ resourceType: ResourceType.REMOTE_AGENT,
+ permBits: PermissionBits.VIEW | PermissionBits.EDIT,
+ },
+ {
+ accessRoleId: AccessRoleIds.REMOTE_AGENT_OWNER,
+ name: 'API Owner',
+ description: 'Full API access + can grant remote access to others',
+ resourceType: ResourceType.REMOTE_AGENT,
+ permBits:
+ PermissionBits.VIEW |
+ PermissionBits.EDIT |
+ PermissionBits.DELETE |
+ PermissionBits.SHARE,
+ },
+ ]);
+ }
+
+ // Generate and create an API key for the test user
+ const rawKey = `sk-${await getRandomValues(32)}`;
+ const keyHash = await hashToken(rawKey);
+ const keyPrefix = rawKey.substring(0, 8);
+
+ await AgentApiKey.create({
+ userId: testUser._id,
+ name: 'Test API Key',
+ keyHash,
+ keyPrefix,
+ });
+
+ testApiKey = rawKey;
+
+ // Create test agents with the test user as author
+ testAgent = await createTestAgent({ author: testUser._id });
+ thinkingAgent = await createThinkingAgent({ author: testUser._id });
+
+ // Grant REMOTE_AGENT permissions for the test agents
+ await AclEntry.create([
+ {
+ principalType: PrincipalType.USER,
+ principalModel: PrincipalModel.USER,
+ principalId: testUser._id,
+ resourceType: ResourceType.REMOTE_AGENT,
+ resourceId: testAgent._id,
+ accessRoleId: AccessRoleIds.REMOTE_AGENT_OWNER,
+ permBits:
+ PermissionBits.VIEW | PermissionBits.EDIT | PermissionBits.DELETE | PermissionBits.SHARE,
+ },
+ {
+ principalType: PrincipalType.USER,
+ principalModel: PrincipalModel.USER,
+ principalId: testUser._id,
+ resourceType: ResourceType.REMOTE_AGENT,
+ resourceId: thinkingAgent._id,
+ accessRoleId: AccessRoleIds.REMOTE_AGENT_OWNER,
+ permBits:
+ PermissionBits.VIEW | PermissionBits.EDIT | PermissionBits.DELETE | PermissionBits.SHARE,
+ },
+ ]);
+ }, 60000);
+
+ afterAll(async () => {
+ await mongoose.disconnect();
+ await mongoServer.stop();
+ });
+
+ beforeEach(async () => {
+ // Clean up any test data between tests if needed
+ });
+
+ /* ===========================================================================
+ * COMPLIANCE TESTS
+ * Based on: https://github.com/openresponses/openresponses/blob/main/src/lib/compliance-tests.ts
+ * =========================================================================== */
+
+ /** Helper to add auth header to requests */
+ const authRequest = () => ({
+ post: (url) => request(app).post(url).set('Authorization', `Bearer ${testApiKey}`),
+ get: (url) => request(app).get(url).set('Authorization', `Bearer ${testApiKey}`),
+ });
+
+ describe('Compliance Tests', () => {
+ describe('basic-response', () => {
+ it('should return a valid ResponseResource for a simple text request', async () => {
+ const response = await authRequest()
+ .post('/api/agents/v1/responses')
+ .send({
+ model: testAgent.id,
+ input: [
+ {
+ type: 'message',
+ role: 'user',
+ content: 'Say hello in exactly 3 words.',
+ },
+ ],
+ });
+
+ expect(response.status).toBe(200);
+ expect(response.body).toBeDefined();
+
+ // Validate ResponseResource schema
+ const body = response.body;
+ expect(body.id).toMatch(/^resp_/);
+ expect(body.object).toBe('response');
+ expect(typeof body.created_at).toBe('number');
+ expect(body.status).toBe('completed');
+ expect(body.model).toBe(testAgent.id);
+
+ // Validate output
+ expect(Array.isArray(body.output)).toBe(true);
+ expect(body.output.length).toBeGreaterThan(0);
+
+ // Should have at least one message item
+ const messageItem = body.output.find((item) => item.type === 'message');
+ expect(messageItem).toBeDefined();
+ expect(messageItem.role).toBe('assistant');
+ expect(messageItem.status).toBe('completed');
+ expect(Array.isArray(messageItem.content)).toBe(true);
+ });
+ });
+
+ describe('streaming-response', () => {
+ it('should return valid SSE streaming events', async () => {
+ const response = await authRequest()
+ .post('/api/agents/v1/responses')
+ .send({
+ model: testAgent.id,
+ input: [
+ {
+ type: 'message',
+ role: 'user',
+ content: 'Count from 1 to 5.',
+ },
+ ],
+ stream: true,
+ })
+ .buffer(true)
+ .parse((res, callback) => {
+ let data = '';
+ res.on('data', (chunk) => {
+ data += chunk.toString();
+ });
+ res.on('end', () => {
+ callback(null, data);
+ });
+ });
+
+ expect(response.status).toBe(200);
+ expect(response.headers['content-type']).toMatch(/text\/event-stream/);
+
+ const events = parseSSEEvents(response.body);
+ expect(events.length).toBeGreaterThan(0);
+
+ // Validate all streaming events against Open Responses spec
+ // This catches issues like:
+ // - Invalid event types (e.g., response.reasoning_text.delta instead of response.reasoning.delta)
+ // - Missing required fields (e.g., logprobs on output_text events)
+ const validationErrors = validateAllStreamingEvents(events);
+ if (validationErrors.length > 0) {
+ console.error('Streaming event validation errors:', validationErrors);
+ }
+ expect(validationErrors).toEqual([]);
+
+ // Validate streaming event types
+ const eventTypes = events.map((e) => e.event);
+
+ // Should have response.created first (per Open Responses spec)
+ expect(eventTypes).toContain('response.created');
+
+ // Should have response.in_progress
+ expect(eventTypes).toContain('response.in_progress');
+
+ // response.created should come before response.in_progress
+ const createdIdx = eventTypes.indexOf('response.created');
+ const inProgressIdx = eventTypes.indexOf('response.in_progress');
+ expect(createdIdx).toBeLessThan(inProgressIdx);
+
+ // Should have response.completed or response.failed
+ expect(eventTypes.some((t) => t === 'response.completed' || t === 'response.failed')).toBe(
+ true,
+ );
+
+ // Should have [DONE]
+ expect(eventTypes).toContain('done');
+
+ // Validate response.completed has full response
+ const completedEvent = events.find((e) => e.event === 'response.completed');
+ if (completedEvent) {
+ expect(completedEvent.data.response).toBeDefined();
+ expect(completedEvent.data.response.status).toBe('completed');
+ expect(completedEvent.data.response.output.length).toBeGreaterThan(0);
+ }
+ });
+
+ it('should emit valid event types per Open Responses spec', async () => {
+ const response = await authRequest()
+ .post('/api/agents/v1/responses')
+ .send({
+ model: testAgent.id,
+ input: [
+ {
+ type: 'message',
+ role: 'user',
+ content: 'Say hi.',
+ },
+ ],
+ stream: true,
+ })
+ .buffer(true)
+ .parse((res, callback) => {
+ let data = '';
+ res.on('data', (chunk) => {
+ data += chunk.toString();
+ });
+ res.on('end', () => {
+ callback(null, data);
+ });
+ });
+
+ expect(response.status).toBe(200);
+
+ const events = parseSSEEvents(response.body);
+
+ // Check all event types are valid
+ for (const event of events) {
+ if (event.data && typeof event.data === 'object' && event.data.type) {
+ expect(VALID_STREAMING_EVENT_TYPES.has(event.data.type)).toBe(true);
+ }
+ }
+ });
+
+ it('should include logprobs array in output_text events', async () => {
+ const response = await authRequest()
+ .post('/api/agents/v1/responses')
+ .send({
+ model: testAgent.id,
+ input: [
+ {
+ type: 'message',
+ role: 'user',
+ content: 'Say one word.',
+ },
+ ],
+ stream: true,
+ })
+ .buffer(true)
+ .parse((res, callback) => {
+ let data = '';
+ res.on('data', (chunk) => {
+ data += chunk.toString();
+ });
+ res.on('end', () => {
+ callback(null, data);
+ });
+ });
+
+ expect(response.status).toBe(200);
+
+ const events = parseSSEEvents(response.body);
+
+ // Find output_text delta/done events and verify logprobs
+ const textDeltaEvents = events.filter(
+ (e) => e.data && e.data.type === 'response.output_text.delta',
+ );
+ const textDoneEvents = events.filter(
+ (e) => e.data && e.data.type === 'response.output_text.done',
+ );
+
+ // Should have at least one output_text event
+ expect(textDeltaEvents.length + textDoneEvents.length).toBeGreaterThan(0);
+
+ // All output_text.delta events must have logprobs array
+ for (const event of textDeltaEvents) {
+ expect(Array.isArray(event.data.logprobs)).toBe(true);
+ }
+
+ // All output_text.done events must have logprobs array
+ for (const event of textDoneEvents) {
+ expect(Array.isArray(event.data.logprobs)).toBe(true);
+ }
+ });
+ });
+
+ describe('system-prompt', () => {
+ it('should handle developer role messages in input (as system)', async () => {
+ // Note: For Anthropic, system messages must be first and there can only be one.
+ // Since the agent already has instructions, we use 'developer' role which
+ // gets merged into the system prompt, or we test with a simple user message
+ // that instructs the behavior.
+ const response = await authRequest()
+ .post('/api/agents/v1/responses')
+ .send({
+ model: testAgent.id,
+ input: [
+ {
+ type: 'message',
+ role: 'user',
+ content: 'Pretend you are a pirate and say hello in pirate speak.',
+ },
+ ],
+ });
+
+ expect(response.status).toBe(200);
+ expect(response.body.status).toBe('completed');
+ expect(response.body.output.length).toBeGreaterThan(0);
+
+ // The response should reflect the pirate persona
+ const messageItem = response.body.output.find((item) => item.type === 'message');
+ expect(messageItem).toBeDefined();
+ expect(messageItem.content.length).toBeGreaterThan(0);
+ });
+ });
+
+ describe('multi-turn', () => {
+ it('should handle multi-turn conversation history', async () => {
+ const response = await authRequest()
+ .post('/api/agents/v1/responses')
+ .send({
+ model: testAgent.id,
+ input: [
+ {
+ type: 'message',
+ role: 'user',
+ content: 'My name is Alice.',
+ },
+ {
+ type: 'message',
+ role: 'assistant',
+ content: 'Hello Alice! Nice to meet you. How can I help you today?',
+ },
+ {
+ type: 'message',
+ role: 'user',
+ content: 'What is my name?',
+ },
+ ],
+ });
+
+ expect(response.status).toBe(200);
+ expect(response.body.status).toBe('completed');
+
+ // The response should reference "Alice"
+ const messageItem = response.body.output.find((item) => item.type === 'message');
+ expect(messageItem).toBeDefined();
+
+ const textContent = messageItem.content.find((c) => c.type === 'output_text');
+ expect(textContent).toBeDefined();
+ expect(textContent.text.toLowerCase()).toContain('alice');
+ });
+ });
+
+ // Note: tool-calling test requires tool setup which may need additional configuration
+ // Note: image-input test requires vision-capable model
+
+ describe('string-input', () => {
+ it('should accept simple string input', async () => {
+ const response = await authRequest().post('/api/agents/v1/responses').send({
+ model: testAgent.id,
+ input: 'Hello!',
+ });
+
+ expect(response.status).toBe(200);
+ expect(response.body.status).toBe('completed');
+ expect(response.body.output.length).toBeGreaterThan(0);
+ });
+ });
+ });
+
+ /* ===========================================================================
+ * EXTENDED THINKING TESTS
+ * Tests reasoning output from Claude models with extended thinking enabled
+ * =========================================================================== */
+
+ describe('Extended Thinking', () => {
+ it('should return reasoning output when thinking is enabled', async () => {
+ const response = await authRequest()
+ .post('/api/agents/v1/responses')
+ .send({
+ model: thinkingAgent.id,
+ input: [
+ {
+ type: 'message',
+ role: 'user',
+ content: 'What is 15 * 7? Think step by step.',
+ },
+ ],
+ });
+
+ expect(response.status).toBe(200);
+ expect(response.body.status).toBe('completed');
+
+ // Check for reasoning item in output
+ const reasoningItem = response.body.output.find((item) => item.type === 'reasoning');
+ // If reasoning is present, validate its structure per Open Responses spec
+ // Note: reasoning items do NOT have a 'status' field per the spec
+ // @see https://github.com/openresponses/openresponses/blob/main/src/generated/kubb/zod/reasoningBodySchema.ts
+ if (reasoningItem) {
+ expect(reasoningItem).toHaveProperty('id');
+ expect(reasoningItem).toHaveProperty('type', 'reasoning');
+ // Note: 'status' is NOT a field on reasoning items per the spec
+ expect(reasoningItem).toHaveProperty('summary');
+ expect(Array.isArray(reasoningItem.summary)).toBe(true);
+
+ // Validate content items
+ if (reasoningItem.content && reasoningItem.content.length > 0) {
+ const reasoningContent = reasoningItem.content[0];
+ expect(reasoningContent).toHaveProperty('type', 'reasoning_text');
+ expect(reasoningContent).toHaveProperty('text');
+ }
+ }
+
+ const messageItem = response.body.output.find((item) => item.type === 'message');
+ expect(messageItem).toBeDefined();
+ });
+
+ it('should stream reasoning events when thinking is enabled', async () => {
+ const response = await authRequest()
+ .post('/api/agents/v1/responses')
+ .send({
+ model: thinkingAgent.id,
+ input: [
+ {
+ type: 'message',
+ role: 'user',
+ content: 'What is 12 + 8? Think step by step.',
+ },
+ ],
+ stream: true,
+ })
+ .buffer(true)
+ .parse((res, callback) => {
+ let data = '';
+ res.on('data', (chunk) => {
+ data += chunk.toString();
+ });
+ res.on('end', () => {
+ callback(null, data);
+ });
+ });
+
+ expect(response.status).toBe(200);
+
+ const events = parseSSEEvents(response.body);
+
+ // Validate all events against Open Responses spec
+ const validationErrors = validateAllStreamingEvents(events);
+ if (validationErrors.length > 0) {
+ console.error('Reasoning streaming event validation errors:', validationErrors);
+ }
+ expect(validationErrors).toEqual([]);
+
+ // Check for reasoning-related events using correct event types per Open Responses spec
+ // Note: The spec uses response.reasoning.delta NOT response.reasoning_text.delta
+ const reasoningDeltaEvents = events.filter(
+ (e) => e.data && e.data.type === 'response.reasoning.delta',
+ );
+ const reasoningDoneEvents = events.filter(
+ (e) => e.data && e.data.type === 'response.reasoning.done',
+ );
+
+ // If reasoning events are present, validate their structure
+ if (reasoningDeltaEvents.length > 0) {
+ const deltaEvent = reasoningDeltaEvents[0];
+ expect(deltaEvent.data).toHaveProperty('item_id');
+ expect(deltaEvent.data).toHaveProperty('delta');
+ expect(deltaEvent.data).toHaveProperty('output_index');
+ expect(deltaEvent.data).toHaveProperty('content_index');
+ expect(deltaEvent.data).toHaveProperty('sequence_number');
+ }
+
+ if (reasoningDoneEvents.length > 0) {
+ const doneEvent = reasoningDoneEvents[0];
+ expect(doneEvent.data).toHaveProperty('item_id');
+ expect(doneEvent.data).toHaveProperty('text');
+ expect(doneEvent.data).toHaveProperty('output_index');
+ expect(doneEvent.data).toHaveProperty('content_index');
+ expect(doneEvent.data).toHaveProperty('sequence_number');
+ }
+
+ // Verify stream completed properly
+ const eventTypes = events.map((e) => e.event);
+ expect(eventTypes).toContain('response.completed');
+ });
+ });
+
+ /* ===========================================================================
+ * SCHEMA VALIDATION TESTS
+ * Verify response schema compliance
+ * =========================================================================== */
+
+ describe('Schema Validation', () => {
+ it('should include all required fields in response', async () => {
+ const response = await authRequest().post('/api/agents/v1/responses').send({
+ model: testAgent.id,
+ input: 'Test',
+ });
+
+ expect(response.status).toBe(200);
+ const body = response.body;
+
+ // Required fields per Open Responses spec
+ expect(body).toHaveProperty('id');
+ expect(body).toHaveProperty('object', 'response');
+ expect(body).toHaveProperty('created_at');
+ expect(body).toHaveProperty('completed_at');
+ expect(body).toHaveProperty('status');
+ expect(body).toHaveProperty('model');
+ expect(body).toHaveProperty('output');
+ expect(body).toHaveProperty('tools');
+ expect(body).toHaveProperty('tool_choice');
+ expect(body).toHaveProperty('truncation');
+ expect(body).toHaveProperty('parallel_tool_calls');
+ expect(body).toHaveProperty('text');
+ expect(body).toHaveProperty('temperature');
+ expect(body).toHaveProperty('top_p');
+ expect(body).toHaveProperty('presence_penalty');
+ expect(body).toHaveProperty('frequency_penalty');
+ expect(body).toHaveProperty('top_logprobs');
+ expect(body).toHaveProperty('store');
+ expect(body).toHaveProperty('background');
+ expect(body).toHaveProperty('service_tier');
+ expect(body).toHaveProperty('metadata');
+
+ // top_logprobs must be a number (not null)
+ expect(typeof body.top_logprobs).toBe('number');
+
+ // Usage must have required detail fields
+ expect(body).toHaveProperty('usage');
+ expect(body.usage).toHaveProperty('input_tokens');
+ expect(body.usage).toHaveProperty('output_tokens');
+ expect(body.usage).toHaveProperty('total_tokens');
+ expect(body.usage).toHaveProperty('input_tokens_details');
+ expect(body.usage).toHaveProperty('output_tokens_details');
+ expect(body.usage.input_tokens_details).toHaveProperty('cached_tokens');
+ expect(body.usage.output_tokens_details).toHaveProperty('reasoning_tokens');
+ });
+
+ it('should have valid message item structure', async () => {
+ const response = await authRequest().post('/api/agents/v1/responses').send({
+ model: testAgent.id,
+ input: 'Hello',
+ });
+
+ expect(response.status).toBe(200);
+
+ const messageItem = response.body.output.find((item) => item.type === 'message');
+ expect(messageItem).toBeDefined();
+
+ // Message item required fields
+ expect(messageItem).toHaveProperty('type', 'message');
+ expect(messageItem).toHaveProperty('id');
+ expect(messageItem).toHaveProperty('status');
+ expect(messageItem).toHaveProperty('role', 'assistant');
+ expect(messageItem).toHaveProperty('content');
+ expect(Array.isArray(messageItem.content)).toBe(true);
+
+ // Content part structure - verify all required fields
+ if (messageItem.content.length > 0) {
+ const textContent = messageItem.content.find((c) => c.type === 'output_text');
+ if (textContent) {
+ expect(textContent).toHaveProperty('type', 'output_text');
+ expect(textContent).toHaveProperty('text');
+ expect(textContent).toHaveProperty('annotations');
+ expect(textContent).toHaveProperty('logprobs');
+ expect(Array.isArray(textContent.annotations)).toBe(true);
+ expect(Array.isArray(textContent.logprobs)).toBe(true);
+ }
+ }
+
+ // Verify reasoning item has required summary field
+ const reasoningItem = response.body.output.find((item) => item.type === 'reasoning');
+ if (reasoningItem) {
+ expect(reasoningItem).toHaveProperty('type', 'reasoning');
+ expect(reasoningItem).toHaveProperty('id');
+ expect(reasoningItem).toHaveProperty('summary');
+ expect(Array.isArray(reasoningItem.summary)).toBe(true);
+ }
+ });
+ });
+
+ /* ===========================================================================
+ * RESPONSE STORAGE TESTS
+ * Tests for store: true and GET /v1/responses/:id
+ * =========================================================================== */
+
+ describe('Response Storage', () => {
+ it('should store response when store: true and retrieve it', async () => {
+ // Create a stored response
+ const createResponse = await authRequest().post('/api/agents/v1/responses').send({
+ model: testAgent.id,
+ input: 'Remember this: The answer is 42.',
+ store: true,
+ });
+
+ expect(createResponse.status).toBe(200);
+ expect(createResponse.body.status).toBe('completed');
+
+ const responseId = createResponse.body.id;
+ expect(responseId).toMatch(/^resp_/);
+
+ // Small delay to ensure database write completes
+ await new Promise((resolve) => setTimeout(resolve, 500));
+
+ // Retrieve the stored response
+ const getResponseResult = await authRequest().get(`/api/agents/v1/responses/${responseId}`);
+
+ // Note: The response might be stored under conversationId, not responseId
+ // If we get 404, that's expected behavior for now since we store by conversationId
+ if (getResponseResult.status === 200) {
+ expect(getResponseResult.body.object).toBe('response');
+ expect(getResponseResult.body.status).toBe('completed');
+ expect(getResponseResult.body.output.length).toBeGreaterThan(0);
+ }
+ });
+
+ it('should return 404 for non-existent response', async () => {
+ const response = await authRequest().get('/api/agents/v1/responses/resp_nonexistent123');
+
+ expect(response.status).toBe(404);
+ expect(response.body.error).toBeDefined();
+ });
+ });
+
+ /* ===========================================================================
+ * ERROR HANDLING TESTS
+ * =========================================================================== */
+
+ describe('Error Handling', () => {
+ it('should return error for missing model', async () => {
+ const response = await authRequest().post('/api/agents/v1/responses').send({
+ input: 'Hello',
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body.error).toBeDefined();
+ });
+
+ it('should return error for missing input', async () => {
+ const response = await authRequest().post('/api/agents/v1/responses').send({
+ model: testAgent.id,
+ });
+
+ expect(response.status).toBe(400);
+ expect(response.body.error).toBeDefined();
+ });
+
+ it('should return error for non-existent agent', async () => {
+ const response = await authRequest().post('/api/agents/v1/responses').send({
+ model: 'agent_nonexistent123456789',
+ input: 'Hello',
+ });
+
+ expect(response.status).toBe(404);
+ expect(response.body.error).toBeDefined();
+ });
+ });
+
+ /* ===========================================================================
+ * MODELS ENDPOINT TESTS
+ * =========================================================================== */
+
+ describe('GET /v1/responses/models', () => {
+ it('should list available agents as models', async () => {
+ const response = await authRequest().get('/api/agents/v1/responses/models');
+
+ expect(response.status).toBe(200);
+ expect(response.body.object).toBe('list');
+ expect(Array.isArray(response.body.data)).toBe(true);
+
+ // Should include our test agent
+ const foundAgent = response.body.data.find((m) => m.id === testAgent.id);
+ expect(foundAgent).toBeDefined();
+ expect(foundAgent.object).toBe('model');
+ expect(foundAgent.name).toBe(testAgent.name);
+ });
+ });
+});
diff --git a/api/server/routes/agents/chat.js b/api/server/routes/agents/chat.js
index 7ac4ce811d..37b83f4f54 100644
--- a/api/server/routes/agents/chat.js
+++ b/api/server/routes/agents/chat.js
@@ -2,7 +2,6 @@ const express = require('express');
const { generateCheckAccess, skipAgentCheck } = require('@librechat/api');
const { PermissionTypes, Permissions, PermissionBits } = require('librechat-data-provider');
const {
- setHeaders,
moderateText,
// validateModel,
validateConvoAccess,
@@ -16,8 +15,6 @@ const { getRoleByName } = require('~/models/Role');
const router = express.Router();
-router.use(moderateText);
-
const checkAgentAccess = generateCheckAccess({
permissionType: PermissionTypes.AGENTS,
permissions: [Permissions.USE],
@@ -28,11 +25,11 @@ const checkAgentResourceAccess = canAccessAgentFromBody({
requiredPermission: PermissionBits.VIEW,
});
+router.use(moderateText);
router.use(checkAgentAccess);
router.use(checkAgentResourceAccess);
router.use(validateConvoAccess);
router.use(buildEndpointOption);
-router.use(setHeaders);
const controller = async (req, res, next) => {
await AgentController(req, res, next, initializeClient, addTitle);
diff --git a/api/server/routes/agents/index.js b/api/server/routes/agents/index.js
index b5e249b059..f8d39cb4d8 100644
--- a/api/server/routes/agents/index.js
+++ b/api/server/routes/agents/index.js
@@ -1,34 +1,277 @@
const express = require('express');
-const { isEnabled } = require('@librechat/api');
+const { isEnabled, GenerationJobManager } = require('@librechat/api');
+const { logger } = require('@librechat/data-schemas');
const {
uaParser,
checkBan,
requireJwtAuth,
messageIpLimiter,
configMiddleware,
- concurrentLimiter,
messageUserLimiter,
} = require('~/server/middleware');
+const { saveMessage } = require('~/models');
+const openai = require('./openai');
+const responses = require('./responses');
const { v1 } = require('./v1');
const chat = require('./chat');
-const { LIMIT_CONCURRENT_MESSAGES, LIMIT_MESSAGE_IP, LIMIT_MESSAGE_USER } = process.env ?? {};
+const { LIMIT_MESSAGE_IP, LIMIT_MESSAGE_USER } = process.env ?? {};
const router = express.Router();
+/**
+ * Open Responses API routes (API key authentication handled in route file)
+ * Mounted at /agents/v1/responses (full path: /api/agents/v1/responses)
+ * NOTE: Must be mounted BEFORE /v1 to avoid being caught by the less specific route
+ * @see https://openresponses.org/specification
+ */
+router.use('/v1/responses', responses);
+
+/**
+ * OpenAI-compatible API routes (API key authentication handled in route file)
+ * Mounted at /agents/v1 (full path: /api/agents/v1/chat/completions)
+ */
+router.use('/v1', openai);
+
router.use(requireJwtAuth);
router.use(checkBan);
router.use(uaParser);
router.use('/', v1);
+/**
+ * Stream endpoints - mounted before chatRouter to bypass rate limiters
+ * These are GET requests and don't need message body validation or rate limiting
+ */
+
+/**
+ * @route GET /chat/stream/:streamId
+ * @desc Subscribe to an ongoing generation job's SSE stream with replay support
+ * @access Private
+ * @description Sends sync event with resume state, replays missed chunks, then streams live
+ * @query resume=true - Indicates this is a reconnection (sends sync event)
+ */
+router.get('/chat/stream/:streamId', async (req, res) => {
+ const { streamId } = req.params;
+ const isResume = req.query.resume === 'true';
+
+ const job = await GenerationJobManager.getJob(streamId);
+ if (!job) {
+ return res.status(404).json({
+ error: 'Stream not found',
+ message: 'The generation job does not exist or has expired.',
+ });
+ }
+
+ if (job.metadata?.userId && job.metadata.userId !== req.user.id) {
+ return res.status(403).json({ error: 'Unauthorized' });
+ }
+
+ res.setHeader('Content-Encoding', 'identity');
+ res.setHeader('Content-Type', 'text/event-stream');
+ res.setHeader('Cache-Control', 'no-cache, no-transform');
+ res.setHeader('Connection', 'keep-alive');
+ res.setHeader('X-Accel-Buffering', 'no');
+ res.flushHeaders();
+
+ logger.debug(`[AgentStream] Client subscribed to ${streamId}, resume: ${isResume}`);
+
+ // Send sync event with resume state for ALL reconnecting clients
+ // This supports multi-tab scenarios where each tab needs run step data
+ if (isResume) {
+ const resumeState = await GenerationJobManager.getResumeState(streamId);
+ if (resumeState && !res.writableEnded) {
+ // Send sync event with run steps AND aggregatedContent
+ // Client will use aggregatedContent to initialize message state
+ res.write(`event: message\ndata: ${JSON.stringify({ sync: true, resumeState })}\n\n`);
+ if (typeof res.flush === 'function') {
+ res.flush();
+ }
+ logger.debug(
+ `[AgentStream] Sent sync event for ${streamId} with ${resumeState.runSteps.length} run steps`,
+ );
+ }
+ }
+
+ const result = await GenerationJobManager.subscribe(
+ streamId,
+ (event) => {
+ if (!res.writableEnded) {
+ res.write(`event: message\ndata: ${JSON.stringify(event)}\n\n`);
+ if (typeof res.flush === 'function') {
+ res.flush();
+ }
+ }
+ },
+ (event) => {
+ if (!res.writableEnded) {
+ res.write(`event: message\ndata: ${JSON.stringify(event)}\n\n`);
+ if (typeof res.flush === 'function') {
+ res.flush();
+ }
+ res.end();
+ }
+ },
+ (error) => {
+ if (!res.writableEnded) {
+ res.write(`event: error\ndata: ${JSON.stringify({ error })}\n\n`);
+ if (typeof res.flush === 'function') {
+ res.flush();
+ }
+ res.end();
+ }
+ },
+ );
+
+ if (!result) {
+ return res.status(404).json({ error: 'Failed to subscribe to stream' });
+ }
+
+ req.on('close', () => {
+ logger.debug(`[AgentStream] Client disconnected from ${streamId}`);
+ result.unsubscribe();
+ });
+});
+
+/**
+ * @route GET /chat/active
+ * @desc Get all active generation job IDs for the current user
+ * @access Private
+ * @returns { activeJobIds: string[] }
+ */
+router.get('/chat/active', async (req, res) => {
+ const activeJobIds = await GenerationJobManager.getActiveJobIdsForUser(req.user.id);
+ res.json({ activeJobIds });
+});
+
+/**
+ * @route GET /chat/status/:conversationId
+ * @desc Check if there's an active generation job for a conversation
+ * @access Private
+ * @returns { active, streamId, status, aggregatedContent, createdAt, resumeState }
+ */
+router.get('/chat/status/:conversationId', async (req, res) => {
+ const { conversationId } = req.params;
+
+ // streamId === conversationId, so we can use getJob directly
+ const job = await GenerationJobManager.getJob(conversationId);
+
+ if (!job) {
+ return res.json({ active: false });
+ }
+
+ if (job.metadata.userId !== req.user.id) {
+ return res.status(403).json({ error: 'Unauthorized' });
+ }
+
+ // Get resume state which contains aggregatedContent
+ // Avoid calling both getStreamInfo and getResumeState (both fetch content)
+ const resumeState = await GenerationJobManager.getResumeState(conversationId);
+ const isActive = job.status === 'running';
+
+ res.json({
+ active: isActive,
+ streamId: conversationId,
+ status: job.status,
+ aggregatedContent: resumeState?.aggregatedContent ?? [],
+ createdAt: job.createdAt,
+ resumeState,
+ });
+});
+
+/**
+ * @route POST /chat/abort
+ * @desc Abort an ongoing generation job
+ * @access Private
+ * @description Mounted before chatRouter to bypass buildEndpointOption middleware
+ */
+router.post('/chat/abort', async (req, res) => {
+ logger.debug(`[AgentStream] ========== ABORT ENDPOINT HIT ==========`);
+ logger.debug(`[AgentStream] Method: ${req.method}, Path: ${req.path}`);
+ logger.debug(`[AgentStream] Body:`, req.body);
+
+ const { streamId, conversationId, abortKey } = req.body;
+ const userId = req.user?.id;
+
+ // streamId === conversationId, so try any of the provided IDs
+ // Skip "new" as it's a placeholder for new conversations, not an actual ID
+ let jobStreamId =
+ streamId || (conversationId !== 'new' ? conversationId : null) || abortKey?.split(':')[0];
+ let job = jobStreamId ? await GenerationJobManager.getJob(jobStreamId) : null;
+
+ // Fallback: if job not found and we have a userId, look up active jobs for user
+ // This handles the case where frontend sends "new" but job was created with a UUID
+ if (!job && userId) {
+ logger.debug(`[AgentStream] Job not found by ID, checking active jobs for user: ${userId}`);
+ const activeJobIds = await GenerationJobManager.getActiveJobIdsForUser(userId);
+ if (activeJobIds.length > 0) {
+ // Abort the most recent active job for this user
+ jobStreamId = activeJobIds[0];
+ job = await GenerationJobManager.getJob(jobStreamId);
+ logger.debug(`[AgentStream] Found active job for user: ${jobStreamId}`);
+ }
+ }
+
+ logger.debug(`[AgentStream] Computed jobStreamId: ${jobStreamId}`);
+
+ if (job && jobStreamId) {
+ if (job.metadata?.userId && job.metadata.userId !== userId) {
+ logger.warn(`[AgentStream] Unauthorized abort attempt for ${jobStreamId} by user ${userId}`);
+ return res.status(403).json({ error: 'Unauthorized' });
+ }
+
+ logger.debug(`[AgentStream] Job found, aborting: ${jobStreamId}`);
+ const abortResult = await GenerationJobManager.abortJob(jobStreamId);
+ logger.debug(`[AgentStream] Job aborted successfully: ${jobStreamId}`, {
+ abortResultSuccess: abortResult.success,
+ abortResultUserMessageId: abortResult.jobData?.userMessage?.messageId,
+ abortResultResponseMessageId: abortResult.jobData?.responseMessageId,
+ });
+
+ // CRITICAL: Save partial response BEFORE returning to prevent race condition.
+ // If user sends a follow-up immediately after abort, the parentMessageId must exist in DB.
+ // Only save if we have a valid responseMessageId (skip early aborts before generation started)
+ if (
+ abortResult.success &&
+ abortResult.jobData?.userMessage?.messageId &&
+ abortResult.jobData?.responseMessageId
+ ) {
+ const { jobData, content, text } = abortResult;
+ const responseMessage = {
+ messageId: jobData.responseMessageId,
+ parentMessageId: jobData.userMessage.messageId,
+ conversationId: jobData.conversationId,
+ content: content || [],
+ text: text || '',
+ sender: jobData.sender || 'AI',
+ endpoint: jobData.endpoint,
+ model: jobData.model,
+ unfinished: true,
+ error: false,
+ isCreatedByUser: false,
+ user: userId,
+ };
+
+ try {
+ await saveMessage(req, responseMessage, {
+ context: 'api/server/routes/agents/index.js - abort endpoint',
+ });
+ logger.debug(`[AgentStream] Saved partial response for: ${jobStreamId}`);
+ } catch (saveError) {
+ logger.error(`[AgentStream] Failed to save partial response: ${saveError.message}`);
+ }
+ }
+
+ return res.json({ success: true, aborted: jobStreamId });
+ }
+
+ logger.warn(`[AgentStream] Job not found for streamId: ${jobStreamId}`);
+ return res.status(404).json({ error: 'Job not found', streamId: jobStreamId });
+});
+
const chatRouter = express.Router();
chatRouter.use(configMiddleware);
-if (isEnabled(LIMIT_CONCURRENT_MESSAGES)) {
- chatRouter.use(concurrentLimiter);
-}
-
if (isEnabled(LIMIT_MESSAGE_IP)) {
chatRouter.use(messageIpLimiter);
}
diff --git a/api/server/routes/agents/openai.js b/api/server/routes/agents/openai.js
new file mode 100644
index 0000000000..9a0d9a3564
--- /dev/null
+++ b/api/server/routes/agents/openai.js
@@ -0,0 +1,110 @@
+/**
+ * OpenAI-compatible API routes for LibreChat agents.
+ *
+ * Provides a /v1/chat/completions compatible interface for
+ * interacting with LibreChat agents remotely via API.
+ *
+ * Usage:
+ * POST /v1/chat/completions - Chat with an agent
+ * GET /v1/models - List available agents
+ * GET /v1/models/:model - Get agent details
+ *
+ * Request format:
+ * {
+ * "model": "agent_id_here",
+ * "messages": [{"role": "user", "content": "Hello!"}],
+ * "stream": true
+ * }
+ */
+const express = require('express');
+const { PermissionTypes, Permissions } = require('librechat-data-provider');
+const {
+ generateCheckAccess,
+ createRequireApiKeyAuth,
+ createCheckRemoteAgentAccess,
+} = require('@librechat/api');
+const {
+ OpenAIChatCompletionController,
+ ListModelsController,
+ GetModelController,
+} = require('~/server/controllers/agents/openai');
+const { getEffectivePermissions } = require('~/server/services/PermissionService');
+const { validateAgentApiKey, findUser } = require('~/models');
+const { configMiddleware } = require('~/server/middleware');
+const { getRoleByName } = require('~/models/Role');
+const { getAgent } = require('~/models/Agent');
+
+const router = express.Router();
+
+const requireApiKeyAuth = createRequireApiKeyAuth({
+ validateAgentApiKey,
+ findUser,
+});
+
+const checkRemoteAgentsFeature = generateCheckAccess({
+ permissionType: PermissionTypes.REMOTE_AGENTS,
+ permissions: [Permissions.USE],
+ getRoleByName,
+});
+
+const checkAgentPermission = createCheckRemoteAgentAccess({
+ getAgent,
+ getEffectivePermissions,
+});
+
+router.use(requireApiKeyAuth);
+router.use(configMiddleware);
+router.use(checkRemoteAgentsFeature);
+
+/**
+ * @route POST /v1/chat/completions
+ * @desc OpenAI-compatible chat completions with agents
+ * @access Private (API key auth required)
+ *
+ * Request body:
+ * {
+ * "model": "agent_id", // Required: The agent ID to use
+ * "messages": [...], // Required: Array of chat messages
+ * "stream": true, // Optional: Whether to stream (default: false)
+ * "conversation_id": "...", // Optional: Conversation ID for context
+ * "parent_message_id": "..." // Optional: Parent message for threading
+ * }
+ *
+ * Response (streaming):
+ * - SSE stream with OpenAI chat.completion.chunk format
+ * - Includes delta.reasoning for thinking/reasoning content
+ *
+ * Response (non-streaming):
+ * - Standard OpenAI chat.completion format
+ */
+router.post('/chat/completions', checkAgentPermission, OpenAIChatCompletionController);
+
+/**
+ * @route GET /v1/models
+ * @desc List available agents as models
+ * @access Private (API key auth required)
+ *
+ * Response:
+ * {
+ * "object": "list",
+ * "data": [
+ * {
+ * "id": "agent_id",
+ * "object": "model",
+ * "name": "Agent Name",
+ * "provider": "openai",
+ * ...
+ * }
+ * ]
+ * }
+ */
+router.get('/models', ListModelsController);
+
+/**
+ * @route GET /v1/models/:model
+ * @desc Get details for a specific agent/model
+ * @access Private (API key auth required)
+ */
+router.get('/models/:model', GetModelController);
+
+module.exports = router;
diff --git a/api/server/routes/agents/responses.js b/api/server/routes/agents/responses.js
new file mode 100644
index 0000000000..431942e921
--- /dev/null
+++ b/api/server/routes/agents/responses.js
@@ -0,0 +1,144 @@
+/**
+ * Open Responses API routes for LibreChat agents.
+ *
+ * Implements the Open Responses specification for a forward-looking,
+ * agentic API that uses items as the fundamental unit and semantic
+ * streaming events.
+ *
+ * Usage:
+ * POST /v1/responses - Create a response
+ * GET /v1/models - List available agents
+ *
+ * Request format:
+ * {
+ * "model": "agent_id_here",
+ * "input": "Hello!" or [{ type: "message", role: "user", content: "Hello!" }],
+ * "stream": true,
+ * "previous_response_id": "optional_conversation_id"
+ * }
+ *
+ * @see https://openresponses.org/specification
+ */
+const express = require('express');
+const { PermissionTypes, Permissions } = require('librechat-data-provider');
+const {
+ generateCheckAccess,
+ createRequireApiKeyAuth,
+ createCheckRemoteAgentAccess,
+} = require('@librechat/api');
+const {
+ createResponse,
+ getResponse,
+ listModels,
+} = require('~/server/controllers/agents/responses');
+const { getEffectivePermissions } = require('~/server/services/PermissionService');
+const { validateAgentApiKey, findUser } = require('~/models');
+const { configMiddleware } = require('~/server/middleware');
+const { getRoleByName } = require('~/models/Role');
+const { getAgent } = require('~/models/Agent');
+
+const router = express.Router();
+
+const requireApiKeyAuth = createRequireApiKeyAuth({
+ validateAgentApiKey,
+ findUser,
+});
+
+const checkRemoteAgentsFeature = generateCheckAccess({
+ permissionType: PermissionTypes.REMOTE_AGENTS,
+ permissions: [Permissions.USE],
+ getRoleByName,
+});
+
+const checkAgentPermission = createCheckRemoteAgentAccess({
+ getAgent,
+ getEffectivePermissions,
+});
+
+router.use(requireApiKeyAuth);
+router.use(configMiddleware);
+router.use(checkRemoteAgentsFeature);
+
+/**
+ * @route POST /v1/responses
+ * @desc Create a model response following Open Responses specification
+ * @access Private (API key auth required)
+ *
+ * Request body:
+ * {
+ * "model": "agent_id", // Required: The agent ID to use
+ * "input": "..." | [...], // Required: String or array of input items
+ * "stream": true, // Optional: Whether to stream (default: false)
+ * "previous_response_id": "...", // Optional: Previous response for continuation
+ * "instructions": "...", // Optional: Additional instructions
+ * "tools": [...], // Optional: Additional tools
+ * "tool_choice": "auto", // Optional: Tool choice mode
+ * "max_output_tokens": 4096, // Optional: Max tokens
+ * "temperature": 0.7 // Optional: Temperature
+ * }
+ *
+ * Response (streaming):
+ * - SSE stream with semantic events:
+ * - response.in_progress
+ * - response.output_item.added
+ * - response.content_part.added
+ * - response.output_text.delta
+ * - response.output_text.done
+ * - response.function_call_arguments.delta
+ * - response.output_item.done
+ * - response.completed
+ * - [DONE]
+ *
+ * Response (non-streaming):
+ * {
+ * "id": "resp_xxx",
+ * "object": "response",
+ * "created_at": 1234567890,
+ * "status": "completed",
+ * "model": "agent_id",
+ * "output": [...], // Array of output items
+ * "usage": { ... }
+ * }
+ */
+router.post('/', checkAgentPermission, createResponse);
+
+/**
+ * @route GET /v1/responses/models
+ * @desc List available agents as models
+ * @access Private (API key auth required)
+ *
+ * Response:
+ * {
+ * "object": "list",
+ * "data": [
+ * {
+ * "id": "agent_id",
+ * "object": "model",
+ * "name": "Agent Name",
+ * "provider": "openai",
+ * ...
+ * }
+ * ]
+ * }
+ */
+router.get('/models', listModels);
+
+/**
+ * @route GET /v1/responses/:id
+ * @desc Retrieve a stored response by ID
+ * @access Private (API key auth required)
+ *
+ * Response:
+ * {
+ * "id": "resp_xxx",
+ * "object": "response",
+ * "created_at": 1234567890,
+ * "status": "completed",
+ * "model": "agent_id",
+ * "output": [...],
+ * "usage": { ... }
+ * }
+ */
+router.get('/:id', getResponse);
+
+module.exports = router;
diff --git a/api/server/routes/agents/v1.js b/api/server/routes/agents/v1.js
index 1e4f1c0118..682a9c795f 100644
--- a/api/server/routes/agents/v1.js
+++ b/api/server/routes/agents/v1.js
@@ -25,7 +25,7 @@ const checkGlobalAgentShare = generateCheckAccess({
permissionType: PermissionTypes.AGENTS,
permissions: [Permissions.USE, Permissions.CREATE],
bodyProps: {
- [Permissions.SHARED_GLOBAL]: ['projectIds', 'removeProjectIds'],
+ [Permissions.SHARE]: ['projectIds', 'removeProjectIds'],
},
getRoleByName,
});
diff --git a/api/server/routes/apiKeys.js b/api/server/routes/apiKeys.js
new file mode 100644
index 0000000000..29dcc326f5
--- /dev/null
+++ b/api/server/routes/apiKeys.js
@@ -0,0 +1,36 @@
+const express = require('express');
+const { generateCheckAccess, createApiKeyHandlers } = require('@librechat/api');
+const { PermissionTypes, Permissions } = require('librechat-data-provider');
+const {
+ getAgentApiKeyById,
+ createAgentApiKey,
+ deleteAgentApiKey,
+ listAgentApiKeys,
+} = require('~/models');
+const { requireJwtAuth } = require('~/server/middleware');
+const { getRoleByName } = require('~/models/Role');
+
+const router = express.Router();
+
+const handlers = createApiKeyHandlers({
+ createAgentApiKey,
+ listAgentApiKeys,
+ deleteAgentApiKey,
+ getAgentApiKeyById,
+});
+
+const checkRemoteAgentsUse = generateCheckAccess({
+ permissionType: PermissionTypes.REMOTE_AGENTS,
+ permissions: [Permissions.USE],
+ getRoleByName,
+});
+
+router.post('/', requireJwtAuth, checkRemoteAgentsUse, handlers.createApiKey);
+
+router.get('/', requireJwtAuth, checkRemoteAgentsUse, handlers.listApiKeys);
+
+router.get('/:id', requireJwtAuth, checkRemoteAgentsUse, handlers.getApiKey);
+
+router.delete('/:id', requireJwtAuth, checkRemoteAgentsUse, handlers.deleteApiKey);
+
+module.exports = router;
diff --git a/api/server/routes/assistants/actions.js b/api/server/routes/assistants/actions.js
index 3a1a844926..57975d32a7 100644
--- a/api/server/routes/assistants/actions.js
+++ b/api/server/routes/assistants/actions.js
@@ -154,6 +154,7 @@ router.post('/:assistant_id', async (req, res) => {
router.delete('/:assistant_id/:action_id/:model', async (req, res) => {
try {
const { assistant_id, action_id, model } = req.params;
+ req.body = req.body || {}; // Express 5: ensure req.body exists
req.body.model = model;
const { openai } = await getOpenAIClient({ req, res });
diff --git a/api/server/routes/assistants/chatV1.js b/api/server/routes/assistants/chatV1.js
index 36ed6d49e0..67bfc007a6 100644
--- a/api/server/routes/assistants/chatV1.js
+++ b/api/server/routes/assistants/chatV1.js
@@ -5,7 +5,6 @@ const {
setHeaders,
handleAbort,
validateModel,
- // validateEndpoint,
buildEndpointOption,
} = require('~/server/middleware');
const validateConvoAccess = require('~/server/middleware/validate/convoAccess');
diff --git a/api/server/routes/assistants/chatV2.js b/api/server/routes/assistants/chatV2.js
index e50994e9bc..4612743e47 100644
--- a/api/server/routes/assistants/chatV2.js
+++ b/api/server/routes/assistants/chatV2.js
@@ -5,7 +5,6 @@ const {
setHeaders,
handleAbort,
validateModel,
- // validateEndpoint,
buildEndpointOption,
} = require('~/server/middleware');
const validateConvoAccess = require('~/server/middleware/validate/convoAccess');
diff --git a/api/server/routes/config.js b/api/server/routes/config.js
index 6f97639dd1..a2dc5b79d2 100644
--- a/api/server/routes/config.js
+++ b/api/server/routes/config.js
@@ -1,18 +1,11 @@
const express = require('express');
const { logger } = require('@librechat/data-schemas');
const { isEnabled, getBalanceConfig } = require('@librechat/api');
-const {
- Constants,
- CacheKeys,
- removeNullishValues,
- defaultSocialLogins,
-} = require('librechat-data-provider');
+const { Constants, CacheKeys, defaultSocialLogins } = require('librechat-data-provider');
const { getLdapConfig } = require('~/server/services/Config/ldap');
const { getAppConfig } = require('~/server/services/Config/app');
const { getProjectByName } = require('~/models/Project');
-const { getMCPManager } = require('~/config');
const { getLogStores } = require('~/cache');
-const { mcpServersRegistry } = require('@librechat/api');
const router = express.Router();
const emailLoginEnabled =
@@ -30,46 +23,11 @@ const publicSharedLinksEnabled =
const sharePointFilePickerEnabled = isEnabled(process.env.ENABLE_SHAREPOINT_FILEPICKER);
const openidReuseTokens = isEnabled(process.env.OPENID_REUSE_TOKENS);
-/**
- * Fetches MCP servers from registry and adds them to the payload.
- * Registry now includes all configured servers (from YAML) plus inspection data when available.
- * Always fetches fresh to avoid caching incomplete initialization state.
- */
-const getMCPServers = async (payload, appConfig) => {
- try {
- if (appConfig?.mcpConfig == null) {
- return;
- }
- const mcpManager = getMCPManager();
- if (!mcpManager) {
- return;
- }
- const mcpServers = await mcpServersRegistry.getAllServerConfigs();
- if (!mcpServers) return;
- for (const serverName in mcpServers) {
- if (!payload.mcpServers) {
- payload.mcpServers = {};
- }
- const serverConfig = mcpServers[serverName];
- payload.mcpServers[serverName] = removeNullishValues({
- startup: serverConfig?.startup,
- chatMenu: serverConfig?.chatMenu,
- isOAuth: serverConfig.requiresOAuth,
- customUserVars: serverConfig?.customUserVars,
- });
- }
- } catch (error) {
- logger.error('Error loading MCP servers', error);
- }
-};
-
router.get('/', async function (req, res) {
const cache = getLogStores(CacheKeys.CONFIG_STORE);
const cachedStartupConfig = await cache.get(CacheKeys.STARTUP_CONFIG);
if (cachedStartupConfig) {
- const appConfig = await getAppConfig({ role: req.user?.role });
- await getMCPServers(cachedStartupConfig, appConfig);
res.send(cachedStartupConfig);
return;
}
@@ -190,7 +148,6 @@ router.get('/', async function (req, res) {
}
await cache.set(CacheKeys.STARTUP_CONFIG, payload);
- await getMCPServers(payload, appConfig);
return res.status(200).send(payload);
} catch (err) {
logger.error('Error in startup config', err);
diff --git a/api/server/routes/convos.js b/api/server/routes/convos.js
index 766b2a21b0..bb9c4ebea9 100644
--- a/api/server/routes/convos.js
+++ b/api/server/routes/convos.js
@@ -6,6 +6,7 @@ const { logger } = require('@librechat/data-schemas');
const { CacheKeys, EModelEndpoint } = require('librechat-data-provider');
const {
createImportLimiters,
+ validateConvoAccess,
createForkLimiters,
configMiddleware,
} = require('~/server/middleware');
@@ -31,7 +32,8 @@ router.get('/', async (req, res) => {
const cursor = req.query.cursor;
const isArchived = isEnabled(req.query.isArchived);
const search = req.query.search ? decodeURIComponent(req.query.search) : undefined;
- const order = req.query.order || 'desc';
+ const sortBy = req.query.sortBy || 'updatedAt';
+ const sortDirection = req.query.sortDirection || 'desc';
let tags;
if (req.query.tags) {
@@ -45,7 +47,8 @@ router.get('/', async (req, res) => {
isArchived,
tags,
search,
- order,
+ sortBy,
+ sortDirection,
});
res.status(200).json(result);
} catch (error) {
@@ -65,16 +68,17 @@ router.get('/:conversationId', async (req, res) => {
}
});
-router.post('/gen_title', async (req, res) => {
- const { conversationId } = req.body;
+router.get('/gen_title/:conversationId', async (req, res) => {
+ const { conversationId } = req.params;
const titleCache = getLogStores(CacheKeys.GEN_TITLE);
const key = `${req.user.id}-${conversationId}`;
let title = await titleCache.get(key);
if (!title) {
- // Retry every 1s for up to 20s
- for (let i = 0; i < 20; i++) {
- await sleep(1000);
+ // Exponential backoff: 500ms, 1s, 2s, 4s, 8s (total ~15.5s max wait)
+ const delays = [500, 1000, 2000, 4000, 8000];
+ for (const delay of delays) {
+ await sleep(delay);
title = await titleCache.get(key);
if (title) {
break;
@@ -94,7 +98,7 @@ router.post('/gen_title', async (req, res) => {
router.delete('/', async (req, res) => {
let filter = {};
- const { conversationId, source, thread_id, endpoint } = req.body.arg;
+ const { conversationId, source, thread_id, endpoint } = req.body?.arg ?? {};
// Prevent deletion of all conversations
if (!conversationId && !source && !thread_id && !endpoint) {
@@ -148,17 +152,70 @@ router.delete('/all', async (req, res) => {
}
});
-router.post('/update', async (req, res) => {
- const update = req.body.arg;
+/**
+ * Archives or unarchives a conversation.
+ * @route POST /archive
+ * @param {string} req.body.arg.conversationId - The conversation ID to archive/unarchive.
+ * @param {boolean} req.body.arg.isArchived - Whether to archive (true) or unarchive (false).
+ * @returns {object} 200 - The updated conversation object.
+ */
+router.post('/archive', validateConvoAccess, async (req, res) => {
+ const { conversationId, isArchived } = req.body?.arg ?? {};
- if (!update.conversationId) {
+ if (!conversationId) {
return res.status(400).json({ error: 'conversationId is required' });
}
+ if (typeof isArchived !== 'boolean') {
+ return res.status(400).json({ error: 'isArchived must be a boolean' });
+ }
+
try {
- const dbResponse = await saveConvo(req, update, {
- context: `POST /api/convos/update ${update.conversationId}`,
- });
+ const dbResponse = await saveConvo(
+ req,
+ { conversationId, isArchived },
+ { context: `POST /api/convos/archive ${conversationId}` },
+ );
+ res.status(200).json(dbResponse);
+ } catch (error) {
+ logger.error('Error archiving conversation', error);
+ res.status(500).send('Error archiving conversation');
+ }
+});
+
+/** Maximum allowed length for conversation titles */
+const MAX_CONVO_TITLE_LENGTH = 1024;
+
+/**
+ * Updates a conversation's title.
+ * @route POST /update
+ * @param {string} req.body.arg.conversationId - The conversation ID to update.
+ * @param {string} req.body.arg.title - The new title for the conversation.
+ * @returns {object} 201 - The updated conversation object.
+ */
+router.post('/update', validateConvoAccess, async (req, res) => {
+ const { conversationId, title } = req.body?.arg ?? {};
+
+ if (!conversationId) {
+ return res.status(400).json({ error: 'conversationId is required' });
+ }
+
+ if (title === undefined) {
+ return res.status(400).json({ error: 'title is required' });
+ }
+
+ if (typeof title !== 'string') {
+ return res.status(400).json({ error: 'title must be a string' });
+ }
+
+ const sanitizedTitle = title.trim().slice(0, MAX_CONVO_TITLE_LENGTH);
+
+ try {
+ const dbResponse = await saveConvo(
+ req,
+ { conversationId, title: sanitizedTitle },
+ { context: `POST /api/convos/update ${conversationId}` },
+ );
res.status(201).json(dbResponse);
} catch (error) {
logger.error('Error updating conversation', error);
diff --git a/api/server/routes/edit/anthropic.js b/api/server/routes/edit/anthropic.js
deleted file mode 100644
index 704a9f4ea4..0000000000
--- a/api/server/routes/edit/anthropic.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const express = require('express');
-const EditController = require('~/server/controllers/EditController');
-const { initializeClient } = require('~/server/services/Endpoints/anthropic');
-const {
- setHeaders,
- validateModel,
- validateEndpoint,
- buildEndpointOption,
-} = require('~/server/middleware');
-
-const router = express.Router();
-
-router.post(
- '/',
- validateEndpoint,
- validateModel,
- buildEndpointOption,
- setHeaders,
- async (req, res, next) => {
- await EditController(req, res, next, initializeClient);
- },
-);
-
-module.exports = router;
diff --git a/api/server/routes/edit/custom.js b/api/server/routes/edit/custom.js
deleted file mode 100644
index a6fd804763..0000000000
--- a/api/server/routes/edit/custom.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const express = require('express');
-const EditController = require('~/server/controllers/EditController');
-const { initializeClient } = require('~/server/services/Endpoints/custom');
-const { addTitle } = require('~/server/services/Endpoints/openAI');
-const {
- handleAbort,
- setHeaders,
- validateModel,
- validateEndpoint,
- buildEndpointOption,
-} = require('~/server/middleware');
-
-const router = express.Router();
-
-router.post(
- '/',
- validateEndpoint,
- validateModel,
- buildEndpointOption,
- setHeaders,
- async (req, res, next) => {
- await EditController(req, res, next, initializeClient, addTitle);
- },
-);
-
-module.exports = router;
diff --git a/api/server/routes/edit/google.js b/api/server/routes/edit/google.js
deleted file mode 100644
index 187f4f6158..0000000000
--- a/api/server/routes/edit/google.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const express = require('express');
-const EditController = require('~/server/controllers/EditController');
-const { initializeClient } = require('~/server/services/Endpoints/google');
-const {
- setHeaders,
- validateModel,
- validateEndpoint,
- buildEndpointOption,
-} = require('~/server/middleware');
-
-const router = express.Router();
-
-router.post(
- '/',
- validateEndpoint,
- validateModel,
- buildEndpointOption,
- setHeaders,
- async (req, res, next) => {
- await EditController(req, res, next, initializeClient);
- },
-);
-
-module.exports = router;
diff --git a/api/server/routes/edit/index.js b/api/server/routes/edit/index.js
deleted file mode 100644
index 2ebc57a13f..0000000000
--- a/api/server/routes/edit/index.js
+++ /dev/null
@@ -1,45 +0,0 @@
-const { isEnabled } = require('@librechat/api');
-const { EModelEndpoint } = require('librechat-data-provider');
-const {
- validateConvoAccess,
- messageUserLimiter,
- concurrentLimiter,
- messageIpLimiter,
- requireJwtAuth,
- checkBan,
- uaParser,
-} = require('~/server/middleware');
-const anthropic = require('./anthropic');
-const express = require('express');
-const openAI = require('./openAI');
-const custom = require('./custom');
-const google = require('./google');
-
-const { LIMIT_CONCURRENT_MESSAGES, LIMIT_MESSAGE_IP, LIMIT_MESSAGE_USER } = process.env ?? {};
-
-const router = express.Router();
-
-router.use(requireJwtAuth);
-router.use(checkBan);
-router.use(uaParser);
-
-if (isEnabled(LIMIT_CONCURRENT_MESSAGES)) {
- router.use(concurrentLimiter);
-}
-
-if (isEnabled(LIMIT_MESSAGE_IP)) {
- router.use(messageIpLimiter);
-}
-
-if (isEnabled(LIMIT_MESSAGE_USER)) {
- router.use(messageUserLimiter);
-}
-
-router.use(validateConvoAccess);
-
-router.use([`/${EModelEndpoint.azureOpenAI}`, `/${EModelEndpoint.openAI}`], openAI);
-router.use(`/${EModelEndpoint.anthropic}`, anthropic);
-router.use(`/${EModelEndpoint.google}`, google);
-router.use(`/${EModelEndpoint.custom}`, custom);
-
-module.exports = router;
diff --git a/api/server/routes/edit/openAI.js b/api/server/routes/edit/openAI.js
deleted file mode 100644
index ee25a42ee3..0000000000
--- a/api/server/routes/edit/openAI.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const express = require('express');
-const EditController = require('~/server/controllers/EditController');
-const { initializeClient } = require('~/server/services/Endpoints/openAI');
-const {
- setHeaders,
- validateModel,
- validateEndpoint,
- buildEndpointOption,
- moderateText,
-} = require('~/server/middleware');
-
-const router = express.Router();
-router.use(moderateText);
-
-router.post(
- '/',
- validateEndpoint,
- validateModel,
- buildEndpointOption,
- setHeaders,
- async (req, res, next) => {
- await EditController(req, res, next, initializeClient);
- },
-);
-
-module.exports = router;
diff --git a/api/server/routes/files/files.agents.test.js b/api/server/routes/files/files.agents.test.js
index fbccf62a2b..7c21e95234 100644
--- a/api/server/routes/files/files.agents.test.js
+++ b/api/server/routes/files/files.agents.test.js
@@ -4,16 +4,27 @@ const mongoose = require('mongoose');
const { v4: uuidv4 } = require('uuid');
const { createMethods } = require('@librechat/data-schemas');
const { MongoMemoryServer } = require('mongodb-memory-server');
-const { AccessRoleIds, ResourceType, PrincipalType } = require('librechat-data-provider');
+const {
+ SystemRoles,
+ AccessRoleIds,
+ ResourceType,
+ PrincipalType,
+} = require('librechat-data-provider');
const { createAgent } = require('~/models/Agent');
-const { createFile } = require('~/models/File');
+const { createFile } = require('~/models');
// Only mock the external dependencies that we don't want to test
jest.mock('~/server/services/Files/process', () => ({
processDeleteRequest: jest.fn().mockResolvedValue({}),
filterFile: jest.fn(),
processFileUpload: jest.fn(),
- processAgentFileUpload: jest.fn(),
+ processAgentFileUpload: jest.fn().mockImplementation(async ({ res }) => {
+ // processAgentFileUpload sends response directly via res.json()
+ return res.status(200).json({
+ message: 'Agent file uploaded and processed successfully',
+ file_id: 'test-file-id',
+ });
+ }),
}));
jest.mock('~/server/services/Files/strategies', () => ({
@@ -28,6 +39,31 @@ jest.mock('~/server/services/Tools/credentials', () => ({
loadAuthValues: jest.fn(),
}));
+jest.mock('~/server/services/Files/S3/crud', () => ({
+ refreshS3FileUrls: jest.fn(),
+}));
+
+jest.mock('~/cache', () => ({
+ getLogStores: jest.fn(() => ({
+ get: jest.fn(),
+ set: jest.fn(),
+ })),
+}));
+
+// Mock fs.promises.unlink to prevent file cleanup errors in tests
+jest.mock('fs', () => {
+ const actualFs = jest.requireActual('fs');
+ return {
+ ...actualFs,
+ promises: {
+ ...actualFs.promises,
+ unlink: jest.fn().mockResolvedValue(undefined),
+ },
+ };
+});
+
+const { processAgentFileUpload } = require('~/server/services/Files/process');
+
// Import the router
const router = require('~/server/routes/files/files');
@@ -339,4 +375,347 @@ describe('File Routes - Agent Files Endpoint', () => {
expect(response.body.map((f) => f.file_id)).toContain(otherUserFileId);
});
});
+
+ describe('POST /files - Agent File Upload Permission Check', () => {
+ let agentCustomId;
+
+ beforeEach(async () => {
+ agentCustomId = `agent_${uuidv4().replace(/-/g, '').substring(0, 21)}`;
+ jest.clearAllMocks();
+ });
+
+ /**
+ * Helper to create an Express app with specific user context
+ */
+ const createAppWithUser = (userId, userRole = SystemRoles.USER) => {
+ const testApp = express();
+ testApp.use(express.json());
+
+ // Mock multer - populate req.file
+ testApp.use((req, res, next) => {
+ if (req.method === 'POST') {
+ req.file = {
+ originalname: 'test.txt',
+ mimetype: 'text/plain',
+ size: 100,
+ path: '/tmp/test.txt',
+ };
+ req.file_id = uuidv4();
+ }
+ next();
+ });
+
+ testApp.use((req, res, next) => {
+ req.user = { id: userId.toString(), role: userRole };
+ req.app = { locals: {} };
+ req.config = { fileStrategy: 'local' };
+ next();
+ });
+
+ testApp.use('/files', router);
+ return testApp;
+ };
+
+ it('should deny file upload to agent when user has no permission', async () => {
+ // Create an agent owned by authorId
+ await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const testApp = createAppWithUser(otherUserId);
+
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(403);
+ expect(response.body.error).toBe('Forbidden');
+ expect(response.body.message).toBe('Insufficient permissions to upload files to this agent');
+ expect(processAgentFileUpload).not.toHaveBeenCalled();
+ });
+
+ it('should allow file upload to agent for agent author', async () => {
+ // Create an agent owned by authorId
+ await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const testApp = createAppWithUser(authorId);
+
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should allow file upload to agent for user with EDIT permission', async () => {
+ // Create an agent owned by authorId
+ const agent = await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ // Grant EDIT permission to otherUserId
+ const { grantPermission } = require('~/server/services/PermissionService');
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: otherUserId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_EDITOR,
+ grantedBy: authorId,
+ });
+
+ const testApp = createAppWithUser(otherUserId);
+
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should deny file upload to agent for user with only VIEW permission', async () => {
+ // Create an agent owned by authorId
+ const agent = await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ // Grant only VIEW permission to otherUserId
+ const { grantPermission } = require('~/server/services/PermissionService');
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: otherUserId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_VIEWER,
+ grantedBy: authorId,
+ });
+
+ const testApp = createAppWithUser(otherUserId);
+
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'file_search',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(403);
+ expect(response.body.error).toBe('Forbidden');
+ expect(processAgentFileUpload).not.toHaveBeenCalled();
+ });
+
+ it('should allow file upload for admin user regardless of agent ownership', async () => {
+ // Create an agent owned by authorId
+ await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ // Create app with admin user (otherUserId as admin)
+ const testApp = createAppWithUser(otherUserId, SystemRoles.ADMIN);
+
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should return 404 when uploading to non-existent agent', async () => {
+ const testApp = createAppWithUser(otherUserId);
+
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ agent_id: 'agent_nonexistent123456789',
+ tool_resource: 'context',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(404);
+ expect(response.body.error).toBe('Not Found');
+ expect(response.body.message).toBe('Agent not found');
+ expect(processAgentFileUpload).not.toHaveBeenCalled();
+ });
+
+ it('should allow file upload without agent_id (message attachment)', async () => {
+ const testApp = createAppWithUser(otherUserId);
+
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ file_id: uuidv4(),
+ // No agent_id or tool_resource - this is a message attachment
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should allow file upload with agent_id but no tool_resource (message attachment)', async () => {
+ // Create an agent owned by authorId
+ await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ const testApp = createAppWithUser(otherUserId);
+
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ file_id: uuidv4(),
+ // No tool_resource - permission check should not apply
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should allow message_file attachment to agent even without EDIT permission', async () => {
+ // Create an agent owned by authorId
+ const agent = await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ // Grant only VIEW permission to otherUserId
+ const { grantPermission } = require('~/server/services/PermissionService');
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: otherUserId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_VIEWER,
+ grantedBy: authorId,
+ });
+
+ const testApp = createAppWithUser(otherUserId);
+
+ // message_file: true indicates this is a chat message attachment, not a permanent file upload
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ message_file: true,
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should allow message_file attachment (string "true") to agent even without EDIT permission', async () => {
+ // Create an agent owned by authorId
+ const agent = await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ // Grant only VIEW permission to otherUserId
+ const { grantPermission } = require('~/server/services/PermissionService');
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: otherUserId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_VIEWER,
+ grantedBy: authorId,
+ });
+
+ const testApp = createAppWithUser(otherUserId);
+
+ // message_file as string "true" (from form data) should also be allowed
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ message_file: 'true',
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(200);
+ expect(processAgentFileUpload).toHaveBeenCalled();
+ });
+
+ it('should deny file upload when message_file is false (not a message attachment)', async () => {
+ // Create an agent owned by authorId
+ const agent = await createAgent({
+ id: agentCustomId,
+ name: 'Test Agent',
+ provider: 'openai',
+ model: 'gpt-4',
+ author: authorId,
+ });
+
+ // Grant only VIEW permission to otherUserId
+ const { grantPermission } = require('~/server/services/PermissionService');
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: otherUserId,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ accessRoleId: AccessRoleIds.AGENT_VIEWER,
+ grantedBy: authorId,
+ });
+
+ const testApp = createAppWithUser(otherUserId);
+
+ // message_file: false should NOT bypass permission check
+ const response = await request(testApp).post('/files').send({
+ endpoint: 'agents',
+ agent_id: agentCustomId,
+ tool_resource: 'context',
+ message_file: false,
+ file_id: uuidv4(),
+ });
+
+ expect(response.status).toBe(403);
+ expect(response.body.error).toBe('Forbidden');
+ expect(processAgentFileUpload).not.toHaveBeenCalled();
+ });
+ });
});
diff --git a/api/server/routes/files/files.js b/api/server/routes/files/files.js
index 7237729c87..5de2ddb379 100644
--- a/api/server/routes/files/files.js
+++ b/api/server/routes/files/files.js
@@ -7,6 +7,7 @@ const {
isUUID,
CacheKeys,
FileSources,
+ SystemRoles,
ResourceType,
EModelEndpoint,
PermissionBits,
@@ -26,7 +27,7 @@ const { checkPermission } = require('~/server/services/PermissionService');
const { loadAuthValues } = require('~/server/services/Tools/credentials');
const { refreshS3FileUrls } = require('~/server/services/Files/S3/crud');
const { hasAccessToFilesViaAgent } = require('~/server/services/Files');
-const { getFiles, batchUpdateFiles } = require('~/models/File');
+const { getFiles, batchUpdateFiles } = require('~/models');
const { cleanFileName } = require('~/server/utils/files');
const { getAssistant } = require('~/models/Assistant');
const { getAgent } = require('~/models/Agent');
@@ -380,6 +381,50 @@ router.post('/', async (req, res) => {
return await processFileUpload({ req, res, metadata });
}
+ /**
+ * Check agent permissions for permanent agent file uploads (not message attachments).
+ * Message attachments (message_file=true) are temporary files for a single conversation
+ * and should be allowed for users who can chat with the agent.
+ * Permanent file uploads to tool_resources require EDIT permission.
+ */
+ const isMessageAttachment = metadata.message_file === true || metadata.message_file === 'true';
+ if (metadata.agent_id && metadata.tool_resource && !isMessageAttachment) {
+ const userId = req.user.id;
+
+ /** Admin users bypass permission checks */
+ if (req.user.role !== SystemRoles.ADMIN) {
+ const agent = await getAgent({ id: metadata.agent_id });
+
+ if (!agent) {
+ return res.status(404).json({
+ error: 'Not Found',
+ message: 'Agent not found',
+ });
+ }
+
+ /** Check if user is the author or has edit permission */
+ if (agent.author.toString() !== userId) {
+ const hasEditPermission = await checkPermission({
+ userId,
+ role: req.user.role,
+ resourceType: ResourceType.AGENT,
+ resourceId: agent._id,
+ requiredPermission: PermissionBits.EDIT,
+ });
+
+ if (!hasEditPermission) {
+ logger.warn(
+ `[/files] User ${userId} denied upload to agent ${metadata.agent_id} (insufficient permissions)`,
+ );
+ return res.status(403).json({
+ error: 'Forbidden',
+ message: 'Insufficient permissions to upload files to this agent',
+ });
+ }
+ }
+ }
+ }
+
return await processAgentFileUpload({ req, res, metadata });
} catch (error) {
let message = 'Error processing file';
diff --git a/api/server/routes/files/files.test.js b/api/server/routes/files/files.test.js
index 896542b6f4..1d548b44be 100644
--- a/api/server/routes/files/files.test.js
+++ b/api/server/routes/files/files.test.js
@@ -11,7 +11,7 @@ const {
PrincipalType,
} = require('librechat-data-provider');
const { createAgent } = require('~/models/Agent');
-const { createFile } = require('~/models/File');
+const { createFile } = require('~/models');
// Only mock the external dependencies that we don't want to test
jest.mock('~/server/services/Files/process', () => ({
diff --git a/api/server/routes/files/images.js b/api/server/routes/files/images.js
index b8be413f4f..8072612a69 100644
--- a/api/server/routes/files/images.js
+++ b/api/server/routes/files/images.js
@@ -2,11 +2,11 @@ const path = require('path');
const fs = require('fs').promises;
const express = require('express');
const { logger } = require('@librechat/data-schemas');
-const { isAgentsEndpoint } = require('librechat-data-provider');
+const { isAssistantsEndpoint } = require('librechat-data-provider');
const {
- filterFile,
- processImageFile,
processAgentFileUpload,
+ processImageFile,
+ filterFile,
} = require('~/server/services/Files/process');
const router = express.Router();
@@ -21,7 +21,7 @@ router.post('/', async (req, res) => {
metadata.temp_file_id = metadata.file_id;
metadata.file_id = req.file_id;
- if (isAgentsEndpoint(metadata.endpoint) && metadata.tool_resource != null) {
+ if (!isAssistantsEndpoint(metadata.endpoint) && metadata.tool_resource != null) {
return await processAgentFileUpload({ req, res, metadata });
}
diff --git a/api/server/routes/files/index.js b/api/server/routes/files/index.js
index d2f6126fe9..5d32b91036 100644
--- a/api/server/routes/files/index.js
+++ b/api/server/routes/files/index.js
@@ -29,7 +29,20 @@ const initialize = async () => {
router.use('/speech', speech);
const { fileUploadIpLimiter, fileUploadUserLimiter } = createFileLimiters();
- router.post('*', fileUploadIpLimiter, fileUploadUserLimiter);
+
+ /** Apply rate limiters to all POST routes (excluding /speech which is handled above) */
+ router.use((req, res, next) => {
+ if (req.method === 'POST' && !req.path.startsWith('/speech')) {
+ return fileUploadIpLimiter(req, res, (err) => {
+ if (err) {
+ return next(err);
+ }
+ return fileUploadUserLimiter(req, res, next);
+ });
+ }
+ next();
+ });
+
router.post('/', upload.single('file'));
router.post('/images', upload.single('file'));
router.post('/images/avatar', upload.single('file'));
diff --git a/api/server/routes/index.js b/api/server/routes/index.js
index e8250a1f4d..6a48919db3 100644
--- a/api/server/routes/index.js
+++ b/api/server/routes/index.js
@@ -1,6 +1,7 @@
const accessPermissions = require('./accessPermissions');
const assistants = require('./assistants');
const categories = require('./categories');
+const adminAuth = require('./admin/auth');
const endpoints = require('./endpoints');
const staticRoute = require('./static');
const messages = require('./messages');
@@ -8,8 +9,8 @@ const memories = require('./memories');
const presets = require('./presets');
const prompts = require('./prompts');
const balance = require('./balance');
-const plugins = require('./plugins');
const actions = require('./actions');
+const apiKeys = require('./apiKeys');
const banner = require('./banner');
const search = require('./search');
const models = require('./models');
@@ -22,16 +23,16 @@ const files = require('./files');
const share = require('./share');
const tags = require('./tags');
const auth = require('./auth');
-const edit = require('./edit');
const keys = require('./keys');
const user = require('./user');
const mcp = require('./mcp');
module.exports = {
mcp,
- edit,
auth,
+ adminAuth,
keys,
+ apiKeys,
user,
tags,
roles,
@@ -45,7 +46,6 @@ module.exports = {
config,
models,
prompts,
- plugins,
actions,
presets,
balance,
diff --git a/api/server/routes/keys.js b/api/server/routes/keys.js
index cb8a4a5d92..dfd68f69c4 100644
--- a/api/server/routes/keys.js
+++ b/api/server/routes/keys.js
@@ -1,10 +1,15 @@
const express = require('express');
+const { updateUserKey, deleteUserKey, getUserKeyExpiry } = require('~/models');
+const { requireJwtAuth } = require('~/server/middleware');
+
const router = express.Router();
-const { updateUserKey, deleteUserKey, getUserKeyExpiry } = require('../services/UserService');
-const { requireJwtAuth } = require('../middleware/');
router.put('/', requireJwtAuth, async (req, res) => {
- await updateUserKey({ userId: req.user.id, ...req.body });
+ if (req.body == null || typeof req.body !== 'object') {
+ return res.status(400).send({ error: 'Invalid request body.' });
+ }
+ const { name, value, expiresAt } = req.body;
+ await updateUserKey({ userId: req.user.id, name, value, expiresAt });
res.status(201).send();
});
diff --git a/api/server/routes/mcp.js b/api/server/routes/mcp.js
index 39c4f4fa43..2db8c2c462 100644
--- a/api/server/routes/mcp.js
+++ b/api/server/routes/mcp.js
@@ -1,26 +1,54 @@
const { Router } = require('express');
const { logger } = require('@librechat/data-schemas');
-const { CacheKeys, Constants } = require('librechat-data-provider');
const {
+ CacheKeys,
+ Constants,
+ PermissionBits,
+ PermissionTypes,
+ Permissions,
+} = require('librechat-data-provider');
+const {
+ getBasePath,
createSafeUser,
MCPOAuthHandler,
MCPTokenStorage,
+ setOAuthSession,
getUserMCPAuthMap,
- mcpServersRegistry,
+ validateOAuthCsrf,
+ OAUTH_CSRF_COOKIE,
+ setOAuthCsrfCookie,
+ generateCheckAccess,
+ validateOAuthSession,
+ OAUTH_SESSION_COOKIE,
} = require('@librechat/api');
-const { getMCPManager, getFlowStateManager, getOAuthReconnectionManager } = require('~/config');
+const {
+ createMCPServerController,
+ updateMCPServerController,
+ deleteMCPServerController,
+ getMCPServersList,
+ getMCPServerById,
+ getMCPTools,
+} = require('~/server/controllers/mcp');
+const {
+ getOAuthReconnectionManager,
+ getMCPServersRegistry,
+ getFlowStateManager,
+ getMCPManager,
+} = require('~/config');
const { getMCPSetupData, getServerConnectionStatus } = require('~/server/services/MCP');
+const { requireJwtAuth, canAccessMCPServerResource } = require('~/server/middleware');
const { findToken, updateToken, createToken, deleteTokens } = require('~/models');
const { getUserPluginAuthValue } = require('~/server/services/PluginService');
const { updateMCPServerTools } = require('~/server/services/Config/mcp');
const { reinitMCPServer } = require('~/server/services/Tools/mcp');
-const { getMCPTools } = require('~/server/controllers/mcp');
-const { requireJwtAuth } = require('~/server/middleware');
const { findPluginAuthsByKeys } = require('~/models');
+const { getRoleByName } = require('~/models/Role');
const { getLogStores } = require('~/cache');
const router = Router();
+const OAUTH_CSRF_COOKIE_PATH = '/api/mcp';
+
/**
* Get all MCP tools available to the user
* Returns only MCP tools, completely decoupled from regular LibreChat tools
@@ -33,7 +61,7 @@ router.get('/tools', requireJwtAuth, async (req, res) => {
* Initiate OAuth flow
* This endpoint is called when the user clicks the auth link in the UI
*/
-router.get('/:serverName/oauth/initiate', requireJwtAuth, async (req, res) => {
+router.get('/:serverName/oauth/initiate', requireJwtAuth, setOAuthSession, async (req, res) => {
try {
const { serverName } = req.params;
const { userId, flowId } = req.query;
@@ -73,7 +101,7 @@ router.get('/:serverName/oauth/initiate', requireJwtAuth, async (req, res) => {
logger.debug('[MCP OAuth] OAuth flow initiated', { oauthFlowId, authorizationUrl });
- // Redirect user to the authorization URL
+ setOAuthCsrfCookie(res, oauthFlowId, OAUTH_CSRF_COOKIE_PATH);
res.redirect(authorizationUrl);
} catch (error) {
logger.error('[MCP OAuth] Failed to initiate OAuth', error);
@@ -86,6 +114,7 @@ router.get('/:serverName/oauth/initiate', requireJwtAuth, async (req, res) => {
* This handles the OAuth callback after the user has authorized the application
*/
router.get('/:serverName/oauth/callback', async (req, res) => {
+ const basePath = getBasePath();
try {
const { serverName } = req.params;
const { code, state, error: oauthError } = req.query;
@@ -99,22 +128,43 @@ router.get('/:serverName/oauth/callback', async (req, res) => {
if (oauthError) {
logger.error('[MCP OAuth] OAuth error received', { error: oauthError });
- return res.redirect(`/oauth/error?error=${encodeURIComponent(String(oauthError))}`);
+ return res.redirect(
+ `${basePath}/oauth/error?error=${encodeURIComponent(String(oauthError))}`,
+ );
}
if (!code || typeof code !== 'string') {
logger.error('[MCP OAuth] Missing or invalid code');
- return res.redirect('/oauth/error?error=missing_code');
+ return res.redirect(`${basePath}/oauth/error?error=missing_code`);
}
if (!state || typeof state !== 'string') {
logger.error('[MCP OAuth] Missing or invalid state');
- return res.redirect('/oauth/error?error=missing_state');
+ return res.redirect(`${basePath}/oauth/error?error=missing_state`);
}
const flowId = state;
logger.debug('[MCP OAuth] Using flow ID from state', { flowId });
+ const flowParts = flowId.split(':');
+ if (flowParts.length < 2 || !flowParts[0] || !flowParts[1]) {
+ logger.error('[MCP OAuth] Invalid flow ID format in state', { flowId });
+ return res.redirect(`${basePath}/oauth/error?error=invalid_state`);
+ }
+
+ const [flowUserId] = flowParts;
+ if (
+ !validateOAuthCsrf(req, res, flowId, OAUTH_CSRF_COOKIE_PATH) &&
+ !validateOAuthSession(req, flowUserId)
+ ) {
+ logger.error('[MCP OAuth] CSRF validation failed: no valid CSRF or session cookie', {
+ flowId,
+ hasCsrfCookie: !!req.cookies?.[OAUTH_CSRF_COOKIE],
+ hasSessionCookie: !!req.cookies?.[OAUTH_SESSION_COOKIE],
+ });
+ return res.redirect(`${basePath}/oauth/error?error=csrf_validation_failed`);
+ }
+
const flowsCache = getLogStores(CacheKeys.FLOWS);
const flowManager = getFlowStateManager(flowsCache);
@@ -123,7 +173,7 @@ router.get('/:serverName/oauth/callback', async (req, res) => {
if (!flowState) {
logger.error('[MCP OAuth] Flow state not found for flowId:', flowId);
- return res.redirect('/oauth/error?error=invalid_state');
+ return res.redirect(`${basePath}/oauth/error?error=invalid_state`);
}
logger.debug('[MCP OAuth] Flow state details', {
@@ -141,7 +191,7 @@ router.get('/:serverName/oauth/callback', async (req, res) => {
flowId,
serverName,
});
- return res.redirect(`/oauth/success?serverName=${encodeURIComponent(serverName)}`);
+ return res.redirect(`${basePath}/oauth/success?serverName=${encodeURIComponent(serverName)}`);
}
logger.debug('[MCP OAuth] Completing OAuth flow');
@@ -235,11 +285,11 @@ router.get('/:serverName/oauth/callback', async (req, res) => {
}
/** Redirect to success page with flowId and serverName */
- const redirectUrl = `/oauth/success?serverName=${encodeURIComponent(serverName)}`;
+ const redirectUrl = `${basePath}/oauth/success?serverName=${encodeURIComponent(serverName)}`;
res.redirect(redirectUrl);
} catch (error) {
logger.error('[MCP OAuth] OAuth callback error', error);
- res.redirect('/oauth/error?error=callback_failed');
+ res.redirect(`${basePath}/oauth/error?error=callback_failed`);
}
});
@@ -279,13 +329,47 @@ router.get('/oauth/tokens/:flowId', requireJwtAuth, async (req, res) => {
}
});
+/**
+ * Set CSRF binding cookie for OAuth flows initiated outside of HTTP request/response
+ * (e.g. during chat via SSE). The frontend should call this before opening the OAuth URL
+ * so the callback can verify the browser matches the flow initiator.
+ */
+router.post('/:serverName/oauth/bind', requireJwtAuth, setOAuthSession, async (req, res) => {
+ try {
+ const { serverName } = req.params;
+ const user = req.user;
+
+ if (!user?.id) {
+ return res.status(401).json({ error: 'User not authenticated' });
+ }
+
+ const flowId = MCPOAuthHandler.generateFlowId(user.id, serverName);
+ setOAuthCsrfCookie(res, flowId, OAUTH_CSRF_COOKIE_PATH);
+
+ res.json({ success: true });
+ } catch (error) {
+ logger.error('[MCP OAuth] Failed to set CSRF binding cookie', error);
+ res.status(500).json({ error: 'Failed to bind OAuth flow' });
+ }
+});
+
/**
* Check OAuth flow status
* This endpoint can be used to poll the status of an OAuth flow
*/
-router.get('/oauth/status/:flowId', async (req, res) => {
+router.get('/oauth/status/:flowId', requireJwtAuth, async (req, res) => {
try {
const { flowId } = req.params;
+ const user = req.user;
+
+ if (!user?.id) {
+ return res.status(401).json({ error: 'User not authenticated' });
+ }
+
+ if (!flowId.startsWith(`${user.id}:`) && !flowId.startsWith('system:')) {
+ return res.status(403).json({ error: 'Access denied' });
+ }
+
const flowsCache = getLogStores(CacheKeys.FLOWS);
const flowManager = getFlowStateManager(flowsCache);
@@ -352,7 +436,7 @@ router.post('/oauth/cancel/:serverName', requireJwtAuth, async (req, res) => {
* Reinitialize MCP server
* This endpoint allows reinitializing a specific MCP server
*/
-router.post('/:serverName/reinitialize', requireJwtAuth, async (req, res) => {
+router.post('/:serverName/reinitialize', requireJwtAuth, setOAuthSession, async (req, res) => {
try {
const { serverName } = req.params;
const user = createSafeUser(req.user);
@@ -364,7 +448,7 @@ router.post('/:serverName/reinitialize', requireJwtAuth, async (req, res) => {
logger.info(`[MCP Reinitialize] Reinitializing server: ${serverName}`);
const mcpManager = getMCPManager();
- const serverConfig = await mcpServersRegistry.getServerConfig(serverName, user.id);
+ const serverConfig = await getMCPServersRegistry().getServerConfig(serverName, user.id);
if (!serverConfig) {
return res.status(404).json({
error: `MCP server '${serverName}' not found in configuration`,
@@ -398,6 +482,11 @@ router.post('/:serverName/reinitialize', requireJwtAuth, async (req, res) => {
const { success, message, oauthRequired, oauthUrl } = result;
+ if (oauthRequired) {
+ const flowId = MCPOAuthHandler.generateFlowId(user.id, serverName);
+ setOAuthCsrfCookie(res, flowId, OAUTH_CSRF_COOKIE_PATH);
+ }
+
res.json({
success,
message,
@@ -428,11 +517,12 @@ router.get('/connection/status', requireJwtAuth, async (req, res) => {
);
const connectionStatus = {};
- for (const [serverName] of Object.entries(mcpConfig)) {
+ for (const [serverName, config] of Object.entries(mcpConfig)) {
try {
connectionStatus[serverName] = await getServerConnectionStatus(
user.id,
serverName,
+ config,
appConnections,
userConnections,
oauthServers,
@@ -487,6 +577,7 @@ router.get('/connection/status/:serverName', requireJwtAuth, async (req, res) =>
const serverStatus = await getServerConnectionStatus(
user.id,
serverName,
+ mcpConfig[serverName],
appConnections,
userConnections,
oauthServers,
@@ -523,7 +614,7 @@ router.get('/:serverName/auth-values', requireJwtAuth, async (req, res) => {
return res.status(401).json({ error: 'User not authenticated' });
}
- const serverConfig = await mcpServersRegistry.getServerConfig(serverName, user.id);
+ const serverConfig = await getMCPServersRegistry().getServerConfig(serverName, user.id);
if (!serverConfig) {
return res.status(404).json({
error: `MCP server '${serverName}' not found in configuration`,
@@ -563,8 +654,96 @@ router.get('/:serverName/auth-values', requireJwtAuth, async (req, res) => {
});
async function getOAuthHeaders(serverName, userId) {
- const serverConfig = await mcpServersRegistry.getServerConfig(serverName, userId);
+ const serverConfig = await getMCPServersRegistry().getServerConfig(serverName, userId);
return serverConfig?.oauth_headers ?? {};
}
+/**
+MCP Server CRUD Routes (User-Managed MCP Servers)
+*/
+
+// Permission checkers for MCP server management
+const checkMCPUsePermissions = generateCheckAccess({
+ permissionType: PermissionTypes.MCP_SERVERS,
+ permissions: [Permissions.USE],
+ getRoleByName,
+});
+
+const checkMCPCreate = generateCheckAccess({
+ permissionType: PermissionTypes.MCP_SERVERS,
+ permissions: [Permissions.USE, Permissions.CREATE],
+ getRoleByName,
+});
+
+/**
+ * Get list of accessible MCP servers
+ * @route GET /api/mcp/servers
+ * @param {Object} req.query - Query parameters for pagination and search
+ * @param {number} [req.query.limit] - Number of results per page
+ * @param {string} [req.query.after] - Pagination cursor
+ * @param {string} [req.query.search] - Search query for title/description
+ * @returns {MCPServerListResponse} 200 - Success response - application/json
+ */
+router.get('/servers', requireJwtAuth, checkMCPUsePermissions, getMCPServersList);
+
+/**
+ * Create a new MCP server
+ * @route POST /api/mcp/servers
+ * @param {MCPServerCreateParams} req.body - The MCP server creation parameters.
+ * @returns {MCPServer} 201 - Success response - application/json
+ */
+router.post('/servers', requireJwtAuth, checkMCPCreate, createMCPServerController);
+
+/**
+ * Get single MCP server by ID
+ * @route GET /api/mcp/servers/:serverName
+ * @param {string} req.params.serverName - MCP server identifier.
+ * @returns {MCPServer} 200 - Success response - application/json
+ */
+router.get(
+ '/servers/:serverName',
+ requireJwtAuth,
+ checkMCPUsePermissions,
+ canAccessMCPServerResource({
+ requiredPermission: PermissionBits.VIEW,
+ resourceIdParam: 'serverName',
+ }),
+ getMCPServerById,
+);
+
+/**
+ * Update MCP server
+ * @route PATCH /api/mcp/servers/:serverName
+ * @param {string} req.params.serverName - MCP server identifier.
+ * @param {MCPServerUpdateParams} req.body - The MCP server update parameters.
+ * @returns {MCPServer} 200 - Success response - application/json
+ */
+router.patch(
+ '/servers/:serverName',
+ requireJwtAuth,
+ checkMCPCreate,
+ canAccessMCPServerResource({
+ requiredPermission: PermissionBits.EDIT,
+ resourceIdParam: 'serverName',
+ }),
+ updateMCPServerController,
+);
+
+/**
+ * Delete MCP server
+ * @route DELETE /api/mcp/servers/:serverName
+ * @param {string} req.params.serverName - MCP server identifier.
+ * @returns {Object} 200 - Success response - application/json
+ */
+router.delete(
+ '/servers/:serverName',
+ requireJwtAuth,
+ checkMCPCreate,
+ canAccessMCPServerResource({
+ requiredPermission: PermissionBits.DELETE,
+ resourceIdParam: 'serverName',
+ }),
+ deleteMCPServerController,
+);
+
module.exports = router;
diff --git a/api/server/routes/messages.js b/api/server/routes/messages.js
index 901dd8961f..c208e9c406 100644
--- a/api/server/routes/messages.js
+++ b/api/server/routes/messages.js
@@ -1,4 +1,5 @@
const express = require('express');
+const { v4: uuidv4 } = require('uuid');
const { logger } = require('@librechat/data-schemas');
const { ContentTypes } = require('librechat-data-provider');
const { unescapeLaTeX, countTokens } = require('@librechat/api');
@@ -12,7 +13,6 @@ const {
} = require('~/models');
const { findAllArtifacts, replaceArtifactContent } = require('~/server/services/Artifacts/update');
const { requireJwtAuth, validateMessageReq } = require('~/server/middleware');
-const { cleanUpPrimaryKeyValue } = require('~/lib/utils/misc');
const { getConvosQueried } = require('~/models/Conversation');
const { Message } = require('~/db/models');
@@ -24,7 +24,7 @@ router.get('/', async (req, res) => {
const user = req.user.id ?? '';
const {
cursor = null,
- sortBy = 'createdAt',
+ sortBy = 'updatedAt',
sortDirection = 'desc',
pageSize: pageSizeRaw,
conversationId,
@@ -55,7 +55,12 @@ router.get('/', async (req, res) => {
.sort({ [sortField]: sortOrder })
.limit(pageSize + 1)
.lean();
- const nextCursor = messages.length > pageSize ? messages.pop()[sortField] : null;
+ let nextCursor = null;
+ if (messages.length > pageSize) {
+ messages.pop(); // Remove extra item used to detect next page
+ // Create cursor from the last RETURNED item (not the popped one)
+ nextCursor = messages[messages.length - 1][sortField];
+ }
response = { messages, nextCursor };
} else if (search) {
const searchResults = await Message.meiliSearch(search, { filter: `user = "${user}"` }, true);
@@ -68,9 +73,6 @@ router.get('/', async (req, res) => {
const cleanedMessages = [];
for (let i = 0; i < messages.length; i++) {
let message = messages[i];
- if (message.conversationId.includes('--')) {
- message.conversationId = cleanUpPrimaryKeyValue(message.conversationId);
- }
if (result.convoMap[message.conversationId]) {
messageIds.push(message.messageId);
cleanedMessages.push(message);
@@ -115,6 +117,91 @@ router.get('/', async (req, res) => {
}
});
+/**
+ * Creates a new branch message from a specific agent's content within a parallel response message.
+ * Filters the original message's content to only include parts attributed to the specified agentId.
+ * Only available for non-user messages with content attributions.
+ *
+ * @route POST /branch
+ * @param {string} req.body.messageId - The ID of the source message
+ * @param {string} req.body.agentId - The agentId to filter content by
+ * @returns {TMessage} The newly created branch message
+ */
+router.post('/branch', async (req, res) => {
+ try {
+ const { messageId, agentId } = req.body;
+ const userId = req.user.id;
+
+ if (!messageId || !agentId) {
+ return res.status(400).json({ error: 'messageId and agentId are required' });
+ }
+
+ const sourceMessage = await getMessage({ user: userId, messageId });
+ if (!sourceMessage) {
+ return res.status(404).json({ error: 'Source message not found' });
+ }
+
+ if (sourceMessage.isCreatedByUser) {
+ return res.status(400).json({ error: 'Cannot branch from user messages' });
+ }
+
+ if (!Array.isArray(sourceMessage.content)) {
+ return res.status(400).json({ error: 'Message does not have content' });
+ }
+
+ const hasAgentMetadata = sourceMessage.content.some((part) => part?.agentId);
+ if (!hasAgentMetadata) {
+ return res
+ .status(400)
+ .json({ error: 'Message does not have parallel content with attributions' });
+ }
+
+ /** @type {Array} */
+ const filteredContent = [];
+ for (const part of sourceMessage.content) {
+ if (part?.agentId === agentId) {
+ const { agentId: _a, groupId: _g, ...cleanPart } = part;
+ filteredContent.push(cleanPart);
+ }
+ }
+
+ if (filteredContent.length === 0) {
+ return res.status(400).json({ error: 'No content found for the specified agentId' });
+ }
+
+ const newMessageId = uuidv4();
+ /** @type {import('librechat-data-provider').TMessage} */
+ const newMessage = {
+ messageId: newMessageId,
+ conversationId: sourceMessage.conversationId,
+ parentMessageId: sourceMessage.parentMessageId,
+ attachments: sourceMessage.attachments,
+ isCreatedByUser: false,
+ model: sourceMessage.model,
+ endpoint: sourceMessage.endpoint,
+ sender: sourceMessage.sender,
+ iconURL: sourceMessage.iconURL,
+ content: filteredContent,
+ unfinished: false,
+ error: false,
+ user: userId,
+ };
+
+ const savedMessage = await saveMessage(req, newMessage, {
+ context: 'POST /api/messages/branch',
+ });
+
+ if (!savedMessage) {
+ return res.status(500).json({ error: 'Failed to save branch message' });
+ }
+
+ res.status(201).json(savedMessage);
+ } catch (error) {
+ logger.error('Error creating branch message:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
+});
+
router.post('/artifact/:messageId', async (req, res) => {
try {
const { messageId } = req.params;
diff --git a/api/server/routes/oauth.js b/api/server/routes/oauth.js
index 0b1252f636..f4bb5b6026 100644
--- a/api/server/routes/oauth.js
+++ b/api/server/routes/oauth.js
@@ -4,10 +4,9 @@ const passport = require('passport');
const { randomState } = require('openid-client');
const { logger } = require('@librechat/data-schemas');
const { ErrorTypes } = require('librechat-data-provider');
-const { isEnabled, createSetBalanceConfig } = require('@librechat/api');
-const { checkDomainAllowed, loginLimiter, logHeaders, checkBan } = require('~/server/middleware');
-const { syncUserEntraGroupMemberships } = require('~/server/services/PermissionService');
-const { setAuthTokens, setOpenIDAuthTokens } = require('~/server/services/AuthService');
+const { createSetBalanceConfig } = require('@librechat/api');
+const { checkDomainAllowed, loginLimiter, logHeaders } = require('~/server/middleware');
+const { createOAuthHandler } = require('~/server/controllers/auth/oauth');
const { getAppConfig } = require('~/server/services/Config');
const { Balance } = require('~/db/models');
@@ -26,36 +25,11 @@ const domains = {
router.use(logHeaders);
router.use(loginLimiter);
-const oauthHandler = async (req, res, next) => {
- try {
- if (res.headersSent) {
- return;
- }
-
- await checkBan(req, res);
- if (req.banned) {
- return;
- }
- if (
- req.user &&
- req.user.provider == 'openid' &&
- isEnabled(process.env.OPENID_REUSE_TOKENS) === true
- ) {
- await syncUserEntraGroupMemberships(req.user, req.user.tokenset.access_token);
- setOpenIDAuthTokens(req.user.tokenset, res, req.user._id.toString());
- } else {
- await setAuthTokens(req.user._id, res);
- }
- res.redirect(domains.client);
- } catch (err) {
- logger.error('Error in setting authentication tokens:', err);
- next(err);
- }
-};
+const oauthHandler = createOAuthHandler();
router.get('/error', (req, res) => {
/** A single error message is pushed by passport when authentication fails. */
- const errorMessage = req.session?.messages?.pop() || 'Unknown error';
+ const errorMessage = req.session?.messages?.pop() || 'Unknown OAuth error';
logger.error('Error in OAuth authentication:', {
message: errorMessage,
});
diff --git a/api/server/routes/plugins.js b/api/server/routes/plugins.js
deleted file mode 100644
index 00f3fca75b..0000000000
--- a/api/server/routes/plugins.js
+++ /dev/null
@@ -1,9 +0,0 @@
-const express = require('express');
-const { getAvailablePluginsController } = require('~/server/controllers/PluginController');
-const { requireJwtAuth } = require('~/server/middleware');
-
-const router = express.Router();
-
-router.get('/', requireJwtAuth, getAvailablePluginsController);
-
-module.exports = router;
diff --git a/api/server/routes/prompts.js b/api/server/routes/prompts.js
index c833719075..037bf04813 100644
--- a/api/server/routes/prompts.js
+++ b/api/server/routes/prompts.js
@@ -60,7 +60,7 @@ const checkGlobalPromptShare = generateCheckAccess({
permissionType: PermissionTypes.PROMPTS,
permissions: [Permissions.USE, Permissions.CREATE],
bodyProps: {
- [Permissions.SHARED_GLOBAL]: ['projectIds', 'removeProjectIds'],
+ [Permissions.SHARE]: ['projectIds', 'removeProjectIds'],
},
getRoleByName,
});
diff --git a/api/server/routes/prompts.test.js b/api/server/routes/prompts.test.js
index 1aeca1c93c..caeb90ddfb 100644
--- a/api/server/routes/prompts.test.js
+++ b/api/server/routes/prompts.test.js
@@ -159,7 +159,7 @@ async function setupTestData() {
case SystemRoles.USER:
return { permissions: { PROMPTS: { USE: true, CREATE: true } } };
case SystemRoles.ADMIN:
- return { permissions: { PROMPTS: { USE: true, CREATE: true, SHARED_GLOBAL: true } } };
+ return { permissions: { PROMPTS: { USE: true, CREATE: true, SHARE: true } } };
default:
return null;
}
diff --git a/api/server/routes/roles.js b/api/server/routes/roles.js
index f197417774..12e18c7624 100644
--- a/api/server/routes/roles.js
+++ b/api/server/routes/roles.js
@@ -6,8 +6,10 @@ const {
agentPermissionsSchema,
promptPermissionsSchema,
memoryPermissionsSchema,
+ mcpServersPermissionsSchema,
marketplacePermissionsSchema,
peoplePickerPermissionsSchema,
+ remoteAgentsPermissionsSchema,
} = require('librechat-data-provider');
const { checkAdmin, requireJwtAuth } = require('~/server/middleware');
const { updateRoleByName, getRoleByName } = require('~/models/Role');
@@ -40,11 +42,21 @@ const permissionConfigs = {
permissionType: PermissionTypes.PEOPLE_PICKER,
errorMessage: 'Invalid people picker permissions.',
},
+ 'mcp-servers': {
+ schema: mcpServersPermissionsSchema,
+ permissionType: PermissionTypes.MCP_SERVERS,
+ errorMessage: 'Invalid MCP servers permissions.',
+ },
marketplace: {
schema: marketplacePermissionsSchema,
permissionType: PermissionTypes.MARKETPLACE,
errorMessage: 'Invalid marketplace permissions.',
},
+ 'remote-agents': {
+ schema: remoteAgentsPermissionsSchema,
+ permissionType: PermissionTypes.REMOTE_AGENTS,
+ errorMessage: 'Invalid remote agents permissions.',
+ },
};
/**
@@ -142,10 +154,22 @@ router.put('/:roleName/memories', checkAdmin, createPermissionUpdateHandler('mem
*/
router.put('/:roleName/people-picker', checkAdmin, createPermissionUpdateHandler('people-picker'));
+/**
+ * PUT /api/roles/:roleName/mcp-servers
+ * Update MCP servers permissions for a specific role
+ */
+router.put('/:roleName/mcp-servers', checkAdmin, createPermissionUpdateHandler('mcp-servers'));
+
/**
* PUT /api/roles/:roleName/marketplace
* Update marketplace permissions for a specific role
*/
router.put('/:roleName/marketplace', checkAdmin, createPermissionUpdateHandler('marketplace'));
+/**
+ * PUT /api/roles/:roleName/remote-agents
+ * Update remote agents (API) permissions for a specific role
+ */
+router.put('/:roleName/remote-agents', checkAdmin, createPermissionUpdateHandler('remote-agents'));
+
module.exports = router;
diff --git a/api/server/routes/settings.js b/api/server/routes/settings.js
new file mode 100644
index 0000000000..22162fed4e
--- /dev/null
+++ b/api/server/routes/settings.js
@@ -0,0 +1,13 @@
+const express = require('express');
+const {
+ updateFavoritesController,
+ getFavoritesController,
+} = require('~/server/controllers/FavoritesController');
+const { requireJwtAuth } = require('~/server/middleware');
+
+const router = express.Router();
+
+router.get('/favorites', requireJwtAuth, getFavoritesController);
+router.post('/favorites', requireJwtAuth, updateFavoritesController);
+
+module.exports = router;
diff --git a/api/server/routes/user.js b/api/server/routes/user.js
index 7efab9d026..1858be22be 100644
--- a/api/server/routes/user.js
+++ b/api/server/routes/user.js
@@ -15,8 +15,11 @@ const {
requireJwtAuth,
} = require('~/server/middleware');
+const settings = require('./settings');
+
const router = express.Router();
+router.use('/settings', settings);
router.get('/', requireJwtAuth, getUserController);
router.get('/terms', requireJwtAuth, getTermsStatusController);
router.post('/terms/accept', requireJwtAuth, acceptTermsController);
diff --git a/api/server/services/ActionService.js b/api/server/services/ActionService.js
index b9555a752c..5e96726a46 100644
--- a/api/server/services/ActionService.js
+++ b/api/server/services/ActionService.js
@@ -1,14 +1,14 @@
const jwt = require('jsonwebtoken');
const { nanoid } = require('nanoid');
const { tool } = require('@langchain/core/tools');
-const { logger } = require('@librechat/data-schemas');
const { GraphEvents, sleep } = require('@librechat/agents');
+const { logger, encryptV2, decryptV2 } = require('@librechat/data-schemas');
const {
sendEvent,
- encryptV2,
- decryptV2,
logAxiosError,
refreshAccessToken,
+ GenerationJobManager,
+ createSSRFSafeAgents,
} = require('@librechat/api');
const {
Time,
@@ -133,6 +133,8 @@ async function loadActionSets(searchParams) {
* @param {string | undefined} [params.description] - The description for the tool.
* @param {import('zod').ZodTypeAny | undefined} [params.zodSchema] - The Zod schema for tool input validation/definition
* @param {{ oauth_client_id?: string; oauth_client_secret?: string; }} params.encrypted - The encrypted values for the action.
+ * @param {string | null} [params.streamId] - The stream ID for resumable streams.
+ * @param {boolean} [params.useSSRFProtection] - When true, uses SSRF-safe HTTP agents that validate resolved IPs at connect time.
* @returns { Promise unknown}> } An object with `_call` method to execute the tool input.
*/
async function createActionTool({
@@ -144,7 +146,10 @@ async function createActionTool({
name,
description,
encrypted,
+ streamId = null,
+ useSSRFProtection = false,
}) {
+ const ssrfAgents = useSSRFProtection ? createSSRFSafeAgents() : undefined;
/** @type {(toolInput: Object | string, config: GraphRunnableConfig) => Promise} */
const _call = async (toolInput, config) => {
try {
@@ -198,7 +203,12 @@ async function createActionTool({
`${identifier}:oauth_login:${config.metadata.thread_id}:${config.metadata.run_id}`,
'oauth_login',
async () => {
- sendEvent(res, { event: GraphEvents.ON_RUN_STEP_DELTA, data });
+ const eventData = { event: GraphEvents.ON_RUN_STEP_DELTA, data };
+ if (streamId) {
+ await GenerationJobManager.emitChunk(streamId, eventData);
+ } else {
+ sendEvent(res, eventData);
+ }
logger.debug('Sent OAuth login request to client', { action_id, identifier });
return true;
},
@@ -223,7 +233,12 @@ async function createActionTool({
logger.debug('Received OAuth Authorization response', { action_id, identifier });
data.delta.auth = undefined;
data.delta.expires_at = undefined;
- sendEvent(res, { event: GraphEvents.ON_RUN_STEP_DELTA, data });
+ const successEventData = { event: GraphEvents.ON_RUN_STEP_DELTA, data };
+ if (streamId) {
+ await GenerationJobManager.emitChunk(streamId, successEventData);
+ } else {
+ sendEvent(res, successEventData);
+ }
await sleep(3000);
metadata.oauth_access_token = result.access_token;
metadata.oauth_refresh_token = result.refresh_token;
@@ -313,7 +328,7 @@ async function createActionTool({
}
}
- const response = await preparedExecutor.execute();
+ const response = await preparedExecutor.execute(ssrfAgents);
if (typeof response.data === 'object') {
return JSON.stringify(response.data);
diff --git a/api/server/services/Artifacts/update.js b/api/server/services/Artifacts/update.js
index d068593f8c..be1644b11c 100644
--- a/api/server/services/Artifacts/update.js
+++ b/api/server/services/Artifacts/update.js
@@ -73,15 +73,25 @@ const replaceArtifactContent = (originalText, artifact, original, updated) => {
return null;
}
- // Check if there are code blocks
- const codeBlockStart = artifactContent.indexOf('```\n', contentStart);
+ // Check if there are code blocks - handle both ```\n and ```lang\n formats
+ let codeBlockStart = artifactContent.indexOf('```', contentStart);
const codeBlockEnd = artifactContent.lastIndexOf('\n```', contentEnd);
+ // If we found opening backticks, find the actual newline (skipping any language identifier)
+ if (codeBlockStart !== -1) {
+ const newlineAfterBackticks = artifactContent.indexOf('\n', codeBlockStart);
+ if (newlineAfterBackticks !== -1 && newlineAfterBackticks < contentEnd) {
+ codeBlockStart = newlineAfterBackticks;
+ } else {
+ codeBlockStart = -1;
+ }
+ }
+
// Determine where to look for the original content
let searchStart, searchEnd;
if (codeBlockStart !== -1) {
- // Code block starts
- searchStart = codeBlockStart + 4; // after ```\n
+ // Code block starts - searchStart is right after the newline following ```[lang]
+ searchStart = codeBlockStart + 1; // after the newline
if (codeBlockEnd !== -1 && codeBlockEnd > codeBlockStart) {
// Code block has proper ending
diff --git a/api/server/services/Artifacts/update.spec.js b/api/server/services/Artifacts/update.spec.js
index 2a3e0bbe39..39a4f02863 100644
--- a/api/server/services/Artifacts/update.spec.js
+++ b/api/server/services/Artifacts/update.spec.js
@@ -494,5 +494,268 @@ ${original}`;
/```\n {2}function test\(\) \{\n {4}return \{\n {6}value: 100\n {4}\};\n {2}\}\n```/,
);
});
+
+ test('should handle code blocks with language identifiers (```svg, ```html, etc.)', () => {
+ const svgContent = `
+
+
+ `;
+
+ /** Artifact with language identifier in code block */
+ const artifactText = `${ARTIFACT_START}{identifier="test-svg" type="image/svg+xml" title="Test SVG"}
+\`\`\`svg
+${svgContent}
+\`\`\`
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+ expect(artifacts).toHaveLength(1);
+
+ const updatedSvg = svgContent.replace('#FFFFFF', '#131313');
+ const result = replaceArtifactContent(artifactText, artifacts[0], svgContent, updatedSvg);
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('#131313');
+ expect(result).not.toContain('#FFFFFF');
+ expect(result).toMatch(/```svg\n/);
+ });
+
+ test('should handle code blocks with complex language identifiers', () => {
+ const htmlContent = `
+
+Test
+Hello
+`;
+
+ const artifactText = `${ARTIFACT_START}{identifier="test-html" type="text/html" title="Test HTML"}
+\`\`\`html
+${htmlContent}
+\`\`\`
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+
+ const updatedHtml = htmlContent.replace('Hello', 'Updated');
+ const result = replaceArtifactContent(artifactText, artifacts[0], htmlContent, updatedHtml);
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('Updated');
+ expect(result).toMatch(/```html\n/);
+ });
+ });
+
+ describe('code block edge cases', () => {
+ test('should handle code block without language identifier (```\\n)', () => {
+ const content = 'const x = 1;\nconst y = 2;';
+ const artifactText = `${ARTIFACT_START}{identifier="test" type="text/plain" title="Test"}
+\`\`\`
+${content}
+\`\`\`
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+
+ const result = replaceArtifactContent(artifactText, artifacts[0], content, 'updated');
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('updated');
+ expect(result).toMatch(/```\nupdated\n```/);
+ });
+
+ test('should handle various language identifiers', () => {
+ const languages = [
+ 'javascript',
+ 'typescript',
+ 'python',
+ 'jsx',
+ 'tsx',
+ 'css',
+ 'json',
+ 'xml',
+ 'markdown',
+ 'md',
+ ];
+
+ for (const lang of languages) {
+ const content = `test content for ${lang}`;
+ const artifactText = `${ARTIFACT_START}{identifier="test-${lang}" type="text/plain" title="Test"}
+\`\`\`${lang}
+${content}
+\`\`\`
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+ expect(artifacts).toHaveLength(1);
+
+ const result = replaceArtifactContent(artifactText, artifacts[0], content, 'updated');
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('updated');
+ expect(result).toMatch(new RegExp(`\`\`\`${lang}\\n`));
+ }
+ });
+
+ test('should handle single character language identifier', () => {
+ const content = 'single char lang';
+ const artifactText = `${ARTIFACT_START}{identifier="test" type="text/plain" title="Test"}
+\`\`\`r
+${content}
+\`\`\`
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+
+ const result = replaceArtifactContent(artifactText, artifacts[0], content, 'updated');
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('updated');
+ expect(result).toMatch(/```r\n/);
+ });
+
+ test('should handle code block with content that looks like code fence', () => {
+ const content = 'Line 1\nSome text with ``` backticks in middle\nLine 3';
+ const artifactText = `${ARTIFACT_START}{identifier="test" type="text/plain" title="Test"}
+\`\`\`text
+${content}
+\`\`\`
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+
+ const result = replaceArtifactContent(artifactText, artifacts[0], content, 'updated');
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('updated');
+ });
+
+ test('should handle code block with trailing whitespace in language line', () => {
+ const content = 'whitespace test';
+ /** Note: trailing spaces after 'python' */
+ const artifactText = `${ARTIFACT_START}{identifier="test" type="text/plain" title="Test"}
+\`\`\`python
+${content}
+\`\`\`
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+
+ const result = replaceArtifactContent(artifactText, artifacts[0], content, 'updated');
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('updated');
+ });
+
+ test('should handle react/jsx content with complex syntax', () => {
+ const jsxContent = `function App() {
+ const [count, setCount] = useState(0);
+ return (
+
+
Count: {count}
+ setCount(c => c + 1)}>
+ Increment
+
+
+ );
+}`;
+
+ const artifactText = `${ARTIFACT_START}{identifier="react-app" type="application/vnd.react" title="React App"}
+\`\`\`jsx
+${jsxContent}
+\`\`\`
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+
+ const updatedJsx = jsxContent.replace('Increment', 'Click me');
+ const result = replaceArtifactContent(artifactText, artifacts[0], jsxContent, updatedJsx);
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('Click me');
+ expect(result).not.toContain('Increment');
+ expect(result).toMatch(/```jsx\n/);
+ });
+
+ test('should handle mermaid diagram content', () => {
+ const mermaidContent = `graph TD
+ A[Start] --> B{Is it?}
+ B -->|Yes| C[OK]
+ B -->|No| D[End]`;
+
+ const artifactText = `${ARTIFACT_START}{identifier="diagram" type="application/vnd.mermaid" title="Flow"}
+\`\`\`mermaid
+${mermaidContent}
+\`\`\`
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+
+ const updatedMermaid = mermaidContent.replace('Start', 'Begin');
+ const result = replaceArtifactContent(
+ artifactText,
+ artifacts[0],
+ mermaidContent,
+ updatedMermaid,
+ );
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('Begin');
+ expect(result).toMatch(/```mermaid\n/);
+ });
+
+ test('should handle artifact without code block (plain text)', () => {
+ const content = 'Just plain text without code fences';
+ const artifactText = `${ARTIFACT_START}{identifier="plain" type="text/plain" title="Plain"}
+${content}
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+
+ const result = replaceArtifactContent(
+ artifactText,
+ artifacts[0],
+ content,
+ 'updated plain text',
+ );
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('updated plain text');
+ expect(result).not.toContain('```');
+ });
+
+ test('should handle multiline content with various newline patterns', () => {
+ const content = `Line 1
+Line 2
+
+Line 4 after empty line
+ Indented line
+ Double indented`;
+
+ const artifactText = `${ARTIFACT_START}{identifier="test" type="text/plain" title="Test"}
+\`\`\`
+${content}
+\`\`\`
+${ARTIFACT_END}`;
+
+ const message = { text: artifactText };
+ const artifacts = findAllArtifacts(message);
+
+ const updated = content.replace('Line 1', 'First Line');
+ const result = replaceArtifactContent(artifactText, artifacts[0], content, updated);
+
+ expect(result).not.toBeNull();
+ expect(result).toContain('First Line');
+ expect(result).toContain(' Indented line');
+ expect(result).toContain(' Double indented');
+ });
});
});
diff --git a/api/server/services/AssistantService.js b/api/server/services/AssistantService.js
index 892afb7002..a7018f715b 100644
--- a/api/server/services/AssistantService.js
+++ b/api/server/services/AssistantService.js
@@ -23,7 +23,7 @@ const { TextStream } = require('~/app/clients');
* Sorts, processes, and flattens messages to a single string.
*
* @param {Object} params - Params for creating the onTextProgress function.
- * @param {OpenAIClient} params.openai - The OpenAI client instance.
+ * @param {OpenAI} params.openai - The OpenAI SDK client instance.
* @param {string} params.conversationId - The current conversation ID.
* @param {string} params.userMessageId - The user message ID; response's `parentMessageId`.
* @param {string} params.messageId - The response message ID.
@@ -74,7 +74,7 @@ async function createOnTextProgress({
* Retrieves the response from an OpenAI run.
*
* @param {Object} params - The parameters for getting the response.
- * @param {OpenAIClient} params.openai - The OpenAI client instance.
+ * @param {OpenAI} params.openai - The OpenAI SDK client instance.
* @param {string} params.run_id - The ID of the run to get the response for.
* @param {string} params.thread_id - The ID of the thread associated with the run.
* @return {Promise}
@@ -162,7 +162,7 @@ function hasToolCallChanged(previousCall, currentCall) {
* Creates a handler function for steps in progress, specifically for
* processing messages and managing seen completed messages.
*
- * @param {OpenAIClient} openai - The OpenAI client instance.
+ * @param {OpenAI} openai - The OpenAI SDK client instance.
* @param {string} thread_id - The ID of the thread the run is in.
* @param {ThreadMessage[]} messages - The accumulated messages for the run.
* @return {InProgressFunction} a function to handle steps in progress.
@@ -334,7 +334,7 @@ function createInProgressHandler(openai, thread_id, messages) {
* Initializes a RunManager with handlers, then invokes waitForRun to monitor and manage an OpenAI run.
*
* @param {Object} params - The parameters for managing and monitoring the run.
- * @param {OpenAIClient} params.openai - The OpenAI client instance.
+ * @param {OpenAI} params.openai - The OpenAI SDK client instance.
* @param {string} params.run_id - The ID of the run to manage and monitor.
* @param {string} params.thread_id - The ID of the thread associated with the run.
* @param {RunStep[]} params.accumulatedSteps - The accumulated steps for the run.
diff --git a/api/server/services/AuthService.js b/api/server/services/AuthService.js
index 72bda67322..ef50a365b9 100644
--- a/api/server/services/AuthService.js
+++ b/api/server/services/AuthService.js
@@ -1,9 +1,19 @@
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { webcrypto } = require('node:crypto');
-const { logger } = require('@librechat/data-schemas');
-const { isEnabled, checkEmailConfig, isEmailDomainAllowed } = require('@librechat/api');
+const {
+ logger,
+ DEFAULT_SESSION_EXPIRY,
+ DEFAULT_REFRESH_TOKEN_EXPIRY,
+} = require('@librechat/data-schemas');
const { ErrorTypes, SystemRoles, errorsToString } = require('librechat-data-provider');
+const {
+ math,
+ isEnabled,
+ checkEmailConfig,
+ isEmailDomainAllowed,
+ shouldUseSecureCookie,
+} = require('@librechat/api');
const {
findUser,
findToken,
@@ -29,7 +39,6 @@ const domains = {
server: process.env.DOMAIN_SERVER,
};
-const isProduction = process.env.NODE_ENV === 'production';
const genericVerificationMessage = 'Please check your email to verify your email address.';
/**
@@ -369,30 +378,32 @@ const setAuthTokens = async (userId, res, _session = null) => {
let session = _session;
let refreshToken;
let refreshTokenExpires;
+ const expiresIn = math(process.env.REFRESH_TOKEN_EXPIRY, DEFAULT_REFRESH_TOKEN_EXPIRY);
if (session && session._id && session.expiration != null) {
refreshTokenExpires = session.expiration.getTime();
refreshToken = await generateRefreshToken(session);
} else {
- const result = await createSession(userId);
+ const result = await createSession(userId, { expiresIn });
session = result.session;
refreshToken = result.refreshToken;
refreshTokenExpires = session.expiration.getTime();
}
const user = await getUserById(userId);
- const token = await generateToken(user);
+ const sessionExpiry = math(process.env.SESSION_EXPIRY, DEFAULT_SESSION_EXPIRY);
+ const token = await generateToken(user, sessionExpiry);
res.cookie('refreshToken', refreshToken, {
expires: new Date(refreshTokenExpires),
httpOnly: true,
- secure: isProduction,
+ secure: shouldUseSecureCookie(),
sameSite: 'strict',
});
res.cookie('token_provider', 'librechat', {
expires: new Date(refreshTokenExpires),
httpOnly: true,
- secure: isProduction,
+ secure: shouldUseSecureCookie(),
sameSite: 'strict',
});
return token;
@@ -405,23 +416,26 @@ const setAuthTokens = async (userId, res, _session = null) => {
/**
* @function setOpenIDAuthTokens
* Set OpenID Authentication Tokens
- * //type tokenset from openid-client
+ * Stores tokens server-side in express-session to avoid large cookie sizes
+ * that can exceed HTTP/2 header limits (especially for users with many group memberships).
+ *
* @param {import('openid-client').TokenEndpointResponse & import('openid-client').TokenEndpointResponseHelpers} tokenset
* - The tokenset object containing access and refresh tokens
+ * @param {Object} req - request object (for session access)
* @param {Object} res - response object
* @param {string} [userId] - Optional MongoDB user ID for image path validation
- * @returns {String} - access token
+ * @returns {String} - id_token (preferred) or access_token as the app auth token
*/
-const setOpenIDAuthTokens = (tokenset, res, userId, existingRefreshToken) => {
+const setOpenIDAuthTokens = (tokenset, req, res, userId, existingRefreshToken) => {
try {
if (!tokenset) {
logger.error('[setOpenIDAuthTokens] No tokenset found in request');
return;
}
- const { REFRESH_TOKEN_EXPIRY } = process.env ?? {};
- const expiryInMilliseconds = REFRESH_TOKEN_EXPIRY
- ? eval(REFRESH_TOKEN_EXPIRY)
- : 1000 * 60 * 60 * 24 * 7; // 7 days default
+ const expiryInMilliseconds = math(
+ process.env.REFRESH_TOKEN_EXPIRY,
+ DEFAULT_REFRESH_TOKEN_EXPIRY,
+ );
const expirationDate = new Date(Date.now() + expiryInMilliseconds);
if (tokenset == null) {
logger.error('[setOpenIDAuthTokens] No tokenset found in request');
@@ -439,22 +453,62 @@ const setOpenIDAuthTokens = (tokenset, res, userId, existingRefreshToken) => {
return;
}
+ /**
+ * Use id_token as the app authentication token (Bearer token for JWKS validation).
+ * The id_token is always a standard JWT signed by the IdP's JWKS keys with the app's
+ * client_id as audience. The access_token may be opaque or intended for a different
+ * audience (e.g., Microsoft Graph API), which fails JWKS validation.
+ * Falls back to access_token for providers where id_token is not available.
+ */
+ const appAuthToken = tokenset.id_token || tokenset.access_token;
+
+ /**
+ * Always set refresh token cookie so it survives express session expiry.
+ * The session cookie maxAge (SESSION_EXPIRY, default 15 min) is typically shorter
+ * than the OIDC token lifetime (~1 hour). Without this cookie fallback, the refresh
+ * token stored only in the session is lost when the session expires, causing the user
+ * to be signed out on the next token refresh attempt.
+ * The refresh token is small (opaque string) so it doesn't hit the HTTP/2 header
+ * size limits that motivated session storage for the larger access_token/id_token.
+ */
res.cookie('refreshToken', refreshToken, {
expires: expirationDate,
httpOnly: true,
- secure: isProduction,
- sameSite: 'strict',
- });
- res.cookie('openid_access_token', tokenset.access_token, {
- expires: expirationDate,
- httpOnly: true,
- secure: isProduction,
+ secure: shouldUseSecureCookie(),
sameSite: 'strict',
});
+
+ /** Store tokens server-side in session to avoid large cookies */
+ if (req.session) {
+ req.session.openidTokens = {
+ accessToken: tokenset.access_token,
+ idToken: tokenset.id_token,
+ refreshToken: refreshToken,
+ expiresAt: expirationDate.getTime(),
+ };
+ } else {
+ logger.warn('[setOpenIDAuthTokens] No session available, falling back to cookies');
+ res.cookie('openid_access_token', tokenset.access_token, {
+ expires: expirationDate,
+ httpOnly: true,
+ secure: shouldUseSecureCookie(),
+ sameSite: 'strict',
+ });
+ if (tokenset.id_token) {
+ res.cookie('openid_id_token', tokenset.id_token, {
+ expires: expirationDate,
+ httpOnly: true,
+ secure: shouldUseSecureCookie(),
+ sameSite: 'strict',
+ });
+ }
+ }
+
+ /** Small cookie to indicate token provider (required for auth middleware) */
res.cookie('token_provider', 'openid', {
expires: expirationDate,
httpOnly: true,
- secure: isProduction,
+ secure: shouldUseSecureCookie(),
sameSite: 'strict',
});
if (userId && isEnabled(process.env.OPENID_REUSE_TOKENS)) {
@@ -465,11 +519,11 @@ const setOpenIDAuthTokens = (tokenset, res, userId, existingRefreshToken) => {
res.cookie('openid_user_id', signedUserId, {
expires: expirationDate,
httpOnly: true,
- secure: isProduction,
+ secure: shouldUseSecureCookie(),
sameSite: 'strict',
});
}
- return tokenset.access_token;
+ return appAuthToken;
} catch (error) {
logger.error('[setOpenIDAuthTokens] Error in setting authentication tokens:', error);
throw error;
diff --git a/api/server/services/AuthService.spec.js b/api/server/services/AuthService.spec.js
new file mode 100644
index 0000000000..da78f8d775
--- /dev/null
+++ b/api/server/services/AuthService.spec.js
@@ -0,0 +1,269 @@
+jest.mock('@librechat/data-schemas', () => ({
+ logger: { info: jest.fn(), warn: jest.fn(), debug: jest.fn(), error: jest.fn() },
+ DEFAULT_SESSION_EXPIRY: 900000,
+ DEFAULT_REFRESH_TOKEN_EXPIRY: 604800000,
+}));
+jest.mock('librechat-data-provider', () => ({
+ ErrorTypes: {},
+ SystemRoles: { USER: 'USER', ADMIN: 'ADMIN' },
+ errorsToString: jest.fn(),
+}));
+jest.mock('@librechat/api', () => ({
+ isEnabled: jest.fn((val) => val === 'true' || val === true),
+ checkEmailConfig: jest.fn(),
+ isEmailDomainAllowed: jest.fn(),
+ math: jest.fn((val, fallback) => (val ? Number(val) : fallback)),
+ shouldUseSecureCookie: jest.fn(() => false),
+}));
+jest.mock('~/models', () => ({
+ findUser: jest.fn(),
+ findToken: jest.fn(),
+ createUser: jest.fn(),
+ updateUser: jest.fn(),
+ countUsers: jest.fn(),
+ getUserById: jest.fn(),
+ findSession: jest.fn(),
+ createToken: jest.fn(),
+ deleteTokens: jest.fn(),
+ deleteSession: jest.fn(),
+ createSession: jest.fn(),
+ generateToken: jest.fn(),
+ deleteUserById: jest.fn(),
+ generateRefreshToken: jest.fn(),
+}));
+jest.mock('~/strategies/validators', () => ({ registerSchema: { parse: jest.fn() } }));
+jest.mock('~/server/services/Config', () => ({ getAppConfig: jest.fn() }));
+jest.mock('~/server/utils', () => ({ sendEmail: jest.fn() }));
+
+const { shouldUseSecureCookie } = require('@librechat/api');
+const { setOpenIDAuthTokens } = require('./AuthService');
+
+/** Helper to build a mock Express response */
+function mockResponse() {
+ const cookies = {};
+ const res = {
+ cookie: jest.fn((name, value, options) => {
+ cookies[name] = { value, options };
+ }),
+ _cookies: cookies,
+ };
+ return res;
+}
+
+/** Helper to build a mock Express request with session */
+function mockRequest(sessionData = {}) {
+ return {
+ session: { openidTokens: null, ...sessionData },
+ };
+}
+
+describe('setOpenIDAuthTokens', () => {
+ const env = process.env;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ process.env = {
+ ...env,
+ JWT_REFRESH_SECRET: 'test-refresh-secret',
+ OPENID_REUSE_TOKENS: 'true',
+ };
+ });
+
+ afterAll(() => {
+ process.env = env;
+ });
+
+ describe('token selection (id_token vs access_token)', () => {
+ it('should return id_token when both id_token and access_token are present', () => {
+ const tokenset = {
+ id_token: 'the-id-token',
+ access_token: 'the-access-token',
+ refresh_token: 'the-refresh-token',
+ };
+ const req = mockRequest();
+ const res = mockResponse();
+
+ const result = setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+ expect(result).toBe('the-id-token');
+ });
+
+ it('should return access_token when id_token is not available', () => {
+ const tokenset = {
+ access_token: 'the-access-token',
+ refresh_token: 'the-refresh-token',
+ };
+ const req = mockRequest();
+ const res = mockResponse();
+
+ const result = setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+ expect(result).toBe('the-access-token');
+ });
+
+ it('should return access_token when id_token is undefined', () => {
+ const tokenset = {
+ id_token: undefined,
+ access_token: 'the-access-token',
+ refresh_token: 'the-refresh-token',
+ };
+ const req = mockRequest();
+ const res = mockResponse();
+
+ const result = setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+ expect(result).toBe('the-access-token');
+ });
+
+ it('should return access_token when id_token is null', () => {
+ const tokenset = {
+ id_token: null,
+ access_token: 'the-access-token',
+ refresh_token: 'the-refresh-token',
+ };
+ const req = mockRequest();
+ const res = mockResponse();
+
+ const result = setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+ expect(result).toBe('the-access-token');
+ });
+
+ it('should return id_token even when id_token and access_token differ', () => {
+ const tokenset = {
+ id_token: 'id-token-jwt-signed-by-idp',
+ access_token: 'opaque-graph-api-token',
+ refresh_token: 'refresh-token',
+ };
+ const req = mockRequest();
+ const res = mockResponse();
+
+ const result = setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+ expect(result).toBe('id-token-jwt-signed-by-idp');
+ expect(result).not.toBe('opaque-graph-api-token');
+ });
+ });
+
+ describe('session token storage', () => {
+ it('should store the original access_token in session (not id_token)', () => {
+ const tokenset = {
+ id_token: 'the-id-token',
+ access_token: 'the-access-token',
+ refresh_token: 'the-refresh-token',
+ };
+ const req = mockRequest();
+ const res = mockResponse();
+
+ setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+
+ expect(req.session.openidTokens.accessToken).toBe('the-access-token');
+ expect(req.session.openidTokens.refreshToken).toBe('the-refresh-token');
+ });
+ });
+
+ describe('cookie secure flag', () => {
+ it('should call shouldUseSecureCookie for every cookie set', () => {
+ const tokenset = {
+ id_token: 'the-id-token',
+ access_token: 'the-access-token',
+ refresh_token: 'the-refresh-token',
+ };
+ const req = mockRequest();
+ const res = mockResponse();
+
+ setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+
+ // token_provider + openid_user_id (session path, so no refreshToken/openid_access_token cookies)
+ const secureCalls = shouldUseSecureCookie.mock.calls.length;
+ expect(secureCalls).toBeGreaterThanOrEqual(2);
+
+ // Verify all cookies use the result of shouldUseSecureCookie
+ for (const [, cookie] of Object.entries(res._cookies)) {
+ expect(cookie.options.secure).toBe(false);
+ }
+ });
+
+ it('should set secure: true when shouldUseSecureCookie returns true', () => {
+ shouldUseSecureCookie.mockReturnValue(true);
+
+ const tokenset = {
+ id_token: 'the-id-token',
+ access_token: 'the-access-token',
+ refresh_token: 'the-refresh-token',
+ };
+ const req = mockRequest();
+ const res = mockResponse();
+
+ setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+
+ for (const [, cookie] of Object.entries(res._cookies)) {
+ expect(cookie.options.secure).toBe(true);
+ }
+ });
+
+ it('should use shouldUseSecureCookie for cookie fallback path (no session)', () => {
+ shouldUseSecureCookie.mockReturnValue(false);
+
+ const tokenset = {
+ id_token: 'the-id-token',
+ access_token: 'the-access-token',
+ refresh_token: 'the-refresh-token',
+ };
+ const req = { session: null };
+ const res = mockResponse();
+
+ setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+
+ // In the cookie fallback path, we get: refreshToken, openid_access_token, token_provider, openid_user_id
+ expect(res.cookie).toHaveBeenCalledWith(
+ 'refreshToken',
+ expect.any(String),
+ expect.objectContaining({ secure: false }),
+ );
+ expect(res.cookie).toHaveBeenCalledWith(
+ 'openid_access_token',
+ expect.any(String),
+ expect.objectContaining({ secure: false }),
+ );
+ expect(res.cookie).toHaveBeenCalledWith(
+ 'token_provider',
+ 'openid',
+ expect.objectContaining({ secure: false }),
+ );
+ });
+ });
+
+ describe('edge cases', () => {
+ it('should return undefined when tokenset is null', () => {
+ const req = mockRequest();
+ const res = mockResponse();
+ const result = setOpenIDAuthTokens(null, req, res, 'user-123');
+ expect(result).toBeUndefined();
+ });
+
+ it('should return undefined when access_token is missing', () => {
+ const tokenset = { refresh_token: 'refresh' };
+ const req = mockRequest();
+ const res = mockResponse();
+ const result = setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+ expect(result).toBeUndefined();
+ });
+
+ it('should return undefined when no refresh token is available', () => {
+ const tokenset = { access_token: 'access', id_token: 'id' };
+ const req = mockRequest();
+ const res = mockResponse();
+ const result = setOpenIDAuthTokens(tokenset, req, res, 'user-123');
+ expect(result).toBeUndefined();
+ });
+
+ it('should use existingRefreshToken when tokenset has no refresh_token', () => {
+ const tokenset = {
+ id_token: 'the-id-token',
+ access_token: 'the-access-token',
+ };
+ const req = mockRequest();
+ const res = mockResponse();
+
+ const result = setOpenIDAuthTokens(tokenset, req, res, 'user-123', 'existing-refresh');
+ expect(result).toBe('the-id-token');
+ expect(req.session.openidTokens.refreshToken).toBe('existing-refresh');
+ });
+ });
+});
diff --git a/api/server/services/Config/EndpointService.js b/api/server/services/Config/EndpointService.js
index d8277dd67f..b10c0d2890 100644
--- a/api/server/services/Config/EndpointService.js
+++ b/api/server/services/Config/EndpointService.js
@@ -1,4 +1,4 @@
-const { isUserProvided } = require('@librechat/api');
+const { isUserProvided, isEnabled } = require('@librechat/api');
const { EModelEndpoint } = require('librechat-data-provider');
const { generateConfig } = require('~/server/utils/handleText');
@@ -8,8 +8,6 @@ const {
ASSISTANTS_API_KEY: assistantsApiKey,
AZURE_API_KEY: azureOpenAIApiKey,
ANTHROPIC_API_KEY: anthropicApiKey,
- CHATGPT_TOKEN: chatGPTToken,
- PLUGINS_USE_AZURE,
GOOGLE_KEY: googleKey,
OPENAI_REVERSE_PROXY,
AZURE_OPENAI_BASEURL,
@@ -17,21 +15,17 @@ const {
AZURE_ASSISTANTS_BASE_URL,
} = process.env ?? {};
-const useAzurePlugins = !!PLUGINS_USE_AZURE;
-
-const userProvidedOpenAI = useAzurePlugins
- ? isUserProvided(azureOpenAIApiKey)
- : isUserProvided(openAIApiKey);
+const userProvidedOpenAI = isUserProvided(openAIApiKey);
module.exports = {
config: {
+ googleKey,
openAIApiKey,
azureOpenAIApiKey,
- useAzurePlugins,
userProvidedOpenAI,
- googleKey,
- [EModelEndpoint.anthropic]: generateConfig(anthropicApiKey),
- [EModelEndpoint.chatGPTBrowser]: generateConfig(chatGPTToken),
+ [EModelEndpoint.anthropic]: generateConfig(
+ anthropicApiKey || isEnabled(process.env.ANTHROPIC_USE_VERTEX),
+ ),
[EModelEndpoint.openAI]: generateConfig(openAIApiKey, OPENAI_REVERSE_PROXY),
[EModelEndpoint.azureOpenAI]: generateConfig(azureOpenAIApiKey, AZURE_OPENAI_BASEURL),
[EModelEndpoint.assistants]: generateConfig(
diff --git a/api/server/services/Config/__tests__/getCachedTools.spec.js b/api/server/services/Config/__tests__/getCachedTools.spec.js
index 48ab6e0737..38d488ed38 100644
--- a/api/server/services/Config/__tests__/getCachedTools.spec.js
+++ b/api/server/services/Config/__tests__/getCachedTools.spec.js
@@ -1,10 +1,92 @@
-const { ToolCacheKeys } = require('../getCachedTools');
+const { CacheKeys } = require('librechat-data-provider');
+
+jest.mock('~/cache/getLogStores');
+const getLogStores = require('~/cache/getLogStores');
+
+const mockCache = { get: jest.fn(), set: jest.fn(), delete: jest.fn() };
+getLogStores.mockReturnValue(mockCache);
+
+const {
+ ToolCacheKeys,
+ getCachedTools,
+ setCachedTools,
+ getMCPServerTools,
+ invalidateCachedTools,
+} = require('../getCachedTools');
+
+describe('getCachedTools', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ getLogStores.mockReturnValue(mockCache);
+ });
-describe('getCachedTools - Cache Isolation Security', () => {
describe('ToolCacheKeys.MCP_SERVER', () => {
it('should generate cache keys that include userId', () => {
const key = ToolCacheKeys.MCP_SERVER('user123', 'github');
expect(key).toBe('tools:mcp:user123:github');
});
});
+
+ describe('TOOL_CACHE namespace usage', () => {
+ it('getCachedTools should use TOOL_CACHE namespace', async () => {
+ mockCache.get.mockResolvedValue(null);
+ await getCachedTools();
+ expect(getLogStores).toHaveBeenCalledWith(CacheKeys.TOOL_CACHE);
+ });
+
+ it('getCachedTools with MCP server options should use TOOL_CACHE namespace', async () => {
+ mockCache.get.mockResolvedValue({ tool1: {} });
+ await getCachedTools({ userId: 'user1', serverName: 'github' });
+ expect(getLogStores).toHaveBeenCalledWith(CacheKeys.TOOL_CACHE);
+ expect(mockCache.get).toHaveBeenCalledWith(ToolCacheKeys.MCP_SERVER('user1', 'github'));
+ });
+
+ it('setCachedTools should use TOOL_CACHE namespace', async () => {
+ mockCache.set.mockResolvedValue(true);
+ const tools = { tool1: { type: 'function' } };
+ await setCachedTools(tools);
+ expect(getLogStores).toHaveBeenCalledWith(CacheKeys.TOOL_CACHE);
+ expect(mockCache.set).toHaveBeenCalledWith(ToolCacheKeys.GLOBAL, tools, expect.any(Number));
+ });
+
+ it('setCachedTools with MCP server options should use TOOL_CACHE namespace', async () => {
+ mockCache.set.mockResolvedValue(true);
+ const tools = { tool1: { type: 'function' } };
+ await setCachedTools(tools, { userId: 'user1', serverName: 'github' });
+ expect(getLogStores).toHaveBeenCalledWith(CacheKeys.TOOL_CACHE);
+ expect(mockCache.set).toHaveBeenCalledWith(
+ ToolCacheKeys.MCP_SERVER('user1', 'github'),
+ tools,
+ expect.any(Number),
+ );
+ });
+
+ it('invalidateCachedTools should use TOOL_CACHE namespace', async () => {
+ mockCache.delete.mockResolvedValue(true);
+ await invalidateCachedTools({ invalidateGlobal: true });
+ expect(getLogStores).toHaveBeenCalledWith(CacheKeys.TOOL_CACHE);
+ expect(mockCache.delete).toHaveBeenCalledWith(ToolCacheKeys.GLOBAL);
+ });
+
+ it('getMCPServerTools should use TOOL_CACHE namespace', async () => {
+ mockCache.get.mockResolvedValue(null);
+ await getMCPServerTools('user1', 'github');
+ expect(getLogStores).toHaveBeenCalledWith(CacheKeys.TOOL_CACHE);
+ expect(mockCache.get).toHaveBeenCalledWith(ToolCacheKeys.MCP_SERVER('user1', 'github'));
+ });
+
+ it('should NOT use CONFIG_STORE namespace', async () => {
+ mockCache.get.mockResolvedValue(null);
+ await getCachedTools();
+ await getMCPServerTools('user1', 'github');
+ mockCache.set.mockResolvedValue(true);
+ await setCachedTools({ tool1: {} });
+ mockCache.delete.mockResolvedValue(true);
+ await invalidateCachedTools({ invalidateGlobal: true });
+
+ const allCalls = getLogStores.mock.calls.flat();
+ expect(allCalls).not.toContain(CacheKeys.CONFIG_STORE);
+ expect(allCalls.every((key) => key === CacheKeys.TOOL_CACHE)).toBe(true);
+ });
+ });
});
diff --git a/api/server/services/Config/getCachedTools.js b/api/server/services/Config/getCachedTools.js
index 841ca04c94..eb7a08305a 100644
--- a/api/server/services/Config/getCachedTools.js
+++ b/api/server/services/Config/getCachedTools.js
@@ -1,4 +1,4 @@
-const { CacheKeys } = require('librechat-data-provider');
+const { CacheKeys, Time } = require('librechat-data-provider');
const getLogStores = require('~/cache/getLogStores');
/**
@@ -20,7 +20,7 @@ const ToolCacheKeys = {
* @returns {Promise} The available tools object or null if not cached
*/
async function getCachedTools(options = {}) {
- const cache = getLogStores(CacheKeys.CONFIG_STORE);
+ const cache = getLogStores(CacheKeys.TOOL_CACHE);
const { userId, serverName } = options;
// Return MCP server-specific tools if requested
@@ -39,12 +39,12 @@ async function getCachedTools(options = {}) {
* @param {Object} options - Options for caching tools
* @param {string} [options.userId] - User ID for user-specific MCP tools
* @param {string} [options.serverName] - MCP server name for server-specific tools
- * @param {number} [options.ttl] - Time to live in milliseconds
+ * @param {number} [options.ttl] - Time to live in milliseconds (default: 12 hours)
* @returns {Promise} Whether the operation was successful
*/
async function setCachedTools(tools, options = {}) {
- const cache = getLogStores(CacheKeys.CONFIG_STORE);
- const { userId, serverName, ttl } = options;
+ const cache = getLogStores(CacheKeys.TOOL_CACHE);
+ const { userId, serverName, ttl = Time.TWELVE_HOURS } = options;
// Cache by MCP server if specified (requires userId)
if (serverName && userId) {
@@ -65,7 +65,7 @@ async function setCachedTools(tools, options = {}) {
* @returns {Promise}
*/
async function invalidateCachedTools(options = {}) {
- const cache = getLogStores(CacheKeys.CONFIG_STORE);
+ const cache = getLogStores(CacheKeys.TOOL_CACHE);
const { userId, serverName, invalidateGlobal = false } = options;
const keysToDelete = [];
@@ -89,7 +89,7 @@ async function invalidateCachedTools(options = {}) {
* @returns {Promise} The available tools for the server
*/
async function getMCPServerTools(userId, serverName) {
- const cache = getLogStores(CacheKeys.CONFIG_STORE);
+ const cache = getLogStores(CacheKeys.TOOL_CACHE);
const serverTools = await cache.get(ToolCacheKeys.MCP_SERVER(userId, serverName));
if (serverTools) {
diff --git a/api/server/services/Config/getEndpointsConfig.js b/api/server/services/Config/getEndpointsConfig.js
index 82c8f01abe..bb22584851 100644
--- a/api/server/services/Config/getEndpointsConfig.js
+++ b/api/server/services/Config/getEndpointsConfig.js
@@ -19,7 +19,11 @@ async function getEndpointsConfig(req) {
const cache = getLogStores(CacheKeys.CONFIG_STORE);
const cachedEndpointsConfig = await cache.get(CacheKeys.ENDPOINT_CONFIG);
if (cachedEndpointsConfig) {
- return cachedEndpointsConfig;
+ if (cachedEndpointsConfig.gptPlugins) {
+ await cache.delete(CacheKeys.ENDPOINT_CONFIG);
+ } else {
+ return cachedEndpointsConfig;
+ }
}
const appConfig = req.config ?? (await getAppConfig({ role: req.user?.role }));
@@ -39,6 +43,14 @@ async function getEndpointsConfig(req) {
};
}
+ // Enable Anthropic endpoint when Vertex AI is configured in YAML
+ if (appConfig.endpoints?.[EModelEndpoint.anthropic]?.vertexConfig?.enabled) {
+ /** @type {Omit} */
+ mergedConfig[EModelEndpoint.anthropic] = {
+ userProvide: false,
+ };
+ }
+
if (appConfig.endpoints?.[EModelEndpoint.azureOpenAI]?.assistants) {
/** @type {Omit} */
mergedConfig[EModelEndpoint.azureAssistants] = {
diff --git a/api/server/services/Config/loadAsyncEndpoints.js b/api/server/services/Config/loadAsyncEndpoints.js
index 48b42131e0..0d6a05aff7 100644
--- a/api/server/services/Config/loadAsyncEndpoints.js
+++ b/api/server/services/Config/loadAsyncEndpoints.js
@@ -1,17 +1,11 @@
const path = require('path');
const { logger } = require('@librechat/data-schemas');
-const { EModelEndpoint } = require('librechat-data-provider');
const { loadServiceKey, isUserProvided } = require('@librechat/api');
const { config } = require('./EndpointService');
-const { openAIApiKey, azureOpenAIApiKey, useAzurePlugins, userProvidedOpenAI, googleKey } = config;
-
-/**
- * Load async endpoints and return a configuration object
- * @param {AppConfig} [appConfig] - The app configuration object
- */
-async function loadAsyncEndpoints(appConfig) {
+async function loadAsyncEndpoints() {
let serviceKey, googleUserProvides;
+ const { googleKey } = config;
/** Check if GOOGLE_KEY is provided at all(including 'user_provided') */
const isGoogleKeyProvided = googleKey && googleKey.trim() !== '';
@@ -34,21 +28,7 @@ async function loadAsyncEndpoints(appConfig) {
const google = serviceKey || isGoogleKeyProvided ? { userProvide: googleUserProvides } : false;
- const useAzure = !!appConfig?.endpoints?.[EModelEndpoint.azureOpenAI]?.plugins;
- const gptPlugins =
- useAzure || openAIApiKey || azureOpenAIApiKey
- ? {
- availableAgents: ['classic', 'functions'],
- userProvide: useAzure ? false : userProvidedOpenAI,
- userProvideURL: useAzure
- ? false
- : config[EModelEndpoint.openAI]?.userProvideURL ||
- config[EModelEndpoint.azureOpenAI]?.userProvideURL,
- azure: useAzurePlugins || useAzure,
- }
- : false;
-
- return { google, gptPlugins };
+ return { google };
}
module.exports = loadAsyncEndpoints;
diff --git a/api/server/services/Config/loadConfigModels.js b/api/server/services/Config/loadConfigModels.js
index 34b6a1ecd2..2bc83ecc3a 100644
--- a/api/server/services/Config/loadConfigModels.js
+++ b/api/server/services/Config/loadConfigModels.js
@@ -1,10 +1,9 @@
-const { isUserProvided } = require('@librechat/api');
+const { isUserProvided, fetchModels } = require('@librechat/api');
const {
EModelEndpoint,
extractEnvVariable,
normalizeEndpointName,
} = require('librechat-data-provider');
-const { fetchModels } = require('~/server/services/ModelService');
const { getAppConfig } = require('./app');
/**
@@ -25,14 +24,15 @@ async function loadConfigModels(req) {
modelsConfig[EModelEndpoint.azureOpenAI] = modelNames;
}
- if (modelNames && azureConfig && azureConfig.plugins) {
- modelsConfig[EModelEndpoint.gptPlugins] = modelNames;
- }
-
if (azureConfig?.assistants && azureConfig.assistantModels) {
modelsConfig[EModelEndpoint.azureAssistants] = azureConfig.assistantModels;
}
+ const bedrockConfig = appConfig.endpoints?.[EModelEndpoint.bedrock];
+ if (bedrockConfig?.models && Array.isArray(bedrockConfig.models)) {
+ modelsConfig[EModelEndpoint.bedrock] = bedrockConfig.models;
+ }
+
if (!Array.isArray(appConfig.endpoints?.[EModelEndpoint.custom])) {
return modelsConfig;
}
diff --git a/api/server/services/Config/loadConfigModels.spec.js b/api/server/services/Config/loadConfigModels.spec.js
index 1e0e8780a7..6ffb8ba522 100644
--- a/api/server/services/Config/loadConfigModels.spec.js
+++ b/api/server/services/Config/loadConfigModels.spec.js
@@ -1,8 +1,11 @@
-const { fetchModels } = require('~/server/services/ModelService');
+const { fetchModels } = require('@librechat/api');
const loadConfigModels = require('./loadConfigModels');
const { getAppConfig } = require('./app');
-jest.mock('~/server/services/ModelService');
+jest.mock('@librechat/api', () => ({
+ ...jest.requireActual('@librechat/api'),
+ fetchModels: jest.fn(),
+}));
jest.mock('./app');
const exampleConfig = {
diff --git a/api/server/services/Config/loadCustomConfig.js b/api/server/services/Config/loadCustomConfig.js
index c0415674b9..db25049957 100644
--- a/api/server/services/Config/loadCustomConfig.js
+++ b/api/server/services/Config/loadCustomConfig.js
@@ -85,26 +85,32 @@ Please specify a correct \`imageOutputType\` value (case-sensitive).
let errorMessage = `Invalid custom config file at ${configPath}:
${JSON.stringify(result.error, null, 2)}`;
- if (i === 0) {
- logger.error(errorMessage);
- const speechError = result.error.errors.find(
- (err) =>
- err.code === 'unrecognized_keys' &&
- (err.message?.includes('stt') || err.message?.includes('tts')),
- );
+ logger.error(errorMessage);
+ const speechError = result.error.errors.find(
+ (err) =>
+ err.code === 'unrecognized_keys' &&
+ (err.message?.includes('stt') || err.message?.includes('tts')),
+ );
- if (speechError) {
- logger.warn(`
+ if (speechError) {
+ logger.warn(`
The Speech-to-text and Text-to-speech configuration format has recently changed.
If you're getting this error, please refer to the latest documentation:
https://www.librechat.ai/docs/configuration/stt_tts`);
- }
-
- i++;
}
- return null;
+ if (process.env.CONFIG_BYPASS_VALIDATION === 'true') {
+ logger.warn(
+ 'CONFIG_BYPASS_VALIDATION is enabled. Continuing with default configuration despite validation errors.',
+ );
+ return null;
+ }
+
+ logger.error(
+ 'Exiting due to invalid configuration. Set CONFIG_BYPASS_VALIDATION=true to bypass this check.',
+ );
+ process.exit(1);
} else {
if (printConfig) {
logger.info('Custom config file loaded:');
diff --git a/api/server/services/Config/loadCustomConfig.spec.js b/api/server/services/Config/loadCustomConfig.spec.js
index 4f2006a053..f7f11dc8f6 100644
--- a/api/server/services/Config/loadCustomConfig.spec.js
+++ b/api/server/services/Config/loadCustomConfig.spec.js
@@ -50,8 +50,25 @@ const { logger } = require('@librechat/data-schemas');
const loadCustomConfig = require('./loadCustomConfig');
describe('loadCustomConfig', () => {
+ const originalExit = process.exit;
+ const mockExit = jest.fn((code) => {
+ throw new Error(`process.exit called with "${code}"`);
+ });
+
+ beforeAll(() => {
+ process.exit = mockExit;
+ });
+
+ afterAll(() => {
+ process.exit = originalExit;
+ });
+
beforeEach(() => {
jest.resetAllMocks();
+ // Re-apply the exit mock implementation after resetAllMocks
+ mockExit.mockImplementation((code) => {
+ throw new Error(`process.exit called with "${code}"`);
+ });
delete process.env.CONFIG_PATH;
});
@@ -94,20 +111,38 @@ describe('loadCustomConfig', () => {
it('should return null and log if config schema validation fails', async () => {
const invalidConfig = { invalidField: true };
process.env.CONFIG_PATH = 'invalidConfig.yaml';
+ process.env.CONFIG_BYPASS_VALIDATION = 'true';
loadYaml.mockReturnValueOnce(invalidConfig);
const result = await loadCustomConfig();
expect(result).toBeNull();
+ expect(logger.warn).toHaveBeenCalledWith(
+ 'CONFIG_BYPASS_VALIDATION is enabled. Continuing with default configuration despite validation errors.',
+ );
+ delete process.env.CONFIG_BYPASS_VALIDATION;
+ });
+
+ it('should call process.exit(1) when config validation fails without bypass', async () => {
+ const invalidConfig = { invalidField: true };
+ process.env.CONFIG_PATH = 'invalidConfig.yaml';
+ loadYaml.mockReturnValueOnce(invalidConfig);
+
+ await expect(loadCustomConfig()).rejects.toThrow('process.exit called with "1"');
+ expect(logger.error).toHaveBeenCalledWith(
+ 'Exiting due to invalid configuration. Set CONFIG_BYPASS_VALIDATION=true to bypass this check.',
+ );
});
it('should handle and return null on YAML parse error for a string response from remote', async () => {
process.env.CONFIG_PATH = 'http://example.com/config.yaml';
+ process.env.CONFIG_BYPASS_VALIDATION = 'true';
axios.get.mockResolvedValue({ data: 'invalidYAMLContent' });
const result = await loadCustomConfig();
expect(result).toBeNull();
+ delete process.env.CONFIG_BYPASS_VALIDATION;
});
it('should return the custom config object for a valid remote config file', async () => {
diff --git a/api/server/services/Config/loadDefaultEConfig.js b/api/server/services/Config/loadDefaultEConfig.js
index f3c12a4933..557b93ce8e 100644
--- a/api/server/services/Config/loadDefaultEConfig.js
+++ b/api/server/services/Config/loadDefaultEConfig.js
@@ -8,8 +8,8 @@ const { config } = require('./EndpointService');
* @returns {Promise>} An object whose keys are endpoint names and values are objects that contain the endpoint configuration and an order.
*/
async function loadDefaultEndpointsConfig(appConfig) {
- const { google, gptPlugins } = await loadAsyncEndpoints(appConfig);
- const { assistants, azureAssistants, azureOpenAI, chatGPTBrowser } = config;
+ const { google } = await loadAsyncEndpoints(appConfig);
+ const { assistants, azureAssistants, azureOpenAI } = config;
const enabledEndpoints = getEnabledEndpoints();
@@ -20,8 +20,6 @@ async function loadDefaultEndpointsConfig(appConfig) {
[EModelEndpoint.azureAssistants]: azureAssistants,
[EModelEndpoint.azureOpenAI]: azureOpenAI,
[EModelEndpoint.google]: google,
- [EModelEndpoint.chatGPTBrowser]: chatGPTBrowser,
- [EModelEndpoint.gptPlugins]: gptPlugins,
[EModelEndpoint.anthropic]: config[EModelEndpoint.anthropic],
[EModelEndpoint.bedrock]: config[EModelEndpoint.bedrock],
};
diff --git a/api/server/services/Config/loadDefaultModels.js b/api/server/services/Config/loadDefaultModels.js
index a70fa58495..31aa831a70 100644
--- a/api/server/services/Config/loadDefaultModels.js
+++ b/api/server/services/Config/loadDefaultModels.js
@@ -5,7 +5,8 @@ const {
getBedrockModels,
getOpenAIModels,
getGoogleModels,
-} = require('~/server/services/ModelService');
+} = require('@librechat/api');
+const { getAppConfig } = require('./app');
/**
* Loads the default models for the application.
@@ -15,16 +16,21 @@ const {
*/
async function loadDefaultModels(req) {
try {
+ const appConfig = req.config ?? (await getAppConfig({ role: req.user?.role }));
+ const vertexConfig = appConfig?.endpoints?.[EModelEndpoint.anthropic]?.vertexConfig;
+
const [openAI, anthropic, azureOpenAI, assistants, azureAssistants, google, bedrock] =
await Promise.all([
getOpenAIModels({ user: req.user.id }).catch((error) => {
logger.error('Error fetching OpenAI models:', error);
return [];
}),
- getAnthropicModels({ user: req.user.id }).catch((error) => {
- logger.error('Error fetching Anthropic models:', error);
- return [];
- }),
+ getAnthropicModels({ user: req.user.id, vertexModels: vertexConfig?.modelNames }).catch(
+ (error) => {
+ logger.error('Error fetching Anthropic models:', error);
+ return [];
+ },
+ ),
getOpenAIModels({ user: req.user.id, azure: true }).catch((error) => {
logger.error('Error fetching Azure OpenAI models:', error);
return [];
diff --git a/api/server/services/Config/mcp.js b/api/server/services/Config/mcp.js
index 15ea62a028..cc4e98b59e 100644
--- a/api/server/services/Config/mcp.js
+++ b/api/server/services/Config/mcp.js
@@ -35,7 +35,7 @@ async function updateMCPServerTools({ userId, serverName, tools }) {
await setCachedTools(serverTools, { userId, serverName });
- const cache = getLogStores(CacheKeys.CONFIG_STORE);
+ const cache = getLogStores(CacheKeys.TOOL_CACHE);
await cache.delete(CacheKeys.TOOLS);
logger.debug(
`[MCP Cache] Updated ${tools.length} tools for server ${serverName} (user: ${userId})`,
@@ -61,7 +61,7 @@ async function mergeAppTools(appTools) {
const cachedTools = await getCachedTools();
const mergedTools = { ...cachedTools, ...appTools };
await setCachedTools(mergedTools);
- const cache = getLogStores(CacheKeys.CONFIG_STORE);
+ const cache = getLogStores(CacheKeys.TOOL_CACHE);
await cache.delete(CacheKeys.TOOLS);
logger.debug(`Merged ${count} app-level tools`);
} catch (error) {
diff --git a/api/server/services/Endpoints/agents/addedConvo.js b/api/server/services/Endpoints/agents/addedConvo.js
new file mode 100644
index 0000000000..7e9385267a
--- /dev/null
+++ b/api/server/services/Endpoints/agents/addedConvo.js
@@ -0,0 +1,142 @@
+const { logger } = require('@librechat/data-schemas');
+const { initializeAgent, validateAgentModel } = require('@librechat/api');
+const { loadAddedAgent, setGetAgent, ADDED_AGENT_ID } = require('~/models/loadAddedAgent');
+const { getConvoFiles } = require('~/models/Conversation');
+const { getAgent } = require('~/models/Agent');
+const db = require('~/models');
+
+// Initialize the getAgent dependency
+setGetAgent(getAgent);
+
+/**
+ * Process addedConvo for parallel agent execution.
+ * Creates a parallel agent config from an added conversation.
+ *
+ * When an added agent has no incoming edges, it becomes a start node
+ * and runs in parallel with the primary agent automatically.
+ *
+ * Edge cases handled:
+ * - Primary agent has edges (handoffs): Added agent runs in parallel with primary,
+ * but doesn't participate in the primary's handoff graph
+ * - Primary agent has agent_ids (legacy chain): Added agent runs in parallel with primary,
+ * but doesn't participate in the chain
+ * - Primary agent has both: Added agent is independent, runs parallel from start
+ *
+ * @param {Object} params
+ * @param {import('express').Request} params.req
+ * @param {import('express').Response} params.res
+ * @param {Object} params.endpointOption - The endpoint option containing addedConvo
+ * @param {Object} params.modelsConfig - The models configuration
+ * @param {Function} params.logViolation - Function to log violations
+ * @param {Function} params.loadTools - Function to load agent tools
+ * @param {Array} params.requestFiles - Request files
+ * @param {string} params.conversationId - The conversation ID
+ * @param {string} [params.parentMessageId] - The parent message ID for thread filtering
+ * @param {Set} params.allowedProviders - Set of allowed providers
+ * @param {Map} params.agentConfigs - Map of agent configs to add to
+ * @param {string} params.primaryAgentId - The primary agent ID
+ * @param {Object|undefined} params.userMCPAuthMap - User MCP auth map to merge into
+ * @returns {Promise<{userMCPAuthMap: Object|undefined}>} The updated userMCPAuthMap
+ */
+const processAddedConvo = async ({
+ req,
+ res,
+ endpointOption,
+ modelsConfig,
+ logViolation,
+ loadTools,
+ requestFiles,
+ conversationId,
+ parentMessageId,
+ allowedProviders,
+ agentConfigs,
+ primaryAgentId,
+ primaryAgent,
+ userMCPAuthMap,
+}) => {
+ const addedConvo = endpointOption.addedConvo;
+ logger.debug('[processAddedConvo] Called with addedConvo:', {
+ hasAddedConvo: addedConvo != null,
+ addedConvoEndpoint: addedConvo?.endpoint,
+ addedConvoModel: addedConvo?.model,
+ addedConvoAgentId: addedConvo?.agent_id,
+ });
+ if (addedConvo == null) {
+ return { userMCPAuthMap };
+ }
+
+ try {
+ const addedAgent = await loadAddedAgent({ req, conversation: addedConvo, primaryAgent });
+ if (!addedAgent) {
+ return { userMCPAuthMap };
+ }
+
+ const addedValidation = await validateAgentModel({
+ req,
+ res,
+ modelsConfig,
+ logViolation,
+ agent: addedAgent,
+ });
+
+ if (!addedValidation.isValid) {
+ logger.warn(
+ `[processAddedConvo] Added agent validation failed: ${addedValidation.error?.message}`,
+ );
+ return { userMCPAuthMap };
+ }
+
+ const addedConfig = await initializeAgent(
+ {
+ req,
+ res,
+ loadTools,
+ requestFiles,
+ conversationId,
+ parentMessageId,
+ agent: addedAgent,
+ endpointOption,
+ allowedProviders,
+ },
+ {
+ getConvoFiles,
+ getFiles: db.getFiles,
+ getUserKey: db.getUserKey,
+ getMessages: db.getMessages,
+ updateFilesUsage: db.updateFilesUsage,
+ getUserCodeFiles: db.getUserCodeFiles,
+ getUserKeyValues: db.getUserKeyValues,
+ getToolFilesByIds: db.getToolFilesByIds,
+ getCodeGeneratedFiles: db.getCodeGeneratedFiles,
+ },
+ );
+
+ if (userMCPAuthMap != null) {
+ Object.assign(userMCPAuthMap, addedConfig.userMCPAuthMap ?? {});
+ } else {
+ userMCPAuthMap = addedConfig.userMCPAuthMap;
+ }
+
+ const addedAgentId = addedConfig.id || ADDED_AGENT_ID;
+ agentConfigs.set(addedAgentId, addedConfig);
+
+ // No edges needed - agent without incoming edges becomes a start node
+ // and runs in parallel with the primary agent automatically.
+ // This is independent of any edges/agent_ids the primary agent has.
+
+ logger.debug(
+ `[processAddedConvo] Added parallel agent: ${addedAgentId} (primary: ${primaryAgentId}, ` +
+ `primary has edges: ${!!endpointOption.edges}, primary has agent_ids: ${!!endpointOption.agent_ids})`,
+ );
+
+ return { userMCPAuthMap };
+ } catch (err) {
+ logger.error('[processAddedConvo] Error processing addedConvo for parallel agent', err);
+ return { userMCPAuthMap };
+ }
+};
+
+module.exports = {
+ processAddedConvo,
+ ADDED_AGENT_ID,
+};
diff --git a/api/server/services/Endpoints/agents/agent.js b/api/server/services/Endpoints/agents/agent.js
deleted file mode 100644
index eebaa2cfc0..0000000000
--- a/api/server/services/Endpoints/agents/agent.js
+++ /dev/null
@@ -1,226 +0,0 @@
-const { Providers } = require('@librechat/agents');
-const {
- primeResources,
- getModelMaxTokens,
- extractLibreChatParams,
- filterFilesByEndpointConfig,
- optionalChainWithEmptyCheck,
-} = require('@librechat/api');
-const {
- ErrorTypes,
- EModelEndpoint,
- EToolResources,
- paramEndpoints,
- isAgentsEndpoint,
- replaceSpecialVars,
- providerEndpointMap,
-} = require('librechat-data-provider');
-const generateArtifactsPrompt = require('~/app/clients/prompts/artifacts');
-const { getProviderConfig } = require('~/server/services/Endpoints');
-const { processFiles } = require('~/server/services/Files/process');
-const { getFiles, getToolFilesByIds } = require('~/models/File');
-const { getConvoFiles } = require('~/models/Conversation');
-
-/**
- * @param {object} params
- * @param {ServerRequest} params.req
- * @param {ServerResponse} params.res
- * @param {Agent} params.agent
- * @param {string | null} [params.conversationId]
- * @param {Array} [params.requestFiles]
- * @param {typeof import('~/server/services/ToolService').loadAgentTools | undefined} [params.loadTools]
- * @param {TEndpointOption} [params.endpointOption]
- * @param {Set} [params.allowedProviders]
- * @param {boolean} [params.isInitialAgent]
- * @returns {Promise,
- * toolContextMap: Record,
- * maxContextTokens: number,
- * userMCPAuthMap?: Record>
- * }>}
- */
-const initializeAgent = async ({
- req,
- res,
- agent,
- loadTools,
- requestFiles,
- conversationId,
- endpointOption,
- allowedProviders,
- isInitialAgent = false,
-}) => {
- const appConfig = req.config;
- if (
- isAgentsEndpoint(endpointOption?.endpoint) &&
- allowedProviders.size > 0 &&
- !allowedProviders.has(agent.provider)
- ) {
- throw new Error(
- `{ "type": "${ErrorTypes.INVALID_AGENT_PROVIDER}", "info": "${agent.provider}" }`,
- );
- }
- let currentFiles;
-
- const _modelOptions = structuredClone(
- Object.assign(
- { model: agent.model },
- agent.model_parameters ?? { model: agent.model },
- isInitialAgent === true ? endpointOption?.model_parameters : {},
- ),
- );
-
- const { resendFiles, maxContextTokens, modelOptions } = extractLibreChatParams(_modelOptions);
-
- const provider = agent.provider;
- agent.endpoint = provider;
-
- if (isInitialAgent && conversationId != null && resendFiles) {
- const fileIds = (await getConvoFiles(conversationId)) ?? [];
- /** @type {Set} */
- const toolResourceSet = new Set();
- for (const tool of agent.tools) {
- if (EToolResources[tool]) {
- toolResourceSet.add(EToolResources[tool]);
- }
- }
- const toolFiles = await getToolFilesByIds(fileIds, toolResourceSet);
- if (requestFiles.length || toolFiles.length) {
- currentFiles = await processFiles(requestFiles.concat(toolFiles));
- }
- } else if (isInitialAgent && requestFiles.length) {
- currentFiles = await processFiles(requestFiles);
- }
-
- if (currentFiles && currentFiles.length) {
- let endpointType;
- if (!paramEndpoints.has(agent.endpoint)) {
- endpointType = EModelEndpoint.custom;
- }
-
- currentFiles = filterFilesByEndpointConfig(req, {
- files: currentFiles,
- endpoint: agent.endpoint,
- endpointType,
- });
- }
-
- const { attachments, tool_resources } = await primeResources({
- req,
- getFiles,
- appConfig,
- agentId: agent.id,
- attachments: currentFiles,
- tool_resources: agent.tool_resources,
- requestFileSet: new Set(requestFiles?.map((file) => file.file_id)),
- });
-
- const {
- tools: structuredTools,
- toolContextMap,
- userMCPAuthMap,
- } = (await loadTools?.({
- req,
- res,
- provider,
- agentId: agent.id,
- tools: agent.tools,
- model: agent.model,
- tool_resources,
- })) ?? {};
-
- const { getOptions, overrideProvider } = getProviderConfig({ provider, appConfig });
- if (overrideProvider !== agent.provider) {
- agent.provider = overrideProvider;
- }
-
- const _endpointOption =
- isInitialAgent === true
- ? Object.assign({}, endpointOption, { model_parameters: modelOptions })
- : { model_parameters: modelOptions };
-
- const options = await getOptions({
- req,
- res,
- optionsOnly: true,
- overrideEndpoint: provider,
- overrideModel: agent.model,
- endpointOption: _endpointOption,
- });
-
- const tokensModel =
- agent.provider === EModelEndpoint.azureOpenAI ? agent.model : options.llmConfig?.model;
- const maxOutputTokens = optionalChainWithEmptyCheck(
- options.llmConfig?.maxOutputTokens,
- options.llmConfig?.maxTokens,
- 0,
- );
- const agentMaxContextTokens = optionalChainWithEmptyCheck(
- maxContextTokens,
- getModelMaxTokens(tokensModel, providerEndpointMap[provider], options.endpointTokenConfig),
- 18000,
- );
-
- if (
- agent.endpoint === EModelEndpoint.azureOpenAI &&
- options.llmConfig?.azureOpenAIApiInstanceName == null
- ) {
- agent.provider = Providers.OPENAI;
- }
-
- if (options.provider != null) {
- agent.provider = options.provider;
- }
-
- /** @type {import('@librechat/agents').GenericTool[]} */
- let tools = options.tools?.length ? options.tools : structuredTools;
- if (
- (agent.provider === Providers.GOOGLE || agent.provider === Providers.VERTEXAI) &&
- options.tools?.length &&
- structuredTools?.length
- ) {
- throw new Error(`{ "type": "${ErrorTypes.GOOGLE_TOOL_CONFLICT}"}`);
- } else if (
- (agent.provider === Providers.OPENAI ||
- agent.provider === Providers.AZURE ||
- agent.provider === Providers.ANTHROPIC) &&
- options.tools?.length &&
- structuredTools?.length
- ) {
- tools = structuredTools.concat(options.tools);
- }
-
- /** @type {import('@librechat/agents').ClientOptions} */
- agent.model_parameters = { ...options.llmConfig };
- if (options.configOptions) {
- agent.model_parameters.configuration = options.configOptions;
- }
-
- if (agent.instructions && agent.instructions !== '') {
- agent.instructions = replaceSpecialVars({
- text: agent.instructions,
- user: req.user,
- });
- }
-
- if (typeof agent.artifacts === 'string' && agent.artifacts !== '') {
- agent.additional_instructions = generateArtifactsPrompt({
- endpoint: agent.provider,
- artifacts: agent.artifacts,
- });
- }
-
- return {
- ...agent,
- tools,
- attachments,
- resendFiles,
- userMCPAuthMap,
- toolContextMap,
- useLegacyContent: !!options.useLegacyContent,
- maxContextTokens: Math.round((agentMaxContextTokens - maxOutputTokens) * 0.9),
- };
-};
-
-module.exports = { initializeAgent };
diff --git a/api/server/services/Endpoints/agents/build.js b/api/server/services/Endpoints/agents/build.js
index 34fcaf4be4..a95640e528 100644
--- a/api/server/services/Endpoints/agents/build.js
+++ b/api/server/services/Endpoints/agents/build.js
@@ -15,6 +15,9 @@ const buildOptions = (req, endpoint, parsedBody, endpointType) => {
return undefined;
});
+ /** @type {import('librechat-data-provider').TConversation | undefined} */
+ const addedConvo = req.body?.addedConvo;
+
return removeNullishValues({
spec,
iconURL,
@@ -23,6 +26,7 @@ const buildOptions = (req, endpoint, parsedBody, endpointType) => {
endpointType,
model_parameters,
agent: agentPromise,
+ addedConvo,
});
};
diff --git a/api/server/services/Endpoints/agents/initialize.js b/api/server/services/Endpoints/agents/initialize.js
index 3064a03662..0888f23cd5 100644
--- a/api/server/services/Endpoints/agents/initialize.js
+++ b/api/server/services/Endpoints/agents/initialize.js
@@ -1,31 +1,41 @@
const { logger } = require('@librechat/data-schemas');
const { createContentAggregator } = require('@librechat/agents');
const {
+ initializeAgent,
validateAgentModel,
+ createEdgeCollector,
+ filterOrphanedEdges,
+ GenerationJobManager,
getCustomEndpointConfig,
createSequentialChainEdges,
} = require('@librechat/api');
const {
- Constants,
EModelEndpoint,
isAgentsEndpoint,
getResponseSender,
+ isEphemeralAgentId,
} = require('librechat-data-provider');
const {
createToolEndCallback,
getDefaultHandlers,
} = require('~/server/controllers/agents/callbacks');
-const { initializeAgent } = require('~/server/services/Endpoints/agents/agent');
+const { loadAgentTools, loadToolsForExecution } = require('~/server/services/ToolService');
const { getModelsConfig } = require('~/server/controllers/ModelController');
-const { loadAgentTools } = require('~/server/services/ToolService');
const AgentClient = require('~/server/controllers/agents/client');
+const { getConvoFiles } = require('~/models/Conversation');
+const { processAddedConvo } = require('./addedConvo');
const { getAgent } = require('~/models/Agent');
const { logViolation } = require('~/cache');
+const db = require('~/models');
/**
- * @param {AbortSignal} signal
+ * Creates a tool loader function for the agent.
+ * @param {AbortSignal} signal - The abort signal
+ * @param {string | null} [streamId] - The stream ID for resumable mode
+ * @param {boolean} [definitionsOnly=false] - When true, returns only serializable
+ * tool definitions without creating full tool instances (for event-driven mode)
*/
-function createToolLoader(signal) {
+function createToolLoader(signal, streamId = null, definitionsOnly = false) {
/**
* @param {object} params
* @param {ServerRequest} params.req
@@ -36,20 +46,33 @@ function createToolLoader(signal) {
* @param {string} params.model
* @param {AgentToolResources} params.tool_resources
* @returns {Promise<{
- * tools: StructuredTool[],
- * toolContextMap: Record,
- * userMCPAuthMap?: Record>
+ * tools?: StructuredTool[],
+ * toolContextMap: Record,
+ * toolDefinitions?: import('@librechat/agents').LCTool[],
+ * userMCPAuthMap?: Record>,
+ * toolRegistry?: import('@librechat/agents').LCToolRegistry
* } | undefined>}
*/
- return async function loadTools({ req, res, agentId, tools, provider, model, tool_resources }) {
- const agent = { id: agentId, tools, provider, model };
+ return async function loadTools({
+ req,
+ res,
+ tools,
+ model,
+ agentId,
+ provider,
+ tool_options,
+ tool_resources,
+ }) {
+ const agent = { id: agentId, tools, provider, model, tool_options };
try {
return await loadAgentTools({
req,
res,
agent,
signal,
+ streamId,
tool_resources,
+ definitionsOnly,
});
} catch (error) {
logger.error('Error loading tools for agent ' + agentId, error);
@@ -63,18 +86,60 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
}
const appConfig = req.config;
- // TODO: use endpointOption to determine options/modelOptions
+ /** @type {string | null} */
+ const streamId = req._resumableStreamId || null;
+
/** @type {Array} */
const collectedUsage = [];
/** @type {ArtifactPromises} */
const artifactPromises = [];
const { contentParts, aggregateContent } = createContentAggregator();
- const toolEndCallback = createToolEndCallback({ req, res, artifactPromises });
+ const toolEndCallback = createToolEndCallback({ req, res, artifactPromises, streamId });
+
+ /**
+ * Agent context store - populated after initialization, accessed by callback via closure.
+ * Maps agentId -> { userMCPAuthMap, agent, tool_resources, toolRegistry, openAIApiKey }
+ * @type {Map>,
+ * agent?: object,
+ * tool_resources?: object,
+ * toolRegistry?: import('@librechat/agents').LCToolRegistry,
+ * openAIApiKey?: string
+ * }>}
+ */
+ const agentToolContexts = new Map();
+
+ const toolExecuteOptions = {
+ loadTools: async (toolNames, agentId) => {
+ const ctx = agentToolContexts.get(agentId) ?? {};
+ logger.debug(`[ON_TOOL_EXECUTE] ctx found: ${!!ctx.userMCPAuthMap}, agent: ${ctx.agent?.id}`);
+ logger.debug(`[ON_TOOL_EXECUTE] toolRegistry size: ${ctx.toolRegistry?.size ?? 'undefined'}`);
+
+ const result = await loadToolsForExecution({
+ req,
+ res,
+ signal,
+ streamId,
+ toolNames,
+ agent: ctx.agent,
+ toolRegistry: ctx.toolRegistry,
+ userMCPAuthMap: ctx.userMCPAuthMap,
+ tool_resources: ctx.tool_resources,
+ });
+
+ logger.debug(`[ON_TOOL_EXECUTE] loaded ${result.loadedTools?.length ?? 0} tools`);
+ return result;
+ },
+ toolEndCallback,
+ };
+
const eventHandlers = getDefaultHandlers({
res,
+ toolExecuteOptions,
aggregateContent,
toolEndCallback,
collectedUsage,
+ streamId,
});
if (!endpointOption.agent) {
@@ -103,31 +168,71 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
const agentConfigs = new Map();
const allowedProviders = new Set(appConfig?.endpoints?.[EModelEndpoint.agents]?.allowedProviders);
- const loadTools = createToolLoader(signal);
+ /** Event-driven mode: only load tool definitions, not full instances */
+ const loadTools = createToolLoader(signal, streamId, true);
/** @type {Array} */
const requestFiles = req.body.files ?? [];
/** @type {string} */
const conversationId = req.body.conversationId;
+ /** @type {string | undefined} */
+ const parentMessageId = req.body.parentMessageId;
- const primaryConfig = await initializeAgent({
- req,
- res,
- loadTools,
- requestFiles,
- conversationId,
+ const primaryConfig = await initializeAgent(
+ {
+ req,
+ res,
+ loadTools,
+ requestFiles,
+ conversationId,
+ parentMessageId,
+ agent: primaryAgent,
+ endpointOption,
+ allowedProviders,
+ isInitialAgent: true,
+ },
+ {
+ getConvoFiles,
+ getFiles: db.getFiles,
+ getUserKey: db.getUserKey,
+ getMessages: db.getMessages,
+ updateFilesUsage: db.updateFilesUsage,
+ getUserKeyValues: db.getUserKeyValues,
+ getUserCodeFiles: db.getUserCodeFiles,
+ getToolFilesByIds: db.getToolFilesByIds,
+ getCodeGeneratedFiles: db.getCodeGeneratedFiles,
+ },
+ );
+
+ logger.debug(
+ `[initializeClient] Tool definitions for primary agent: ${primaryConfig.toolDefinitions?.length ?? 0}`,
+ );
+
+ /** Store primary agent's tool context for ON_TOOL_EXECUTE callback */
+ logger.debug(`[initializeClient] Storing tool context for agentId: ${primaryConfig.id}`);
+ logger.debug(
+ `[initializeClient] toolRegistry size: ${primaryConfig.toolRegistry?.size ?? 'undefined'}`,
+ );
+ agentToolContexts.set(primaryConfig.id, {
agent: primaryAgent,
- endpointOption,
- allowedProviders,
- isInitialAgent: true,
+ toolRegistry: primaryConfig.toolRegistry,
+ userMCPAuthMap: primaryConfig.userMCPAuthMap,
+ tool_resources: primaryConfig.tool_resources,
});
const agent_ids = primaryConfig.agent_ids;
let userMCPAuthMap = primaryConfig.userMCPAuthMap;
+ /** @type {Set} Track agents that failed to load (orphaned references) */
+ const skippedAgentIds = new Set();
+
async function processAgent(agentId) {
const agent = await getAgent({ id: agentId });
if (!agent) {
- throw new Error(`Agent ${agentId} not found`);
+ logger.warn(
+ `[processAgent] Handoff agent ${agentId} not found, skipping (orphaned reference)`,
+ );
+ skippedAgentIds.add(agentId);
+ return null;
}
const validationResult = await validateAgentModel({
@@ -142,53 +247,71 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
throw new Error(validationResult.error?.message);
}
- const config = await initializeAgent({
- req,
- res,
- agent,
- loadTools,
- requestFiles,
- conversationId,
- endpointOption,
- allowedProviders,
- });
+ const config = await initializeAgent(
+ {
+ req,
+ res,
+ agent,
+ loadTools,
+ requestFiles,
+ conversationId,
+ parentMessageId,
+ endpointOption,
+ allowedProviders,
+ },
+ {
+ getConvoFiles,
+ getFiles: db.getFiles,
+ getUserKey: db.getUserKey,
+ getMessages: db.getMessages,
+ updateFilesUsage: db.updateFilesUsage,
+ getUserKeyValues: db.getUserKeyValues,
+ getUserCodeFiles: db.getUserCodeFiles,
+ getToolFilesByIds: db.getToolFilesByIds,
+ getCodeGeneratedFiles: db.getCodeGeneratedFiles,
+ },
+ );
+
if (userMCPAuthMap != null) {
Object.assign(userMCPAuthMap, config.userMCPAuthMap ?? {});
} else {
userMCPAuthMap = config.userMCPAuthMap;
}
+
+ /** Store handoff agent's tool context for ON_TOOL_EXECUTE callback */
+ agentToolContexts.set(agentId, {
+ agent,
+ toolRegistry: config.toolRegistry,
+ userMCPAuthMap: config.userMCPAuthMap,
+ tool_resources: config.tool_resources,
+ });
+
agentConfigs.set(agentId, config);
+ return agent;
}
- let edges = primaryConfig.edges;
const checkAgentInit = (agentId) => agentId === primaryConfig.id || agentConfigs.has(agentId);
- if ((edges?.length ?? 0) > 0) {
- for (const edge of edges) {
- if (Array.isArray(edge.to)) {
- for (const to of edge.to) {
- if (checkAgentInit(to)) {
- continue;
- }
- await processAgent(to);
- }
- } else if (typeof edge.to === 'string' && checkAgentInit(edge.to)) {
- continue;
- } else if (typeof edge.to === 'string') {
- await processAgent(edge.to);
- }
- if (Array.isArray(edge.from)) {
- for (const from of edge.from) {
- if (checkAgentInit(from)) {
- continue;
- }
- await processAgent(from);
- }
- } else if (typeof edge.from === 'string' && checkAgentInit(edge.from)) {
- continue;
- } else if (typeof edge.from === 'string') {
- await processAgent(edge.from);
+ // Graph topology discovery for recursive agent handoffs (BFS)
+ const { edgeMap, agentsToProcess, collectEdges } = createEdgeCollector(
+ checkAgentInit,
+ skippedAgentIds,
+ );
+
+ // Seed with primary agent's edges
+ collectEdges(primaryConfig.edges);
+
+ // BFS to load and merge all connected agents (enables transitive handoffs: A->B->C)
+ while (agentsToProcess.size > 0) {
+ const agentId = agentsToProcess.values().next().value;
+ agentsToProcess.delete(agentId);
+ try {
+ const agent = await processAgent(agentId);
+ if (agent?.edges?.length) {
+ collectEdges(agent.edges);
}
+ } catch (err) {
+ logger.error(`[initializeClient] Error processing agent ${agentId}:`, err);
}
}
@@ -200,11 +323,43 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
}
await processAgent(agentId);
}
-
const chain = await createSequentialChainEdges([primaryConfig.id].concat(agent_ids), '{convo}');
- edges = edges ? edges.concat(chain) : chain;
+ collectEdges(chain);
}
+ let edges = Array.from(edgeMap.values());
+
+ /** Multi-Convo: Process addedConvo for parallel agent execution */
+ const { userMCPAuthMap: updatedMCPAuthMap } = await processAddedConvo({
+ req,
+ res,
+ loadTools,
+ logViolation,
+ modelsConfig,
+ requestFiles,
+ agentConfigs,
+ primaryAgent,
+ endpointOption,
+ userMCPAuthMap,
+ conversationId,
+ parentMessageId,
+ allowedProviders,
+ primaryAgentId: primaryConfig.id,
+ });
+
+ if (updatedMCPAuthMap) {
+ userMCPAuthMap = updatedMCPAuthMap;
+ }
+
+ // Ensure edges is an array when we have multiple agents (multi-agent mode)
+ // MultiAgentGraph.categorizeEdges requires edges to be iterable
+ if (agentConfigs.size > 0 && !edges) {
+ edges = [];
+ }
+
+ // Filter out edges referencing non-existent agents (orphaned references)
+ edges = filterOrphanedEdges(edges, skippedAgentIds);
+
primaryConfig.edges = edges;
let endpointConfig = appConfig.endpoints?.[primaryConfig.endpoint];
@@ -248,12 +403,13 @@ const initializeClient = async ({ req, res, signal, endpointOption }) => {
endpointType: endpointOption.endpointType,
resendFiles: primaryConfig.resendFiles ?? true,
maxContextTokens: primaryConfig.maxContextTokens,
- endpoint:
- primaryConfig.id === Constants.EPHEMERAL_AGENT_ID
- ? primaryConfig.endpoint
- : EModelEndpoint.agents,
+ endpoint: isEphemeralAgentId(primaryConfig.id) ? primaryConfig.endpoint : EModelEndpoint.agents,
});
+ if (streamId) {
+ GenerationJobManager.setCollectedUsage(streamId, collectedUsage);
+ }
+
return { client, userMCPAuthMap };
};
diff --git a/api/server/services/Endpoints/agents/title.js b/api/server/services/Endpoints/agents/title.js
index 74cdc0b2c2..e31cdeea11 100644
--- a/api/server/services/Endpoints/agents/title.js
+++ b/api/server/services/Endpoints/agents/title.js
@@ -17,6 +17,11 @@ const addTitle = async (req, { text, response, client }) => {
return;
}
+ // Skip title generation for temporary conversations
+ if (req?.body?.isTemporary) {
+ return;
+ }
+
const titleCache = getLogStores(CacheKeys.GEN_TITLE);
const key = `${req.user.id}-${response.conversationId}`;
/** @type {NodeJS.Timeout} */
@@ -66,7 +71,7 @@ const addTitle = async (req, { text, response, client }) => {
conversationId: response.conversationId,
title,
},
- { context: 'api/server/services/Endpoints/agents/title.js' },
+ { context: 'api/server/services/Endpoints/agents/title.js', noUpsert: true },
);
} catch (error) {
logger.error('Error generating title:', error);
diff --git a/api/server/services/Endpoints/anthropic/build.js b/api/server/services/Endpoints/anthropic/build.js
deleted file mode 100644
index 1d2c29d81e..0000000000
--- a/api/server/services/Endpoints/anthropic/build.js
+++ /dev/null
@@ -1,44 +0,0 @@
-const { removeNullishValues, anthropicSettings } = require('librechat-data-provider');
-const generateArtifactsPrompt = require('~/app/clients/prompts/artifacts');
-
-const buildOptions = (endpoint, parsedBody) => {
- const {
- modelLabel,
- promptPrefix,
- maxContextTokens,
- fileTokenLimit,
- resendFiles = anthropicSettings.resendFiles.default,
- promptCache = anthropicSettings.promptCache.default,
- thinking = anthropicSettings.thinking.default,
- thinkingBudget = anthropicSettings.thinkingBudget.default,
- iconURL,
- greeting,
- spec,
- artifacts,
- ...modelOptions
- } = parsedBody;
-
- const endpointOption = removeNullishValues({
- endpoint,
- modelLabel,
- promptPrefix,
- resendFiles,
- promptCache,
- thinking,
- thinkingBudget,
- iconURL,
- greeting,
- spec,
- maxContextTokens,
- fileTokenLimit,
- modelOptions,
- });
-
- if (typeof artifacts === 'string') {
- endpointOption.artifactsPrompt = generateArtifactsPrompt({ endpoint, artifacts });
- }
-
- return endpointOption;
-};
-
-module.exports = buildOptions;
diff --git a/api/server/services/Endpoints/anthropic/index.js b/api/server/services/Endpoints/anthropic/index.js
deleted file mode 100644
index c4e7533c5d..0000000000
--- a/api/server/services/Endpoints/anthropic/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-const addTitle = require('./title');
-const buildOptions = require('./build');
-const initializeClient = require('./initialize');
-
-module.exports = {
- addTitle,
- buildOptions,
- initializeClient,
-};
diff --git a/api/server/services/Endpoints/anthropic/initialize.js b/api/server/services/Endpoints/anthropic/initialize.js
deleted file mode 100644
index 88639b3d7c..0000000000
--- a/api/server/services/Endpoints/anthropic/initialize.js
+++ /dev/null
@@ -1,70 +0,0 @@
-const { getLLMConfig } = require('@librechat/api');
-const { EModelEndpoint } = require('librechat-data-provider');
-const { getUserKey, checkUserKeyExpiry } = require('~/server/services/UserService');
-const AnthropicClient = require('~/app/clients/AnthropicClient');
-
-const initializeClient = async ({ req, res, endpointOption, overrideModel, optionsOnly }) => {
- const appConfig = req.config;
- const { ANTHROPIC_API_KEY, ANTHROPIC_REVERSE_PROXY, PROXY } = process.env;
- const expiresAt = req.body.key;
- const isUserProvided = ANTHROPIC_API_KEY === 'user_provided';
-
- const anthropicApiKey = isUserProvided
- ? await getUserKey({ userId: req.user.id, name: EModelEndpoint.anthropic })
- : ANTHROPIC_API_KEY;
-
- if (!anthropicApiKey) {
- throw new Error('Anthropic API key not provided. Please provide it again.');
- }
-
- if (expiresAt && isUserProvided) {
- checkUserKeyExpiry(expiresAt, EModelEndpoint.anthropic);
- }
-
- let clientOptions = {};
-
- /** @type {undefined | TBaseEndpoint} */
- const anthropicConfig = appConfig.endpoints?.[EModelEndpoint.anthropic];
-
- if (anthropicConfig) {
- clientOptions._lc_stream_delay = anthropicConfig.streamRate;
- clientOptions.titleModel = anthropicConfig.titleModel;
- }
-
- const allConfig = appConfig.endpoints?.all;
- if (allConfig) {
- clientOptions._lc_stream_delay = allConfig.streamRate;
- }
-
- if (optionsOnly) {
- clientOptions = Object.assign(
- {
- proxy: PROXY ?? null,
- reverseProxyUrl: ANTHROPIC_REVERSE_PROXY ?? null,
- modelOptions: endpointOption?.model_parameters ?? {},
- },
- clientOptions,
- );
- if (overrideModel) {
- clientOptions.modelOptions.model = overrideModel;
- }
- clientOptions.modelOptions.user = req.user.id;
- return getLLMConfig(anthropicApiKey, clientOptions);
- }
-
- const client = new AnthropicClient(anthropicApiKey, {
- req,
- res,
- reverseProxyUrl: ANTHROPIC_REVERSE_PROXY ?? null,
- proxy: PROXY ?? null,
- ...clientOptions,
- ...endpointOption,
- });
-
- return {
- client,
- anthropicApiKey,
- };
-};
-
-module.exports = initializeClient;
diff --git a/api/server/services/Endpoints/anthropic/title.js b/api/server/services/Endpoints/anthropic/title.js
deleted file mode 100644
index cac39fa2be..0000000000
--- a/api/server/services/Endpoints/anthropic/title.js
+++ /dev/null
@@ -1,35 +0,0 @@
-const { isEnabled } = require('@librechat/api');
-const { CacheKeys } = require('librechat-data-provider');
-const getLogStores = require('~/cache/getLogStores');
-const { saveConvo } = require('~/models');
-
-const addTitle = async (req, { text, response, client }) => {
- const { TITLE_CONVO = 'true' } = process.env ?? {};
- if (!isEnabled(TITLE_CONVO)) {
- return;
- }
-
- if (client.options.titleConvo === false) {
- return;
- }
-
- const titleCache = getLogStores(CacheKeys.GEN_TITLE);
- const key = `${req.user.id}-${response.conversationId}`;
-
- const title = await client.titleConvo({
- text,
- responseText: response?.text ?? '',
- conversationId: response.conversationId,
- });
- await titleCache.set(key, title, 120000);
- await saveConvo(
- req,
- {
- conversationId: response.conversationId,
- title,
- },
- { context: 'api/server/services/Endpoints/anthropic/addTitle.js' },
- );
-};
-
-module.exports = addTitle;
diff --git a/api/server/services/Endpoints/assistants/initalize.js b/api/server/services/Endpoints/assistants/initalize.js
index 6b1af9b3db..d5a246dff7 100644
--- a/api/server/services/Endpoints/assistants/initalize.js
+++ b/api/server/services/Endpoints/assistants/initalize.js
@@ -1,15 +1,10 @@
const OpenAI = require('openai');
const { ProxyAgent } = require('undici');
-const { isUserProvided } = require('@librechat/api');
+const { isUserProvided, checkUserKeyExpiry } = require('@librechat/api');
const { ErrorTypes, EModelEndpoint } = require('librechat-data-provider');
-const {
- getUserKeyValues,
- getUserKeyExpiry,
- checkUserKeyExpiry,
-} = require('~/server/services/UserService');
-const OAIClient = require('~/app/clients/OpenAIClient');
+const { getUserKeyValues, getUserKeyExpiry } = require('~/models');
-const initializeClient = async ({ req, res, endpointOption, version, initAppClient = false }) => {
+const initializeClient = async ({ req, res, version }) => {
const { PROXY, OPENAI_ORGANIZATION, ASSISTANTS_API_KEY, ASSISTANTS_BASE_URL } = process.env;
const userProvidesKey = isUserProvided(ASSISTANTS_API_KEY);
@@ -34,14 +29,6 @@ const initializeClient = async ({ req, res, endpointOption, version, initAppClie
},
};
- const clientOptions = {
- reverseProxyUrl: baseURL ?? null,
- proxy: PROXY ?? null,
- req,
- res,
- ...endpointOption,
- };
-
if (userProvidesKey & !apiKey) {
throw new Error(
JSON.stringify({
@@ -78,15 +65,6 @@ const initializeClient = async ({ req, res, endpointOption, version, initAppClie
openai.req = req;
openai.res = res;
- if (endpointOption && initAppClient) {
- const client = new OAIClient(apiKey, clientOptions);
- return {
- client,
- openai,
- openAIApiKey: apiKey,
- };
- }
-
return {
openai,
openAIApiKey: apiKey,
diff --git a/api/server/services/Endpoints/assistants/initialize.spec.js b/api/server/services/Endpoints/assistants/initialize.spec.js
deleted file mode 100644
index 3a870dc61d..0000000000
--- a/api/server/services/Endpoints/assistants/initialize.spec.js
+++ /dev/null
@@ -1,113 +0,0 @@
-// const OpenAI = require('openai');
-const { ProxyAgent } = require('undici');
-const { ErrorTypes } = require('librechat-data-provider');
-const { getUserKey, getUserKeyExpiry, getUserKeyValues } = require('~/server/services/UserService');
-const initializeClient = require('./initalize');
-// const { OpenAIClient } = require('~/app');
-
-jest.mock('~/server/services/UserService', () => ({
- getUserKey: jest.fn(),
- getUserKeyExpiry: jest.fn(),
- getUserKeyValues: jest.fn(),
- checkUserKeyExpiry: jest.requireActual('~/server/services/UserService').checkUserKeyExpiry,
-}));
-
-const today = new Date();
-const tenDaysFromToday = new Date(today.setDate(today.getDate() + 10));
-const isoString = tenDaysFromToday.toISOString();
-
-describe('initializeClient', () => {
- // Set up environment variables
- const originalEnvironment = process.env;
- const app = {
- locals: {},
- };
-
- beforeEach(() => {
- jest.resetModules(); // Clears the cache
- process.env = { ...originalEnvironment }; // Make a copy
- });
-
- afterAll(() => {
- process.env = originalEnvironment; // Restore original env vars
- });
-
- test('initializes OpenAI client with default API key and URL', async () => {
- process.env.ASSISTANTS_API_KEY = 'default-api-key';
- process.env.ASSISTANTS_BASE_URL = 'https://default.api.url';
-
- // Assuming 'isUserProvided' to return false for this test case
- jest.mock('~/server/utils', () => ({
- isUserProvided: jest.fn().mockReturnValueOnce(false),
- }));
-
- const req = { user: { id: 'user123' }, app };
- const res = {};
-
- const { openai, openAIApiKey } = await initializeClient({ req, res });
- expect(openai.apiKey).toBe('default-api-key');
- expect(openAIApiKey).toBe('default-api-key');
- expect(openai.baseURL).toBe('https://default.api.url');
- });
-
- test('initializes OpenAI client with user-provided API key and URL', async () => {
- process.env.ASSISTANTS_API_KEY = 'user_provided';
- process.env.ASSISTANTS_BASE_URL = 'user_provided';
-
- getUserKeyValues.mockResolvedValue({ apiKey: 'user-api-key', baseURL: 'https://user.api.url' });
- getUserKeyExpiry.mockResolvedValue(isoString);
-
- const req = { user: { id: 'user123' }, app };
- const res = {};
-
- const { openai, openAIApiKey } = await initializeClient({ req, res });
- expect(openAIApiKey).toBe('user-api-key');
- expect(openai.apiKey).toBe('user-api-key');
- expect(openai.baseURL).toBe('https://user.api.url');
- });
-
- test('throws error for invalid JSON in user-provided values', async () => {
- process.env.ASSISTANTS_API_KEY = 'user_provided';
- getUserKey.mockResolvedValue('invalid-json');
- getUserKeyExpiry.mockResolvedValue(isoString);
- getUserKeyValues.mockImplementation(() => {
- let userValues = getUserKey();
- try {
- userValues = JSON.parse(userValues);
- } catch (e) {
- throw new Error(
- JSON.stringify({
- type: ErrorTypes.INVALID_USER_KEY,
- }),
- );
- }
- return userValues;
- });
-
- const req = { user: { id: 'user123' } };
- const res = {};
-
- await expect(initializeClient({ req, res })).rejects.toThrow(/invalid_user_key/);
- });
-
- test('throws error if API key is not provided', async () => {
- delete process.env.ASSISTANTS_API_KEY; // Simulate missing API key
-
- const req = { user: { id: 'user123' }, app };
- const res = {};
-
- await expect(initializeClient({ req, res })).rejects.toThrow(/Assistants API key not/);
- });
-
- test('initializes OpenAI client with proxy configuration', async () => {
- process.env.ASSISTANTS_API_KEY = 'test-key';
- process.env.PROXY = 'http://proxy.server';
-
- const req = { user: { id: 'user123' }, app };
- const res = {};
-
- const { openai } = await initializeClient({ req, res });
- expect(openai.fetchOptions).toBeDefined();
- expect(openai.fetchOptions.dispatcher).toBeInstanceOf(ProxyAgent);
- });
-});
diff --git a/api/server/services/Endpoints/assistants/title.js b/api/server/services/Endpoints/assistants/title.js
index 223d3badc6..1fae68cf54 100644
--- a/api/server/services/Endpoints/assistants/title.js
+++ b/api/server/services/Endpoints/assistants/title.js
@@ -1,32 +1,89 @@
-const { isEnabled } = require('@librechat/api');
+const { isEnabled, sanitizeTitle } = require('@librechat/api');
+const { logger } = require('@librechat/data-schemas');
const { CacheKeys } = require('librechat-data-provider');
const { saveConvo } = require('~/models/Conversation');
const getLogStores = require('~/cache/getLogStores');
+const initializeClient = require('./initalize');
-const addTitle = async (req, { text, responseText, conversationId, client }) => {
+/**
+ * Generates a conversation title using OpenAI SDK
+ * @param {Object} params
+ * @param {OpenAI} params.openai - The OpenAI SDK client instance
+ * @param {string} params.text - User's message text
+ * @param {string} params.responseText - Assistant's response text
+ * @returns {Promise}
+ */
+const generateTitle = async ({ openai, text, responseText }) => {
+ const titlePrompt = `Please generate a concise title (max 40 characters) for a conversation that starts with:
+User: ${text}
+Assistant: ${responseText}
+
+Title:`;
+
+ const completion = await openai.chat.completions.create({
+ model: 'gpt-3.5-turbo',
+ messages: [
+ {
+ role: 'user',
+ content: titlePrompt,
+ },
+ ],
+ temperature: 0.7,
+ max_tokens: 20,
+ });
+
+ const title = completion.choices[0]?.message?.content?.trim() || 'New conversation';
+ return sanitizeTitle(title);
+};
+
+/**
+ * Adds a title to a conversation asynchronously
+ * @param {ServerRequest} req
+ * @param {Object} params
+ * @param {string} params.text - User's message text
+ * @param {string} params.responseText - Assistant's response text
+ * @param {string} params.conversationId - Conversation ID
+ */
+const addTitle = async (req, { text, responseText, conversationId }) => {
const { TITLE_CONVO = 'true' } = process.env ?? {};
if (!isEnabled(TITLE_CONVO)) {
return;
}
- if (client.options.titleConvo === false) {
+ // Skip title generation for temporary conversations
+ if (req?.body?.isTemporary) {
return;
}
const titleCache = getLogStores(CacheKeys.GEN_TITLE);
const key = `${req.user.id}-${conversationId}`;
- const title = await client.titleConvo({ text, conversationId, responseText });
- await titleCache.set(key, title, 120000);
+ try {
+ const { openai } = await initializeClient({ req });
+ const title = await generateTitle({ openai, text, responseText });
+ await titleCache.set(key, title, 120000);
- await saveConvo(
- req,
- {
- conversationId,
- title,
- },
- { context: 'api/server/services/Endpoints/assistants/addTitle.js' },
- );
+ await saveConvo(
+ req,
+ {
+ conversationId,
+ title,
+ },
+ { context: 'api/server/services/Endpoints/assistants/addTitle.js', noUpsert: true },
+ );
+ } catch (error) {
+ logger.error('[addTitle] Error generating title:', error);
+ const fallbackTitle = text.length > 40 ? text.substring(0, 37) + '...' : text;
+ await titleCache.set(key, fallbackTitle, 120000);
+ await saveConvo(
+ req,
+ {
+ conversationId,
+ title: fallbackTitle,
+ },
+ { context: 'api/server/services/Endpoints/assistants/addTitle.js', noUpsert: true },
+ );
+ }
};
module.exports = addTitle;
diff --git a/api/server/services/Endpoints/azureAssistants/build.js b/api/server/services/Endpoints/azureAssistants/build.js
index 54a32e4d3c..53b1dbeb68 100644
--- a/api/server/services/Endpoints/azureAssistants/build.js
+++ b/api/server/services/Endpoints/azureAssistants/build.js
@@ -3,7 +3,6 @@ const generateArtifactsPrompt = require('~/app/clients/prompts/artifacts');
const { getAssistant } = require('~/models/Assistant');
const buildOptions = async (endpoint, parsedBody) => {
-
const { promptPrefix, assistant_id, iconURL, greeting, spec, artifacts, ...modelOptions } =
parsedBody;
const endpointOption = removeNullishValues({
diff --git a/api/server/services/Endpoints/azureAssistants/initialize.js b/api/server/services/Endpoints/azureAssistants/initialize.js
index a6fb3e85f7..e81f0bcd8a 100644
--- a/api/server/services/Endpoints/azureAssistants/initialize.js
+++ b/api/server/services/Endpoints/azureAssistants/initialize.js
@@ -1,13 +1,13 @@
const OpenAI = require('openai');
const { ProxyAgent } = require('undici');
-const { constructAzureURL, isUserProvided, resolveHeaders } = require('@librechat/api');
-const { ErrorTypes, EModelEndpoint, mapModelToAzureConfig } = require('librechat-data-provider');
const {
+ isUserProvided,
+ resolveHeaders,
+ constructAzureURL,
checkUserKeyExpiry,
- getUserKeyValues,
- getUserKeyExpiry,
-} = require('~/server/services/UserService');
-const OAIClient = require('~/app/clients/OpenAIClient');
+} = require('@librechat/api');
+const { ErrorTypes, EModelEndpoint, mapModelToAzureConfig } = require('librechat-data-provider');
+const { getUserKeyValues, getUserKeyExpiry } = require('~/models');
class Files {
constructor(client) {
@@ -128,7 +128,6 @@ const initializeClient = async ({ req, res, version, endpointOption, initAppClie
const groupName = modelGroupMap[modelName].group;
clientOptions.addParams = azureConfig.groupMap[groupName].addParams;
clientOptions.dropParams = azureConfig.groupMap[groupName].dropParams;
- clientOptions.forcePrompt = azureConfig.groupMap[groupName].forcePrompt;
clientOptions.reverseProxyUrl = baseURL ?? clientOptions.reverseProxyUrl;
clientOptions.headers = opts.defaultHeaders;
@@ -184,15 +183,6 @@ const initializeClient = async ({ req, res, version, endpointOption, initAppClie
openai.locals = { ...(openai.locals ?? {}), azureOptions };
}
- if (endpointOption && initAppClient) {
- const client = new OAIClient(apiKey, clientOptions);
- return {
- client,
- openai,
- openAIApiKey: apiKey,
- };
- }
-
return {
openai,
openAIApiKey: apiKey,
diff --git a/api/server/services/Endpoints/azureAssistants/initialize.spec.js b/api/server/services/Endpoints/azureAssistants/initialize.spec.js
deleted file mode 100644
index d74373ae1b..0000000000
--- a/api/server/services/Endpoints/azureAssistants/initialize.spec.js
+++ /dev/null
@@ -1,134 +0,0 @@
-// const OpenAI = require('openai');
-const { ProxyAgent } = require('undici');
-const { ErrorTypes, EModelEndpoint } = require('librechat-data-provider');
-const { getUserKey, getUserKeyExpiry, getUserKeyValues } = require('~/server/services/UserService');
-const initializeClient = require('./initialize');
-// const { OpenAIClient } = require('~/app');
-
-jest.mock('~/server/services/UserService', () => ({
- getUserKey: jest.fn(),
- getUserKeyExpiry: jest.fn(),
- getUserKeyValues: jest.fn(),
- checkUserKeyExpiry: jest.requireActual('~/server/services/UserService').checkUserKeyExpiry,
-}));
-
-// Config is now passed via req.config, not getAppConfig
-
-const today = new Date();
-const tenDaysFromToday = new Date(today.setDate(today.getDate() + 10));
-const isoString = tenDaysFromToday.toISOString();
-
-describe('initializeClient', () => {
- // Set up environment variables
- const originalEnvironment = process.env;
- const app = {
- locals: {},
- };
-
- beforeEach(() => {
- jest.resetModules(); // Clears the cache
- process.env = { ...originalEnvironment }; // Make a copy
- });
-
- afterAll(() => {
- process.env = originalEnvironment; // Restore original env vars
- });
-
- test('initializes OpenAI client with default API key and URL', async () => {
- process.env.AZURE_ASSISTANTS_API_KEY = 'default-api-key';
- process.env.AZURE_ASSISTANTS_BASE_URL = 'https://default.api.url';
-
- // Assuming 'isUserProvided' to return false for this test case
- jest.mock('~/server/utils', () => ({
- isUserProvided: jest.fn().mockReturnValueOnce(false),
- }));
-
- const req = {
- user: { id: 'user123' },
- app,
- config: { endpoints: { [EModelEndpoint.azureOpenAI]: {} } },
- };
- const res = {};
-
- const { openai, openAIApiKey } = await initializeClient({ req, res });
- expect(openai.apiKey).toBe('default-api-key');
- expect(openAIApiKey).toBe('default-api-key');
- expect(openai.baseURL).toBe('https://default.api.url');
- });
-
- test('initializes OpenAI client with user-provided API key and URL', async () => {
- process.env.AZURE_ASSISTANTS_API_KEY = 'user_provided';
- process.env.AZURE_ASSISTANTS_BASE_URL = 'user_provided';
-
- getUserKeyValues.mockResolvedValue({ apiKey: 'user-api-key', baseURL: 'https://user.api.url' });
- getUserKeyExpiry.mockResolvedValue(isoString);
-
- const req = {
- user: { id: 'user123' },
- app,
- config: { endpoints: { [EModelEndpoint.azureOpenAI]: {} } },
- };
- const res = {};
-
- const { openai, openAIApiKey } = await initializeClient({ req, res });
- expect(openAIApiKey).toBe('user-api-key');
- expect(openai.apiKey).toBe('user-api-key');
- expect(openai.baseURL).toBe('https://user.api.url');
- });
-
- test('throws error for invalid JSON in user-provided values', async () => {
- process.env.AZURE_ASSISTANTS_API_KEY = 'user_provided';
- getUserKey.mockResolvedValue('invalid-json');
- getUserKeyExpiry.mockResolvedValue(isoString);
- getUserKeyValues.mockImplementation(() => {
- let userValues = getUserKey();
- try {
- userValues = JSON.parse(userValues);
- } catch {
- throw new Error(
- JSON.stringify({
- type: ErrorTypes.INVALID_USER_KEY,
- }),
- );
- }
- return userValues;
- });
-
- const req = {
- user: { id: 'user123' },
- config: { endpoints: { [EModelEndpoint.azureOpenAI]: {} } },
- };
- const res = {};
-
- await expect(initializeClient({ req, res })).rejects.toThrow(/invalid_user_key/);
- });
-
- test('throws error if API key is not provided', async () => {
- delete process.env.AZURE_ASSISTANTS_API_KEY; // Simulate missing API key
-
- const req = {
- user: { id: 'user123' },
- app,
- config: { endpoints: { [EModelEndpoint.azureOpenAI]: {} } },
- };
- const res = {};
-
- await expect(initializeClient({ req, res })).rejects.toThrow(/Assistants API key not/);
- });
-
- test('initializes OpenAI client with proxy configuration', async () => {
- process.env.AZURE_ASSISTANTS_API_KEY = 'test-key';
- process.env.PROXY = 'http://proxy.server';
-
- const req = {
- user: { id: 'user123' },
- app,
- config: { endpoints: { [EModelEndpoint.azureOpenAI]: {} } },
- };
- const res = {};
-
- const { openai } = await initializeClient({ req, res });
- expect(openai.fetchOptions).toBeDefined();
- expect(openai.fetchOptions.dispatcher).toBeInstanceOf(ProxyAgent);
- });
-});
diff --git a/api/server/services/Endpoints/bedrock/build.js b/api/server/services/Endpoints/bedrock/build.js
deleted file mode 100644
index b9f281bd99..0000000000
--- a/api/server/services/Endpoints/bedrock/build.js
+++ /dev/null
@@ -1,39 +0,0 @@
-const { removeNullishValues } = require('librechat-data-provider');
-const generateArtifactsPrompt = require('~/app/clients/prompts/artifacts');
-
-const buildOptions = (endpoint, parsedBody) => {
- const {
- modelLabel: name,
- promptPrefix,
- maxContextTokens,
- fileTokenLimit,
- resendFiles = true,
- imageDetail,
- iconURL,
- greeting,
- spec,
- artifacts,
- ...model_parameters
- } = parsedBody;
- const endpointOption = removeNullishValues({
- endpoint,
- name,
- resendFiles,
- imageDetail,
- iconURL,
- greeting,
- spec,
- promptPrefix,
- maxContextTokens,
- fileTokenLimit,
- model_parameters,
- });
-
- if (typeof artifacts === 'string') {
- endpointOption.artifactsPrompt = generateArtifactsPrompt({ endpoint, artifacts });
- }
-
- return endpointOption;
-};
-
-module.exports = { buildOptions };
diff --git a/api/server/services/Endpoints/bedrock/index.js b/api/server/services/Endpoints/bedrock/index.js
deleted file mode 100644
index 8989f7df8c..0000000000
--- a/api/server/services/Endpoints/bedrock/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const build = require('./build');
-const initialize = require('./initialize');
-
-module.exports = {
- ...build,
- ...initialize,
-};
diff --git a/api/server/services/Endpoints/bedrock/initialize.js b/api/server/services/Endpoints/bedrock/initialize.js
deleted file mode 100644
index bbee7caf39..0000000000
--- a/api/server/services/Endpoints/bedrock/initialize.js
+++ /dev/null
@@ -1,79 +0,0 @@
-const { getModelMaxTokens } = require('@librechat/api');
-const { createContentAggregator } = require('@librechat/agents');
-const {
- EModelEndpoint,
- providerEndpointMap,
- getResponseSender,
-} = require('librechat-data-provider');
-const { getDefaultHandlers } = require('~/server/controllers/agents/callbacks');
-const getOptions = require('~/server/services/Endpoints/bedrock/options');
-const AgentClient = require('~/server/controllers/agents/client');
-
-const initializeClient = async ({ req, res, endpointOption }) => {
- if (!endpointOption) {
- throw new Error('Endpoint option not provided');
- }
-
- /** @type {Array} */
- const collectedUsage = [];
- const { contentParts, aggregateContent } = createContentAggregator();
- const eventHandlers = getDefaultHandlers({ res, aggregateContent, collectedUsage });
-
- /** @type {Agent} */
- const agent = {
- id: EModelEndpoint.bedrock,
- name: endpointOption.name,
- provider: EModelEndpoint.bedrock,
- endpoint: EModelEndpoint.bedrock,
- instructions: endpointOption.promptPrefix,
- model: endpointOption.model_parameters.model,
- model_parameters: endpointOption.model_parameters,
- };
-
- if (typeof endpointOption.artifactsPrompt === 'string' && endpointOption.artifactsPrompt) {
- agent.instructions = `${agent.instructions ?? ''}\n${endpointOption.artifactsPrompt}`.trim();
- }
-
- // TODO: pass-in override settings that are specific to current run
- const options = await getOptions({
- req,
- res,
- endpointOption,
- });
-
- agent.model_parameters = Object.assign(agent.model_parameters, options.llmConfig);
- if (options.configOptions) {
- agent.model_parameters.configuration = options.configOptions;
- }
-
- const sender =
- agent.name ??
- getResponseSender({
- ...endpointOption,
- model: endpointOption.model_parameters.model,
- });
-
- const client = new AgentClient({
- req,
- res,
- agent,
- sender,
- // tools,
- contentParts,
- eventHandlers,
- collectedUsage,
- spec: endpointOption.spec,
- iconURL: endpointOption.iconURL,
- endpoint: EModelEndpoint.bedrock,
- resendFiles: endpointOption.resendFiles,
- maxContextTokens:
- endpointOption.maxContextTokens ??
- agent.max_context_tokens ??
- getModelMaxTokens(agent.model_parameters.model, providerEndpointMap[agent.provider]) ??
- 4000,
- attachments: endpointOption.attachments,
- });
- return { client };
-};
-
-module.exports = { initializeClient };
diff --git a/api/server/services/Endpoints/bedrock/options.js b/api/server/services/Endpoints/bedrock/options.js
deleted file mode 100644
index 0d02d09b07..0000000000
--- a/api/server/services/Endpoints/bedrock/options.js
+++ /dev/null
@@ -1,98 +0,0 @@
-const { HttpsProxyAgent } = require('https-proxy-agent');
-const {
- AuthType,
- EModelEndpoint,
- bedrockInputParser,
- bedrockOutputParser,
- removeNullishValues,
-} = require('librechat-data-provider');
-const { getUserKey, checkUserKeyExpiry } = require('~/server/services/UserService');
-
-const getOptions = async ({ req, overrideModel, endpointOption }) => {
- const {
- BEDROCK_AWS_SECRET_ACCESS_KEY,
- BEDROCK_AWS_ACCESS_KEY_ID,
- BEDROCK_AWS_SESSION_TOKEN,
- BEDROCK_REVERSE_PROXY,
- BEDROCK_AWS_DEFAULT_REGION,
- PROXY,
- } = process.env;
- const expiresAt = req.body.key;
- const isUserProvided = BEDROCK_AWS_SECRET_ACCESS_KEY === AuthType.USER_PROVIDED;
-
- let credentials = isUserProvided
- ? await getUserKey({ userId: req.user.id, name: EModelEndpoint.bedrock })
- : {
- accessKeyId: BEDROCK_AWS_ACCESS_KEY_ID,
- secretAccessKey: BEDROCK_AWS_SECRET_ACCESS_KEY,
- ...(BEDROCK_AWS_SESSION_TOKEN && { sessionToken: BEDROCK_AWS_SESSION_TOKEN }),
- };
-
- if (!credentials) {
- throw new Error('Bedrock credentials not provided. Please provide them again.');
- }
-
- if (
- !isUserProvided &&
- (credentials.accessKeyId === undefined || credentials.accessKeyId === '') &&
- (credentials.secretAccessKey === undefined || credentials.secretAccessKey === '')
- ) {
- credentials = undefined;
- }
-
- if (expiresAt && isUserProvided) {
- checkUserKeyExpiry(expiresAt, EModelEndpoint.bedrock);
- }
-
- /*
- Callback for stream rate no longer awaits and may end the stream prematurely
- /** @type {number}
- let streamRate = Constants.DEFAULT_STREAM_RATE;
-
- /** @type {undefined | TBaseEndpoint}
- const bedrockConfig = appConfig.endpoints?.[EModelEndpoint.bedrock];
-
- if (bedrockConfig && bedrockConfig.streamRate) {
- streamRate = bedrockConfig.streamRate;
- }
-
- const allConfig = appConfig.endpoints?.all;
- if (allConfig && allConfig.streamRate) {
- streamRate = allConfig.streamRate;
- }
- */
-
- /** @type {BedrockClientOptions} */
- const requestOptions = {
- model: overrideModel ?? endpointOption?.model,
- region: BEDROCK_AWS_DEFAULT_REGION,
- };
-
- const configOptions = {};
- if (PROXY) {
- /** NOTE: NOT SUPPORTED BY BEDROCK */
- configOptions.httpAgent = new HttpsProxyAgent(PROXY);
- }
-
- const llmConfig = bedrockOutputParser(
- bedrockInputParser.parse(
- removeNullishValues(Object.assign(requestOptions, endpointOption?.model_parameters ?? {})),
- ),
- );
-
- if (credentials) {
- llmConfig.credentials = credentials;
- }
-
- if (BEDROCK_REVERSE_PROXY) {
- llmConfig.endpointHost = BEDROCK_REVERSE_PROXY;
- }
-
- return {
- /** @type {BedrockClientOptions} */
- llmConfig,
- configOptions,
- };
-};
-
-module.exports = getOptions;
diff --git a/api/server/services/Endpoints/custom/build.js b/api/server/services/Endpoints/custom/build.js
deleted file mode 100644
index b1839ee035..0000000000
--- a/api/server/services/Endpoints/custom/build.js
+++ /dev/null
@@ -1,42 +0,0 @@
-const { removeNullishValues } = require('librechat-data-provider');
-const generateArtifactsPrompt = require('~/app/clients/prompts/artifacts');
-
-const buildOptions = (endpoint, parsedBody, endpointType) => {
- const {
- modelLabel,
- chatGptLabel,
- promptPrefix,
- maxContextTokens,
- fileTokenLimit,
- resendFiles = true,
- imageDetail,
- iconURL,
- greeting,
- spec,
- artifacts,
- ...modelOptions
- } = parsedBody;
- const endpointOption = removeNullishValues({
- endpoint,
- endpointType,
- modelLabel,
- chatGptLabel,
- promptPrefix,
- resendFiles,
- imageDetail,
- iconURL,
- greeting,
- spec,
- maxContextTokens,
- fileTokenLimit,
- modelOptions,
- });
-
- if (typeof artifacts === 'string') {
- endpointOption.artifactsPrompt = generateArtifactsPrompt({ endpoint, artifacts });
- }
-
- return endpointOption;
-};
-
-module.exports = buildOptions;
diff --git a/api/server/services/Endpoints/custom/index.js b/api/server/services/Endpoints/custom/index.js
deleted file mode 100644
index 5a70d78749..0000000000
--- a/api/server/services/Endpoints/custom/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const initializeClient = require('./initialize');
-const buildOptions = require('./build');
-
-module.exports = {
- initializeClient,
- buildOptions,
-};
diff --git a/api/server/services/Endpoints/custom/initialize.js b/api/server/services/Endpoints/custom/initialize.js
deleted file mode 100644
index 5aa8b08a92..0000000000
--- a/api/server/services/Endpoints/custom/initialize.js
+++ /dev/null
@@ -1,157 +0,0 @@
-const { isUserProvided, getOpenAIConfig, getCustomEndpointConfig } = require('@librechat/api');
-const {
- CacheKeys,
- ErrorTypes,
- envVarRegex,
- FetchTokenConfig,
- extractEnvVariable,
-} = require('librechat-data-provider');
-const { getUserKeyValues, checkUserKeyExpiry } = require('~/server/services/UserService');
-const { fetchModels } = require('~/server/services/ModelService');
-const OpenAIClient = require('~/app/clients/OpenAIClient');
-const getLogStores = require('~/cache/getLogStores');
-
-const { PROXY } = process.env;
-
-const initializeClient = async ({ req, res, endpointOption, optionsOnly, overrideEndpoint }) => {
- const appConfig = req.config;
- const { key: expiresAt } = req.body;
- const endpoint = overrideEndpoint ?? req.body.endpoint;
-
- const endpointConfig = getCustomEndpointConfig({
- endpoint,
- appConfig,
- });
- if (!endpointConfig) {
- throw new Error(`Config not found for the ${endpoint} custom endpoint.`);
- }
-
- const CUSTOM_API_KEY = extractEnvVariable(endpointConfig.apiKey);
- const CUSTOM_BASE_URL = extractEnvVariable(endpointConfig.baseURL);
-
- if (CUSTOM_API_KEY.match(envVarRegex)) {
- throw new Error(`Missing API Key for ${endpoint}.`);
- }
-
- if (CUSTOM_BASE_URL.match(envVarRegex)) {
- throw new Error(`Missing Base URL for ${endpoint}.`);
- }
-
- const userProvidesKey = isUserProvided(CUSTOM_API_KEY);
- const userProvidesURL = isUserProvided(CUSTOM_BASE_URL);
-
- let userValues = null;
- if (expiresAt && (userProvidesKey || userProvidesURL)) {
- checkUserKeyExpiry(expiresAt, endpoint);
- userValues = await getUserKeyValues({ userId: req.user.id, name: endpoint });
- }
-
- let apiKey = userProvidesKey ? userValues?.apiKey : CUSTOM_API_KEY;
- let baseURL = userProvidesURL ? userValues?.baseURL : CUSTOM_BASE_URL;
-
- if (userProvidesKey & !apiKey) {
- throw new Error(
- JSON.stringify({
- type: ErrorTypes.NO_USER_KEY,
- }),
- );
- }
-
- if (userProvidesURL && !baseURL) {
- throw new Error(
- JSON.stringify({
- type: ErrorTypes.NO_BASE_URL,
- }),
- );
- }
-
- if (!apiKey) {
- throw new Error(`${endpoint} API key not provided.`);
- }
-
- if (!baseURL) {
- throw new Error(`${endpoint} Base URL not provided.`);
- }
-
- const cache = getLogStores(CacheKeys.TOKEN_CONFIG);
- const tokenKey =
- !endpointConfig.tokenConfig && (userProvidesKey || userProvidesURL)
- ? `${endpoint}:${req.user.id}`
- : endpoint;
-
- let endpointTokenConfig =
- !endpointConfig.tokenConfig &&
- FetchTokenConfig[endpoint.toLowerCase()] &&
- (await cache.get(tokenKey));
-
- if (
- FetchTokenConfig[endpoint.toLowerCase()] &&
- endpointConfig &&
- endpointConfig.models.fetch &&
- !endpointTokenConfig
- ) {
- await fetchModels({ apiKey, baseURL, name: endpoint, user: req.user.id, tokenKey });
- endpointTokenConfig = await cache.get(tokenKey);
- }
-
- const customOptions = {
- headers: endpointConfig.headers,
- addParams: endpointConfig.addParams,
- dropParams: endpointConfig.dropParams,
- customParams: endpointConfig.customParams,
- titleConvo: endpointConfig.titleConvo,
- titleModel: endpointConfig.titleModel,
- forcePrompt: endpointConfig.forcePrompt,
- summaryModel: endpointConfig.summaryModel,
- modelDisplayLabel: endpointConfig.modelDisplayLabel,
- titleMethod: endpointConfig.titleMethod ?? 'completion',
- contextStrategy: endpointConfig.summarize ? 'summarize' : null,
- directEndpoint: endpointConfig.directEndpoint,
- titleMessageRole: endpointConfig.titleMessageRole,
- streamRate: endpointConfig.streamRate,
- endpointTokenConfig,
- };
-
- const allConfig = appConfig.endpoints?.all;
- if (allConfig) {
- customOptions.streamRate = allConfig.streamRate;
- }
-
- let clientOptions = {
- reverseProxyUrl: baseURL ?? null,
- proxy: PROXY ?? null,
- req,
- res,
- ...customOptions,
- ...endpointOption,
- };
-
- if (optionsOnly) {
- const modelOptions = endpointOption?.model_parameters ?? {};
- clientOptions = Object.assign(
- {
- modelOptions,
- },
- clientOptions,
- );
- clientOptions.modelOptions.user = req.user.id;
- const options = getOpenAIConfig(apiKey, clientOptions, endpoint);
- if (options != null) {
- options.useLegacyContent = true;
- options.endpointTokenConfig = endpointTokenConfig;
- }
- if (!clientOptions.streamRate) {
- return options;
- }
- options.llmConfig._lc_stream_delay = clientOptions.streamRate;
- return options;
- }
-
- const client = new OpenAIClient(apiKey, clientOptions);
- return {
- client,
- openAIApiKey: apiKey,
- };
-};
-
-module.exports = initializeClient;
diff --git a/api/server/services/Endpoints/custom/initialize.spec.js b/api/server/services/Endpoints/custom/initialize.spec.js
deleted file mode 100644
index d12906df9a..0000000000
--- a/api/server/services/Endpoints/custom/initialize.spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-const initializeClient = require('./initialize');
-
-jest.mock('@librechat/api', () => ({
- ...jest.requireActual('@librechat/api'),
- resolveHeaders: jest.fn(),
- getOpenAIConfig: jest.fn(),
- getCustomEndpointConfig: jest.fn().mockReturnValue({
- apiKey: 'test-key',
- baseURL: 'https://test.com',
- headers: { 'x-user': '{{LIBRECHAT_USER_ID}}', 'x-email': '{{LIBRECHAT_USER_EMAIL}}' },
- models: { default: ['test-model'] },
- }),
-}));
-
-jest.mock('~/server/services/UserService', () => ({
- getUserKeyValues: jest.fn(),
- checkUserKeyExpiry: jest.fn(),
-}));
-
-// Config is now passed via req.config, not getAppConfig
-
-jest.mock('~/server/services/ModelService', () => ({
- fetchModels: jest.fn(),
-}));
-
-jest.mock('~/app/clients/OpenAIClient', () => {
- return jest.fn().mockImplementation(() => ({
- options: {},
- }));
-});
-
-jest.mock('~/cache/getLogStores', () =>
- jest.fn().mockReturnValue({
- get: jest.fn(),
- }),
-);
-
-describe('custom/initializeClient', () => {
- const mockRequest = {
- body: { endpoint: 'test-endpoint' },
- user: { id: 'user-123', email: 'test@example.com', role: 'user' },
- app: { locals: {} },
- config: {
- endpoints: {
- all: {
- streamRate: 25,
- },
- },
- },
- };
- const mockResponse = {};
-
- beforeEach(() => {
- jest.clearAllMocks();
- const { getCustomEndpointConfig, resolveHeaders, getOpenAIConfig } = require('@librechat/api');
- getCustomEndpointConfig.mockReturnValue({
- apiKey: 'test-key',
- baseURL: 'https://test.com',
- headers: { 'x-user': '{{LIBRECHAT_USER_ID}}', 'x-email': '{{LIBRECHAT_USER_EMAIL}}' },
- models: { default: ['test-model'] },
- });
- resolveHeaders.mockReturnValue({ 'x-user': 'user-123', 'x-email': 'test@example.com' });
- getOpenAIConfig.mockReturnValue({
- useLegacyContent: true,
- endpointTokenConfig: null,
- llmConfig: {
- callbacks: [],
- },
- });
- });
-
- it('stores original template headers for deferred resolution', async () => {
- /**
- * Note: Request-based Header Resolution is deferred until right before LLM request is made
- * in the OpenAIClient or AgentClient, not during initialization.
- * This test verifies that the initialize function completes successfully with optionsOnly flag,
- * and that headers are passed through to be resolved later during the actual LLM request.
- */
- const result = await initializeClient({
- req: mockRequest,
- res: mockResponse,
- optionsOnly: true,
- });
- // Verify that options are returned for later use
- expect(result).toBeDefined();
- expect(result).toHaveProperty('useLegacyContent', true);
- });
-
- it('throws if endpoint config is missing', async () => {
- const { getCustomEndpointConfig } = require('@librechat/api');
- getCustomEndpointConfig.mockReturnValueOnce(null);
- await expect(
- initializeClient({ req: mockRequest, res: mockResponse, optionsOnly: true }),
- ).rejects.toThrow('Config not found for the test-endpoint custom endpoint.');
- });
-
- it('throws if user is missing', async () => {
- await expect(
- initializeClient({
- req: { ...mockRequest, user: undefined },
- res: mockResponse,
- optionsOnly: true,
- }),
- ).rejects.toThrow("Cannot read properties of undefined (reading 'id')");
- });
-});
diff --git a/api/server/services/Endpoints/google/build.js b/api/server/services/Endpoints/google/build.js
deleted file mode 100644
index 3ac6b167c4..0000000000
--- a/api/server/services/Endpoints/google/build.js
+++ /dev/null
@@ -1,39 +0,0 @@
-const { removeNullishValues } = require('librechat-data-provider');
-const generateArtifactsPrompt = require('~/app/clients/prompts/artifacts');
-
-const buildOptions = (endpoint, parsedBody) => {
- const {
- examples,
- modelLabel,
- resendFiles = true,
- promptPrefix,
- iconURL,
- greeting,
- spec,
- artifacts,
- maxContextTokens,
- fileTokenLimit,
- ...modelOptions
- } = parsedBody;
- const endpointOption = removeNullishValues({
- examples,
- endpoint,
- modelLabel,
- resendFiles,
- promptPrefix,
- iconURL,
- greeting,
- spec,
- maxContextTokens,
- fileTokenLimit,
- modelOptions,
- });
-
- if (typeof artifacts === 'string') {
- endpointOption.artifactsPrompt = generateArtifactsPrompt({ endpoint, artifacts });
- }
-
- return endpointOption;
-};
-
-module.exports = buildOptions;
diff --git a/api/server/services/Endpoints/google/index.js b/api/server/services/Endpoints/google/index.js
deleted file mode 100644
index c4e7533c5d..0000000000
--- a/api/server/services/Endpoints/google/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-const addTitle = require('./title');
-const buildOptions = require('./build');
-const initializeClient = require('./initialize');
-
-module.exports = {
- addTitle,
- buildOptions,
- initializeClient,
-};
diff --git a/api/server/services/Endpoints/google/initialize.js b/api/server/services/Endpoints/google/initialize.js
deleted file mode 100644
index 9a685d679a..0000000000
--- a/api/server/services/Endpoints/google/initialize.js
+++ /dev/null
@@ -1,95 +0,0 @@
-const path = require('path');
-const { EModelEndpoint, AuthKeys } = require('librechat-data-provider');
-const { getGoogleConfig, isEnabled, loadServiceKey } = require('@librechat/api');
-const { getUserKey, checkUserKeyExpiry } = require('~/server/services/UserService');
-const { GoogleClient } = require('~/app');
-
-const initializeClient = async ({ req, res, endpointOption, overrideModel, optionsOnly }) => {
- const { GOOGLE_KEY, GOOGLE_REVERSE_PROXY, GOOGLE_AUTH_HEADER, PROXY } = process.env;
- const isUserProvided = GOOGLE_KEY === 'user_provided';
- const { key: expiresAt } = req.body;
-
- let userKey = null;
- if (expiresAt && isUserProvided) {
- checkUserKeyExpiry(expiresAt, EModelEndpoint.google);
- userKey = await getUserKey({ userId: req.user.id, name: EModelEndpoint.google });
- }
-
- let serviceKey = {};
-
- /** Check if GOOGLE_KEY is provided at all (including 'user_provided') */
- const isGoogleKeyProvided =
- (GOOGLE_KEY && GOOGLE_KEY.trim() !== '') || (isUserProvided && userKey != null);
-
- if (!isGoogleKeyProvided) {
- /** Only attempt to load service key if GOOGLE_KEY is not provided */
- try {
- const serviceKeyPath =
- process.env.GOOGLE_SERVICE_KEY_FILE ||
- path.join(__dirname, '../../../..', 'data', 'auth.json');
- serviceKey = await loadServiceKey(serviceKeyPath);
- if (!serviceKey) {
- serviceKey = {};
- }
- } catch (_e) {
- // Service key loading failed, but that's okay if not required
- serviceKey = {};
- }
- }
-
- const credentials = isUserProvided
- ? userKey
- : {
- [AuthKeys.GOOGLE_SERVICE_KEY]: serviceKey,
- [AuthKeys.GOOGLE_API_KEY]: GOOGLE_KEY,
- };
-
- let clientOptions = {};
-
- const appConfig = req.config;
- /** @type {undefined | TBaseEndpoint} */
- const allConfig = appConfig.endpoints?.all;
- /** @type {undefined | TBaseEndpoint} */
- const googleConfig = appConfig.endpoints?.[EModelEndpoint.google];
-
- if (googleConfig) {
- clientOptions.streamRate = googleConfig.streamRate;
- clientOptions.titleModel = googleConfig.titleModel;
- }
-
- if (allConfig) {
- clientOptions.streamRate = allConfig.streamRate;
- }
-
- clientOptions = {
- req,
- res,
- reverseProxyUrl: GOOGLE_REVERSE_PROXY ?? null,
- authHeader: isEnabled(GOOGLE_AUTH_HEADER) ?? null,
- proxy: PROXY ?? null,
- ...clientOptions,
- ...endpointOption,
- };
-
- if (optionsOnly) {
- clientOptions = Object.assign(
- {
- modelOptions: endpointOption?.model_parameters ?? {},
- },
- clientOptions,
- );
- if (overrideModel) {
- clientOptions.modelOptions.model = overrideModel;
- }
- return getGoogleConfig(credentials, clientOptions);
- }
-
- const client = new GoogleClient(credentials, clientOptions);
-
- return {
- client,
- credentials,
- };
-};
-
-module.exports = initializeClient;
diff --git a/api/server/services/Endpoints/google/initialize.spec.js b/api/server/services/Endpoints/google/initialize.spec.js
deleted file mode 100644
index aa8a61e9c2..0000000000
--- a/api/server/services/Endpoints/google/initialize.spec.js
+++ /dev/null
@@ -1,101 +0,0 @@
-// file deepcode ignore HardcodedNonCryptoSecret: No hardcoded secrets
-const { getUserKey } = require('~/server/services/UserService');
-const initializeClient = require('./initialize');
-const { GoogleClient } = require('~/app');
-
-jest.mock('~/server/services/UserService', () => ({
- checkUserKeyExpiry: jest.requireActual('~/server/services/UserService').checkUserKeyExpiry,
- getUserKey: jest.fn().mockImplementation(() => ({})),
-}));
-
-// Config is now passed via req.config, not getAppConfig
-
-const app = { locals: {} };
-
-describe('google/initializeClient', () => {
- afterEach(() => {
- jest.clearAllMocks();
- });
-
- test('should initialize GoogleClient with user-provided credentials', async () => {
- process.env.GOOGLE_KEY = 'user_provided';
- process.env.GOOGLE_REVERSE_PROXY = 'http://reverse.proxy';
- process.env.PROXY = 'http://proxy';
-
- const expiresAt = new Date(Date.now() + 60000).toISOString();
-
- const req = {
- body: { key: expiresAt },
- user: { id: '123' },
- app,
- config: {
- endpoints: {
- all: {},
- google: {},
- },
- },
- };
- const res = {};
- const endpointOption = { modelOptions: { model: 'default-model' } };
-
- const { client, credentials } = await initializeClient({ req, res, endpointOption });
-
- expect(getUserKey).toHaveBeenCalledWith({ userId: '123', name: 'google' });
- expect(client).toBeInstanceOf(GoogleClient);
- expect(client.options.reverseProxyUrl).toBe('http://reverse.proxy');
- expect(client.options.proxy).toBe('http://proxy');
- expect(credentials).toEqual({});
- });
-
- test('should initialize GoogleClient with service key credentials', async () => {
- process.env.GOOGLE_KEY = 'service_key';
- process.env.GOOGLE_REVERSE_PROXY = 'http://reverse.proxy';
- process.env.PROXY = 'http://proxy';
-
- const req = {
- body: { key: null },
- user: { id: '123' },
- app,
- config: {
- endpoints: {
- all: {},
- google: {},
- },
- },
- };
- const res = {};
- const endpointOption = { modelOptions: { model: 'default-model' } };
-
- const { client, credentials } = await initializeClient({ req, res, endpointOption });
-
- expect(client).toBeInstanceOf(GoogleClient);
- expect(client.options.reverseProxyUrl).toBe('http://reverse.proxy');
- expect(client.options.proxy).toBe('http://proxy');
- expect(credentials).toEqual({
- GOOGLE_SERVICE_KEY: {},
- GOOGLE_API_KEY: 'service_key',
- });
- });
-
- test('should handle expired user-provided key', async () => {
- process.env.GOOGLE_KEY = 'user_provided';
-
- const expiresAt = new Date(Date.now() - 10000).toISOString(); // Expired
- const req = {
- body: { key: expiresAt },
- user: { id: '123' },
- app,
- config: {
- endpoints: {
- all: {},
- google: {},
- },
- },
- };
- const res = {};
- const endpointOption = { modelOptions: { model: 'default-model' } };
- await expect(initializeClient({ req, res, endpointOption })).rejects.toThrow(
- /expired_user_key/,
- );
- });
-});
diff --git a/api/server/services/Endpoints/google/title.js b/api/server/services/Endpoints/google/title.js
deleted file mode 100644
index 63ed8aae5f..0000000000
--- a/api/server/services/Endpoints/google/title.js
+++ /dev/null
@@ -1,60 +0,0 @@
-const { isEnabled } = require('@librechat/api');
-const { EModelEndpoint, CacheKeys, Constants, googleSettings } = require('librechat-data-provider');
-const getLogStores = require('~/cache/getLogStores');
-const initializeClient = require('./initialize');
-const { saveConvo } = require('~/models');
-
-const addTitle = async (req, { text, response, client }) => {
- const { TITLE_CONVO = 'true' } = process.env ?? {};
- if (!isEnabled(TITLE_CONVO)) {
- return;
- }
-
- if (client.options.titleConvo === false) {
- return;
- }
- const { GOOGLE_TITLE_MODEL } = process.env ?? {};
- const appConfig = req.config;
- const providerConfig = appConfig.endpoints?.[EModelEndpoint.google];
- let model =
- providerConfig?.titleModel ??
- GOOGLE_TITLE_MODEL ??
- client.options?.modelOptions.model ??
- googleSettings.model.default;
-
- if (GOOGLE_TITLE_MODEL === Constants.CURRENT_MODEL) {
- model = client.options?.modelOptions.model;
- }
-
- const titleEndpointOptions = {
- ...client.options,
- modelOptions: { ...client.options?.modelOptions, model: model },
- attachments: undefined, // After a response, this is set to an empty array which results in an error during setOptions
- };
-
- const { client: titleClient } = await initializeClient({
- req,
- res: response,
- endpointOption: titleEndpointOptions,
- });
-
- const titleCache = getLogStores(CacheKeys.GEN_TITLE);
- const key = `${req.user.id}-${response.conversationId}`;
-
- const title = await titleClient.titleConvo({
- text,
- responseText: response?.text ?? '',
- conversationId: response.conversationId,
- });
- await titleCache.set(key, title, 120000);
- await saveConvo(
- req,
- {
- conversationId: response.conversationId,
- title,
- },
- { context: 'api/server/services/Endpoints/google/addTitle.js' },
- );
-};
-
-module.exports = addTitle;
diff --git a/api/server/services/Endpoints/index.js b/api/server/services/Endpoints/index.js
index 034162702d..3cabfe1c58 100644
--- a/api/server/services/Endpoints/index.js
+++ b/api/server/services/Endpoints/index.js
@@ -12,7 +12,7 @@ const initGoogle = require('~/server/services/Endpoints/google/initialize');
* @returns {boolean} - True if the provider is a known custom provider, false otherwise
*/
function isKnownCustomProvider(provider) {
- return [Providers.XAI, Providers.DEEPSEEK, Providers.OPENROUTER].includes(
+ return [Providers.XAI, Providers.DEEPSEEK, Providers.OPENROUTER, Providers.MOONSHOT].includes(
provider?.toLowerCase() || '',
);
}
@@ -20,6 +20,7 @@ function isKnownCustomProvider(provider) {
const providerConfigMap = {
[Providers.XAI]: initCustom,
[Providers.DEEPSEEK]: initCustom,
+ [Providers.MOONSHOT]: initCustom,
[Providers.OPENROUTER]: initCustom,
[EModelEndpoint.openAI]: initOpenAI,
[EModelEndpoint.google]: initGoogle,
diff --git a/api/server/services/Endpoints/openAI/build.js b/api/server/services/Endpoints/openAI/build.js
deleted file mode 100644
index 611546a545..0000000000
--- a/api/server/services/Endpoints/openAI/build.js
+++ /dev/null
@@ -1,42 +0,0 @@
-const { removeNullishValues } = require('librechat-data-provider');
-const generateArtifactsPrompt = require('~/app/clients/prompts/artifacts');
-
-const buildOptions = (endpoint, parsedBody) => {
- const {
- modelLabel,
- chatGptLabel,
- promptPrefix,
- maxContextTokens,
- fileTokenLimit,
- resendFiles = true,
- imageDetail,
- iconURL,
- greeting,
- spec,
- artifacts,
- ...modelOptions
- } = parsedBody;
-
- const endpointOption = removeNullishValues({
- endpoint,
- modelLabel,
- chatGptLabel,
- promptPrefix,
- resendFiles,
- imageDetail,
- iconURL,
- greeting,
- spec,
- maxContextTokens,
- fileTokenLimit,
- modelOptions,
- });
-
- if (typeof artifacts === 'string') {
- endpointOption.artifactsPrompt = generateArtifactsPrompt({ endpoint, artifacts });
- }
-
- return endpointOption;
-};
-
-module.exports = buildOptions;
diff --git a/api/server/services/Endpoints/openAI/index.js b/api/server/services/Endpoints/openAI/index.js
deleted file mode 100644
index c4e7533c5d..0000000000
--- a/api/server/services/Endpoints/openAI/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-const addTitle = require('./title');
-const buildOptions = require('./build');
-const initializeClient = require('./initialize');
-
-module.exports = {
- addTitle,
- buildOptions,
- initializeClient,
-};
diff --git a/api/server/services/Endpoints/openAI/initialize.js b/api/server/services/Endpoints/openAI/initialize.js
deleted file mode 100644
index cd691c6240..0000000000
--- a/api/server/services/Endpoints/openAI/initialize.js
+++ /dev/null
@@ -1,164 +0,0 @@
-const { ErrorTypes, EModelEndpoint, mapModelToAzureConfig } = require('librechat-data-provider');
-const {
- isEnabled,
- resolveHeaders,
- isUserProvided,
- getOpenAIConfig,
- getAzureCredentials,
-} = require('@librechat/api');
-const { getUserKeyValues, checkUserKeyExpiry } = require('~/server/services/UserService');
-const OpenAIClient = require('~/app/clients/OpenAIClient');
-
-const initializeClient = async ({
- req,
- res,
- endpointOption,
- optionsOnly,
- overrideEndpoint,
- overrideModel,
-}) => {
- const appConfig = req.config;
- const {
- PROXY,
- OPENAI_API_KEY,
- AZURE_API_KEY,
- OPENAI_REVERSE_PROXY,
- AZURE_OPENAI_BASEURL,
- OPENAI_SUMMARIZE,
- DEBUG_OPENAI,
- } = process.env;
- const { key: expiresAt } = req.body;
- const modelName = overrideModel ?? req.body.model;
- const endpoint = overrideEndpoint ?? req.body.endpoint;
- const contextStrategy = isEnabled(OPENAI_SUMMARIZE) ? 'summarize' : null;
-
- const credentials = {
- [EModelEndpoint.openAI]: OPENAI_API_KEY,
- [EModelEndpoint.azureOpenAI]: AZURE_API_KEY,
- };
-
- const baseURLOptions = {
- [EModelEndpoint.openAI]: OPENAI_REVERSE_PROXY,
- [EModelEndpoint.azureOpenAI]: AZURE_OPENAI_BASEURL,
- };
-
- const userProvidesKey = isUserProvided(credentials[endpoint]);
- const userProvidesURL = isUserProvided(baseURLOptions[endpoint]);
-
- let userValues = null;
- if (expiresAt && (userProvidesKey || userProvidesURL)) {
- checkUserKeyExpiry(expiresAt, endpoint);
- userValues = await getUserKeyValues({ userId: req.user.id, name: endpoint });
- }
-
- let apiKey = userProvidesKey ? userValues?.apiKey : credentials[endpoint];
- let baseURL = userProvidesURL ? userValues?.baseURL : baseURLOptions[endpoint];
-
- let clientOptions = {
- contextStrategy,
- proxy: PROXY ?? null,
- debug: isEnabled(DEBUG_OPENAI),
- reverseProxyUrl: baseURL ? baseURL : null,
- ...endpointOption,
- };
-
- const isAzureOpenAI = endpoint === EModelEndpoint.azureOpenAI;
- /** @type {false | TAzureConfig} */
- const azureConfig = isAzureOpenAI && appConfig.endpoints?.[EModelEndpoint.azureOpenAI];
- let serverless = false;
- if (isAzureOpenAI && azureConfig) {
- const { modelGroupMap, groupMap } = azureConfig;
- const {
- azureOptions,
- baseURL,
- headers = {},
- serverless: _serverless,
- } = mapModelToAzureConfig({
- modelName,
- modelGroupMap,
- groupMap,
- });
- serverless = _serverless;
-
- clientOptions.reverseProxyUrl = baseURL ?? clientOptions.reverseProxyUrl;
- clientOptions.headers = resolveHeaders({
- headers: { ...headers, ...(clientOptions.headers ?? {}) },
- user: req.user,
- });
-
- clientOptions.titleConvo = azureConfig.titleConvo;
- clientOptions.titleModel = azureConfig.titleModel;
-
- const azureRate = modelName.includes('gpt-4') ? 30 : 17;
- clientOptions.streamRate = azureConfig.streamRate ?? azureRate;
-
- clientOptions.titleMethod = azureConfig.titleMethod ?? 'completion';
-
- const groupName = modelGroupMap[modelName].group;
- clientOptions.addParams = azureConfig.groupMap[groupName].addParams;
- clientOptions.dropParams = azureConfig.groupMap[groupName].dropParams;
- clientOptions.forcePrompt = azureConfig.groupMap[groupName].forcePrompt;
-
- apiKey = azureOptions.azureOpenAIApiKey;
- clientOptions.azure = !serverless && azureOptions;
- if (serverless === true) {
- clientOptions.defaultQuery = azureOptions.azureOpenAIApiVersion
- ? { 'api-version': azureOptions.azureOpenAIApiVersion }
- : undefined;
- clientOptions.headers['api-key'] = apiKey;
- }
- } else if (isAzureOpenAI) {
- clientOptions.azure = userProvidesKey ? JSON.parse(userValues.apiKey) : getAzureCredentials();
- apiKey = clientOptions.azure.azureOpenAIApiKey;
- }
-
- /** @type {undefined | TBaseEndpoint} */
- const openAIConfig = appConfig.endpoints?.[EModelEndpoint.openAI];
-
- if (!isAzureOpenAI && openAIConfig) {
- clientOptions.streamRate = openAIConfig.streamRate;
- clientOptions.titleModel = openAIConfig.titleModel;
- }
-
- const allConfig = appConfig.endpoints?.all;
- if (allConfig) {
- clientOptions.streamRate = allConfig.streamRate;
- }
-
- if (userProvidesKey & !apiKey) {
- throw new Error(
- JSON.stringify({
- type: ErrorTypes.NO_USER_KEY,
- }),
- );
- }
-
- if (!apiKey) {
- throw new Error(`${endpoint} API Key not provided.`);
- }
-
- if (optionsOnly) {
- const modelOptions = endpointOption?.model_parameters ?? {};
- modelOptions.model = modelName;
- clientOptions = Object.assign({ modelOptions }, clientOptions);
- clientOptions.modelOptions.user = req.user.id;
- const options = getOpenAIConfig(apiKey, clientOptions, endpoint);
- if (options != null && serverless === true) {
- options.useLegacyContent = true;
- }
- const streamRate = clientOptions.streamRate;
- if (!streamRate) {
- return options;
- }
- options.llmConfig._lc_stream_delay = streamRate;
- return options;
- }
-
- const client = new OpenAIClient(apiKey, Object.assign({ req, res }, clientOptions));
- return {
- client,
- openAIApiKey: apiKey,
- };
-};
-
-module.exports = initializeClient;
diff --git a/api/server/services/Endpoints/openAI/initialize.spec.js b/api/server/services/Endpoints/openAI/initialize.spec.js
deleted file mode 100644
index d51300aafe..0000000000
--- a/api/server/services/Endpoints/openAI/initialize.spec.js
+++ /dev/null
@@ -1,431 +0,0 @@
-jest.mock('~/cache/getLogStores', () => ({
- getLogStores: jest.fn().mockReturnValue({
- get: jest.fn().mockResolvedValue({
- openAI: { apiKey: 'test-key' },
- }),
- set: jest.fn(),
- delete: jest.fn(),
- }),
-}));
-
-const { EModelEndpoint, ErrorTypes, validateAzureGroups } = require('librechat-data-provider');
-const { getUserKey, getUserKeyValues } = require('~/server/services/UserService');
-const initializeClient = require('./initialize');
-const { OpenAIClient } = require('~/app');
-
-// Mock getUserKey since it's the only function we want to mock
-jest.mock('~/server/services/UserService', () => ({
- getUserKey: jest.fn(),
- getUserKeyValues: jest.fn(),
- checkUserKeyExpiry: jest.requireActual('~/server/services/UserService').checkUserKeyExpiry,
-}));
-
-const mockAppConfig = {
- endpoints: {
- openAI: {
- apiKey: 'test-key',
- },
- azureOpenAI: {
- apiKey: 'test-azure-key',
- modelNames: ['gpt-4-vision-preview', 'gpt-3.5-turbo', 'gpt-4'],
- modelGroupMap: {
- 'gpt-4-vision-preview': {
- group: 'librechat-westus',
- deploymentName: 'gpt-4-vision-preview',
- version: '2024-02-15-preview',
- },
- },
- groupMap: {
- 'librechat-westus': {
- apiKey: 'WESTUS_API_KEY',
- instanceName: 'librechat-westus',
- version: '2023-12-01-preview',
- models: {
- 'gpt-4-vision-preview': {
- deploymentName: 'gpt-4-vision-preview',
- version: '2024-02-15-preview',
- },
- },
- },
- },
- },
- },
-};
-
-describe('initializeClient', () => {
- // Set up environment variables
- const originalEnvironment = process.env;
- const app = {
- locals: {},
- };
-
- const validAzureConfigs = [
- {
- group: 'librechat-westus',
- apiKey: 'WESTUS_API_KEY',
- instanceName: 'librechat-westus',
- version: '2023-12-01-preview',
- models: {
- 'gpt-4-vision-preview': {
- deploymentName: 'gpt-4-vision-preview',
- version: '2024-02-15-preview',
- },
- 'gpt-3.5-turbo': {
- deploymentName: 'gpt-35-turbo',
- },
- 'gpt-3.5-turbo-1106': {
- deploymentName: 'gpt-35-turbo-1106',
- },
- 'gpt-4': {
- deploymentName: 'gpt-4',
- },
- 'gpt-4-1106-preview': {
- deploymentName: 'gpt-4-1106-preview',
- },
- },
- },
- {
- group: 'librechat-eastus',
- apiKey: 'EASTUS_API_KEY',
- instanceName: 'librechat-eastus',
- deploymentName: 'gpt-4-turbo',
- version: '2024-02-15-preview',
- models: {
- 'gpt-4-turbo': true,
- },
- baseURL: 'https://eastus.example.com',
- additionalHeaders: {
- 'x-api-key': 'x-api-key-value',
- },
- },
- {
- group: 'mistral-inference',
- apiKey: 'AZURE_MISTRAL_API_KEY',
- baseURL:
- 'https://Mistral-large-vnpet-serverless.region.inference.ai.azure.com/v1/chat/completions',
- serverless: true,
- models: {
- 'mistral-large': true,
- },
- },
- {
- group: 'llama-70b-chat',
- apiKey: 'AZURE_LLAMA2_70B_API_KEY',
- baseURL:
- 'https://Llama-2-70b-chat-qmvyb-serverless.region.inference.ai.azure.com/v1/chat/completions',
- serverless: true,
- models: {
- 'llama-70b-chat': true,
- },
- },
- ];
-
- const { modelNames } = validateAzureGroups(validAzureConfigs);
-
- beforeEach(() => {
- jest.resetModules(); // Clears the cache
- process.env = { ...originalEnvironment }; // Make a copy
- });
-
- afterAll(() => {
- process.env = originalEnvironment; // Restore original env vars
- });
-
- test('should initialize client with OpenAI API key and default options', async () => {
- process.env.OPENAI_API_KEY = 'test-openai-api-key';
- process.env.DEBUG_OPENAI = 'false';
- process.env.OPENAI_SUMMARIZE = 'false';
-
- const req = {
- body: { key: null, endpoint: EModelEndpoint.openAI },
- user: { id: '123' },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- const result = await initializeClient({ req, res, endpointOption });
-
- expect(result.openAIApiKey).toBe('test-openai-api-key');
- expect(result.client).toBeInstanceOf(OpenAIClient);
- });
-
- test('should initialize client with Azure credentials when endpoint is azureOpenAI', async () => {
- process.env.AZURE_API_KEY = 'test-azure-api-key';
- (process.env.AZURE_OPENAI_API_INSTANCE_NAME = 'some-value'),
- (process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME = 'some-value'),
- (process.env.AZURE_OPENAI_API_VERSION = 'some-value'),
- (process.env.AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME = 'some-value'),
- (process.env.AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME = 'some-value'),
- (process.env.OPENAI_API_KEY = 'test-openai-api-key');
- process.env.DEBUG_OPENAI = 'false';
- process.env.OPENAI_SUMMARIZE = 'false';
-
- const req = {
- body: {
- key: null,
- endpoint: 'azureOpenAI',
- model: 'gpt-4-vision-preview',
- },
- user: { id: '123' },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- const client = await initializeClient({ req, res, endpointOption });
-
- expect(client.openAIApiKey).toBe('WESTUS_API_KEY');
- expect(client.client).toBeInstanceOf(OpenAIClient);
- });
-
- test('should use the debug option when DEBUG_OPENAI is enabled', async () => {
- process.env.OPENAI_API_KEY = 'test-openai-api-key';
- process.env.DEBUG_OPENAI = 'true';
-
- const req = {
- body: { key: null, endpoint: EModelEndpoint.openAI },
- user: { id: '123' },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- const client = await initializeClient({ req, res, endpointOption });
-
- expect(client.client.options.debug).toBe(true);
- });
-
- test('should set contextStrategy to summarize when OPENAI_SUMMARIZE is enabled', async () => {
- process.env.OPENAI_API_KEY = 'test-openai-api-key';
- process.env.OPENAI_SUMMARIZE = 'true';
-
- const req = {
- body: { key: null, endpoint: EModelEndpoint.openAI },
- user: { id: '123' },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- const client = await initializeClient({ req, res, endpointOption });
-
- expect(client.client.options.contextStrategy).toBe('summarize');
- });
-
- test('should set reverseProxyUrl and proxy when they are provided in the environment', async () => {
- process.env.OPENAI_API_KEY = 'test-openai-api-key';
- process.env.OPENAI_REVERSE_PROXY = 'http://reverse.proxy';
- process.env.PROXY = 'http://proxy';
-
- const req = {
- body: { key: null, endpoint: EModelEndpoint.openAI },
- user: { id: '123' },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- const client = await initializeClient({ req, res, endpointOption });
-
- expect(client.client.options.reverseProxyUrl).toBe('http://reverse.proxy');
- expect(client.client.options.proxy).toBe('http://proxy');
- });
-
- test('should throw an error if the user-provided key has expired', async () => {
- process.env.OPENAI_API_KEY = 'user_provided';
- process.env.AZURE_API_KEY = 'user_provided';
- process.env.DEBUG_OPENAI = 'false';
- process.env.OPENAI_SUMMARIZE = 'false';
-
- const expiresAt = new Date(Date.now() - 10000).toISOString(); // Expired
- const req = {
- body: { key: expiresAt, endpoint: EModelEndpoint.openAI },
- user: { id: '123' },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- await expect(initializeClient({ req, res, endpointOption })).rejects.toThrow(
- /expired_user_key/,
- );
- });
-
- test('should throw an error if no API keys are provided in the environment', async () => {
- // Clear the environment variables for API keys
- delete process.env.OPENAI_API_KEY;
- delete process.env.AZURE_API_KEY;
-
- const req = {
- body: { key: null, endpoint: EModelEndpoint.openAI },
- user: { id: '123' },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- await expect(initializeClient({ req, res, endpointOption })).rejects.toThrow(
- `${EModelEndpoint.openAI} API Key not provided.`,
- );
- });
-
- it('should handle user-provided keys and check expiry', async () => {
- // Set up the req.body to simulate user-provided key scenario
- const req = {
- body: {
- key: new Date(Date.now() + 10000).toISOString(),
- endpoint: EModelEndpoint.openAI,
- },
- user: {
- id: '123',
- },
- app,
- config: mockAppConfig,
- };
-
- const res = {};
- const endpointOption = {};
-
- // Ensure the environment variable is set to 'user_provided' to match the isUserProvided condition
- process.env.OPENAI_API_KEY = 'user_provided';
-
- // Mock getUserKey to return the expected key
- getUserKeyValues.mockResolvedValue({ apiKey: 'test-user-provided-openai-api-key' });
-
- // Call the initializeClient function
- const result = await initializeClient({ req, res, endpointOption });
-
- // Assertions
- expect(result.openAIApiKey).toBe('test-user-provided-openai-api-key');
- });
-
- test('should throw an error if the user-provided key is invalid', async () => {
- const invalidKey = new Date(Date.now() - 100000).toISOString();
- const req = {
- body: { key: invalidKey, endpoint: EModelEndpoint.openAI },
- user: { id: '123' },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- // Ensure the environment variable is set to 'user_provided' to match the isUserProvided condition
- process.env.OPENAI_API_KEY = 'user_provided';
-
- // Mock getUserKey to return an invalid key
- getUserKey.mockResolvedValue(invalidKey);
-
- await expect(initializeClient({ req, res, endpointOption })).rejects.toThrow(
- /expired_user_key/,
- );
- });
-
- test('should throw an error when user-provided values are not valid JSON', async () => {
- process.env.OPENAI_API_KEY = 'user_provided';
- const req = {
- body: { key: new Date(Date.now() + 10000).toISOString(), endpoint: EModelEndpoint.openAI },
- user: { id: '123' },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- // Mock getUserKey to return a non-JSON string
- getUserKey.mockResolvedValue('not-a-json');
- getUserKeyValues.mockImplementation(() => {
- let userValues = getUserKey();
- try {
- userValues = JSON.parse(userValues);
- } catch {
- throw new Error(
- JSON.stringify({
- type: ErrorTypes.INVALID_USER_KEY,
- }),
- );
- }
- return userValues;
- });
-
- await expect(initializeClient({ req, res, endpointOption })).rejects.toThrow(
- /invalid_user_key/,
- );
- });
-
- test('should initialize client correctly for Azure OpenAI with valid configuration', async () => {
- // Set up Azure environment variables
- process.env.WESTUS_API_KEY = 'test-westus-key';
-
- const req = {
- body: {
- key: null,
- endpoint: EModelEndpoint.azureOpenAI,
- model: modelNames[0],
- },
- user: { id: '123' },
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- const client = await initializeClient({ req, res, endpointOption });
- expect(client.client.options.azure).toBeDefined();
- });
-
- test('should initialize client with default options when certain env vars are not set', async () => {
- delete process.env.DEBUG_OPENAI;
- delete process.env.OPENAI_SUMMARIZE;
- process.env.OPENAI_API_KEY = 'some-api-key';
-
- const req = {
- body: { key: null, endpoint: EModelEndpoint.openAI },
- user: { id: '123' },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- const client = await initializeClient({ req, res, endpointOption });
-
- expect(client.client.options.debug).toBe(false);
- expect(client.client.options.contextStrategy).toBe(null);
- });
-
- test('should correctly use user-provided apiKey and baseURL when provided', async () => {
- process.env.OPENAI_API_KEY = 'user_provided';
- process.env.OPENAI_REVERSE_PROXY = 'user_provided';
- const req = {
- body: {
- key: new Date(Date.now() + 10000).toISOString(),
- endpoint: EModelEndpoint.openAI,
- },
- user: {
- id: '123',
- },
- app,
- config: mockAppConfig,
- };
- const res = {};
- const endpointOption = {};
-
- getUserKeyValues.mockResolvedValue({
- apiKey: 'test',
- baseURL: 'https://user-provided-url.com',
- });
-
- const result = await initializeClient({ req, res, endpointOption });
-
- expect(result.openAIApiKey).toBe('test');
- expect(result.client.options.reverseProxyUrl).toBe('https://user-provided-url.com');
- });
-});
diff --git a/api/server/services/Endpoints/openAI/title.js b/api/server/services/Endpoints/openAI/title.js
deleted file mode 100644
index f8624ef657..0000000000
--- a/api/server/services/Endpoints/openAI/title.js
+++ /dev/null
@@ -1,35 +0,0 @@
-const { isEnabled } = require('@librechat/api');
-const { CacheKeys } = require('librechat-data-provider');
-const getLogStores = require('~/cache/getLogStores');
-const { saveConvo } = require('~/models');
-
-const addTitle = async (req, { text, response, client }) => {
- const { TITLE_CONVO = 'true' } = process.env ?? {};
- if (!isEnabled(TITLE_CONVO)) {
- return;
- }
-
- if (client.options.titleConvo === false) {
- return;
- }
-
- const titleCache = getLogStores(CacheKeys.GEN_TITLE);
- const key = `${req.user.id}-${response.conversationId}`;
-
- const title = await client.titleConvo({
- text,
- responseText: response?.text ?? '',
- conversationId: response.conversationId,
- });
- await titleCache.set(key, title, 120000);
- await saveConvo(
- req,
- {
- conversationId: response.conversationId,
- title,
- },
- { context: 'api/server/services/Endpoints/openAI/addTitle.js' },
- );
-};
-
-module.exports = addTitle;
diff --git a/api/server/services/Files/Azure/crud.js b/api/server/services/Files/Azure/crud.js
index 25bd749276..8f681bd06c 100644
--- a/api/server/services/Files/Azure/crud.js
+++ b/api/server/services/Files/Azure/crud.js
@@ -4,7 +4,7 @@ const mime = require('mime');
const axios = require('axios');
const fetch = require('node-fetch');
const { logger } = require('@librechat/data-schemas');
-const { getAzureContainerClient } = require('@librechat/api');
+const { getAzureContainerClient, deleteRagFile } = require('@librechat/api');
const defaultBasePath = 'images';
const { AZURE_STORAGE_PUBLIC_ACCESS = 'true', AZURE_CONTAINER_NAME = 'files' } = process.env;
@@ -102,6 +102,8 @@ async function getAzureURL({ fileName, basePath = defaultBasePath, userId, conta
* @param {MongoFile} params.file - The file object.
*/
async function deleteFileFromAzure(req, file) {
+ await deleteRagFile({ userId: req.user.id, file });
+
try {
const containerClient = await getAzureContainerClient(AZURE_CONTAINER_NAME);
const blobPath = file.filepath.split(`${AZURE_CONTAINER_NAME}/`)[1];
diff --git a/api/server/services/Files/Code/process.js b/api/server/services/Files/Code/process.js
index c38aad7087..3f0bfcfc87 100644
--- a/api/server/services/Files/Code/process.js
+++ b/api/server/services/Files/Code/process.js
@@ -6,27 +6,68 @@ const { getCodeBaseURL } = require('@librechat/agents');
const { logAxiosError, getBasePath } = require('@librechat/api');
const {
Tools,
+ megabyte,
+ fileConfig,
FileContext,
FileSources,
imageExtRegex,
+ inferMimeType,
EToolResources,
+ EModelEndpoint,
+ mergeFileConfig,
+ getEndpointFileConfig,
} = require('librechat-data-provider');
const { filterFilesByAgentAccess } = require('~/server/services/Files/permissions');
+const { createFile, getFiles, updateFile, claimCodeFile } = require('~/models');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
const { convertImage } = require('~/server/services/Files/images/convert');
-const { createFile, getFiles, updateFile } = require('~/models/File');
+const { determineFileType } = require('~/server/utils');
/**
- * Process OpenAI image files, convert to target format, save and return file metadata.
+ * Creates a fallback download URL response when file cannot be processed locally.
+ * Used when: file exceeds size limit, storage strategy unavailable, or download error occurs.
+ * @param {Object} params - The parameters.
+ * @param {string} params.name - The filename.
+ * @param {string} params.session_id - The code execution session ID.
+ * @param {string} params.id - The file ID from the code environment.
+ * @param {string} params.conversationId - The current conversation ID.
+ * @param {string} params.toolCallId - The tool call ID that generated the file.
+ * @param {string} params.messageId - The current message ID.
+ * @param {number} params.expiresAt - Expiration timestamp (24 hours from creation).
+ * @returns {Object} Fallback response with download URL.
+ */
+const createDownloadFallback = ({
+ id,
+ name,
+ messageId,
+ expiresAt,
+ session_id,
+ toolCallId,
+ conversationId,
+}) => {
+ const basePath = getBasePath();
+ return {
+ filename: name,
+ filepath: `${basePath}/api/files/code/download/${session_id}/${id}`,
+ expiresAt,
+ conversationId,
+ toolCallId,
+ messageId,
+ };
+};
+
+/**
+ * Process code execution output files - downloads and saves both images and non-image files.
+ * All files are saved to local storage with fileIdentifier metadata for code env re-upload.
* @param {ServerRequest} params.req - The Express request object.
- * @param {string} params.id - The file ID.
+ * @param {string} params.id - The file ID from the code environment.
* @param {string} params.name - The filename.
* @param {string} params.apiKey - The code execution API key.
* @param {string} params.toolCallId - The tool call ID that generated the file.
* @param {string} params.session_id - The code execution session ID.
* @param {string} params.conversationId - The current conversation ID.
* @param {string} params.messageId - The current message ID.
- * @returns {Promise} The file metadata or undefined if an error occurs.
+ * @returns {Promise} The file metadata or undefined if an error occurs.
*/
const processCodeOutput = async ({
req,
@@ -41,19 +82,15 @@ const processCodeOutput = async ({
const appConfig = req.config;
const currentDate = new Date();
const baseURL = getCodeBaseURL();
- const basePath = getBasePath();
- const fileExt = path.extname(name);
- if (!fileExt || !imageExtRegex.test(name)) {
- return {
- filename: name,
- filepath: `${basePath}/api/files/code/download/${session_id}/${id}`,
- /** Note: expires 24 hours after creation */
- expiresAt: currentDate.getTime() + 86400000,
- conversationId,
- toolCallId,
- messageId,
- };
- }
+ const fileExt = path.extname(name).toLowerCase();
+ const isImage = fileExt && imageExtRegex.test(name);
+
+ const mergedFileConfig = mergeFileConfig(appConfig.fileConfig);
+ const endpointFileConfig = getEndpointFileConfig({
+ fileConfig: mergedFileConfig,
+ endpoint: EModelEndpoint.agents,
+ });
+ const fileSizeLimit = endpointFileConfig.fileSizeLimit ?? mergedFileConfig.serverFileSizeLimit;
try {
const formattedDate = currentDate.toISOString();
@@ -70,29 +107,143 @@ const processCodeOutput = async ({
const buffer = Buffer.from(response.data, 'binary');
- const file_id = v4();
- const _file = await convertImage(req, buffer, 'high', `${file_id}${fileExt}`);
- const file = {
- ..._file,
- file_id,
- usage: 1,
+ // Enforce file size limit
+ if (buffer.length > fileSizeLimit) {
+ logger.warn(
+ `[processCodeOutput] File "${name}" (${(buffer.length / megabyte).toFixed(2)} MB) exceeds size limit of ${(fileSizeLimit / megabyte).toFixed(2)} MB, falling back to download URL`,
+ );
+ return createDownloadFallback({
+ id,
+ name,
+ messageId,
+ toolCallId,
+ session_id,
+ conversationId,
+ expiresAt: currentDate.getTime() + 86400000,
+ });
+ }
+
+ const fileIdentifier = `${session_id}/${id}`;
+
+ /**
+ * Atomically claim a file_id for this (filename, conversationId, context) tuple.
+ * Uses $setOnInsert so concurrent calls for the same filename converge on
+ * a single record instead of creating duplicates (TOCTOU race fix).
+ */
+ const newFileId = v4();
+ const claimed = await claimCodeFile({
filename: name,
conversationId,
+ file_id: newFileId,
user: req.user.id,
- type: `image/${appConfig.imageOutputType}`,
- createdAt: formattedDate,
+ });
+ const file_id = claimed.file_id;
+ const isUpdate = file_id !== newFileId;
+
+ if (isUpdate) {
+ logger.debug(
+ `[processCodeOutput] Updating existing file "${name}" (${file_id}) instead of creating duplicate`,
+ );
+ }
+
+ if (isImage) {
+ const usage = isUpdate ? (claimed.usage ?? 0) + 1 : 1;
+ const _file = await convertImage(req, buffer, 'high', `${file_id}${fileExt}`);
+ const filepath = usage > 1 ? `${_file.filepath}?v=${Date.now()}` : _file.filepath;
+ const file = {
+ ..._file,
+ filepath,
+ file_id,
+ messageId,
+ usage,
+ filename: name,
+ conversationId,
+ user: req.user.id,
+ type: `image/${appConfig.imageOutputType}`,
+ createdAt: isUpdate ? claimed.createdAt : formattedDate,
+ updatedAt: formattedDate,
+ source: appConfig.fileStrategy,
+ context: FileContext.execute_code,
+ metadata: { fileIdentifier },
+ };
+ await createFile(file, true);
+ return Object.assign(file, { messageId, toolCallId });
+ }
+
+ const { saveBuffer } = getStrategyFunctions(appConfig.fileStrategy);
+ if (!saveBuffer) {
+ logger.warn(
+ `[processCodeOutput] saveBuffer not available for strategy ${appConfig.fileStrategy}, falling back to download URL`,
+ );
+ return createDownloadFallback({
+ id,
+ name,
+ messageId,
+ toolCallId,
+ session_id,
+ conversationId,
+ expiresAt: currentDate.getTime() + 86400000,
+ });
+ }
+
+ const detectedType = await determineFileType(buffer, true);
+ const mimeType = detectedType?.mime || inferMimeType(name, '') || 'application/octet-stream';
+
+ /** Check MIME type support - for code-generated files, we're lenient but log unsupported types */
+ const isSupportedMimeType = fileConfig.checkType(
+ mimeType,
+ endpointFileConfig.supportedMimeTypes,
+ );
+ if (!isSupportedMimeType) {
+ logger.warn(
+ `[processCodeOutput] File "${name}" has unsupported MIME type "${mimeType}", proceeding with storage but may not be usable as tool resource`,
+ );
+ }
+
+ const fileName = `${file_id}__${name}`;
+ const filepath = await saveBuffer({
+ userId: req.user.id,
+ buffer,
+ fileName,
+ basePath: 'uploads',
+ });
+
+ const file = {
+ file_id,
+ filepath,
+ messageId,
+ object: 'file',
+ filename: name,
+ type: mimeType,
+ conversationId,
+ user: req.user.id,
+ bytes: buffer.length,
updatedAt: formattedDate,
+ metadata: { fileIdentifier },
source: appConfig.fileStrategy,
context: FileContext.execute_code,
+ usage: isUpdate ? (claimed.usage ?? 0) + 1 : 1,
+ createdAt: isUpdate ? claimed.createdAt : formattedDate,
};
- createFile(file, true);
- /** Note: `messageId` & `toolCallId` are not part of file DB schema; message object records associated file ID */
+
+ await createFile(file, true);
return Object.assign(file, { messageId, toolCallId });
} catch (error) {
logAxiosError({
- message: 'Error downloading code environment file',
+ message: 'Error downloading/processing code environment file',
error,
});
+
+ // Fallback for download errors - return download URL so user can still manually download
+ return createDownloadFallback({
+ id,
+ name,
+ messageId,
+ toolCallId,
+ session_id,
+ conversationId,
+ expiresAt: currentDate.getTime() + 86400000,
+ });
}
};
@@ -204,9 +355,16 @@ const primeFiles = async (options, apiKey) => {
if (!toolContext) {
toolContext = `- Note: The following files are available in the "${Tools.execute_code}" tool environment:`;
}
- toolContext += `\n\t- /mnt/data/${file.filename}${
- agentResourceIds.has(file.file_id) ? '' : ' (just attached by user)'
- }`;
+
+ let fileSuffix = '';
+ if (!agentResourceIds.has(file.file_id)) {
+ fileSuffix =
+ file.context === FileContext.execute_code
+ ? ' (from previous code execution)'
+ : ' (attached by user)';
+ }
+
+ toolContext += `\n\t- /mnt/data/${file.filename}${fileSuffix}`;
files.push({
id,
session_id,
diff --git a/api/server/services/Files/Code/process.spec.js b/api/server/services/Files/Code/process.spec.js
new file mode 100644
index 0000000000..f01a623f90
--- /dev/null
+++ b/api/server/services/Files/Code/process.spec.js
@@ -0,0 +1,411 @@
+// Configurable file size limit for tests - use a getter so it can be changed per test
+const fileSizeLimitConfig = { value: 20 * 1024 * 1024 }; // Default 20MB
+
+// Mock librechat-data-provider with configurable file size limit
+jest.mock('librechat-data-provider', () => {
+ const actual = jest.requireActual('librechat-data-provider');
+ return {
+ ...actual,
+ mergeFileConfig: jest.fn((config) => {
+ const merged = actual.mergeFileConfig(config);
+ // Override the serverFileSizeLimit with our test value
+ return {
+ ...merged,
+ get serverFileSizeLimit() {
+ return fileSizeLimitConfig.value;
+ },
+ };
+ }),
+ getEndpointFileConfig: jest.fn((options) => {
+ const config = actual.getEndpointFileConfig(options);
+ // Override fileSizeLimit with our test value
+ return {
+ ...config,
+ get fileSizeLimit() {
+ return fileSizeLimitConfig.value;
+ },
+ };
+ }),
+ };
+});
+
+const { FileContext } = require('librechat-data-provider');
+
+// Mock uuid
+jest.mock('uuid', () => ({
+ v4: jest.fn(() => 'mock-uuid-1234'),
+}));
+
+// Mock axios
+jest.mock('axios');
+const axios = require('axios');
+
+// Mock logger
+jest.mock('@librechat/data-schemas', () => ({
+ logger: {
+ warn: jest.fn(),
+ debug: jest.fn(),
+ error: jest.fn(),
+ },
+}));
+
+// Mock getCodeBaseURL
+jest.mock('@librechat/agents', () => ({
+ getCodeBaseURL: jest.fn(() => 'https://code-api.example.com'),
+}));
+
+// Mock logAxiosError and getBasePath
+jest.mock('@librechat/api', () => ({
+ logAxiosError: jest.fn(),
+ getBasePath: jest.fn(() => ''),
+}));
+
+// Mock models
+const mockClaimCodeFile = jest.fn();
+jest.mock('~/models', () => ({
+ createFile: jest.fn().mockResolvedValue({}),
+ getFiles: jest.fn(),
+ updateFile: jest.fn(),
+ claimCodeFile: (...args) => mockClaimCodeFile(...args),
+}));
+
+// Mock permissions (must be before process.js import)
+jest.mock('~/server/services/Files/permissions', () => ({
+ filterFilesByAgentAccess: jest.fn((options) => Promise.resolve(options.files)),
+}));
+
+// Mock strategy functions
+jest.mock('~/server/services/Files/strategies', () => ({
+ getStrategyFunctions: jest.fn(),
+}));
+
+// Mock convertImage
+jest.mock('~/server/services/Files/images/convert', () => ({
+ convertImage: jest.fn(),
+}));
+
+// Mock determineFileType
+jest.mock('~/server/utils', () => ({
+ determineFileType: jest.fn(),
+}));
+
+const { createFile, getFiles } = require('~/models');
+const { getStrategyFunctions } = require('~/server/services/Files/strategies');
+const { convertImage } = require('~/server/services/Files/images/convert');
+const { determineFileType } = require('~/server/utils');
+const { logger } = require('@librechat/data-schemas');
+
+// Import after mocks
+const { processCodeOutput } = require('./process');
+
+describe('Code Process', () => {
+ const mockReq = {
+ user: { id: 'user-123' },
+ config: {
+ fileConfig: {},
+ fileStrategy: 'local',
+ imageOutputType: 'webp',
+ },
+ };
+
+ const baseParams = {
+ req: mockReq,
+ id: 'file-id-123',
+ name: 'test-file.txt',
+ apiKey: 'test-api-key',
+ toolCallId: 'tool-call-123',
+ conversationId: 'conv-123',
+ messageId: 'msg-123',
+ session_id: 'session-123',
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ // Default mock: atomic claim returns a new file record (no existing file)
+ mockClaimCodeFile.mockResolvedValue({
+ file_id: 'mock-uuid-1234',
+ user: 'user-123',
+ });
+ getFiles.mockResolvedValue(null);
+ createFile.mockResolvedValue({});
+ getStrategyFunctions.mockReturnValue({
+ saveBuffer: jest.fn().mockResolvedValue('/uploads/mock-file-path.txt'),
+ });
+ determineFileType.mockResolvedValue({ mime: 'text/plain' });
+ });
+
+ describe('atomic file claim (via processCodeOutput)', () => {
+ it('should reuse file_id from existing record via atomic claim', async () => {
+ mockClaimCodeFile.mockResolvedValue({
+ file_id: 'existing-file-id',
+ filename: 'test-file.txt',
+ usage: 2,
+ createdAt: '2024-01-01T00:00:00.000Z',
+ });
+
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(mockClaimCodeFile).toHaveBeenCalledWith({
+ filename: 'test-file.txt',
+ conversationId: 'conv-123',
+ file_id: 'mock-uuid-1234',
+ user: 'user-123',
+ });
+
+ expect(result.file_id).toBe('existing-file-id');
+ expect(result.usage).toBe(3);
+ expect(result.createdAt).toBe('2024-01-01T00:00:00.000Z');
+ });
+
+ it('should create new file when no existing file found', async () => {
+ mockClaimCodeFile.mockResolvedValue({
+ file_id: 'mock-uuid-1234',
+ user: 'user-123',
+ });
+
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(result.file_id).toBe('mock-uuid-1234');
+ expect(result.usage).toBe(1);
+ });
+ });
+
+ describe('processCodeOutput', () => {
+ describe('image file processing', () => {
+ it('should process image files using convertImage', async () => {
+ const imageParams = { ...baseParams, name: 'chart.png' };
+ const imageBuffer = Buffer.alloc(500);
+ axios.mockResolvedValue({ data: imageBuffer });
+
+ const convertedFile = {
+ filepath: '/uploads/converted-image.webp',
+ bytes: 400,
+ };
+ convertImage.mockResolvedValue(convertedFile);
+
+ const result = await processCodeOutput(imageParams);
+
+ expect(convertImage).toHaveBeenCalledWith(
+ mockReq,
+ imageBuffer,
+ 'high',
+ 'mock-uuid-1234.png',
+ );
+ expect(result.type).toBe('image/webp');
+ expect(result.context).toBe(FileContext.execute_code);
+ expect(result.filename).toBe('chart.png');
+ });
+
+ it('should update existing image file with cache-busted filepath', async () => {
+ const imageParams = { ...baseParams, name: 'chart.png' };
+ mockClaimCodeFile.mockResolvedValue({
+ file_id: 'existing-img-id',
+ usage: 1,
+ createdAt: '2024-01-01T00:00:00.000Z',
+ });
+
+ const imageBuffer = Buffer.alloc(500);
+ axios.mockResolvedValue({ data: imageBuffer });
+ convertImage.mockResolvedValue({ filepath: '/images/user-123/existing-img-id.webp' });
+
+ const result = await processCodeOutput(imageParams);
+
+ expect(convertImage).toHaveBeenCalledWith(
+ mockReq,
+ imageBuffer,
+ 'high',
+ 'existing-img-id.png',
+ );
+ expect(result.file_id).toBe('existing-img-id');
+ expect(result.usage).toBe(2);
+ expect(result.filepath).toMatch(/^\/images\/user-123\/existing-img-id\.webp\?v=\d+$/);
+ expect(logger.debug).toHaveBeenCalledWith(
+ expect.stringContaining('Updating existing file'),
+ );
+ });
+ });
+
+ describe('non-image file processing', () => {
+ it('should process non-image files using saveBuffer', async () => {
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+
+ const mockSaveBuffer = jest.fn().mockResolvedValue('/uploads/saved-file.txt');
+ getStrategyFunctions.mockReturnValue({ saveBuffer: mockSaveBuffer });
+ determineFileType.mockResolvedValue({ mime: 'text/plain' });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(mockSaveBuffer).toHaveBeenCalledWith({
+ userId: 'user-123',
+ buffer: smallBuffer,
+ fileName: 'mock-uuid-1234__test-file.txt',
+ basePath: 'uploads',
+ });
+ expect(result.type).toBe('text/plain');
+ expect(result.filepath).toBe('/uploads/saved-file.txt');
+ expect(result.bytes).toBe(100);
+ });
+
+ it('should detect MIME type from buffer', async () => {
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+ determineFileType.mockResolvedValue({ mime: 'application/pdf' });
+
+ const result = await processCodeOutput({ ...baseParams, name: 'document.pdf' });
+
+ expect(determineFileType).toHaveBeenCalledWith(smallBuffer, true);
+ expect(result.type).toBe('application/pdf');
+ });
+
+ it('should fallback to application/octet-stream for unknown types', async () => {
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+ determineFileType.mockResolvedValue(null);
+
+ const result = await processCodeOutput({ ...baseParams, name: 'unknown.xyz' });
+
+ expect(result.type).toBe('application/octet-stream');
+ });
+ });
+
+ describe('file size limit enforcement', () => {
+ it('should fallback to download URL when file exceeds size limit', async () => {
+ // Set a small file size limit for this test
+ fileSizeLimitConfig.value = 1000; // 1KB limit
+
+ const largeBuffer = Buffer.alloc(5000); // 5KB - exceeds 1KB limit
+ axios.mockResolvedValue({ data: largeBuffer });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('exceeds size limit'));
+ expect(result.filepath).toContain('/api/files/code/download/session-123/file-id-123');
+ expect(result.expiresAt).toBeDefined();
+ // Should not call createFile for oversized files (fallback path)
+ expect(createFile).not.toHaveBeenCalled();
+
+ // Reset to default for other tests
+ fileSizeLimitConfig.value = 20 * 1024 * 1024;
+ });
+ });
+
+ describe('fallback behavior', () => {
+ it('should fallback to download URL when saveBuffer is not available', async () => {
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+ getStrategyFunctions.mockReturnValue({ saveBuffer: null });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(logger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('saveBuffer not available'),
+ );
+ expect(result.filepath).toContain('/api/files/code/download/');
+ expect(result.filename).toBe('test-file.txt');
+ });
+
+ it('should fallback to download URL on axios error', async () => {
+ axios.mockRejectedValue(new Error('Network error'));
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(result.filepath).toContain('/api/files/code/download/session-123/file-id-123');
+ expect(result.conversationId).toBe('conv-123');
+ expect(result.messageId).toBe('msg-123');
+ expect(result.toolCallId).toBe('tool-call-123');
+ });
+ });
+
+ describe('usage counter increment', () => {
+ it('should set usage to 1 for new files', async () => {
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(result.usage).toBe(1);
+ });
+
+ it('should increment usage for existing files', async () => {
+ mockClaimCodeFile.mockResolvedValue({
+ file_id: 'existing-id',
+ usage: 5,
+ createdAt: '2024-01-01',
+ });
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(result.usage).toBe(6);
+ });
+
+ it('should handle existing file with undefined usage', async () => {
+ mockClaimCodeFile.mockResolvedValue({
+ file_id: 'existing-id',
+ createdAt: '2024-01-01',
+ });
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(result.usage).toBe(1);
+ });
+ });
+
+ describe('metadata and file properties', () => {
+ it('should include fileIdentifier in metadata', async () => {
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(result.metadata).toEqual({
+ fileIdentifier: 'session-123/file-id-123',
+ });
+ });
+
+ it('should set correct context for code-generated files', async () => {
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(result.context).toBe(FileContext.execute_code);
+ });
+
+ it('should include toolCallId and messageId in result', async () => {
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+
+ const result = await processCodeOutput(baseParams);
+
+ expect(result.toolCallId).toBe('tool-call-123');
+ expect(result.messageId).toBe('msg-123');
+ });
+
+ it('should call createFile with upsert enabled', async () => {
+ const smallBuffer = Buffer.alloc(100);
+ axios.mockResolvedValue({ data: smallBuffer });
+
+ await processCodeOutput(baseParams);
+
+ expect(createFile).toHaveBeenCalledWith(
+ expect.objectContaining({
+ file_id: 'mock-uuid-1234',
+ context: FileContext.execute_code,
+ }),
+ true, // upsert flag
+ );
+ });
+ });
+ });
+});
diff --git a/api/server/services/Files/Firebase/crud.js b/api/server/services/Files/Firebase/crud.js
index 170df45677..d5e5a409bf 100644
--- a/api/server/services/Files/Firebase/crud.js
+++ b/api/server/services/Files/Firebase/crud.js
@@ -3,7 +3,7 @@ const path = require('path');
const axios = require('axios');
const fetch = require('node-fetch');
const { logger } = require('@librechat/data-schemas');
-const { getFirebaseStorage } = require('@librechat/api');
+const { getFirebaseStorage, deleteRagFile } = require('@librechat/api');
const { ref, uploadBytes, getDownloadURL, deleteObject } = require('firebase/storage');
const { getBufferMetadata } = require('~/server/utils');
@@ -167,27 +167,7 @@ function extractFirebaseFilePath(urlString) {
* Throws an error if there is an issue with deletion.
*/
const deleteFirebaseFile = async (req, file) => {
- if (file.embedded && process.env.RAG_API_URL) {
- const jwtToken = req.headers.authorization.split(' ')[1];
- try {
- await axios.delete(`${process.env.RAG_API_URL}/documents`, {
- headers: {
- Authorization: `Bearer ${jwtToken}`,
- 'Content-Type': 'application/json',
- accept: 'application/json',
- },
- data: [file.file_id],
- });
- } catch (error) {
- if (error.response?.status === 404) {
- logger.warn(
- `[deleteFirebaseFile] Document ${file.file_id} not found in RAG API, may have been deleted already`,
- );
- } else {
- logger.error('[deleteFirebaseFile] Error deleting document from RAG API:', error);
- }
- }
- }
+ await deleteRagFile({ userId: req.user.id, file });
const fileName = extractFirebaseFilePath(file.filepath);
if (!fileName.includes(req.user.id)) {
diff --git a/api/server/services/Files/Local/crud.js b/api/server/services/Files/Local/crud.js
index db553f57dd..1f38a01f83 100644
--- a/api/server/services/Files/Local/crud.js
+++ b/api/server/services/Files/Local/crud.js
@@ -1,9 +1,9 @@
const fs = require('fs');
const path = require('path');
const axios = require('axios');
+const { deleteRagFile } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { EModelEndpoint } = require('librechat-data-provider');
-const { generateShortLivedToken } = require('@librechat/api');
const { resizeImageBuffer } = require('~/server/services/Files/images/resize');
const { getBufferMetadata } = require('~/server/utils');
const paths = require('~/config/paths');
@@ -67,7 +67,12 @@ async function saveLocalBuffer({ userId, buffer, fileName, basePath = 'images' }
try {
const { publicPath, uploads } = paths;
- const directoryPath = path.join(basePath === 'images' ? publicPath : uploads, basePath, userId);
+ /**
+ * For 'images': save to publicPath/images/userId (images are served statically)
+ * For 'uploads': save to uploads/userId (files downloaded via API)
+ * */
+ const directoryPath =
+ basePath === 'images' ? path.join(publicPath, basePath, userId) : path.join(uploads, userId);
if (!fs.existsSync(directoryPath)) {
fs.mkdirSync(directoryPath, { recursive: true });
@@ -208,27 +213,7 @@ const deleteLocalFile = async (req, file) => {
/** Filepath stripped of query parameters (e.g., ?manual=true) */
const cleanFilepath = file.filepath.split('?')[0];
- if (file.embedded && process.env.RAG_API_URL) {
- const jwtToken = generateShortLivedToken(req.user.id);
- try {
- await axios.delete(`${process.env.RAG_API_URL}/documents`, {
- headers: {
- Authorization: `Bearer ${jwtToken}`,
- 'Content-Type': 'application/json',
- accept: 'application/json',
- },
- data: [file.file_id],
- });
- } catch (error) {
- if (error.response?.status === 404) {
- logger.warn(
- `[deleteLocalFile] Document ${file.file_id} not found in RAG API, may have been deleted already`,
- );
- } else {
- logger.error('[deleteLocalFile] Error deleting document from RAG API:', error);
- }
- }
- }
+ await deleteRagFile({ userId: req.user.id, file });
if (cleanFilepath.startsWith(`/uploads/${req.user.id}`)) {
const userUploadDir = path.join(uploads, req.user.id);
diff --git a/api/server/services/Files/S3/crud.js b/api/server/services/Files/S3/crud.js
index 8dac767aa2..c821c0696c 100644
--- a/api/server/services/Files/S3/crud.js
+++ b/api/server/services/Files/S3/crud.js
@@ -1,9 +1,9 @@
const fs = require('fs');
const fetch = require('node-fetch');
-const { initializeS3 } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { FileSources } = require('librechat-data-provider');
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
+const { initializeS3, deleteRagFile, isEnabled } = require('@librechat/api');
const {
PutObjectCommand,
GetObjectCommand,
@@ -13,6 +13,8 @@ const {
const bucketName = process.env.AWS_BUCKET_NAME;
const defaultBasePath = 'images';
+const endpoint = process.env.AWS_ENDPOINT_URL;
+const forcePathStyle = isEnabled(process.env.AWS_FORCE_PATH_STYLE);
let s3UrlExpirySeconds = 2 * 60; // 2 minutes
let s3RefreshExpiryMs = null;
@@ -142,6 +144,8 @@ async function saveURLToS3({ userId, URL, fileName, basePath = defaultBasePath }
* @returns {Promise}
*/
async function deleteFileFromS3(req, file) {
+ await deleteRagFile({ userId: req.user.id, file });
+
const key = extractKeyFromS3Url(file.filepath);
const params = { Bucket: bucketName, Key: key };
if (!key.includes(req.user.id)) {
@@ -250,15 +254,83 @@ function extractKeyFromS3Url(fileUrlOrKey) {
try {
const url = new URL(fileUrlOrKey);
- return url.pathname.substring(1);
+ const hostname = url.hostname;
+ const pathname = url.pathname.substring(1); // Remove leading slash
+
+ // Explicit path-style with custom endpoint: use endpoint pathname for precise key extraction.
+ // Handles endpoints with a base path (e.g. https://example.com/storage/).
+ if (endpoint && forcePathStyle) {
+ const endpointUrl = new URL(endpoint);
+ const startPos =
+ endpointUrl.pathname.length +
+ (endpointUrl.pathname.endsWith('/') ? 0 : 1) +
+ bucketName.length +
+ 1;
+ const key = url.pathname.substring(startPos);
+ if (!key) {
+ logger.warn(
+ `[extractKeyFromS3Url] Extracted key is empty for endpoint path-style URL: ${fileUrlOrKey}`,
+ );
+ } else {
+ logger.debug(`[extractKeyFromS3Url] fileUrlOrKey: ${fileUrlOrKey}, Extracted key: ${key}`);
+ }
+ return key;
+ }
+
+ if (
+ hostname === 's3.amazonaws.com' ||
+ hostname.match(/^s3[-.][a-z0-9-]+\.amazonaws\.com$/) ||
+ (bucketName && pathname.startsWith(`${bucketName}/`))
+ ) {
+ // Path-style: https://s3.amazonaws.com/bucket-name/key or custom endpoint (MinIO, R2, etc.)
+ // Strip the bucket name (first path segment)
+ const firstSlashIndex = pathname.indexOf('/');
+ if (firstSlashIndex > 0) {
+ const key = pathname.substring(firstSlashIndex + 1);
+
+ if (key === '') {
+ logger.warn(
+ `[extractKeyFromS3Url] Extracted key is empty after removing bucket name from URL: ${fileUrlOrKey}`,
+ );
+ } else {
+ logger.debug(
+ `[extractKeyFromS3Url] fileUrlOrKey: ${fileUrlOrKey}, Extracted key: ${key}`,
+ );
+ }
+
+ return key;
+ } else {
+ logger.warn(
+ `[extractKeyFromS3Url] Unable to extract key from path-style URL: ${fileUrlOrKey}`,
+ );
+ return '';
+ }
+ }
+
+ // Virtual-hosted-style or other: https://bucket-name.s3.amazonaws.com/key
+ // Just return the pathname without leading slash
+ logger.debug(`[extractKeyFromS3Url] fileUrlOrKey: ${fileUrlOrKey}, Extracted key: ${pathname}`);
+ return pathname;
} catch (error) {
+ if (fileUrlOrKey.startsWith('http://') || fileUrlOrKey.startsWith('https://')) {
+ logger.error(
+ `[extractKeyFromS3Url] Error parsing URL: ${fileUrlOrKey}, Error: ${error.message}`,
+ );
+ } else {
+ logger.debug(`[extractKeyFromS3Url] Non-URL input, using fallback: ${fileUrlOrKey}`);
+ }
+
const parts = fileUrlOrKey.split('/');
if (parts.length >= 3 && !fileUrlOrKey.startsWith('http') && !fileUrlOrKey.startsWith('/')) {
return fileUrlOrKey;
}
- return fileUrlOrKey.startsWith('/') ? fileUrlOrKey.substring(1) : fileUrlOrKey;
+ const key = fileUrlOrKey.startsWith('/') ? fileUrlOrKey.substring(1) : fileUrlOrKey;
+ logger.debug(
+ `[extractKeyFromS3Url] FALLBACK. fileUrlOrKey: ${fileUrlOrKey}, Extracted key: ${key}`,
+ );
+ return key;
}
}
@@ -480,4 +552,5 @@ module.exports = {
refreshS3Url,
needsRefresh,
getNewS3URL,
+ extractKeyFromS3Url,
};
diff --git a/api/server/services/Files/images/encode.js b/api/server/services/Files/images/encode.js
index e719e58af3..93d0aebd4b 100644
--- a/api/server/services/Files/images/encode.js
+++ b/api/server/services/Files/images/encode.js
@@ -80,7 +80,7 @@ const base64Only = new Set([
EModelEndpoint.bedrock,
]);
-const blobStorageSources = new Set([FileSources.azure_blob, FileSources.s3]);
+const blobStorageSources = new Set([FileSources.azure_blob, FileSources.s3, FileSources.firebase]);
/**
* Encodes and formats the given files.
@@ -127,7 +127,7 @@ async function encodeAndFormat(req, files, params, mode) {
}
const preparePayload = encodingMethods[source].prepareImagePayload;
- /* We need to fetch the image and convert it to base64 if we are using S3/Azure Blob storage. */
+ /* We need to fetch the image and convert it to base64 if we are using S3/Azure Blob/Firebase storage. */
if (blobStorageSources.has(source)) {
try {
const downloadStream = encodingMethods[source].getDownloadStream;
diff --git a/api/server/services/Files/process.js b/api/server/services/Files/process.js
index f586554ae8..d01128927a 100644
--- a/api/server/services/Files/process.js
+++ b/api/server/services/Files/process.js
@@ -16,6 +16,7 @@ const {
removeNullishValues,
isAssistantsEndpoint,
getEndpointFileConfig,
+ documentParserMimeTypes,
} = require('librechat-data-provider');
const { EnvVar } = require('@librechat/agents');
const { logger } = require('@librechat/data-schemas');
@@ -28,8 +29,8 @@ const {
const { addResourceFileId, deleteResourceFileId } = require('~/server/controllers/assistants/v2');
const { addAgentResourceFile, removeAgentResourceFiles } = require('~/models/Agent');
const { getOpenAIClient } = require('~/server/controllers/assistants/helpers');
-const { createFile, updateFileUsage, deleteFiles } = require('~/models/File');
const { loadAuthValues } = require('~/server/services/Tools/credentials');
+const { createFile, updateFileUsage, deleteFiles } = require('~/models');
const { getFileStrategy } = require('~/server/utils/getFileStrategy');
const { checkCapability } = require('~/server/services/Config');
const { LB_QueueAsyncCall } = require('~/server/utils/queue');
@@ -60,45 +61,6 @@ const createSanitizedUploadWrapper = (uploadFunction) => {
};
};
-/**
- *
- * @param {Array} files
- * @param {Array} [fileIds]
- * @returns
- */
-const processFiles = async (files, fileIds) => {
- const promises = [];
- const seen = new Set();
-
- for (let file of files) {
- const { file_id } = file;
- if (seen.has(file_id)) {
- continue;
- }
- seen.add(file_id);
- promises.push(updateFileUsage({ file_id }));
- }
-
- if (!fileIds) {
- const results = await Promise.all(promises);
- // Filter out null results from failed updateFileUsage calls
- return results.filter((result) => result != null);
- }
-
- for (let file_id of fileIds) {
- if (seen.has(file_id)) {
- continue;
- }
- seen.add(file_id);
- promises.push(updateFileUsage({ file_id }));
- }
-
- // TODO: calculate token cost when image is first uploaded
- const results = await Promise.all(promises);
- // Filter out null results from failed updateFileUsage calls
- return results.filter((result) => result != null);
-};
-
/**
* Enqueues the delete operation to the leaky bucket queue if necessary, or adds it directly to promises.
*
@@ -562,6 +524,12 @@ const processAgentFileUpload = async ({ req, res, metadata }) => {
* @return {Promise}
*/
const createTextFile = async ({ text, bytes, filepath, type = 'text/plain' }) => {
+ const textBytes = Buffer.byteLength(text, 'utf8');
+ if (textBytes > 15 * megabyte) {
+ throw new Error(
+ `Extracted text from "${file.originalname}" exceeds the 15MB storage limit (${Math.round(textBytes / megabyte)}MB). Try a shorter document.`,
+ );
+ }
const fileInfo = removeNullishValues({
text,
bytes,
@@ -592,29 +560,52 @@ const processAgentFileUpload = async ({ req, res, metadata }) => {
const fileConfig = mergeFileConfig(appConfig.fileConfig);
- const shouldUseOCR =
+ const shouldUseConfiguredOCR =
appConfig?.ocr != null &&
fileConfig.checkType(file.mimetype, fileConfig.ocr?.supportedMimeTypes || []);
- if (shouldUseOCR && !(await checkCapability(req, AgentCapabilities.ocr))) {
- throw new Error('OCR capability is not enabled for Agents');
- } else if (shouldUseOCR) {
+ const shouldUseDocumentParser =
+ !shouldUseConfiguredOCR && documentParserMimeTypes.some((regex) => regex.test(file.mimetype));
+
+ const shouldUseOCR = shouldUseConfiguredOCR || shouldUseDocumentParser;
+
+ const resolveDocumentText = async () => {
+ if (shouldUseConfiguredOCR) {
+ try {
+ const ocrStrategy = appConfig?.ocr?.strategy ?? FileSources.document_parser;
+ const { handleFileUpload } = getStrategyFunctions(ocrStrategy);
+ return await handleFileUpload({ req, file, loadAuthValues });
+ } catch (err) {
+ logger.error(
+ `[processAgentFileUpload] Configured OCR failed for "${file.originalname}", falling back to document_parser:`,
+ err,
+ );
+ }
+ }
try {
- const { handleFileUpload: uploadOCR } = getStrategyFunctions(
- appConfig?.ocr?.strategy ?? FileSources.mistral_ocr,
- );
- const {
- text,
- bytes,
- filepath: ocrFileURL,
- } = await uploadOCR({ req, file, loadAuthValues });
- return await createTextFile({ text, bytes, filepath: ocrFileURL });
- } catch (ocrError) {
+ const { handleFileUpload } = getStrategyFunctions(FileSources.document_parser);
+ return await handleFileUpload({ req, file, loadAuthValues });
+ } catch (err) {
logger.error(
- `[processAgentFileUpload] OCR processing failed for file "${file.originalname}", falling back to text extraction:`,
- ocrError,
+ `[processAgentFileUpload] Document parser failed for "${file.originalname}":`,
+ err,
);
}
+ };
+
+ if (shouldUseConfiguredOCR && !(await checkCapability(req, AgentCapabilities.ocr))) {
+ throw new Error('OCR capability is not enabled for Agents');
+ }
+
+ if (shouldUseOCR) {
+ const ocrResult = await resolveDocumentText();
+ if (ocrResult) {
+ const { text, bytes, filepath: ocrFileURL } = ocrResult;
+ return await createTextFile({ text, bytes, filepath: ocrFileURL });
+ }
+ throw new Error(
+ `Unable to extract text from "${file.originalname}". The document may be image-based and requires an OCR service to process.`,
+ );
}
const shouldUseSTT = fileConfig.checkType(
@@ -1057,7 +1048,6 @@ function filterFile({ req, image, isAvatar }) {
module.exports = {
filterFile,
- processFiles,
processFileURL,
saveBase64Image,
processImageFile,
diff --git a/api/server/services/Files/process.spec.js b/api/server/services/Files/process.spec.js
new file mode 100644
index 0000000000..7737255a52
--- /dev/null
+++ b/api/server/services/Files/process.spec.js
@@ -0,0 +1,347 @@
+jest.mock('uuid', () => ({ v4: jest.fn(() => 'mock-uuid') }));
+
+jest.mock('@librechat/data-schemas', () => ({
+ logger: { warn: jest.fn(), debug: jest.fn(), error: jest.fn() },
+}));
+
+jest.mock('@librechat/agents', () => ({
+ EnvVar: { CODE_API_KEY: 'CODE_API_KEY' },
+}));
+
+jest.mock('@librechat/api', () => ({
+ sanitizeFilename: jest.fn((n) => n),
+ parseText: jest.fn().mockResolvedValue({ text: '', bytes: 0 }),
+ processAudioFile: jest.fn(),
+}));
+
+jest.mock('librechat-data-provider', () => ({
+ ...jest.requireActual('librechat-data-provider'),
+ mergeFileConfig: jest.fn(),
+}));
+
+jest.mock('~/server/services/Files/images', () => ({
+ convertImage: jest.fn(),
+ resizeAndConvert: jest.fn(),
+ resizeImageBuffer: jest.fn(),
+}));
+
+jest.mock('~/server/controllers/assistants/v2', () => ({
+ addResourceFileId: jest.fn(),
+ deleteResourceFileId: jest.fn(),
+}));
+
+jest.mock('~/models/Agent', () => ({
+ addAgentResourceFile: jest.fn().mockResolvedValue({}),
+ removeAgentResourceFiles: jest.fn(),
+}));
+
+jest.mock('~/server/controllers/assistants/helpers', () => ({
+ getOpenAIClient: jest.fn(),
+}));
+
+jest.mock('~/server/services/Tools/credentials', () => ({
+ loadAuthValues: jest.fn(),
+}));
+
+jest.mock('~/models', () => ({
+ createFile: jest.fn().mockResolvedValue({ file_id: 'created-file-id' }),
+ updateFileUsage: jest.fn(),
+ deleteFiles: jest.fn(),
+}));
+
+jest.mock('~/server/utils/getFileStrategy', () => ({
+ getFileStrategy: jest.fn().mockReturnValue('local'),
+}));
+
+jest.mock('~/server/services/Config', () => ({
+ checkCapability: jest.fn().mockResolvedValue(true),
+}));
+
+jest.mock('~/server/utils/queue', () => ({
+ LB_QueueAsyncCall: jest.fn(),
+}));
+
+jest.mock('~/server/services/Files/strategies', () => ({
+ getStrategyFunctions: jest.fn(),
+}));
+
+jest.mock('~/server/utils', () => ({
+ determineFileType: jest.fn(),
+}));
+
+jest.mock('~/server/services/Files/Audio/STTService', () => ({
+ STTService: { getInstance: jest.fn() },
+}));
+
+const { EToolResources, FileSources, AgentCapabilities } = require('librechat-data-provider');
+const { mergeFileConfig } = require('librechat-data-provider');
+const { checkCapability } = require('~/server/services/Config');
+const { getStrategyFunctions } = require('~/server/services/Files/strategies');
+const { processAgentFileUpload } = require('./process');
+
+const PDF_MIME = 'application/pdf';
+const DOCX_MIME = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
+const XLSX_MIME = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
+const XLS_MIME = 'application/vnd.ms-excel';
+const ODS_MIME = 'application/vnd.oasis.opendocument.spreadsheet';
+const ODT_MIME = 'application/vnd.oasis.opendocument.text';
+const ODP_MIME = 'application/vnd.oasis.opendocument.presentation';
+const ODG_MIME = 'application/vnd.oasis.opendocument.graphics';
+
+const makeReq = ({ mimetype = PDF_MIME, ocrConfig = null } = {}) => ({
+ user: { id: 'user-123' },
+ file: {
+ path: '/tmp/upload.bin',
+ originalname: 'upload.bin',
+ filename: 'upload-uuid.bin',
+ mimetype,
+ },
+ body: { model: 'gpt-4o' },
+ config: {
+ fileConfig: {},
+ fileStrategy: 'local',
+ ocr: ocrConfig,
+ },
+});
+
+const makeMetadata = () => ({
+ agent_id: 'agent-abc',
+ tool_resource: EToolResources.context,
+ file_id: 'file-uuid-123',
+});
+
+const mockRes = {
+ status: jest.fn().mockReturnThis(),
+ json: jest.fn().mockReturnValue({}),
+};
+
+const makeFileConfig = ({ ocrSupportedMimeTypes = [] } = {}) => ({
+ checkType: (mime, types) => (types ?? []).includes(mime),
+ ocr: { supportedMimeTypes: ocrSupportedMimeTypes },
+ stt: { supportedMimeTypes: [] },
+ text: { supportedMimeTypes: [] },
+});
+
+describe('processAgentFileUpload', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockRes.status.mockReturnThis();
+ mockRes.json.mockReturnValue({});
+ checkCapability.mockResolvedValue(true);
+ getStrategyFunctions.mockReturnValue({
+ handleFileUpload: jest
+ .fn()
+ .mockResolvedValue({ text: 'extracted text', bytes: 42, filepath: 'doc://result' }),
+ });
+ mergeFileConfig.mockReturnValue(makeFileConfig());
+ });
+
+ describe('OCR strategy selection', () => {
+ test.each([
+ ['PDF', PDF_MIME],
+ ['DOCX', DOCX_MIME],
+ ['XLSX', XLSX_MIME],
+ ['XLS', XLS_MIME],
+ ['ODS', ODS_MIME],
+ ['Excel variant (msexcel)', 'application/msexcel'],
+ ['Excel variant (x-msexcel)', 'application/x-msexcel'],
+ ])('uses document_parser automatically for %s when no OCR is configured', async (_, mime) => {
+ mergeFileConfig.mockReturnValue(makeFileConfig());
+ const req = makeReq({ mimetype: mime, ocrConfig: null });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ });
+
+ test('does not check OCR capability when using automatic document_parser fallback', async () => {
+ const req = makeReq({ mimetype: PDF_MIME, ocrConfig: null });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).not.toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ });
+
+ test('uses the configured OCR strategy when OCR is set up for the file type', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ const req = makeReq({
+ mimetype: PDF_MIME,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.mistral_ocr);
+ });
+
+ test('uses document_parser as default when OCR is configured but no strategy is specified', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ const req = makeReq({
+ mimetype: PDF_MIME,
+ ocrConfig: { supportedMimeTypes: [PDF_MIME] },
+ });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ });
+
+ test('throws when configured OCR capability is not enabled for the agent', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ checkCapability.mockResolvedValue(false);
+ const req = makeReq({
+ mimetype: PDF_MIME,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).rejects.toThrow('OCR capability is not enabled for Agents');
+ });
+
+ test('uses document_parser (no capability check) when OCR capability returns false but no OCR config', async () => {
+ checkCapability.mockResolvedValue(false);
+ const req = makeReq({ mimetype: PDF_MIME, ocrConfig: null });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).not.toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ });
+
+ test('uses document_parser when OCR is configured but the file type is not in OCR supported types', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ const req = makeReq({
+ mimetype: DOCX_MIME,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).not.toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ expect(getStrategyFunctions).not.toHaveBeenCalledWith(FileSources.mistral_ocr);
+ });
+
+ test('does not invoke any OCR strategy for unsupported MIME types without OCR config', async () => {
+ const req = makeReq({ mimetype: 'text/plain', ocrConfig: null });
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).rejects.toThrow('File type text/plain is not supported for text parsing.');
+
+ expect(getStrategyFunctions).not.toHaveBeenCalled();
+ });
+
+ test.each([
+ ['ODT', ODT_MIME],
+ ['ODP', ODP_MIME],
+ ['ODG', ODG_MIME],
+ ])('routes %s through configured OCR when OCR supports the type', async (_, mime) => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [mime] }));
+ const req = makeReq({
+ mimetype: mime,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+
+ await processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() });
+
+ expect(checkCapability).toHaveBeenCalledWith(expect.anything(), AgentCapabilities.ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.mistral_ocr);
+ });
+
+ test('throws instead of falling back to parseText when document_parser fails for a document MIME type', async () => {
+ getStrategyFunctions.mockReturnValue({
+ handleFileUpload: jest.fn().mockRejectedValue(new Error('No text found in document')),
+ });
+ const req = makeReq({ mimetype: PDF_MIME, ocrConfig: null });
+ const { parseText } = require('@librechat/api');
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).rejects.toThrow(/image-based and requires an OCR service/);
+
+ expect(parseText).not.toHaveBeenCalled();
+ });
+
+ test('falls back to document_parser when configured OCR fails for a document MIME type', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ const failingUpload = jest.fn().mockRejectedValue(new Error('OCR API returned 500'));
+ const fallbackUpload = jest
+ .fn()
+ .mockResolvedValue({ text: 'parsed text', bytes: 11, filepath: 'doc://result' });
+ getStrategyFunctions
+ .mockReturnValueOnce({ handleFileUpload: failingUpload })
+ .mockReturnValueOnce({ handleFileUpload: fallbackUpload });
+ const req = makeReq({
+ mimetype: PDF_MIME,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).resolves.not.toThrow();
+
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.mistral_ocr);
+ expect(getStrategyFunctions).toHaveBeenCalledWith(FileSources.document_parser);
+ });
+
+ test('throws when both configured OCR and document_parser fallback fail', async () => {
+ mergeFileConfig.mockReturnValue(makeFileConfig({ ocrSupportedMimeTypes: [PDF_MIME] }));
+ getStrategyFunctions.mockReturnValue({
+ handleFileUpload: jest.fn().mockRejectedValue(new Error('failure')),
+ });
+ const req = makeReq({
+ mimetype: PDF_MIME,
+ ocrConfig: { strategy: FileSources.mistral_ocr },
+ });
+ const { parseText } = require('@librechat/api');
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).rejects.toThrow(/image-based and requires an OCR service/);
+
+ expect(parseText).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('text size guard', () => {
+ test('throws before writing to MongoDB when extracted text exceeds 15MB', async () => {
+ const oversizedText = 'x'.repeat(15 * 1024 * 1024 + 1);
+ getStrategyFunctions.mockReturnValue({
+ handleFileUpload: jest.fn().mockResolvedValue({
+ text: oversizedText,
+ bytes: Buffer.byteLength(oversizedText, 'utf8'),
+ filepath: 'doc://result',
+ }),
+ });
+ const req = makeReq({ mimetype: PDF_MIME, ocrConfig: null });
+ const { createFile } = require('~/models');
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).rejects.toThrow(/exceeds the 15MB storage limit/);
+
+ expect(createFile).not.toHaveBeenCalled();
+ });
+
+ test('succeeds when extracted text is within the 15MB limit', async () => {
+ const okText = 'x'.repeat(1024);
+ getStrategyFunctions.mockReturnValue({
+ handleFileUpload: jest.fn().mockResolvedValue({
+ text: okText,
+ bytes: Buffer.byteLength(okText, 'utf8'),
+ filepath: 'doc://result',
+ }),
+ });
+ const req = makeReq({ mimetype: PDF_MIME, ocrConfig: null });
+
+ await expect(
+ processAgentFileUpload({ req, res: mockRes, metadata: makeMetadata() }),
+ ).resolves.not.toThrow();
+ });
+ });
+});
diff --git a/api/server/services/Files/processFiles.test.js b/api/server/services/Files/processFiles.test.js
deleted file mode 100644
index 8417f639e9..0000000000
--- a/api/server/services/Files/processFiles.test.js
+++ /dev/null
@@ -1,248 +0,0 @@
-// Mock the updateFileUsage function before importing the actual processFiles
-jest.mock('~/models/File', () => ({
- updateFileUsage: jest.fn(),
-}));
-
-// Mock winston and logger configuration to avoid dependency issues
-jest.mock('~/config', () => ({
- logger: {
- info: jest.fn(),
- warn: jest.fn(),
- debug: jest.fn(),
- error: jest.fn(),
- },
-}));
-
-// Mock all other dependencies that might cause issues
-jest.mock('librechat-data-provider', () => ({
- isUUID: { parse: jest.fn() },
- megabyte: 1024 * 1024,
- PrincipalType: {
- USER: 'user',
- GROUP: 'group',
- PUBLIC: 'public',
- },
- PrincipalModel: {
- USER: 'User',
- GROUP: 'Group',
- },
- ResourceType: {
- AGENT: 'agent',
- PROJECT: 'project',
- FILE: 'file',
- PROMPTGROUP: 'promptGroup',
- },
- FileContext: { message_attachment: 'message_attachment' },
- FileSources: { local: 'local' },
- EModelEndpoint: { assistants: 'assistants' },
- EToolResources: { file_search: 'file_search' },
- mergeFileConfig: jest.fn(),
- removeNullishValues: jest.fn((obj) => obj),
- isAssistantsEndpoint: jest.fn(),
- Constants: { COMMANDS_MAX_LENGTH: 56 },
- PermissionTypes: {
- BOOKMARKS: 'BOOKMARKS',
- PROMPTS: 'PROMPTS',
- MEMORIES: 'MEMORIES',
- MULTI_CONVO: 'MULTI_CONVO',
- AGENTS: 'AGENTS',
- TEMPORARY_CHAT: 'TEMPORARY_CHAT',
- RUN_CODE: 'RUN_CODE',
- WEB_SEARCH: 'WEB_SEARCH',
- FILE_CITATIONS: 'FILE_CITATIONS',
- },
- Permissions: {
- USE: 'USE',
- OPT_OUT: 'OPT_OUT',
- },
- SystemRoles: {
- USER: 'USER',
- ADMIN: 'ADMIN',
- },
-}));
-
-jest.mock('~/server/services/Files/images', () => ({
- convertImage: jest.fn(),
- resizeAndConvert: jest.fn(),
- resizeImageBuffer: jest.fn(),
-}));
-
-jest.mock('~/server/controllers/assistants/v2', () => ({
- addResourceFileId: jest.fn(),
- deleteResourceFileId: jest.fn(),
-}));
-
-jest.mock('~/models/Agent', () => ({
- addAgentResourceFile: jest.fn(),
- removeAgentResourceFiles: jest.fn(),
-}));
-
-jest.mock('~/server/controllers/assistants/helpers', () => ({
- getOpenAIClient: jest.fn(),
-}));
-
-jest.mock('~/server/services/Tools/credentials', () => ({
- loadAuthValues: jest.fn(),
-}));
-
-jest.mock('~/server/services/Config', () => ({
- checkCapability: jest.fn(),
-}));
-
-jest.mock('~/server/utils/queue', () => ({
- LB_QueueAsyncCall: jest.fn(),
-}));
-
-jest.mock('./strategies', () => ({
- getStrategyFunctions: jest.fn(),
-}));
-
-jest.mock('~/server/utils', () => ({
- determineFileType: jest.fn(),
-}));
-
-jest.mock('@librechat/api', () => ({
- parseText: jest.fn(),
- parseTextNative: jest.fn(),
-}));
-
-// Import the actual processFiles function after all mocks are set up
-const { processFiles } = require('./process');
-const { updateFileUsage } = require('~/models/File');
-
-describe('processFiles', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- describe('null filtering functionality', () => {
- it('should filter out null results from updateFileUsage when files do not exist', async () => {
- const mockFiles = [
- { file_id: 'existing-file-1' },
- { file_id: 'non-existent-file' },
- { file_id: 'existing-file-2' },
- ];
-
- // Mock updateFileUsage to return null for non-existent files
- updateFileUsage.mockImplementation(({ file_id }) => {
- if (file_id === 'non-existent-file') {
- return Promise.resolve(null); // Simulate file not found in the database
- }
- return Promise.resolve({ file_id, usage: 1 });
- });
-
- const result = await processFiles(mockFiles);
-
- expect(updateFileUsage).toHaveBeenCalledTimes(3);
- expect(result).toEqual([
- { file_id: 'existing-file-1', usage: 1 },
- { file_id: 'existing-file-2', usage: 1 },
- ]);
-
- // Critical test - ensure no null values in result
- expect(result).not.toContain(null);
- expect(result).not.toContain(undefined);
- expect(result.length).toBe(2); // Only valid files should be returned
- });
-
- it('should return empty array when all updateFileUsage calls return null', async () => {
- const mockFiles = [{ file_id: 'non-existent-1' }, { file_id: 'non-existent-2' }];
-
- // All updateFileUsage calls return null
- updateFileUsage.mockResolvedValue(null);
-
- const result = await processFiles(mockFiles);
-
- expect(updateFileUsage).toHaveBeenCalledTimes(2);
- expect(result).toEqual([]);
- expect(result).not.toContain(null);
- expect(result.length).toBe(0);
- });
-
- it('should work correctly when all files exist', async () => {
- const mockFiles = [{ file_id: 'file-1' }, { file_id: 'file-2' }];
-
- updateFileUsage.mockImplementation(({ file_id }) => {
- return Promise.resolve({ file_id, usage: 1 });
- });
-
- const result = await processFiles(mockFiles);
-
- expect(result).toEqual([
- { file_id: 'file-1', usage: 1 },
- { file_id: 'file-2', usage: 1 },
- ]);
- expect(result).not.toContain(null);
- expect(result.length).toBe(2);
- });
-
- it('should handle fileIds parameter and filter nulls correctly', async () => {
- const mockFiles = [{ file_id: 'file-1' }];
- const mockFileIds = ['file-2', 'non-existent-file'];
-
- updateFileUsage.mockImplementation(({ file_id }) => {
- if (file_id === 'non-existent-file') {
- return Promise.resolve(null);
- }
- return Promise.resolve({ file_id, usage: 1 });
- });
-
- const result = await processFiles(mockFiles, mockFileIds);
-
- expect(result).toEqual([
- { file_id: 'file-1', usage: 1 },
- { file_id: 'file-2', usage: 1 },
- ]);
- expect(result).not.toContain(null);
- expect(result).not.toContain(undefined);
- expect(result.length).toBe(2);
- });
-
- it('should handle duplicate file_ids correctly', async () => {
- const mockFiles = [
- { file_id: 'duplicate-file' },
- { file_id: 'duplicate-file' }, // Duplicate should be ignored
- { file_id: 'unique-file' },
- ];
-
- updateFileUsage.mockImplementation(({ file_id }) => {
- return Promise.resolve({ file_id, usage: 1 });
- });
-
- const result = await processFiles(mockFiles);
-
- // Should only call updateFileUsage twice (duplicate ignored)
- expect(updateFileUsage).toHaveBeenCalledTimes(2);
- expect(result).toEqual([
- { file_id: 'duplicate-file', usage: 1 },
- { file_id: 'unique-file', usage: 1 },
- ]);
- expect(result.length).toBe(2);
- });
- });
-
- describe('edge cases', () => {
- it('should handle empty files array', async () => {
- const result = await processFiles([]);
- expect(result).toEqual([]);
- expect(updateFileUsage).not.toHaveBeenCalled();
- });
-
- it('should handle mixed null and undefined returns from updateFileUsage', async () => {
- const mockFiles = [{ file_id: 'file-1' }, { file_id: 'file-2' }, { file_id: 'file-3' }];
-
- updateFileUsage.mockImplementation(({ file_id }) => {
- if (file_id === 'file-1') return Promise.resolve(null);
- if (file_id === 'file-2') return Promise.resolve(undefined);
- return Promise.resolve({ file_id, usage: 1 });
- });
-
- const result = await processFiles(mockFiles);
-
- expect(result).toEqual([{ file_id: 'file-3', usage: 1 }]);
- expect(result).not.toContain(null);
- expect(result).not.toContain(undefined);
- expect(result.length).toBe(1);
- });
- });
-});
diff --git a/api/server/services/Files/strategies.js b/api/server/services/Files/strategies.js
index 2ad526194b..25341b5715 100644
--- a/api/server/services/Files/strategies.js
+++ b/api/server/services/Files/strategies.js
@@ -1,5 +1,6 @@
const { FileSources } = require('librechat-data-provider');
const {
+ parseDocument,
uploadMistralOCR,
uploadAzureMistralOCR,
uploadGoogleVertexMistralOCR,
@@ -246,6 +247,26 @@ const vertexMistralOCRStrategy = () => ({
handleFileUpload: uploadGoogleVertexMistralOCR,
});
+const documentParserStrategy = () => ({
+ /** @type {typeof saveFileFromURL | null} */
+ saveURL: null,
+ /** @type {typeof getLocalFileURL | null} */
+ getFileURL: null,
+ /** @type {typeof saveLocalBuffer | null} */
+ saveBuffer: null,
+ /** @type {typeof processLocalAvatar | null} */
+ processAvatar: null,
+ /** @type {typeof uploadLocalImage | null} */
+ handleImageUpload: null,
+ /** @type {typeof prepareImagesLocal | null} */
+ prepareImagePayload: null,
+ /** @type {typeof deleteLocalFile | null} */
+ deleteFile: null,
+ /** @type {typeof getLocalFileStream | null} */
+ getDownloadStream: null,
+ handleFileUpload: parseDocument,
+});
+
// Strategy Selector
const getStrategyFunctions = (fileSource) => {
if (fileSource === FileSources.firebase) {
@@ -270,6 +291,8 @@ const getStrategyFunctions = (fileSource) => {
return azureMistralOCRStrategy();
} else if (fileSource === FileSources.vertexai_mistral_ocr) {
return vertexMistralOCRStrategy();
+ } else if (fileSource === FileSources.document_parser) {
+ return documentParserStrategy();
} else if (fileSource === FileSources.text) {
return localStrategy(); // Text files use local strategy
} else {
diff --git a/api/server/services/GraphApiService.spec.js b/api/server/services/GraphApiService.spec.js
index fa11190cc3..0a625e77e1 100644
--- a/api/server/services/GraphApiService.spec.js
+++ b/api/server/services/GraphApiService.spec.js
@@ -18,9 +18,6 @@ jest.mock('~/config', () => ({
defaults: {},
})),
}));
-jest.mock('~/utils', () => ({
- logAxiosError: jest.fn(),
-}));
jest.mock('~/server/services/Config', () => ({}));
jest.mock('~/server/services/Files/strategies', () => ({
diff --git a/api/server/services/GraphTokenService.js b/api/server/services/GraphTokenService.js
index d5cd6a94f2..843adbe5a2 100644
--- a/api/server/services/GraphTokenService.js
+++ b/api/server/services/GraphTokenService.js
@@ -7,7 +7,7 @@ const getLogStores = require('~/cache/getLogStores');
/**
* Get Microsoft Graph API token using existing token exchange mechanism
* @param {Object} user - User object with OpenID information
- * @param {string} accessToken - Current access token from Authorization header
+ * @param {string} accessToken - Federated access token used as OBO assertion
* @param {string} scopes - Graph API scopes for the token
* @param {boolean} fromCache - Whether to try getting token from cache first
* @returns {Promise} Graph API token response with access_token and expires_in
diff --git a/api/server/services/MCP.js b/api/server/services/MCP.js
index e91e5e7904..ad1f9f5cc3 100644
--- a/api/server/services/MCP.js
+++ b/api/server/services/MCP.js
@@ -1,4 +1,3 @@
-const { z } = require('zod');
const { tool } = require('@langchain/core/tools');
const { logger } = require('@librechat/data-schemas');
const {
@@ -10,8 +9,11 @@ const {
const {
sendEvent,
MCPOAuthHandler,
+ isMCPDomainAllowed,
normalizeServerName,
- convertWithResolvedRefs,
+ normalizeJsonSchema,
+ GenerationJobManager,
+ resolveJsonSchemaRefs,
} = require('@librechat/api');
const {
Time,
@@ -20,25 +22,41 @@ const {
ContentTypes,
isAssistantsEndpoint,
} = require('librechat-data-provider');
-const { getMCPManager, getFlowStateManager, getOAuthReconnectionManager } = require('~/config');
+const {
+ getOAuthReconnectionManager,
+ getMCPServersRegistry,
+ getFlowStateManager,
+ getMCPManager,
+} = require('~/config');
const { findToken, createToken, updateToken } = require('~/models');
+const { getGraphApiToken } = require('./GraphTokenService');
const { reinitMCPServer } = require('./Tools/mcp');
const { getAppConfig } = require('./Config');
const { getLogStores } = require('~/cache');
-const { mcpServersRegistry } = require('@librechat/api');
+
+function isEmptyObjectSchema(jsonSchema) {
+ return (
+ jsonSchema != null &&
+ typeof jsonSchema === 'object' &&
+ jsonSchema.type === 'object' &&
+ (jsonSchema.properties == null || Object.keys(jsonSchema.properties).length === 0) &&
+ !jsonSchema.additionalProperties
+ );
+}
/**
* @param {object} params
* @param {ServerResponse} params.res - The Express response object for sending events.
* @param {string} params.stepId - The ID of the step in the flow.
* @param {ToolCallChunk} params.toolCall - The tool call object containing tool information.
+ * @param {string | null} [params.streamId] - The stream ID for resumable mode.
*/
-function createRunStepDeltaEmitter({ res, stepId, toolCall }) {
+function createRunStepDeltaEmitter({ res, stepId, toolCall, streamId = null }) {
/**
* @param {string} authURL - The URL to redirect the user for OAuth authentication.
- * @returns {void}
+ * @returns {Promise}
*/
- return function (authURL) {
+ return async function (authURL) {
/** @type {{ id: string; delta: AgentToolCallDelta }} */
const data = {
id: stepId,
@@ -49,7 +67,12 @@ function createRunStepDeltaEmitter({ res, stepId, toolCall }) {
expires_at: Date.now() + Time.TWO_MINUTES,
},
};
- sendEvent(res, { event: GraphEvents.ON_RUN_STEP_DELTA, data });
+ const eventData = { event: GraphEvents.ON_RUN_STEP_DELTA, data };
+ if (streamId) {
+ await GenerationJobManager.emitChunk(streamId, eventData);
+ } else {
+ sendEvent(res, eventData);
+ }
};
}
@@ -60,9 +83,11 @@ function createRunStepDeltaEmitter({ res, stepId, toolCall }) {
* @param {string} params.stepId - The ID of the step in the flow.
* @param {ToolCallChunk} params.toolCall - The tool call object containing tool information.
* @param {number} [params.index]
+ * @param {string | null} [params.streamId] - The stream ID for resumable mode.
+ * @returns {() => Promise}
*/
-function createRunStepEmitter({ res, runId, stepId, toolCall, index }) {
- return function () {
+function createRunStepEmitter({ res, runId, stepId, toolCall, index, streamId = null }) {
+ return async function () {
/** @type {import('@librechat/agents').RunStep} */
const data = {
runId: runId ?? Constants.USE_PRELIM_RESPONSE_MESSAGE_ID,
@@ -74,7 +99,12 @@ function createRunStepEmitter({ res, runId, stepId, toolCall, index }) {
tool_calls: [toolCall],
},
};
- sendEvent(res, { event: GraphEvents.ON_RUN_STEP, data });
+ const eventData = { event: GraphEvents.ON_RUN_STEP, data };
+ if (streamId) {
+ await GenerationJobManager.emitChunk(streamId, eventData);
+ } else {
+ sendEvent(res, eventData);
+ }
};
}
@@ -105,10 +135,9 @@ function createOAuthStart({ flowId, flowManager, callback }) {
* @param {ServerResponse} params.res - The Express response object for sending events.
* @param {string} params.stepId - The ID of the step in the flow.
* @param {ToolCallChunk} params.toolCall - The tool call object containing tool information.
- * @param {string} params.loginFlowId - The ID of the login flow.
- * @param {FlowStateManager} params.flowManager - The flow manager instance.
+ * @param {string | null} [params.streamId] - The stream ID for resumable mode.
*/
-function createOAuthEnd({ res, stepId, toolCall }) {
+function createOAuthEnd({ res, stepId, toolCall, streamId = null }) {
return async function () {
/** @type {{ id: string; delta: AgentToolCallDelta }} */
const data = {
@@ -118,7 +147,12 @@ function createOAuthEnd({ res, stepId, toolCall }) {
tool_calls: [{ ...toolCall }],
},
};
- sendEvent(res, { event: GraphEvents.ON_RUN_STEP_DELTA, data });
+ const eventData = { event: GraphEvents.ON_RUN_STEP_DELTA, data };
+ if (streamId) {
+ await GenerationJobManager.emitChunk(streamId, eventData);
+ } else {
+ sendEvent(res, eventData);
+ }
logger.debug('Sent OAuth login success to client');
};
}
@@ -134,7 +168,9 @@ function createAbortHandler({ userId, serverName, toolName, flowManager }) {
return function () {
logger.info(`[MCP][User: ${userId}][${serverName}][${toolName}] Tool call aborted`);
const flowId = MCPOAuthHandler.generateFlowId(userId, serverName);
+ // Clean up both mcp_oauth and mcp_get_tokens flows
flowManager.failFlow(flowId, 'mcp_oauth', new Error('Tool call aborted'));
+ flowManager.failFlow(flowId, 'mcp_get_tokens', new Error('Tool call aborted'));
};
}
@@ -159,10 +195,22 @@ function createOAuthCallback({ runStepEmitter, runStepDeltaEmitter }) {
* @param {AbortSignal} params.signal
* @param {string} params.model
* @param {number} [params.index]
+ * @param {string | null} [params.streamId] - The stream ID for resumable mode.
* @param {Record>} [params.userMCPAuthMap]
* @returns { Promise unknown}>> } An object with `_call` method to execute the tool input.
*/
-async function reconnectServer({ res, user, index, signal, serverName, userMCPAuthMap }) {
+async function reconnectServer({
+ res,
+ user,
+ index,
+ signal,
+ serverName,
+ userMCPAuthMap,
+ streamId = null,
+}) {
+ logger.debug(
+ `[MCP][reconnectServer] serverName: ${serverName}, user: ${user?.id}, hasUserMCPAuthMap: ${!!userMCPAuthMap}`,
+ );
const runId = Constants.USE_PRELIM_RESPONSE_MESSAGE_ID;
const flowId = `${user.id}:${serverName}:${Date.now()}`;
const flowManager = getFlowStateManager(getLogStores(CacheKeys.FLOWS));
@@ -173,36 +221,60 @@ async function reconnectServer({ res, user, index, signal, serverName, userMCPAu
type: 'tool_call_chunk',
};
- const runStepEmitter = createRunStepEmitter({
- res,
- index,
- runId,
- stepId,
- toolCall,
- });
- const runStepDeltaEmitter = createRunStepDeltaEmitter({
- res,
- stepId,
- toolCall,
- });
- const callback = createOAuthCallback({ runStepEmitter, runStepDeltaEmitter });
- const oauthStart = createOAuthStart({
- res,
- flowId,
- callback,
- flowManager,
- });
- return await reinitMCPServer({
- user,
- signal,
- serverName,
- oauthStart,
- flowManager,
- userMCPAuthMap,
- forceNew: true,
- returnOnOAuth: false,
- connectionTimeout: Time.TWO_MINUTES,
- });
+ // Set up abort handler to clean up OAuth flows if request is aborted
+ const oauthFlowId = MCPOAuthHandler.generateFlowId(user.id, serverName);
+ const abortHandler = () => {
+ logger.info(
+ `[MCP][User: ${user.id}][${serverName}] Tool loading aborted, cleaning up OAuth flows`,
+ );
+ // Clean up both mcp_oauth and mcp_get_tokens flows
+ flowManager.failFlow(oauthFlowId, 'mcp_oauth', new Error('Tool loading aborted'));
+ flowManager.failFlow(oauthFlowId, 'mcp_get_tokens', new Error('Tool loading aborted'));
+ };
+
+ if (signal) {
+ signal.addEventListener('abort', abortHandler, { once: true });
+ }
+
+ try {
+ const runStepEmitter = createRunStepEmitter({
+ res,
+ index,
+ runId,
+ stepId,
+ toolCall,
+ streamId,
+ });
+ const runStepDeltaEmitter = createRunStepDeltaEmitter({
+ res,
+ stepId,
+ toolCall,
+ streamId,
+ });
+ const callback = createOAuthCallback({ runStepEmitter, runStepDeltaEmitter });
+ const oauthStart = createOAuthStart({
+ res,
+ flowId,
+ callback,
+ flowManager,
+ });
+ return await reinitMCPServer({
+ user,
+ signal,
+ serverName,
+ oauthStart,
+ flowManager,
+ userMCPAuthMap,
+ forceNew: true,
+ returnOnOAuth: false,
+ connectionTimeout: Time.TWO_MINUTES,
+ });
+ } finally {
+ // Clean up abort handler to prevent memory leaks
+ if (signal) {
+ signal.removeEventListener('abort', abortHandler);
+ }
+ }
}
/**
@@ -219,11 +291,45 @@ async function reconnectServer({ res, user, index, signal, serverName, userMCPAu
* @param {Providers | EModelEndpoint} params.provider - The provider for the tool.
* @param {number} [params.index]
* @param {AbortSignal} [params.signal]
+ * @param {string | null} [params.streamId] - The stream ID for resumable mode.
+ * @param {import('@librechat/api').ParsedServerConfig} [params.config]
* @param {Record>} [params.userMCPAuthMap]
* @returns { Promise unknown}>> } An object with `_call` method to execute the tool input.
*/
-async function createMCPTools({ res, user, index, signal, serverName, provider, userMCPAuthMap }) {
- const result = await reconnectServer({ res, user, index, signal, serverName, userMCPAuthMap });
+async function createMCPTools({
+ res,
+ user,
+ index,
+ signal,
+ config,
+ provider,
+ serverName,
+ userMCPAuthMap,
+ streamId = null,
+}) {
+ // Early domain validation before reconnecting server (avoid wasted work on disallowed domains)
+ // Use getAppConfig() to support per-user/role domain restrictions
+ const serverConfig =
+ config ?? (await getMCPServersRegistry().getServerConfig(serverName, user?.id));
+ if (serverConfig?.url) {
+ const appConfig = await getAppConfig({ role: user?.role });
+ const allowedDomains = appConfig?.mcpSettings?.allowedDomains;
+ const isDomainAllowed = await isMCPDomainAllowed(serverConfig, allowedDomains);
+ if (!isDomainAllowed) {
+ logger.warn(`[MCP][${serverName}] Domain not allowed, skipping all tools`);
+ return [];
+ }
+ }
+
+ const result = await reconnectServer({
+ res,
+ user,
+ index,
+ signal,
+ serverName,
+ userMCPAuthMap,
+ streamId,
+ });
if (!result || !result.tools) {
logger.warn(`[MCP][${serverName}] Failed to reinitialize MCP server.`);
return;
@@ -236,8 +342,10 @@ async function createMCPTools({ res, user, index, signal, serverName, provider,
user,
provider,
userMCPAuthMap,
+ streamId,
availableTools: result.availableTools,
toolKey: `${tool.name}${Constants.mcp_delimiter}${serverName}`,
+ config: serverConfig,
});
if (toolInstance) {
serverTools.push(toolInstance);
@@ -256,9 +364,11 @@ async function createMCPTools({ res, user, index, signal, serverName, provider,
* @param {string} params.model - The model for the tool.
* @param {number} [params.index]
* @param {AbortSignal} [params.signal]
+ * @param {string | null} [params.streamId] - The stream ID for resumable mode.
* @param {Providers | EModelEndpoint} params.provider - The provider for the tool.
* @param {LCAvailableTools} [params.availableTools]
* @param {Record>} [params.userMCPAuthMap]
+ * @param {import('@librechat/api').ParsedServerConfig} [params.config]
* @returns { Promise unknown}> } An object with `_call` method to execute the tool input.
*/
async function createMCPTool({
@@ -270,9 +380,25 @@ async function createMCPTool({
provider,
userMCPAuthMap,
availableTools,
+ config,
+ streamId = null,
}) {
const [toolName, serverName] = toolKey.split(Constants.mcp_delimiter);
+ // Runtime domain validation: check if the server's domain is still allowed
+ // Use getAppConfig() to support per-user/role domain restrictions
+ const serverConfig =
+ config ?? (await getMCPServersRegistry().getServerConfig(serverName, user?.id));
+ if (serverConfig?.url) {
+ const appConfig = await getAppConfig({ role: user?.role });
+ const allowedDomains = appConfig?.mcpSettings?.allowedDomains;
+ const isDomainAllowed = await isMCPDomainAllowed(serverConfig, allowedDomains);
+ if (!isDomainAllowed) {
+ logger.warn(`[MCP][${serverName}] Domain no longer allowed, skipping tool: ${toolName}`);
+ return undefined;
+ }
+ }
+
/** @type {LCTool | undefined} */
let toolDefinition = availableTools?.[toolKey]?.function;
if (!toolDefinition) {
@@ -286,6 +412,7 @@ async function createMCPTool({
signal,
serverName,
userMCPAuthMap,
+ streamId,
});
toolDefinition = result?.availableTools?.[toolKey]?.function;
}
@@ -301,20 +428,32 @@ async function createMCPTool({
toolName,
serverName,
toolDefinition,
+ streamId,
});
}
-function createToolInstance({ res, toolName, serverName, toolDefinition, provider: _provider }) {
+function createToolInstance({
+ res,
+ toolName,
+ serverName,
+ toolDefinition,
+ provider: _provider,
+ streamId = null,
+}) {
/** @type {LCTool} */
const { description, parameters } = toolDefinition;
const isGoogle = _provider === Providers.VERTEXAI || _provider === Providers.GOOGLE;
- let schema = convertWithResolvedRefs(parameters, {
- allowEmptyObject: !isGoogle,
- transformOneOfAnyOf: true,
- });
- if (!schema) {
- schema = z.object({ input: z.string().optional() });
+ let schema = parameters ? normalizeJsonSchema(resolveJsonSchemaRefs(parameters)) : null;
+
+ if (!schema || (isGoogle && isEmptyObjectSchema(schema))) {
+ schema = {
+ type: 'object',
+ properties: {
+ input: { type: 'string', description: 'Input for the tool' },
+ },
+ required: [],
+ };
}
const normalizedToolKey = `${toolName}${Constants.mcp_delimiter}${normalizeServerName(serverName)}`;
@@ -340,6 +479,7 @@ function createToolInstance({ res, toolName, serverName, toolDefinition, provide
res,
stepId,
toolCall,
+ streamId,
});
const oauthStart = createOAuthStart({
flowId,
@@ -350,6 +490,7 @@ function createToolInstance({ res, toolName, serverName, toolDefinition, provide
res,
stepId,
toolCall,
+ streamId,
});
if (derivedSignal) {
@@ -379,6 +520,7 @@ function createToolInstance({ res, toolName, serverName, toolDefinition, provide
},
oauthStart,
oauthEnd,
+ graphTokenResolver: getGraphApiToken,
});
if (isAssistantsEndpoint(provider) && Array.isArray(result)) {
@@ -426,6 +568,7 @@ function createToolInstance({ res, toolName, serverName, toolDefinition, provide
});
toolInstance.mcp = true;
toolInstance.mcpRawServerName = serverName;
+ toolInstance.mcpJsonSchema = parameters;
return toolInstance;
}
@@ -435,8 +578,7 @@ function createToolInstance({ res, toolName, serverName, toolDefinition, provide
* @returns {Object} Object containing mcpConfig, appConnections, userConnections, and oauthServers
*/
async function getMCPSetupData(userId) {
- const config = await getAppConfig();
- const mcpConfig = config?.mcpConfig;
+ const mcpConfig = await getMCPServersRegistry().getAllServerConfigs(userId);
if (!mcpConfig) {
throw new Error('MCP config not found');
@@ -446,12 +588,15 @@ async function getMCPSetupData(userId) {
/** @type {Map} */
let appConnections = new Map();
try {
- appConnections = (await mcpManager.appConnections?.getAll()) || new Map();
+ // Use getLoaded() instead of getAll() to avoid forcing connection creation
+ // getAll() creates connections for all servers, which is problematic for servers
+ // that require user context (e.g., those with {{LIBRECHAT_USER_ID}} placeholders)
+ appConnections = (await mcpManager.appConnections?.getLoaded()) || new Map();
} catch (error) {
logger.error(`[MCP][User: ${userId}] Error getting app connections:`, error);
}
const userConnections = mcpManager.getUserConnections(userId) || new Map();
- const oauthServers = await mcpServersRegistry.getOAuthServers();
+ const oauthServers = await getMCPServersRegistry().getOAuthServers(userId);
return {
mcpConfig,
@@ -524,24 +669,26 @@ async function checkOAuthFlowStatus(userId, serverName) {
* Get connection status for a specific MCP server
* @param {string} userId - The user ID
* @param {string} serverName - The server name
- * @param {Map} appConnections - App-level connections
- * @param {Map} userConnections - User-level connections
+ * @param {import('@librechat/api').ParsedServerConfig} config - The server configuration
+ * @param {Map} appConnections - App-level connections
+ * @param {Map} userConnections - User-level connections
* @param {Set} oauthServers - Set of OAuth servers
* @returns {Object} Object containing requiresOAuth and connectionState
*/
async function getServerConnectionStatus(
userId,
serverName,
+ config,
appConnections,
userConnections,
oauthServers,
) {
- const getConnectionState = () =>
- appConnections.get(serverName)?.connectionState ??
- userConnections.get(serverName)?.connectionState ??
- 'disconnected';
+ const connection = appConnections.get(serverName) || userConnections.get(serverName);
+ const isStaleOrDoNotExist = connection ? connection?.isStale(config.updatedAt) : true;
- const baseConnectionState = getConnectionState();
+ const baseConnectionState = isStaleOrDoNotExist
+ ? 'disconnected'
+ : connection?.connectionState || 'disconnected';
let finalConnectionState = baseConnectionState;
// connection state overrides specific to OAuth servers
diff --git a/api/server/services/MCP.spec.js b/api/server/services/MCP.spec.js
index 18857c4893..b2caebc91e 100644
--- a/api/server/services/MCP.spec.js
+++ b/api/server/services/MCP.spec.js
@@ -1,14 +1,4 @@
-const { logger } = require('@librechat/data-schemas');
-const { MCPOAuthHandler } = require('@librechat/api');
-const { CacheKeys } = require('librechat-data-provider');
-const {
- createMCPTool,
- createMCPTools,
- getMCPSetupData,
- checkOAuthFlowStatus,
- getServerConnectionStatus,
-} = require('./MCP');
-
+// Mock all dependencies - define mocks before imports
// Mock all dependencies
jest.mock('@librechat/data-schemas', () => ({
logger: {
@@ -19,69 +9,56 @@ jest.mock('@librechat/data-schemas', () => ({
},
}));
-jest.mock('@langchain/core/tools', () => ({
- tool: jest.fn((fn, config) => {
- const toolInstance = { _call: fn, ...config };
- return toolInstance;
- }),
-}));
+// Create mock registry instance
+const mockRegistryInstance = {
+ getOAuthServers: jest.fn(() => Promise.resolve(new Set())),
+ getAllServerConfigs: jest.fn(() => Promise.resolve({})),
+ getServerConfig: jest.fn(() => Promise.resolve(null)),
+};
-jest.mock('@librechat/agents', () => ({
- Providers: {
- VERTEXAI: 'vertexai',
- GOOGLE: 'google',
- },
- StepTypes: {
- TOOL_CALLS: 'tool_calls',
- },
- GraphEvents: {
- ON_RUN_STEP_DELTA: 'on_run_step_delta',
- ON_RUN_STEP: 'on_run_step',
- },
- Constants: {
- CONTENT_AND_ARTIFACT: 'content_and_artifact',
- },
-}));
+// Create isMCPDomainAllowed mock that can be configured per-test
+const mockIsMCPDomainAllowed = jest.fn(() => Promise.resolve(true));
-jest.mock('@librechat/api', () => ({
- MCPOAuthHandler: {
- generateFlowId: jest.fn(),
- },
- sendEvent: jest.fn(),
- normalizeServerName: jest.fn((name) => name),
- convertWithResolvedRefs: jest.fn((params) => params),
- mcpServersRegistry: {
- getOAuthServers: jest.fn(() => Promise.resolve(new Set())),
- },
-}));
+const mockGetAppConfig = jest.fn(() => Promise.resolve({}));
-jest.mock('librechat-data-provider', () => ({
- CacheKeys: {
- FLOWS: 'flows',
- },
- Constants: {
- USE_PRELIM_RESPONSE_MESSAGE_ID: 'prelim_response_id',
- mcp_delimiter: '::',
- mcp_prefix: 'mcp_',
- },
- ContentTypes: {
- TEXT: 'text',
- },
- isAssistantsEndpoint: jest.fn(() => false),
- Time: {
- TWO_MINUTES: 120000,
- },
-}));
+jest.mock('@librechat/api', () => {
+ const actual = jest.requireActual('@librechat/api');
+ return {
+ ...actual,
+ sendEvent: jest.fn(),
+ get isMCPDomainAllowed() {
+ return mockIsMCPDomainAllowed;
+ },
+ GenerationJobManager: {
+ emitChunk: jest.fn(),
+ },
+ };
+});
+
+const { logger } = require('@librechat/data-schemas');
+const { MCPOAuthHandler } = require('@librechat/api');
+const { CacheKeys, Constants } = require('librechat-data-provider');
+const D = Constants.mcp_delimiter;
+const {
+ createMCPTool,
+ createMCPTools,
+ getMCPSetupData,
+ checkOAuthFlowStatus,
+ getServerConnectionStatus,
+} = require('./MCP');
jest.mock('./Config', () => ({
loadCustomConfig: jest.fn(),
- getAppConfig: jest.fn(),
+ get getAppConfig() {
+ return mockGetAppConfig;
+ },
}));
jest.mock('~/config', () => ({
getMCPManager: jest.fn(),
getFlowStateManager: jest.fn(),
getOAuthReconnectionManager: jest.fn(),
+ getMCPServersRegistry: jest.fn(() => mockRegistryInstance),
}));
jest.mock('~/cache', () => ({
@@ -98,66 +75,66 @@ jest.mock('./Tools/mcp', () => ({
reinitMCPServer: jest.fn(),
}));
+jest.mock('./GraphTokenService', () => ({
+ getGraphApiToken: jest.fn(),
+}));
+
describe('tests for the new helper functions used by the MCP connection status endpoints', () => {
let mockGetMCPManager;
let mockGetFlowStateManager;
let mockGetLogStores;
let mockGetOAuthReconnectionManager;
- let mockMcpServersRegistry;
beforeEach(() => {
jest.clearAllMocks();
+ jest.spyOn(MCPOAuthHandler, 'generateFlowId');
mockGetMCPManager = require('~/config').getMCPManager;
mockGetFlowStateManager = require('~/config').getFlowStateManager;
mockGetLogStores = require('~/cache').getLogStores;
mockGetOAuthReconnectionManager = require('~/config').getOAuthReconnectionManager;
- mockMcpServersRegistry = require('@librechat/api').mcpServersRegistry;
});
describe('getMCPSetupData', () => {
const mockUserId = 'user-123';
const mockConfig = {
- mcpServers: {
- server1: { type: 'stdio' },
- server2: { type: 'http' },
- },
+ server1: { type: 'stdio' },
+ server2: { type: 'http' },
};
- let mockGetAppConfig;
beforeEach(() => {
- mockGetAppConfig = require('./Config').getAppConfig;
mockGetMCPManager.mockReturnValue({
- appConnections: { getAll: jest.fn(() => new Map()) },
+ appConnections: { getLoaded: jest.fn(() => new Map()) },
getUserConnections: jest.fn(() => new Map()),
});
- mockMcpServersRegistry.getOAuthServers.mockResolvedValue(new Set());
+ mockRegistryInstance.getOAuthServers.mockResolvedValue(new Set());
+ mockRegistryInstance.getAllServerConfigs.mockResolvedValue(mockConfig);
});
it('should successfully return MCP setup data', async () => {
- mockGetAppConfig.mockResolvedValue({ mcpConfig: mockConfig.mcpServers });
+ mockRegistryInstance.getAllServerConfigs.mockResolvedValue(mockConfig);
const mockAppConnections = new Map([['server1', { status: 'connected' }]]);
const mockUserConnections = new Map([['server2', { status: 'disconnected' }]]);
const mockOAuthServers = new Set(['server2']);
const mockMCPManager = {
- appConnections: { getAll: jest.fn(() => mockAppConnections) },
+ appConnections: { getLoaded: jest.fn(() => Promise.resolve(mockAppConnections)) },
getUserConnections: jest.fn(() => mockUserConnections),
};
mockGetMCPManager.mockReturnValue(mockMCPManager);
- mockMcpServersRegistry.getOAuthServers.mockResolvedValue(mockOAuthServers);
+ mockRegistryInstance.getOAuthServers.mockResolvedValue(mockOAuthServers);
const result = await getMCPSetupData(mockUserId);
- expect(mockGetAppConfig).toHaveBeenCalled();
+ expect(mockRegistryInstance.getAllServerConfigs).toHaveBeenCalledWith(mockUserId);
expect(mockGetMCPManager).toHaveBeenCalledWith(mockUserId);
- expect(mockMCPManager.appConnections.getAll).toHaveBeenCalled();
+ expect(mockMCPManager.appConnections.getLoaded).toHaveBeenCalled();
expect(mockMCPManager.getUserConnections).toHaveBeenCalledWith(mockUserId);
- expect(mockMcpServersRegistry.getOAuthServers).toHaveBeenCalled();
+ expect(mockRegistryInstance.getOAuthServers).toHaveBeenCalledWith(mockUserId);
expect(result).toEqual({
- mcpConfig: mockConfig.mcpServers,
+ mcpConfig: mockConfig,
appConnections: mockAppConnections,
userConnections: mockUserConnections,
oauthServers: mockOAuthServers,
@@ -165,24 +142,24 @@ describe('tests for the new helper functions used by the MCP connection status e
});
it('should throw error when MCP config not found', async () => {
- mockGetAppConfig.mockResolvedValue({});
+ mockRegistryInstance.getAllServerConfigs.mockResolvedValue(null);
await expect(getMCPSetupData(mockUserId)).rejects.toThrow('MCP config not found');
});
it('should handle null values from MCP manager gracefully', async () => {
- mockGetAppConfig.mockResolvedValue({ mcpConfig: mockConfig.mcpServers });
+ mockRegistryInstance.getAllServerConfigs.mockResolvedValue(mockConfig);
const mockMCPManager = {
- appConnections: { getAll: jest.fn(() => null) },
+ appConnections: { getLoaded: jest.fn(() => Promise.resolve(null)) },
getUserConnections: jest.fn(() => null),
};
mockGetMCPManager.mockReturnValue(mockMCPManager);
- mockMcpServersRegistry.getOAuthServers.mockResolvedValue(new Set());
+ mockRegistryInstance.getOAuthServers.mockResolvedValue(new Set());
const result = await getMCPSetupData(mockUserId);
expect(result).toEqual({
- mcpConfig: mockConfig.mcpServers,
+ mcpConfig: mockConfig,
appConnections: new Map(),
userConnections: new Map(),
oauthServers: new Set(),
@@ -329,15 +306,25 @@ describe('tests for the new helper functions used by the MCP connection status e
describe('getServerConnectionStatus', () => {
const mockUserId = 'user-123';
const mockServerName = 'test-server';
+ const mockConfig = { updatedAt: Date.now() };
it('should return app connection state when available', async () => {
- const appConnections = new Map([[mockServerName, { connectionState: 'connected' }]]);
+ const appConnections = new Map([
+ [
+ mockServerName,
+ {
+ connectionState: 'connected',
+ isStale: jest.fn(() => false),
+ },
+ ],
+ ]);
const userConnections = new Map();
const oauthServers = new Set();
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -351,12 +338,21 @@ describe('tests for the new helper functions used by the MCP connection status e
it('should fallback to user connection state when app connection not available', async () => {
const appConnections = new Map();
- const userConnections = new Map([[mockServerName, { connectionState: 'connecting' }]]);
+ const userConnections = new Map([
+ [
+ mockServerName,
+ {
+ connectionState: 'connecting',
+ isStale: jest.fn(() => false),
+ },
+ ],
+ ]);
const oauthServers = new Set();
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -376,6 +372,7 @@ describe('tests for the new helper functions used by the MCP connection status e
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -388,13 +385,30 @@ describe('tests for the new helper functions used by the MCP connection status e
});
it('should prioritize app connection over user connection', async () => {
- const appConnections = new Map([[mockServerName, { connectionState: 'connected' }]]);
- const userConnections = new Map([[mockServerName, { connectionState: 'disconnected' }]]);
+ const appConnections = new Map([
+ [
+ mockServerName,
+ {
+ connectionState: 'connected',
+ isStale: jest.fn(() => false),
+ },
+ ],
+ ]);
+ const userConnections = new Map([
+ [
+ mockServerName,
+ {
+ connectionState: 'disconnected',
+ isStale: jest.fn(() => false),
+ },
+ ],
+ ]);
const oauthServers = new Set();
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -420,6 +434,7 @@ describe('tests for the new helper functions used by the MCP connection status e
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -454,6 +469,7 @@ describe('tests for the new helper functions used by the MCP connection status e
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -491,6 +507,7 @@ describe('tests for the new helper functions used by the MCP connection status e
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -524,6 +541,7 @@ describe('tests for the new helper functions used by the MCP connection status e
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -549,6 +567,7 @@ describe('tests for the new helper functions used by the MCP connection status e
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -571,13 +590,22 @@ describe('tests for the new helper functions used by the MCP connection status e
mockGetFlowStateManager.mockReturnValue(mockFlowManager);
mockGetLogStores.mockReturnValue({});
- const appConnections = new Map([[mockServerName, { connectionState: 'connected' }]]);
+ const appConnections = new Map([
+ [
+ mockServerName,
+ {
+ connectionState: 'connected',
+ isStale: jest.fn(() => false),
+ },
+ ],
+ ]);
const userConnections = new Map();
const oauthServers = new Set([mockServerName]);
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -606,6 +634,7 @@ describe('tests for the new helper functions used by the MCP connection status e
const result = await getServerConnectionStatus(
mockUserId,
mockServerName,
+ mockConfig,
appConnections,
userConnections,
oauthServers,
@@ -639,6 +668,18 @@ describe('User parameter passing tests', () => {
createFlowWithHandler: jest.fn(),
failFlow: jest.fn(),
});
+
+ // Reset domain validation mock to default (allow all)
+ mockIsMCPDomainAllowed.mockReset();
+ mockIsMCPDomainAllowed.mockResolvedValue(true);
+
+ // Reset registry mocks
+ mockRegistryInstance.getServerConfig.mockReset();
+ mockRegistryInstance.getServerConfig.mockResolvedValue(null);
+
+ // Reset getAppConfig mock to default (no restrictions)
+ mockGetAppConfig.mockReset();
+ mockGetAppConfig.mockResolvedValue({});
});
describe('createMCPTools', () => {
@@ -650,7 +691,7 @@ describe('User parameter passing tests', () => {
mockReinitMCPServer.mockResolvedValue({
tools: [{ name: 'test-tool' }],
availableTools: {
- 'test-tool::test-server': {
+ [`test-tool${D}test-server`]: {
function: {
description: 'Test tool',
parameters: { type: 'object', properties: {} },
@@ -710,7 +751,7 @@ describe('User parameter passing tests', () => {
mockReinitMCPServer.mockResolvedValue({
availableTools: {
- 'test-tool::test-server': {
+ [`test-tool${D}test-server`]: {
function: {
description: 'Test tool',
parameters: { type: 'object', properties: {} },
@@ -723,7 +764,7 @@ describe('User parameter passing tests', () => {
await createMCPTool({
res: mockRes,
user: mockUser,
- toolKey: 'test-tool::test-server',
+ toolKey: `test-tool${D}test-server`,
provider: 'openai',
signal: mockSignal,
userMCPAuthMap: {},
@@ -745,7 +786,7 @@ describe('User parameter passing tests', () => {
const mockRes = { write: jest.fn(), flush: jest.fn() };
const availableTools = {
- 'test-tool::test-server': {
+ [`test-tool${D}test-server`]: {
function: {
description: 'Cached tool',
parameters: { type: 'object', properties: {} },
@@ -756,7 +797,7 @@ describe('User parameter passing tests', () => {
await createMCPTool({
res: mockRes,
user: mockUser,
- toolKey: 'test-tool::test-server',
+ toolKey: `test-tool${D}test-server`,
provider: 'openai',
userMCPAuthMap: {},
availableTools: availableTools,
@@ -779,8 +820,8 @@ describe('User parameter passing tests', () => {
return Promise.resolve({
tools: [{ name: 'tool1' }, { name: 'tool2' }],
availableTools: {
- 'tool1::server1': { function: { description: 'Tool 1', parameters: {} } },
- 'tool2::server1': { function: { description: 'Tool 2', parameters: {} } },
+ [`tool1${D}server1`]: { function: { description: 'Tool 1', parameters: {} } },
+ [`tool2${D}server1`]: { function: { description: 'Tool 2', parameters: {} } },
},
});
});
@@ -811,7 +852,7 @@ describe('User parameter passing tests', () => {
reinitCalls.push(params);
return Promise.resolve({
availableTools: {
- 'my-tool::my-server': {
+ [`my-tool${D}my-server`]: {
function: { description: 'My Tool', parameters: {} },
},
},
@@ -821,7 +862,7 @@ describe('User parameter passing tests', () => {
await createMCPTool({
res: mockRes,
user: mockUser,
- toolKey: 'my-tool::my-server',
+ toolKey: `my-tool${D}my-server`,
provider: 'google',
userMCPAuthMap: {},
availableTools: undefined, // Force reinit
@@ -834,6 +875,229 @@ describe('User parameter passing tests', () => {
});
});
+ describe('Runtime domain validation', () => {
+ it('should skip tool creation when domain is not allowed', async () => {
+ const mockUser = { id: 'domain-test-user', role: 'user' };
+ const mockRes = { write: jest.fn(), flush: jest.fn() };
+
+ // Mock server config with URL (remote server)
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
+ url: 'https://disallowed-domain.com/sse',
+ });
+
+ // Mock getAppConfig to return domain restrictions
+ mockGetAppConfig.mockResolvedValue({
+ mcpSettings: { allowedDomains: ['allowed-domain.com'] },
+ });
+
+ // Mock domain validation to return false (domain not allowed)
+ mockIsMCPDomainAllowed.mockResolvedValueOnce(false);
+
+ const result = await createMCPTool({
+ res: mockRes,
+ user: mockUser,
+ toolKey: `test-tool${D}test-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools: {
+ [`test-tool${D}test-server`]: {
+ function: {
+ description: 'Test tool',
+ parameters: { type: 'object', properties: {} },
+ },
+ },
+ },
+ });
+
+ // Should return undefined for disallowed domain
+ expect(result).toBeUndefined();
+
+ // Should not call reinitMCPServer since domain check failed
+ expect(mockReinitMCPServer).not.toHaveBeenCalled();
+
+ // Verify getAppConfig was called with user role
+ expect(mockGetAppConfig).toHaveBeenCalledWith({ role: 'user' });
+
+ // Verify domain validation was called with correct parameters
+ expect(mockIsMCPDomainAllowed).toHaveBeenCalledWith(
+ { url: 'https://disallowed-domain.com/sse' },
+ ['allowed-domain.com'],
+ );
+ });
+
+ it('should allow tool creation when domain is allowed', async () => {
+ const mockUser = { id: 'domain-test-user', role: 'admin' };
+ const mockRes = { write: jest.fn(), flush: jest.fn() };
+
+ // Mock server config with URL (remote server)
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
+ url: 'https://allowed-domain.com/sse',
+ });
+
+ // Mock getAppConfig to return domain restrictions
+ mockGetAppConfig.mockResolvedValue({
+ mcpSettings: { allowedDomains: ['allowed-domain.com'] },
+ });
+
+ // Mock domain validation to return true (domain allowed)
+ mockIsMCPDomainAllowed.mockResolvedValueOnce(true);
+
+ const availableTools = {
+ [`test-tool${D}test-server`]: {
+ function: {
+ description: 'Test tool',
+ parameters: { type: 'object', properties: {} },
+ },
+ },
+ };
+
+ const result = await createMCPTool({
+ res: mockRes,
+ user: mockUser,
+ toolKey: `test-tool${D}test-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools,
+ });
+
+ // Should create tool successfully
+ expect(result).toBeDefined();
+
+ // Verify getAppConfig was called with user role
+ expect(mockGetAppConfig).toHaveBeenCalledWith({ role: 'admin' });
+ });
+
+ it('should skip domain validation for stdio transports (no URL)', async () => {
+ const mockUser = { id: 'stdio-test-user' };
+ const mockRes = { write: jest.fn(), flush: jest.fn() };
+
+ // Mock server config without URL (stdio transport)
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
+ command: 'npx',
+ args: ['@modelcontextprotocol/server'],
+ });
+
+ // Mock getAppConfig (should not be called for stdio)
+ mockGetAppConfig.mockResolvedValue({
+ mcpSettings: { allowedDomains: ['restricted-domain.com'] },
+ });
+
+ const availableTools = {
+ [`test-tool${D}test-server`]: {
+ function: {
+ description: 'Test tool',
+ parameters: { type: 'object', properties: {} },
+ },
+ },
+ };
+
+ const result = await createMCPTool({
+ res: mockRes,
+ user: mockUser,
+ toolKey: `test-tool${D}test-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools,
+ });
+
+ // Should create tool successfully without domain check
+ expect(result).toBeDefined();
+
+ // Should not call getAppConfig or isMCPDomainAllowed for stdio transport (no URL)
+ expect(mockGetAppConfig).not.toHaveBeenCalled();
+ expect(mockIsMCPDomainAllowed).not.toHaveBeenCalled();
+ });
+
+ it('should return empty array from createMCPTools when domain is not allowed', async () => {
+ const mockUser = { id: 'domain-test-user', role: 'user' };
+ const mockRes = { write: jest.fn(), flush: jest.fn() };
+
+ // Mock server config with URL (remote server)
+ const serverConfig = { url: 'https://disallowed-domain.com/sse' };
+ mockRegistryInstance.getServerConfig.mockResolvedValue(serverConfig);
+
+ // Mock getAppConfig to return domain restrictions
+ mockGetAppConfig.mockResolvedValue({
+ mcpSettings: { allowedDomains: ['allowed-domain.com'] },
+ });
+
+ // Mock domain validation to return false (domain not allowed)
+ mockIsMCPDomainAllowed.mockResolvedValueOnce(false);
+
+ const result = await createMCPTools({
+ res: mockRes,
+ user: mockUser,
+ serverName: 'test-server',
+ provider: 'openai',
+ userMCPAuthMap: {},
+ config: serverConfig,
+ });
+
+ // Should return empty array for disallowed domain
+ expect(result).toEqual([]);
+
+ // Should not call reinitMCPServer since domain check failed early
+ expect(mockReinitMCPServer).not.toHaveBeenCalled();
+
+ // Verify getAppConfig was called with user role
+ expect(mockGetAppConfig).toHaveBeenCalledWith({ role: 'user' });
+ });
+
+ it('should use user role when fetching domain restrictions', async () => {
+ const adminUser = { id: 'admin-user', role: 'admin' };
+ const regularUser = { id: 'regular-user', role: 'user' };
+ const mockRes = { write: jest.fn(), flush: jest.fn() };
+
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
+ url: 'https://some-domain.com/sse',
+ });
+
+ // Mock different responses based on role
+ mockGetAppConfig
+ .mockResolvedValueOnce({ mcpSettings: { allowedDomains: ['admin-allowed.com'] } })
+ .mockResolvedValueOnce({ mcpSettings: { allowedDomains: ['user-allowed.com'] } });
+
+ mockIsMCPDomainAllowed.mockResolvedValue(true);
+
+ const availableTools = {
+ [`test-tool${D}test-server`]: {
+ function: {
+ description: 'Test tool',
+ parameters: { type: 'object', properties: {} },
+ },
+ },
+ };
+
+ // Call with admin user
+ await createMCPTool({
+ res: mockRes,
+ user: adminUser,
+ toolKey: `test-tool${D}test-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools,
+ });
+
+ // Reset and call with regular user
+ mockRegistryInstance.getServerConfig.mockResolvedValue({
+ url: 'https://some-domain.com/sse',
+ });
+
+ await createMCPTool({
+ res: mockRes,
+ user: regularUser,
+ toolKey: `test-tool${D}test-server`,
+ provider: 'openai',
+ userMCPAuthMap: {},
+ availableTools,
+ });
+
+ // Verify getAppConfig was called with correct roles
+ expect(mockGetAppConfig).toHaveBeenNthCalledWith(1, { role: 'admin' });
+ expect(mockGetAppConfig).toHaveBeenNthCalledWith(2, { role: 'user' });
+ });
+ });
+
describe('User parameter integrity', () => {
it('should preserve user object properties through the call chain', async () => {
const complexUser = {
@@ -850,7 +1114,7 @@ describe('User parameter passing tests', () => {
return Promise.resolve({
tools: [{ name: 'test' }],
availableTools: {
- 'test::server': { function: { description: 'Test', parameters: {} } },
+ [`test${D}server`]: { function: { description: 'Test', parameters: {} } },
},
});
});
diff --git a/api/server/services/ModelService.js b/api/server/services/ModelService.js
deleted file mode 100644
index d5b36558ba..0000000000
--- a/api/server/services/ModelService.js
+++ /dev/null
@@ -1,355 +0,0 @@
-const axios = require('axios');
-const { logger } = require('@librechat/data-schemas');
-const { HttpsProxyAgent } = require('https-proxy-agent');
-const { logAxiosError, inputSchema, processModelData, isUserProvided } = require('@librechat/api');
-const {
- CacheKeys,
- defaultModels,
- KnownEndpoints,
- EModelEndpoint,
-} = require('librechat-data-provider');
-const { OllamaClient } = require('~/app/clients/OllamaClient');
-const getLogStores = require('~/cache/getLogStores');
-const { extractBaseURL } = require('~/utils');
-
-/**
- * Splits a string by commas and trims each resulting value.
- * @param {string} input - The input string to split.
- * @returns {string[]} An array of trimmed values.
- */
-const splitAndTrim = (input) => {
- if (!input || typeof input !== 'string') {
- return [];
- }
- return input
- .split(',')
- .map((item) => item.trim())
- .filter(Boolean);
-};
-
-const { openAIApiKey, userProvidedOpenAI } = require('./Config/EndpointService').config;
-
-/**
- * Fetches OpenAI models from the specified base API path or Azure, based on the provided configuration.
- *
- * @param {Object} params - The parameters for fetching the models.
- * @param {Object} params.user - The user ID to send to the API.
- * @param {string} params.apiKey - The API key for authentication with the API.
- * @param {string} params.baseURL - The base path URL for the API.
- * @param {string} [params.name='OpenAI'] - The name of the API; defaults to 'OpenAI'.
- * @param {boolean} [params.direct=false] - Whether `directEndpoint` was configured
- * @param {boolean} [params.azure=false] - Whether to fetch models from Azure.
- * @param {boolean} [params.userIdQuery=false] - Whether to send the user ID as a query parameter.
- * @param {boolean} [params.createTokenConfig=true] - Whether to create a token configuration from the API response.
- * @param {string} [params.tokenKey] - The cache key to save the token configuration. Uses `name` if omitted.
- * @param {Record} [params.headers] - Optional headers for the request.
- * @param {Partial} [params.userObject] - Optional user object for header resolution.
- * @returns {Promise} A promise that resolves to an array of model identifiers.
- * @async
- */
-const fetchModels = async ({
- user,
- apiKey,
- baseURL: _baseURL,
- name = EModelEndpoint.openAI,
- direct,
- azure = false,
- userIdQuery = false,
- createTokenConfig = true,
- tokenKey,
- headers,
- userObject,
-}) => {
- let models = [];
- const baseURL = direct ? extractBaseURL(_baseURL) : _baseURL;
-
- if (!baseURL && !azure) {
- return models;
- }
-
- if (!apiKey) {
- return models;
- }
-
- if (name && name.toLowerCase().startsWith(KnownEndpoints.ollama)) {
- try {
- return await OllamaClient.fetchModels(baseURL, { headers, user: userObject });
- } catch (ollamaError) {
- const logMessage =
- 'Failed to fetch models from Ollama API. Attempting to fetch via OpenAI-compatible endpoint.';
- logAxiosError({ message: logMessage, error: ollamaError });
- }
- }
-
- try {
- const options = {
- headers: {
- ...(headers ?? {}),
- },
- timeout: 5000,
- };
-
- if (name === EModelEndpoint.anthropic) {
- options.headers = {
- 'x-api-key': apiKey,
- 'anthropic-version': process.env.ANTHROPIC_VERSION || '2023-06-01',
- };
- } else {
- options.headers.Authorization = `Bearer ${apiKey}`;
- }
-
- if (process.env.PROXY) {
- options.httpsAgent = new HttpsProxyAgent(process.env.PROXY);
- }
-
- if (process.env.OPENAI_ORGANIZATION && baseURL.includes('openai')) {
- options.headers['OpenAI-Organization'] = process.env.OPENAI_ORGANIZATION;
- }
-
- const url = new URL(`${baseURL.replace(/\/+$/, '')}${azure ? '' : '/models'}`);
- if (user && userIdQuery) {
- url.searchParams.append('user', user);
- }
- const res = await axios.get(url.toString(), options);
-
- /** @type {z.infer} */
- const input = res.data;
-
- const validationResult = inputSchema.safeParse(input);
- if (validationResult.success && createTokenConfig) {
- const endpointTokenConfig = processModelData(input);
- const cache = getLogStores(CacheKeys.TOKEN_CONFIG);
- await cache.set(tokenKey ?? name, endpointTokenConfig);
- }
- models = input.data.map((item) => item.id);
- } catch (error) {
- const logMessage = `Failed to fetch models from ${azure ? 'Azure ' : ''}${name} API`;
- logAxiosError({ message: logMessage, error });
- }
-
- return models;
-};
-
-/**
- * Fetches models from the specified API path or Azure, based on the provided options.
- * @async
- * @function
- * @param {object} opts - The options for fetching the models.
- * @param {string} opts.user - The user ID to send to the API.
- * @param {boolean} [opts.azure=false] - Whether to fetch models from Azure.
- * @param {boolean} [opts.assistants=false] - Whether to fetch models from Azure.
- * @param {boolean} [opts.plugins=false] - Whether to fetch models from the plugins.
- * @param {string[]} [_models=[]] - The models to use as a fallback.
- */
-const fetchOpenAIModels = async (opts, _models = []) => {
- let models = _models.slice() ?? [];
- let apiKey = openAIApiKey;
- const openaiBaseURL = 'https://api.openai.com/v1';
- let baseURL = openaiBaseURL;
- let reverseProxyUrl = process.env.OPENAI_REVERSE_PROXY;
-
- if (opts.assistants && process.env.ASSISTANTS_BASE_URL) {
- reverseProxyUrl = process.env.ASSISTANTS_BASE_URL;
- } else if (opts.azure) {
- return models;
- // const azure = getAzureCredentials();
- // baseURL = (genAzureChatCompletion(azure))
- // .split('/deployments')[0]
- // .concat(`/models?api-version=${azure.azureOpenAIApiVersion}`);
- // apiKey = azureOpenAIApiKey;
- }
-
- if (reverseProxyUrl) {
- baseURL = extractBaseURL(reverseProxyUrl);
- }
-
- const modelsCache = getLogStores(CacheKeys.MODEL_QUERIES);
-
- const cachedModels = await modelsCache.get(baseURL);
- if (cachedModels) {
- return cachedModels;
- }
-
- if (baseURL || opts.azure) {
- models = await fetchModels({
- apiKey,
- baseURL,
- azure: opts.azure,
- user: opts.user,
- name: EModelEndpoint.openAI,
- });
- }
-
- if (models.length === 0) {
- return _models;
- }
-
- if (baseURL === openaiBaseURL) {
- const regex = /(text-davinci-003|gpt-|o\d+)/;
- const excludeRegex = /audio|realtime/;
- models = models.filter((model) => regex.test(model) && !excludeRegex.test(model));
- const instructModels = models.filter((model) => model.includes('instruct'));
- const otherModels = models.filter((model) => !model.includes('instruct'));
- models = otherModels.concat(instructModels);
- }
-
- await modelsCache.set(baseURL, models);
- return models;
-};
-
-/**
- * Loads the default models for the application.
- * @async
- * @function
- * @param {object} opts - The options for fetching the models.
- * @param {string} opts.user - The user ID to send to the API.
- * @param {boolean} [opts.azure=false] - Whether to fetch models from Azure.
- * @param {boolean} [opts.plugins=false] - Whether to fetch models for the plugins endpoint.
- * @param {boolean} [opts.assistants=false] - Whether to fetch models for the Assistants endpoint.
- */
-const getOpenAIModels = async (opts) => {
- let models = defaultModels[EModelEndpoint.openAI];
-
- if (opts.assistants) {
- models = defaultModels[EModelEndpoint.assistants];
- } else if (opts.azure) {
- models = defaultModels[EModelEndpoint.azureAssistants];
- }
-
- if (opts.plugins) {
- models = models.filter(
- (model) =>
- !model.includes('text-davinci') &&
- !model.includes('instruct') &&
- !model.includes('0613') &&
- !model.includes('0314') &&
- !model.includes('0301'),
- );
- }
-
- let key;
- if (opts.assistants) {
- key = 'ASSISTANTS_MODELS';
- } else if (opts.azure) {
- key = 'AZURE_OPENAI_MODELS';
- } else if (opts.plugins) {
- key = 'PLUGIN_MODELS';
- } else {
- key = 'OPENAI_MODELS';
- }
-
- if (process.env[key]) {
- models = splitAndTrim(process.env[key]);
- return models;
- }
-
- if (userProvidedOpenAI) {
- return models;
- }
-
- return await fetchOpenAIModels(opts, models);
-};
-
-const getChatGPTBrowserModels = () => {
- let models = ['text-davinci-002-render-sha', 'gpt-4'];
- if (process.env.CHATGPT_MODELS) {
- models = splitAndTrim(process.env.CHATGPT_MODELS);
- }
-
- return models;
-};
-
-/**
- * Fetches models from the Anthropic API.
- * @async
- * @function
- * @param {object} opts - The options for fetching the models.
- * @param {string} opts.user - The user ID to send to the API.
- * @param {string[]} [_models=[]] - The models to use as a fallback.
- */
-const fetchAnthropicModels = async (opts, _models = []) => {
- let models = _models.slice() ?? [];
- let apiKey = process.env.ANTHROPIC_API_KEY;
- const anthropicBaseURL = 'https://api.anthropic.com/v1';
- let baseURL = anthropicBaseURL;
- let reverseProxyUrl = process.env.ANTHROPIC_REVERSE_PROXY;
-
- if (reverseProxyUrl) {
- baseURL = extractBaseURL(reverseProxyUrl);
- }
-
- if (!apiKey) {
- return models;
- }
-
- const modelsCache = getLogStores(CacheKeys.MODEL_QUERIES);
-
- const cachedModels = await modelsCache.get(baseURL);
- if (cachedModels) {
- return cachedModels;
- }
-
- if (baseURL) {
- models = await fetchModels({
- apiKey,
- baseURL,
- user: opts.user,
- name: EModelEndpoint.anthropic,
- tokenKey: EModelEndpoint.anthropic,
- });
- }
-
- if (models.length === 0) {
- return _models;
- }
-
- await modelsCache.set(baseURL, models);
- return models;
-};
-
-const getAnthropicModels = async (opts = {}) => {
- let models = defaultModels[EModelEndpoint.anthropic];
- if (process.env.ANTHROPIC_MODELS) {
- models = splitAndTrim(process.env.ANTHROPIC_MODELS);
- return models;
- }
-
- if (isUserProvided(process.env.ANTHROPIC_API_KEY)) {
- return models;
- }
-
- try {
- return await fetchAnthropicModels(opts, models);
- } catch (error) {
- logger.error('Error fetching Anthropic models:', error);
- return models;
- }
-};
-
-const getGoogleModels = () => {
- let models = defaultModels[EModelEndpoint.google];
- if (process.env.GOOGLE_MODELS) {
- models = splitAndTrim(process.env.GOOGLE_MODELS);
- }
-
- return models;
-};
-
-const getBedrockModels = () => {
- let models = defaultModels[EModelEndpoint.bedrock];
- if (process.env.BEDROCK_AWS_MODELS) {
- models = splitAndTrim(process.env.BEDROCK_AWS_MODELS);
- }
-
- return models;
-};
-
-module.exports = {
- fetchModels,
- splitAndTrim,
- getOpenAIModels,
- getBedrockModels,
- getChatGPTBrowserModels,
- getAnthropicModels,
- getGoogleModels,
-};
diff --git a/api/server/services/PermissionService.js b/api/server/services/PermissionService.js
index 58afffec4a..a843f48f6f 100644
--- a/api/server/services/PermissionService.js
+++ b/api/server/services/PermissionService.js
@@ -12,6 +12,7 @@ const {
const {
findAccessibleResources: findAccessibleResourcesACL,
getEffectivePermissions: getEffectivePermissionsACL,
+ getEffectivePermissionsForResources: getEffectivePermissionsForResourcesACL,
grantPermission: grantPermissionACL,
findEntriesByPrincipalsAndResource,
findGroupByExternalId,
@@ -140,7 +141,6 @@ const checkPermission = async ({ userId, role, resourceType, resourceId, require
validateResourceType(resourceType);
- // Get all principals for the user (user + groups + public)
const principals = await getUserPrincipals({ userId, role });
if (principals.length === 0) {
@@ -150,7 +150,6 @@ const checkPermission = async ({ userId, role, resourceType, resourceId, require
return await hasPermission(principals, resourceType, resourceId, requiredPermission);
} catch (error) {
logger.error(`[PermissionService.checkPermission] Error: ${error.message}`);
- // Re-throw validation errors
if (error.message.includes('requiredPermission must be')) {
throw error;
}
@@ -171,12 +170,12 @@ const getEffectivePermissions = async ({ userId, role, resourceType, resourceId
try {
validateResourceType(resourceType);
- // Get all principals for the user (user + groups + public)
const principals = await getUserPrincipals({ userId, role });
if (principals.length === 0) {
return 0;
}
+
return await getEffectivePermissionsACL(principals, resourceType, resourceId);
} catch (error) {
logger.error(`[PermissionService.getEffectivePermissions] Error: ${error.message}`);
@@ -184,6 +183,49 @@ const getEffectivePermissions = async ({ userId, role, resourceType, resourceId
}
};
+/**
+ * Get effective permissions for multiple resources in a batch operation
+ * Returns map of resourceId → effectivePermissionBits
+ *
+ * @param {Object} params - Parameters
+ * @param {string|mongoose.Types.ObjectId} params.userId - User ID
+ * @param {string} [params.role] - User role (for group membership)
+ * @param {string} params.resourceType - Resource type (must be valid ResourceType)
+ * @param {Array} params.resourceIds - Array of resource IDs
+ * @returns {Promise>} Map of resourceId string → permission bits
+ * @throws {Error} If resourceType is invalid
+ */
+const getResourcePermissionsMap = async ({ userId, role, resourceType, resourceIds }) => {
+ // Validate resource type - throw on invalid type
+ validateResourceType(resourceType);
+
+ // Handle empty input
+ if (!Array.isArray(resourceIds) || resourceIds.length === 0) {
+ return new Map();
+ }
+
+ try {
+ // Get user principals (user + groups + public)
+ const principals = await getUserPrincipals({ userId, role });
+
+ // Use batch method from aclEntry
+ const permissionsMap = await getEffectivePermissionsForResourcesACL(
+ principals,
+ resourceType,
+ resourceIds,
+ );
+
+ logger.debug(
+ `[PermissionService.getResourcePermissionsMap] Computed permissions for ${resourceIds.length} resources, ${permissionsMap.size} have permissions`,
+ );
+
+ return permissionsMap;
+ } catch (error) {
+ logger.error(`[PermissionService.getResourcePermissionsMap] Error: ${error.message}`, error);
+ throw error;
+ }
+};
+
/**
* Find all resources of a specific type that a user has access to with specific permission bits
* @param {Object} params - Parameters for finding accessible resources
@@ -788,6 +830,7 @@ module.exports = {
grantPermission,
checkPermission,
getEffectivePermissions,
+ getResourcePermissionsMap,
findAccessibleResources,
findPubliclyAccessibleResources,
hasPublicPermission,
diff --git a/api/server/services/PermissionService.spec.js b/api/server/services/PermissionService.spec.js
index 5772f3b909..b41780f345 100644
--- a/api/server/services/PermissionService.spec.js
+++ b/api/server/services/PermissionService.spec.js
@@ -1604,4 +1604,332 @@ describe('PermissionService', () => {
expect(effectivePermissions).toBe(3); // EDITOR includes VIEW
});
});
+
+ describe('getResourcePermissionsMap - Batch Permission Queries', () => {
+ const { getResourcePermissionsMap } = require('./PermissionService');
+
+ beforeEach(async () => {
+ await AclEntry.deleteMany({});
+ getUserPrincipals.mockReset();
+ });
+
+ test('should get permissions for multiple resources in single query', async () => {
+ const resource1 = new mongoose.Types.ObjectId();
+ const resource2 = new mongoose.Types.ObjectId();
+ const resource3 = new mongoose.Types.ObjectId();
+
+ // Grant different permissions to different resources
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource1,
+ accessRoleId: AccessRoleIds.MCPSERVER_VIEWER,
+ grantedBy: grantedById,
+ });
+
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource2,
+ accessRoleId: AccessRoleIds.MCPSERVER_EDITOR,
+ grantedBy: grantedById,
+ });
+
+ // resource3 has no permissions
+
+ // Mock getUserPrincipals
+ getUserPrincipals.mockResolvedValue([
+ { principalType: PrincipalType.USER, principalId: userId },
+ { principalType: PrincipalType.PUBLIC },
+ ]);
+
+ const permissionsMap = await getResourcePermissionsMap({
+ userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceIds: [resource1, resource2, resource3],
+ });
+
+ expect(permissionsMap).toBeInstanceOf(Map);
+ expect(permissionsMap.size).toBe(2); // Only resource1 and resource2
+ expect(permissionsMap.get(resource1.toString())).toBe(1); // VIEW
+ expect(permissionsMap.get(resource2.toString())).toBe(3); // VIEW | EDIT
+ expect(permissionsMap.get(resource3.toString())).toBeUndefined();
+ });
+
+ test('should combine permissions from multiple principals', async () => {
+ const resource1 = new mongoose.Types.ObjectId();
+ const resource2 = new mongoose.Types.ObjectId();
+
+ // User has VIEW on both resources
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource1,
+ accessRoleId: AccessRoleIds.MCPSERVER_VIEWER,
+ grantedBy: grantedById,
+ });
+
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource2,
+ accessRoleId: AccessRoleIds.MCPSERVER_VIEWER,
+ grantedBy: grantedById,
+ });
+
+ // Group has EDIT on resource1
+ await grantPermission({
+ principalType: PrincipalType.GROUP,
+ principalId: groupId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource1,
+ accessRoleId: AccessRoleIds.MCPSERVER_EDITOR,
+ grantedBy: grantedById,
+ });
+
+ // Mock getUserPrincipals with user + group
+ getUserPrincipals.mockResolvedValue([
+ { principalType: PrincipalType.USER, principalId: userId },
+ { principalType: PrincipalType.GROUP, principalId: groupId },
+ { principalType: PrincipalType.PUBLIC },
+ ]);
+
+ const permissionsMap = await getResourcePermissionsMap({
+ userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceIds: [resource1, resource2],
+ });
+
+ expect(permissionsMap.size).toBe(2);
+ // Resource1 should have VIEW (1) | EDIT (3) = 3
+ expect(permissionsMap.get(resource1.toString())).toBe(3);
+ // Resource2 should have only VIEW (1)
+ expect(permissionsMap.get(resource2.toString())).toBe(1);
+ });
+
+ test('should handle empty resource list', async () => {
+ getUserPrincipals.mockResolvedValue([
+ { principalType: PrincipalType.USER, principalId: userId },
+ ]);
+
+ const permissionsMap = await getResourcePermissionsMap({
+ userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceIds: [],
+ });
+
+ expect(permissionsMap).toBeInstanceOf(Map);
+ expect(permissionsMap.size).toBe(0);
+ });
+
+ test('should throw on invalid resource type', async () => {
+ const resource1 = new mongoose.Types.ObjectId();
+
+ getUserPrincipals.mockResolvedValue([
+ { principalType: PrincipalType.USER, principalId: userId },
+ ]);
+
+ // Validation errors should throw immediately
+ await expect(
+ getResourcePermissionsMap({
+ userId,
+ resourceType: 'invalid_type',
+ resourceIds: [resource1],
+ }),
+ ).rejects.toThrow('Invalid resourceType: invalid_type');
+ });
+
+ test('should include public permissions in batch query', async () => {
+ const resource1 = new mongoose.Types.ObjectId();
+ const resource2 = new mongoose.Types.ObjectId();
+
+ // User has VIEW | EDIT on resource1
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource1,
+ accessRoleId: AccessRoleIds.MCPSERVER_EDITOR,
+ grantedBy: grantedById,
+ });
+
+ // Public has VIEW on resource2
+ await grantPermission({
+ principalType: PrincipalType.PUBLIC,
+ principalId: null,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource2,
+ accessRoleId: AccessRoleIds.MCPSERVER_VIEWER,
+ grantedBy: grantedById,
+ });
+
+ // Mock getUserPrincipals with user + public
+ getUserPrincipals.mockResolvedValue([
+ { principalType: PrincipalType.USER, principalId: userId },
+ { principalType: PrincipalType.PUBLIC },
+ ]);
+
+ const permissionsMap = await getResourcePermissionsMap({
+ userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceIds: [resource1, resource2],
+ });
+
+ expect(permissionsMap.size).toBe(2);
+ expect(permissionsMap.get(resource1.toString())).toBe(3); // VIEW | EDIT
+ expect(permissionsMap.get(resource2.toString())).toBe(1); // VIEW (public)
+ });
+
+ test('should handle large batch efficiently', async () => {
+ // Create 50 resources
+ const resources = Array.from({ length: 50 }, () => new mongoose.Types.ObjectId());
+
+ // Grant permissions to first 30 resources
+ for (let i = 0; i < 30; i++) {
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resources[i],
+ accessRoleId: AccessRoleIds.MCPSERVER_VIEWER,
+ grantedBy: grantedById,
+ });
+ }
+
+ // Grant group permissions to resources 20-40 (overlap)
+ for (let i = 20; i < 40; i++) {
+ await grantPermission({
+ principalType: PrincipalType.GROUP,
+ principalId: groupId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resources[i],
+ accessRoleId: AccessRoleIds.MCPSERVER_EDITOR,
+ grantedBy: grantedById,
+ });
+ }
+
+ getUserPrincipals.mockResolvedValue([
+ { principalType: PrincipalType.USER, principalId: userId },
+ { principalType: PrincipalType.GROUP, principalId: groupId },
+ ]);
+
+ const startTime = Date.now();
+ const permissionsMap = await getResourcePermissionsMap({
+ userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceIds: resources,
+ });
+ const duration = Date.now() - startTime;
+
+ // Should complete in reasonable time (under 1 second)
+ expect(duration).toBeLessThan(1000);
+
+ // Verify results
+ expect(permissionsMap.size).toBe(40); // Resources 0-39 have permissions
+
+ // Resources 0-19: USER VIEW only
+ for (let i = 0; i < 20; i++) {
+ expect(permissionsMap.get(resources[i].toString())).toBe(1); // VIEW
+ }
+
+ // Resources 20-29: USER VIEW | GROUP EDIT = 3
+ for (let i = 20; i < 30; i++) {
+ expect(permissionsMap.get(resources[i].toString())).toBe(3); // VIEW | EDIT
+ }
+
+ // Resources 30-39: GROUP EDIT = 3
+ for (let i = 30; i < 40; i++) {
+ expect(permissionsMap.get(resources[i].toString())).toBe(3); // EDIT includes VIEW
+ }
+
+ // Resources 40-49: No permissions
+ for (let i = 40; i < 50; i++) {
+ expect(permissionsMap.get(resources[i].toString())).toBeUndefined();
+ }
+ });
+
+ test('should work with role parameter optimization', async () => {
+ const resource1 = new mongoose.Types.ObjectId();
+ const resource2 = new mongoose.Types.ObjectId();
+
+ // Grant permissions to ADMIN role
+ await grantPermission({
+ principalType: PrincipalType.ROLE,
+ principalId: 'ADMIN',
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource1,
+ accessRoleId: AccessRoleIds.MCPSERVER_OWNER,
+ grantedBy: grantedById,
+ });
+
+ await grantPermission({
+ principalType: PrincipalType.ROLE,
+ principalId: 'ADMIN',
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource2,
+ accessRoleId: AccessRoleIds.MCPSERVER_EDITOR,
+ grantedBy: grantedById,
+ });
+
+ getUserPrincipals.mockResolvedValue([
+ { principalType: PrincipalType.USER, principalId: userId },
+ { principalType: PrincipalType.ROLE, principalId: 'ADMIN' },
+ { principalType: PrincipalType.PUBLIC },
+ ]);
+
+ const permissionsMap = await getResourcePermissionsMap({
+ userId,
+ role: 'ADMIN',
+ resourceType: ResourceType.MCPSERVER,
+ resourceIds: [resource1, resource2],
+ });
+
+ expect(permissionsMap.size).toBe(2);
+ expect(permissionsMap.get(resource1.toString())).toBe(15); // OWNER = all bits
+ expect(permissionsMap.get(resource2.toString())).toBe(3); // EDIT
+ expect(getUserPrincipals).toHaveBeenCalledWith({ userId, role: 'ADMIN' });
+ });
+
+ test('should handle mixed ObjectId and string resource IDs', async () => {
+ const resource1 = new mongoose.Types.ObjectId();
+ const resource2 = new mongoose.Types.ObjectId();
+
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource1,
+ accessRoleId: AccessRoleIds.MCPSERVER_VIEWER,
+ grantedBy: grantedById,
+ });
+
+ await grantPermission({
+ principalType: PrincipalType.USER,
+ principalId: userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceId: resource2,
+ accessRoleId: AccessRoleIds.MCPSERVER_EDITOR,
+ grantedBy: grantedById,
+ });
+
+ getUserPrincipals.mockResolvedValue([
+ { principalType: PrincipalType.USER, principalId: userId },
+ ]);
+
+ // Pass mix of ObjectId and string
+ const permissionsMap = await getResourcePermissionsMap({
+ userId,
+ resourceType: ResourceType.MCPSERVER,
+ resourceIds: [resource1, resource2.toString()],
+ });
+
+ expect(permissionsMap.size).toBe(2);
+ expect(permissionsMap.get(resource1.toString())).toBe(1);
+ expect(permissionsMap.get(resource2.toString())).toBe(3);
+ });
+ });
});
diff --git a/api/server/services/Threads/processMessages.spec.js b/api/server/services/Threads/processMessages.spec.js
index 673b96bf7c..a89f2b9f5b 100644
--- a/api/server/services/Threads/processMessages.spec.js
+++ b/api/server/services/Threads/processMessages.spec.js
@@ -255,7 +255,7 @@ describe('processMessages', () => {
type: 'text',
text: {
value:
- 'The text you have uploaded is from the book "Harry Potter and the Philosopher\'s Stone" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:\n\n1. **Discovery and Invitation to Hogwarts**: Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry【11:2†source】【11:4†source】.\n\n2. **Shopping for Supplies**: Hagrid takes Harry to Diagon Alley to buy his school supplies, including his wand from Ollivander\'s【11:9†source】【11:14†source】.\n\n3. **Introduction to Hogwarts**: Harry is introduced to Hogwarts, the magical school where he will learn about magic and discover more about his own background【11:12†source】【11:18†source】.\n\n4. **Meeting Friends and Enemies**: At Hogwarts, Harry makes friends like Ron Weasley and Hermione Granger, and enemies like Draco Malfoy【11:16†source】.\n\n5. **Uncovering the Mystery**: Harry, along with Ron and Hermione, uncovers the mystery of the Philosopher\'s Stone and its connection to the dark wizard Voldemort【11:1†source】【11:10†source】【11:7†source】.\n\nThese points highlight Harry\'s initial experiences in the magical world and set the stage for his adventures at Hogwarts.',
+ "The text you have uploaded is from the book \"Harry Potter and the Philosopher's Stone\" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:\n\n1. **Discovery and Invitation to Hogwarts**: Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry【11:2†source】【11:4†source】.\n\n2. **Shopping for Supplies**: Hagrid takes Harry to Diagon Alley to buy his school supplies, including his wand from Ollivander's【11:9†source】【11:14†source】.\n\n3. **Introduction to Hogwarts**: Harry is introduced to Hogwarts, the magical school where he will learn about magic and discover more about his own background【11:12†source】【11:18†source】.\n\n4. **Meeting Friends and Enemies**: At Hogwarts, Harry makes friends like Ron Weasley and Hermione Granger, and enemies like Draco Malfoy【11:16†source】.\n\n5. **Uncovering the Mystery**: Harry, along with Ron and Hermione, uncovers the mystery of the Philosopher's Stone and its connection to the dark wizard Voldemort【11:1†source】【11:10†source】【11:7†source】.\n\nThese points highlight Harry's initial experiences in the magical world and set the stage for his adventures at Hogwarts.",
annotations: [
{
type: 'file_citation',
@@ -424,7 +424,7 @@ These points highlight Harry's initial experiences in the magical world and set
type: 'text',
text: {
value:
- 'The text you have uploaded is from the book "Harry Potter and the Philosopher\'s Stone" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:\n\n1. **Discovery and Invitation to Hogwarts**: Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry【11:2†source】【11:4†source】.\n\n2. **Shopping for Supplies**: Hagrid takes Harry to Diagon Alley to buy his school supplies, including his wand from Ollivander\'s【11:9†source】【11:14†source】.\n\n3. **Introduction to Hogwarts**: Harry is introduced to Hogwarts, the magical school where he will learn about magic and discover more about his own background【11:12†source】【11:18†source】.\n\n4. **Meeting Friends and Enemies**: At Hogwarts, Harry makes friends like Ron Weasley and Hermione Granger, and enemies like Draco Malfoy【11:16†source】.\n\n5. **Uncovering the Mystery**: Harry, along with Ron and Hermione, uncovers the mystery of the Philosopher\'s Stone and its connection to the dark wizard Voldemort【11:1†source】【11:10†source】【11:7†source】.\n\nThese points highlight Harry\'s initial experiences in the magical world and set the stage for his adventures at Hogwarts.',
+ "The text you have uploaded is from the book \"Harry Potter and the Philosopher's Stone\" by J.K. Rowling. It follows the story of a young boy named Harry Potter who discovers that he is a wizard on his eleventh birthday. Here are some key points of the narrative:\n\n1. **Discovery and Invitation to Hogwarts**: Harry learns that he is a wizard and receives an invitation to attend Hogwarts School of Witchcraft and Wizardry【11:2†source】【11:4†source】.\n\n2. **Shopping for Supplies**: Hagrid takes Harry to Diagon Alley to buy his school supplies, including his wand from Ollivander's【11:9†source】【11:14†source】.\n\n3. **Introduction to Hogwarts**: Harry is introduced to Hogwarts, the magical school where he will learn about magic and discover more about his own background【11:12†source】【11:18†source】.\n\n4. **Meeting Friends and Enemies**: At Hogwarts, Harry makes friends like Ron Weasley and Hermione Granger, and enemies like Draco Malfoy【11:16†source】.\n\n5. **Uncovering the Mystery**: Harry, along with Ron and Hermione, uncovers the mystery of the Philosopher's Stone and its connection to the dark wizard Voldemort【11:1†source】【11:10†source】【11:7†source】.\n\nThese points highlight Harry's initial experiences in the magical world and set the stage for his adventures at Hogwarts.",
annotations: [
{
type: 'file_citation',
@@ -582,7 +582,7 @@ These points highlight Harry's initial experiences in the magical world and set
type: 'text',
text: {
value:
- 'This is a test ^1^ with pre-existing citation-like text. Here\'s a real citation【11:2†source】.',
+ "This is a test ^1^ with pre-existing citation-like text. Here's a real citation【11:2†source】.",
annotations: [
{
type: 'file_citation',
@@ -610,7 +610,7 @@ These points highlight Harry's initial experiences in the magical world and set
});
const expectedText =
- 'This is a test ^1^ with pre-existing citation-like text. Here\'s a real citation^1^.\n\n^1.^ test.txt';
+ "This is a test ^1^ with pre-existing citation-like text. Here's a real citation^1^.\n\n^1.^ test.txt";
expect(result.text).toBe(expectedText);
expect(result.edited).toBe(true);
diff --git a/api/server/services/ToolService.js b/api/server/services/ToolService.js
index fda896ae0b..eedb95bd4d 100644
--- a/api/server/services/ToolService.js
+++ b/api/server/services/ToolService.js
@@ -1,24 +1,43 @@
-const { sleep } = require('@librechat/agents');
const { logger } = require('@librechat/data-schemas');
const { tool: toolFn, DynamicStructuredTool } = require('@langchain/core/tools');
const {
+ sleep,
+ EnvVar,
+ StepTypes,
+ GraphEvents,
+ createToolSearch,
+ Constants: AgentConstants,
+ createProgrammaticToolCallingTool,
+} = require('@librechat/agents');
+const {
+ sendEvent,
getToolkitKey,
hasCustomUserVars,
getUserMCPAuthMap,
+ loadToolDefinitions,
+ GenerationJobManager,
isActionDomainAllowed,
+ buildWebSearchContext,
+ buildImageToolContext,
+ buildToolClassification,
} = require('@librechat/api');
const {
+ Time,
Tools,
Constants,
+ CacheKeys,
ErrorTypes,
ContentTypes,
imageGenTools,
EModelEndpoint,
+ EToolResources,
actionDelimiter,
ImageVisionTool,
openapiToFunction,
AgentCapabilities,
+ isEphemeralAgentId,
validateActionDomain,
+ actionDomainSeparator,
defaultAgentCapabilities,
validateAndParseOpenAPISpec,
} = require('librechat-data-provider');
@@ -28,14 +47,24 @@ const {
loadActionSets,
domainParser,
} = require('./ActionService');
+const {
+ getEndpointsConfig,
+ getMCPServerTools,
+ getCachedTools,
+} = require('~/server/services/Config');
const { processFileURL, uploadImageBuffer } = require('~/server/services/Files/process');
-const { getEndpointsConfig, getCachedTools } = require('~/server/services/Config');
+const { primeFiles: primeSearchFiles } = require('~/app/clients/tools/util/fileSearch');
+const { primeFiles: primeCodeFiles } = require('~/server/services/Files/Code/process');
const { manifestToolMap, toolkits } = require('~/app/clients/tools/manifest');
const { createOnSearchResults } = require('~/server/services/Tools/search');
+const { loadAuthValues } = require('~/server/services/Tools/credentials');
+const { reinitMCPServer } = require('~/server/services/Tools/mcp');
const { recordUsage } = require('~/server/services/Threads');
const { loadTools } = require('~/app/clients/tools/util');
const { redactMessage } = require('~/config/parsers');
const { findPluginAuthsByKeys } = require('~/models');
+const { getFlowStateManager } = require('~/config');
+const { getLogStores } = require('~/cache');
/**
* Processes the required actions by calling the appropriate tools and returning the outputs.
* @param {OpenAIClient} client - OpenAI or StreamRunManager Client.
@@ -79,7 +108,7 @@ async function processRequiredActions(client, requiredActions) {
requiredActions,
);
const appConfig = client.req.config;
- const toolDefinitions = await getCachedTools();
+ const toolDefinitions = (await getCachedTools()) ?? {};
const seenToolkits = new Set();
const tools = requiredActions
.map((action) => {
@@ -309,6 +338,7 @@ async function processRequiredActions(client, requiredActions) {
}
// We've already decrypted the metadata, so we can pass it directly
+ const _allowedDomains = appConfig?.actions?.allowedDomains;
tool = await createActionTool({
userId: client.req.user.id,
res: client.res,
@@ -316,6 +346,7 @@ async function processRequiredActions(client, requiredActions) {
requestBuilder,
// Note: intentionally not passing zodSchema, name, and description for assistants API
encrypted, // Pass the encrypted values for OAuth flow
+ useSSRFProtection: !Array.isArray(_allowedDomains) || _allowedDomains.length === 0,
});
if (!tool) {
logger.warn(
@@ -367,25 +398,421 @@ async function processRequiredActions(client, requiredActions) {
* @param {AbortSignal} params.signal
* @param {Pick> }>} The agent tools.
+ * @returns {Promise<{
+ * tools?: StructuredTool[];
+ * toolContextMap?: Record;
+ * userMCPAuthMap?: Record>;
+ * toolRegistry?: Map;
+ * hasDeferredTools?: boolean;
+ * }>} The agent tools and registry.
*/
-async function loadAgentTools({ req, res, agent, signal, tool_resources, openAIApiKey }) {
+/** Native LibreChat tools that are not in the manifest */
+const nativeTools = new Set([Tools.execute_code, Tools.file_search, Tools.web_search]);
+
+/** Checks if a tool name is a known built-in tool */
+const isBuiltInTool = (toolName) =>
+ Boolean(
+ manifestToolMap[toolName] ||
+ toolkits.some((t) => t.pluginKey === toolName) ||
+ nativeTools.has(toolName),
+ );
+
+/**
+ * Loads only tool definitions without creating tool instances.
+ * This is the efficient path for event-driven mode where tools are loaded on-demand.
+ *
+ * @param {Object} params
+ * @param {ServerRequest} params.req - The request object
+ * @param {ServerResponse} [params.res] - The response object for SSE events
+ * @param {Object} params.agent - The agent configuration
+ * @param {string|null} [params.streamId] - Stream ID for resumable mode
+ * @returns {Promise<{
+ * toolDefinitions?: import('@librechat/api').LCTool[];
+ * toolRegistry?: Map;
+ * userMCPAuthMap?: Record>;
+ * hasDeferredTools?: boolean;
+ * }>}
+ */
+async function loadToolDefinitionsWrapper({ req, res, agent, streamId = null, tool_resources }) {
if (!agent.tools || agent.tools.length === 0) {
- return {};
+ return { toolDefinitions: [] };
+ }
+
+ if (
+ agent.tools.length === 1 &&
+ (agent.tools[0] === AgentCapabilities.context || agent.tools[0] === AgentCapabilities.ocr)
+ ) {
+ return { toolDefinitions: [] };
+ }
+
+ const appConfig = req.config;
+ const endpointsConfig = await getEndpointsConfig(req);
+ let enabledCapabilities = new Set(endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? []);
+
+ if (enabledCapabilities.size === 0 && isEphemeralAgentId(agent.id)) {
+ enabledCapabilities = new Set(
+ appConfig.endpoints?.[EModelEndpoint.agents]?.capabilities ?? defaultAgentCapabilities,
+ );
+ }
+
+ const checkCapability = (capability) => enabledCapabilities.has(capability);
+ const areToolsEnabled = checkCapability(AgentCapabilities.tools);
+ const deferredToolsEnabled = checkCapability(AgentCapabilities.deferred_tools);
+
+ const filteredTools = agent.tools?.filter((tool) => {
+ if (tool === Tools.file_search) {
+ return checkCapability(AgentCapabilities.file_search);
+ }
+ if (tool === Tools.execute_code) {
+ return checkCapability(AgentCapabilities.execute_code);
+ }
+ if (tool === Tools.web_search) {
+ return checkCapability(AgentCapabilities.web_search);
+ }
+ if (!areToolsEnabled && !tool.includes(actionDelimiter)) {
+ return false;
+ }
+ return true;
+ });
+
+ if (!filteredTools || filteredTools.length === 0) {
+ return { toolDefinitions: [] };
+ }
+
+ /** @type {Record>} */
+ let userMCPAuthMap;
+ if (hasCustomUserVars(req.config)) {
+ userMCPAuthMap = await getUserMCPAuthMap({
+ tools: agent.tools,
+ userId: req.user.id,
+ findPluginAuthsByKeys,
+ });
+ }
+
+ const flowsCache = getLogStores(CacheKeys.FLOWS);
+ const flowManager = getFlowStateManager(flowsCache);
+ const pendingOAuthServers = new Set();
+
+ const createOAuthEmitter = (serverName) => {
+ return async (authURL) => {
+ const flowId = `${req.user.id}:${serverName}:${Date.now()}`;
+ const stepId = 'step_oauth_login_' + serverName;
+ const toolCall = {
+ id: flowId,
+ name: serverName,
+ type: 'tool_call_chunk',
+ };
+
+ const runStepData = {
+ runId: Constants.USE_PRELIM_RESPONSE_MESSAGE_ID,
+ id: stepId,
+ type: StepTypes.TOOL_CALLS,
+ index: 0,
+ stepDetails: {
+ type: StepTypes.TOOL_CALLS,
+ tool_calls: [toolCall],
+ },
+ };
+
+ const runStepDeltaData = {
+ id: stepId,
+ delta: {
+ type: StepTypes.TOOL_CALLS,
+ tool_calls: [{ ...toolCall, args: '' }],
+ auth: authURL,
+ expires_at: Date.now() + Time.TWO_MINUTES,
+ },
+ };
+
+ const runStepEvent = { event: GraphEvents.ON_RUN_STEP, data: runStepData };
+ const runStepDeltaEvent = { event: GraphEvents.ON_RUN_STEP_DELTA, data: runStepDeltaData };
+
+ if (streamId) {
+ await GenerationJobManager.emitChunk(streamId, runStepEvent);
+ await GenerationJobManager.emitChunk(streamId, runStepDeltaEvent);
+ } else if (res && !res.writableEnded) {
+ sendEvent(res, runStepEvent);
+ sendEvent(res, runStepDeltaEvent);
+ } else {
+ logger.warn(
+ `[Tool Definitions] Cannot emit OAuth event for ${serverName}: no streamId and res not available`,
+ );
+ }
+ };
+ };
+
+ const getOrFetchMCPServerTools = async (userId, serverName) => {
+ const cached = await getMCPServerTools(userId, serverName);
+ if (cached) {
+ return cached;
+ }
+
+ const oauthStart = async () => {
+ pendingOAuthServers.add(serverName);
+ };
+
+ const result = await reinitMCPServer({
+ user: req.user,
+ oauthStart,
+ flowManager,
+ serverName,
+ userMCPAuthMap,
+ });
+
+ return result?.availableTools || null;
+ };
+
+ const getActionToolDefinitions = async (agentId, actionToolNames) => {
+ const actionSets = (await loadActionSets({ agent_id: agentId })) ?? [];
+ if (actionSets.length === 0) {
+ return [];
+ }
+
+ const definitions = [];
+ const allowedDomains = appConfig?.actions?.allowedDomains;
+ const domainSeparatorRegex = new RegExp(actionDomainSeparator, 'g');
+
+ for (const action of actionSets) {
+ const domain = await domainParser(action.metadata.domain, true);
+ const normalizedDomain = domain.replace(domainSeparatorRegex, '_');
+
+ const isDomainAllowed = await isActionDomainAllowed(action.metadata.domain, allowedDomains);
+ if (!isDomainAllowed) {
+ logger.warn(
+ `[Actions] Domain "${action.metadata.domain}" not in allowedDomains. ` +
+ `Add it to librechat.yaml actions.allowedDomains to enable this action.`,
+ );
+ continue;
+ }
+
+ const validationResult = validateAndParseOpenAPISpec(action.metadata.raw_spec);
+ if (!validationResult.spec || !validationResult.serverUrl) {
+ logger.warn(`[Actions] Invalid OpenAPI spec for domain: ${domain}`);
+ continue;
+ }
+
+ const { functionSignatures } = openapiToFunction(validationResult.spec, true);
+
+ for (const sig of functionSignatures) {
+ const toolName = `${sig.name}${actionDelimiter}${normalizedDomain}`;
+ if (!actionToolNames.some((name) => name.replace(domainSeparatorRegex, '_') === toolName)) {
+ continue;
+ }
+
+ definitions.push({
+ name: toolName,
+ description: sig.description,
+ parameters: sig.parameters,
+ });
+ }
+ }
+
+ return definitions;
+ };
+
+ let { toolDefinitions, toolRegistry, hasDeferredTools } = await loadToolDefinitions(
+ {
+ userId: req.user.id,
+ agentId: agent.id,
+ tools: filteredTools,
+ toolOptions: agent.tool_options,
+ deferredToolsEnabled,
+ },
+ {
+ isBuiltInTool,
+ loadAuthValues,
+ getOrFetchMCPServerTools,
+ getActionToolDefinitions,
+ },
+ );
+
+ if (pendingOAuthServers.size > 0 && (res || streamId)) {
+ const serverNames = Array.from(pendingOAuthServers);
+ logger.info(
+ `[Tool Definitions] OAuth required for ${serverNames.length} server(s): ${serverNames.join(', ')}. Emitting events and waiting.`,
+ );
+
+ const oauthWaitPromises = serverNames.map(async (serverName) => {
+ try {
+ const result = await reinitMCPServer({
+ user: req.user,
+ serverName,
+ userMCPAuthMap,
+ flowManager,
+ returnOnOAuth: false,
+ oauthStart: createOAuthEmitter(serverName),
+ connectionTimeout: Time.TWO_MINUTES,
+ });
+
+ if (result?.availableTools) {
+ logger.info(`[Tool Definitions] OAuth completed for ${serverName}, tools available`);
+ return { serverName, success: true };
+ }
+ return { serverName, success: false };
+ } catch (error) {
+ logger.debug(`[Tool Definitions] OAuth wait failed for ${serverName}:`, error?.message);
+ return { serverName, success: false };
+ }
+ });
+
+ const results = await Promise.allSettled(oauthWaitPromises);
+ const successfulServers = results
+ .filter((r) => r.status === 'fulfilled' && r.value.success)
+ .map((r) => r.value.serverName);
+
+ if (successfulServers.length > 0) {
+ logger.info(
+ `[Tool Definitions] Reloading tools after OAuth for: ${successfulServers.join(', ')}`,
+ );
+ const reloadResult = await loadToolDefinitions(
+ {
+ userId: req.user.id,
+ agentId: agent.id,
+ tools: filteredTools,
+ toolOptions: agent.tool_options,
+ deferredToolsEnabled,
+ },
+ {
+ isBuiltInTool,
+ loadAuthValues,
+ getOrFetchMCPServerTools,
+ getActionToolDefinitions,
+ },
+ );
+ toolDefinitions = reloadResult.toolDefinitions;
+ toolRegistry = reloadResult.toolRegistry;
+ hasDeferredTools = reloadResult.hasDeferredTools;
+ }
+ }
+
+ /** @type {Record} */
+ const toolContextMap = {};
+ const hasWebSearch = filteredTools.includes(Tools.web_search);
+ const hasFileSearch = filteredTools.includes(Tools.file_search);
+ const hasExecuteCode = filteredTools.includes(Tools.execute_code);
+
+ if (hasWebSearch) {
+ toolContextMap[Tools.web_search] = buildWebSearchContext();
+ }
+
+ if (hasExecuteCode && tool_resources) {
+ try {
+ const authValues = await loadAuthValues({
+ userId: req.user.id,
+ authFields: [EnvVar.CODE_API_KEY],
+ });
+ const codeApiKey = authValues[EnvVar.CODE_API_KEY];
+
+ if (codeApiKey) {
+ const { toolContext } = await primeCodeFiles(
+ { req, tool_resources, agentId: agent.id },
+ codeApiKey,
+ );
+ if (toolContext) {
+ toolContextMap[Tools.execute_code] = toolContext;
+ }
+ }
+ } catch (error) {
+ logger.error('[loadToolDefinitionsWrapper] Error priming code files:', error);
+ }
+ }
+
+ if (hasFileSearch && tool_resources) {
+ try {
+ const { toolContext } = await primeSearchFiles({
+ req,
+ tool_resources,
+ agentId: agent.id,
+ });
+ if (toolContext) {
+ toolContextMap[Tools.file_search] = toolContext;
+ }
+ } catch (error) {
+ logger.error('[loadToolDefinitionsWrapper] Error priming search files:', error);
+ }
+ }
+
+ const imageFiles = tool_resources?.[EToolResources.image_edit]?.files ?? [];
+ if (imageFiles.length > 0) {
+ const hasOaiImageGen = filteredTools.includes('image_gen_oai');
+ const hasGeminiImageGen = filteredTools.includes('gemini_image_gen');
+
+ if (hasOaiImageGen) {
+ const toolContext = buildImageToolContext({
+ imageFiles,
+ toolName: `${EToolResources.image_edit}_oai`,
+ contextDescription: 'image editing',
+ });
+ if (toolContext) {
+ toolContextMap.image_edit_oai = toolContext;
+ }
+ }
+
+ if (hasGeminiImageGen) {
+ const toolContext = buildImageToolContext({
+ imageFiles,
+ toolName: 'gemini_image_gen',
+ contextDescription: 'image context',
+ });
+ if (toolContext) {
+ toolContextMap.gemini_image_gen = toolContext;
+ }
+ }
+ }
+
+ return {
+ toolRegistry,
+ userMCPAuthMap,
+ toolContextMap,
+ toolDefinitions,
+ hasDeferredTools,
+ };
+}
+
+/**
+ * Loads agent tools for initialization or execution.
+ * @param {Object} params
+ * @param {ServerRequest} params.req - The request object
+ * @param {ServerResponse} params.res - The response object
+ * @param {Object} params.agent - The agent configuration
+ * @param {AbortSignal} [params.signal] - Abort signal
+ * @param {Object} [params.tool_resources] - Tool resources
+ * @param {string} [params.openAIApiKey] - OpenAI API key
+ * @param {string|null} [params.streamId] - Stream ID for resumable mode
+ * @param {boolean} [params.definitionsOnly=true] - When true, returns only serializable
+ * tool definitions without creating full tool instances. Use for event-driven mode
+ * where tools are loaded on-demand during execution.
+ */
+async function loadAgentTools({
+ req,
+ res,
+ agent,
+ signal,
+ tool_resources,
+ openAIApiKey,
+ streamId = null,
+ definitionsOnly = true,
+}) {
+ if (definitionsOnly) {
+ return loadToolDefinitionsWrapper({ req, res, agent, streamId, tool_resources });
+ }
+
+ if (!agent.tools || agent.tools.length === 0) {
+ return { toolDefinitions: [] };
} else if (
agent.tools &&
agent.tools.length === 1 &&
/** Legacy handling for `ocr` as may still exist in existing Agents */
(agent.tools[0] === AgentCapabilities.context || agent.tools[0] === AgentCapabilities.ocr)
) {
- return {};
+ return { toolDefinitions: [] };
}
const appConfig = req.config;
const endpointsConfig = await getEndpointsConfig(req);
let enabledCapabilities = new Set(endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? []);
/** Edge case: use defined/fallback capabilities when the "agents" endpoint is not enabled */
- if (enabledCapabilities.size === 0 && agent.id === Constants.EPHEMERAL_AGENT_ID) {
+ if (enabledCapabilities.size === 0 && isEphemeralAgentId(agent.id)) {
enabledCapabilities = new Set(
appConfig.endpoints?.[EModelEndpoint.agents]?.capabilities ?? defaultAgentCapabilities,
);
@@ -393,8 +820,14 @@ async function loadAgentTools({ req, res, agent, signal, tool_resources, openAIA
const checkCapability = (capability) => {
const enabled = enabledCapabilities.has(capability);
if (!enabled) {
+ const isToolCapability = [
+ AgentCapabilities.file_search,
+ AgentCapabilities.execute_code,
+ AgentCapabilities.web_search,
+ ].includes(capability);
+ const suffix = isToolCapability ? ' despite configured tool.' : '.';
logger.warn(
- `Capability "${capability}" disabled${capability === AgentCapabilities.tools ? '.' : ' despite configured tool.'} User: ${req.user.id} | Agent: ${agent.id}`,
+ `Capability "${capability}" disabled${suffix} User: ${req.user.id} | Agent: ${agent.id}`,
);
}
return enabled;
@@ -422,11 +855,12 @@ async function loadAgentTools({ req, res, agent, signal, tool_resources, openAIA
/** @type {ReturnType} */
let webSearchCallbacks;
if (includesWebSearch) {
- webSearchCallbacks = createOnSearchResults(res);
+ webSearchCallbacks = createOnSearchResults(res, streamId);
}
/** @type {Record>} */
let userMCPAuthMap;
+ //TODO pass config from registry
if (hasCustomUserVars(req.config)) {
userMCPAuthMap = await getUserMCPAuthMap({
tools: agent.tools,
@@ -457,6 +891,18 @@ async function loadAgentTools({ req, res, agent, signal, tool_resources, openAIA
imageOutputType: appConfig.imageOutputType,
});
+ /** Build tool registry from MCP tools and create PTC/tool search tools if configured */
+ const deferredToolsEnabled = checkCapability(AgentCapabilities.deferred_tools);
+ const { toolRegistry, toolDefinitions, additionalTools, hasDeferredTools } =
+ await buildToolClassification({
+ loadedTools,
+ userId: req.user.id,
+ agentId: agent.id,
+ agentToolOptions: agent.tool_options,
+ deferredToolsEnabled,
+ loadAuthValues,
+ });
+
const agentTools = [];
for (let i = 0; i < loadedTools.length; i++) {
const tool = loadedTools[i];
@@ -501,11 +947,16 @@ async function loadAgentTools({ req, res, agent, signal, tool_resources, openAIA
return map;
}, {});
+ agentTools.push(...additionalTools);
+
if (!checkCapability(AgentCapabilities.actions)) {
return {
- tools: agentTools,
+ toolRegistry,
userMCPAuthMap,
toolContextMap,
+ toolDefinitions,
+ hasDeferredTools,
+ tools: agentTools,
};
}
@@ -515,9 +966,12 @@ async function loadAgentTools({ req, res, agent, signal, tool_resources, openAIA
logger.warn(`No tools found for the specified tool calls: ${_agentTools.join(', ')}`);
}
return {
- tools: agentTools,
+ toolRegistry,
userMCPAuthMap,
toolContextMap,
+ toolDefinitions,
+ hasDeferredTools,
+ tools: agentTools,
};
}
@@ -612,6 +1066,7 @@ async function loadAgentTools({ req, res, agent, signal, tool_resources, openAIA
const zodSchema = zodSchemas[functionName];
if (requestBuilder) {
+ const _allowedDomains = appConfig?.actions?.allowedDomains;
const tool = await createActionTool({
userId: req.user.id,
res,
@@ -621,6 +1076,8 @@ async function loadAgentTools({ req, res, agent, signal, tool_resources, openAIA
encrypted,
name: toolName,
description: functionSig.description,
+ streamId,
+ useSSRFProtection: !Array.isArray(_allowedDomains) || _allowedDomains.length === 0,
});
if (!tool) {
@@ -641,14 +1098,303 @@ async function loadAgentTools({ req, res, agent, signal, tool_resources, openAIA
}
return {
- tools: agentTools,
+ toolRegistry,
toolContextMap,
userMCPAuthMap,
+ toolDefinitions,
+ hasDeferredTools,
+ tools: agentTools,
};
}
+/**
+ * Loads tools for event-driven execution (ON_TOOL_EXECUTE handler).
+ * This function encapsulates all dependencies needed for tool loading,
+ * so callers don't need to import processFileURL, uploadImageBuffer, etc.
+ *
+ * Handles both regular tools (MCP, built-in) and action tools.
+ *
+ * @param {Object} params
+ * @param {ServerRequest} params.req - The request object
+ * @param {ServerResponse} params.res - The response object
+ * @param {AbortSignal} [params.signal] - Abort signal
+ * @param {Object} params.agent - The agent object
+ * @param {string[]} params.toolNames - Names of tools to load
+ * @param {Record>} [params.userMCPAuthMap] - User MCP auth map
+ * @param {Object} [params.tool_resources] - Tool resources
+ * @param {string|null} [params.streamId] - Stream ID for web search callbacks
+ * @returns {Promise<{ loadedTools: Array, configurable: Object }>}
+ */
+async function loadToolsForExecution({
+ req,
+ res,
+ signal,
+ agent,
+ toolNames,
+ toolRegistry,
+ userMCPAuthMap,
+ tool_resources,
+ streamId = null,
+}) {
+ const appConfig = req.config;
+ const allLoadedTools = [];
+ const configurable = { userMCPAuthMap };
+
+ const isToolSearch = toolNames.includes(AgentConstants.TOOL_SEARCH);
+ const isPTC = toolNames.includes(AgentConstants.PROGRAMMATIC_TOOL_CALLING);
+
+ logger.debug(
+ `[loadToolsForExecution] isToolSearch: ${isToolSearch}, toolRegistry: ${toolRegistry?.size ?? 'undefined'}`,
+ );
+
+ if (isToolSearch && toolRegistry) {
+ const toolSearchTool = createToolSearch({
+ mode: 'local',
+ toolRegistry,
+ });
+ allLoadedTools.push(toolSearchTool);
+ configurable.toolRegistry = toolRegistry;
+ }
+
+ if (isPTC && toolRegistry) {
+ configurable.toolRegistry = toolRegistry;
+ try {
+ const authValues = await loadAuthValues({
+ userId: req.user.id,
+ authFields: [EnvVar.CODE_API_KEY],
+ });
+ const codeApiKey = authValues[EnvVar.CODE_API_KEY];
+
+ if (codeApiKey) {
+ const ptcTool = createProgrammaticToolCallingTool({ apiKey: codeApiKey });
+ allLoadedTools.push(ptcTool);
+ } else {
+ logger.warn('[loadToolsForExecution] PTC requested but CODE_API_KEY not available');
+ }
+ } catch (error) {
+ logger.error('[loadToolsForExecution] Error creating PTC tool:', error);
+ }
+ }
+
+ const specialToolNames = new Set([
+ AgentConstants.TOOL_SEARCH,
+ AgentConstants.PROGRAMMATIC_TOOL_CALLING,
+ ]);
+
+ let ptcOrchestratedToolNames = [];
+ if (isPTC && toolRegistry) {
+ ptcOrchestratedToolNames = Array.from(toolRegistry.keys()).filter(
+ (name) => !specialToolNames.has(name),
+ );
+ }
+
+ const requestedNonSpecialToolNames = toolNames.filter((name) => !specialToolNames.has(name));
+ const allToolNamesToLoad = isPTC
+ ? [...new Set([...requestedNonSpecialToolNames, ...ptcOrchestratedToolNames])]
+ : requestedNonSpecialToolNames;
+
+ const actionToolNames = allToolNamesToLoad.filter((name) => name.includes(actionDelimiter));
+ const regularToolNames = allToolNamesToLoad.filter((name) => !name.includes(actionDelimiter));
+
+ /** @type {Record} */
+ if (regularToolNames.length > 0) {
+ const includesWebSearch = regularToolNames.includes(Tools.web_search);
+ const webSearchCallbacks = includesWebSearch ? createOnSearchResults(res, streamId) : undefined;
+
+ const { loadedTools } = await loadTools({
+ agent,
+ signal,
+ userMCPAuthMap,
+ functions: true,
+ tools: regularToolNames,
+ user: req.user.id,
+ options: {
+ req,
+ res,
+ tool_resources,
+ processFileURL,
+ uploadImageBuffer,
+ returnMetadata: true,
+ [Tools.web_search]: webSearchCallbacks,
+ },
+ webSearch: appConfig?.webSearch,
+ fileStrategy: appConfig?.fileStrategy,
+ imageOutputType: appConfig?.imageOutputType,
+ });
+
+ if (loadedTools) {
+ allLoadedTools.push(...loadedTools);
+ }
+ }
+
+ if (actionToolNames.length > 0 && agent) {
+ const actionTools = await loadActionToolsForExecution({
+ req,
+ res,
+ agent,
+ appConfig,
+ streamId,
+ actionToolNames,
+ });
+ allLoadedTools.push(...actionTools);
+ }
+
+ if (isPTC && allLoadedTools.length > 0) {
+ const ptcToolMap = new Map();
+ for (const tool of allLoadedTools) {
+ if (tool.name && tool.name !== AgentConstants.PROGRAMMATIC_TOOL_CALLING) {
+ ptcToolMap.set(tool.name, tool);
+ }
+ }
+ configurable.ptcToolMap = ptcToolMap;
+ }
+
+ return {
+ configurable,
+ loadedTools: allLoadedTools,
+ };
+}
+
+/**
+ * Loads action tools for event-driven execution.
+ * @param {Object} params
+ * @param {ServerRequest} params.req - The request object
+ * @param {ServerResponse} params.res - The response object
+ * @param {Object} params.agent - The agent object
+ * @param {Object} params.appConfig - App configuration
+ * @param {string|null} params.streamId - Stream ID
+ * @param {string[]} params.actionToolNames - Action tool names to load
+ * @returns {Promise} Loaded action tools
+ */
+async function loadActionToolsForExecution({
+ req,
+ res,
+ agent,
+ appConfig,
+ streamId,
+ actionToolNames,
+}) {
+ const loadedActionTools = [];
+
+ const actionSets = (await loadActionSets({ agent_id: agent.id })) ?? [];
+ if (actionSets.length === 0) {
+ return loadedActionTools;
+ }
+
+ const processedActionSets = new Map();
+ const domainMap = new Map();
+ const allowedDomains = appConfig?.actions?.allowedDomains;
+
+ for (const action of actionSets) {
+ const domain = await domainParser(action.metadata.domain, true);
+ domainMap.set(domain, action);
+
+ const isDomainAllowed = await isActionDomainAllowed(action.metadata.domain, allowedDomains);
+ if (!isDomainAllowed) {
+ logger.warn(
+ `[Actions] Domain "${action.metadata.domain}" not in allowedDomains. ` +
+ `Add it to librechat.yaml actions.allowedDomains to enable this action.`,
+ );
+ continue;
+ }
+
+ const validationResult = validateAndParseOpenAPISpec(action.metadata.raw_spec);
+ if (!validationResult.spec || !validationResult.serverUrl) {
+ logger.warn(`[Actions] Invalid OpenAPI spec for domain: ${domain}`);
+ continue;
+ }
+
+ const domainValidation = validateActionDomain(
+ action.metadata.domain,
+ validationResult.serverUrl,
+ );
+ if (!domainValidation.isValid) {
+ logger.error(`Domain mismatch in stored action: ${domainValidation.message}`, {
+ userId: req.user.id,
+ agent_id: agent.id,
+ action_id: action.action_id,
+ });
+ continue;
+ }
+
+ const encrypted = {
+ oauth_client_id: action.metadata.oauth_client_id,
+ oauth_client_secret: action.metadata.oauth_client_secret,
+ };
+
+ const decryptedAction = { ...action };
+ decryptedAction.metadata = await decryptMetadata(action.metadata);
+
+ const { requestBuilders, functionSignatures, zodSchemas } = openapiToFunction(
+ validationResult.spec,
+ true,
+ );
+
+ processedActionSets.set(domain, {
+ action: decryptedAction,
+ requestBuilders,
+ functionSignatures,
+ zodSchemas,
+ encrypted,
+ });
+ }
+
+ const domainSeparatorRegex = new RegExp(actionDomainSeparator, 'g');
+ for (const toolName of actionToolNames) {
+ let currentDomain = '';
+ for (const domain of domainMap.keys()) {
+ const normalizedDomain = domain.replace(domainSeparatorRegex, '_');
+ if (toolName.includes(normalizedDomain)) {
+ currentDomain = domain;
+ break;
+ }
+ }
+
+ if (!currentDomain || !processedActionSets.has(currentDomain)) {
+ continue;
+ }
+
+ const { action, encrypted, zodSchemas, requestBuilders, functionSignatures } =
+ processedActionSets.get(currentDomain);
+ const normalizedDomain = currentDomain.replace(domainSeparatorRegex, '_');
+ const functionName = toolName.replace(`${actionDelimiter}${normalizedDomain}`, '');
+ const functionSig = functionSignatures.find((sig) => sig.name === functionName);
+ const requestBuilder = requestBuilders[functionName];
+ const zodSchema = zodSchemas[functionName];
+
+ if (!requestBuilder) {
+ continue;
+ }
+
+ const tool = await createActionTool({
+ userId: req.user.id,
+ res,
+ action,
+ streamId,
+ zodSchema,
+ encrypted,
+ requestBuilder,
+ name: toolName,
+ description: functionSig?.description ?? '',
+ useSSRFProtection: !Array.isArray(allowedDomains) || allowedDomains.length === 0,
+ });
+
+ if (!tool) {
+ logger.warn(`[Actions] Failed to create action tool: ${toolName}`);
+ continue;
+ }
+
+ loadedActionTools.push(tool);
+ }
+
+ return loadedActionTools;
+}
+
module.exports = {
+ loadTools,
+ isBuiltInTool,
getToolkitKey,
loadAgentTools,
+ loadToolsForExecution,
processRequiredActions,
};
diff --git a/api/server/services/Tools/mcp.js b/api/server/services/Tools/mcp.js
index 521560aad4..10f2d71a18 100644
--- a/api/server/services/Tools/mcp.js
+++ b/api/server/services/Tools/mcp.js
@@ -1,11 +1,14 @@
const { logger } = require('@librechat/data-schemas');
const { CacheKeys, Constants } = require('librechat-data-provider');
const { findToken, createToken, updateToken, deleteTokens } = require('~/models');
-const { getMCPManager, getFlowStateManager } = require('~/config');
const { updateMCPServerTools } = require('~/server/services/Config');
+const { getMCPManager, getFlowStateManager } = require('~/config');
const { getLogStores } = require('~/cache');
/**
+ * Reinitializes an MCP server connection and discovers available tools.
+ * When OAuth is required, uses discovery mode to list tools without full authentication
+ * (per MCP spec, tool listing should be possible without auth).
* @param {Object} params
* @param {IUser} params.user - The user from the request object.
* @param {string} params.serverName - The name of the MCP server
@@ -14,7 +17,7 @@ const { getLogStores } = require('~/cache');
* @param {boolean} [params.forceNew]
* @param {number} [params.connectionTimeout]
* @param {FlowStateManager} [params.flowManager]
- * @param {(authURL: string) => Promise} [params.oauthStart]
+ * @param {(authURL: string) => Promise} [params.oauthStart]
* @param {Record>} [params.userMCPAuthMap]
*/
async function reinitMCPServer({
@@ -36,10 +39,12 @@ async function reinitMCPServer({
let tools = null;
let oauthRequired = false;
let oauthUrl = null;
+
try {
const customUserVars = userMCPAuthMap?.[`${Constants.mcp_prefix}${serverName}`];
const flowManager = _flowManager ?? getFlowStateManager(getLogStores(CacheKeys.FLOWS));
const mcpManager = getMCPManager();
+ const tokenMethods = { findToken, updateToken, createToken, deleteTokens };
const oauthStart =
_oauthStart ??
@@ -57,15 +62,10 @@ async function reinitMCPServer({
oauthStart,
serverName,
flowManager,
+ tokenMethods,
returnOnOAuth,
customUserVars,
connectionTimeout,
- tokenMethods: {
- findToken,
- updateToken,
- createToken,
- deleteTokens,
- },
});
logger.info(`[MCP Reinitialize] Successfully established connection for ${serverName}`);
@@ -84,9 +84,33 @@ async function reinitMCPServer({
if (isOAuthError || oauthRequired || isOAuthFlowInitiated) {
logger.info(
- `[MCP Reinitialize] OAuth required for ${serverName} (isOAuthError: ${isOAuthError}, oauthRequired: ${oauthRequired}, isOAuthFlowInitiated: ${isOAuthFlowInitiated})`,
+ `[MCP Reinitialize] OAuth required for ${serverName}, attempting tool discovery without auth`,
);
oauthRequired = true;
+
+ try {
+ const discoveryResult = await mcpManager.discoverServerTools({
+ user,
+ signal,
+ serverName,
+ flowManager,
+ tokenMethods,
+ oauthStart,
+ customUserVars,
+ connectionTimeout,
+ });
+
+ if (discoveryResult.tools && discoveryResult.tools.length > 0) {
+ tools = discoveryResult.tools;
+ logger.info(
+ `[MCP Reinitialize] Discovered ${tools.length} tools for ${serverName} without full auth`,
+ );
+ }
+ } catch (discoveryErr) {
+ logger.debug(
+ `[MCP Reinitialize] Tool discovery failed for ${serverName}: ${discoveryErr?.message ?? String(discoveryErr)}`,
+ );
+ }
} else {
logger.error(
`[MCP Reinitialize] Error initializing MCP server ${serverName} for user:`,
@@ -97,6 +121,9 @@ async function reinitMCPServer({
if (connection && !oauthRequired) {
tools = await connection.fetchTools();
+ }
+
+ if (tools && tools.length > 0) {
availableTools = await updateMCPServerTools({
userId: user.id,
serverName,
@@ -109,6 +136,9 @@ async function reinitMCPServer({
);
const getResponseMessage = () => {
+ if (oauthRequired && tools && tools.length > 0) {
+ return `MCP server '${serverName}' tools discovered, OAuth required for execution`;
+ }
if (oauthRequired) {
return `MCP server '${serverName}' ready for OAuth authentication`;
}
@@ -120,14 +150,25 @@ async function reinitMCPServer({
const result = {
availableTools,
- success: Boolean((connection && !oauthRequired) || (oauthRequired && oauthUrl)),
+ success: Boolean(
+ (connection && !oauthRequired) ||
+ (oauthRequired && oauthUrl) ||
+ (tools && tools.length > 0),
+ ),
message: getResponseMessage(),
oauthRequired,
serverName,
oauthUrl,
tools,
};
- logger.debug(`[MCP Reinitialize] Response for ${serverName}:`, result);
+
+ logger.debug(`[MCP Reinitialize] Response for ${serverName}:`, {
+ success: result.success,
+ oauthRequired: result.oauthRequired,
+ oauthUrl: result.oauthUrl ? 'present' : null,
+ toolsCount: tools?.length ?? 0,
+ });
+
return result;
} catch (error) {
logger.error(
diff --git a/api/server/services/Tools/search.js b/api/server/services/Tools/search.js
index c10c543141..c4cdfc752f 100644
--- a/api/server/services/Tools/search.js
+++ b/api/server/services/Tools/search.js
@@ -1,13 +1,29 @@
const { nanoid } = require('nanoid');
const { Tools } = require('librechat-data-provider');
const { logger } = require('@librechat/data-schemas');
+const { GenerationJobManager } = require('@librechat/api');
+
+/**
+ * Helper to write attachment events either to res or to job emitter.
+ * @param {import('http').ServerResponse} res - The server response object
+ * @param {string | null} streamId - The stream ID for resumable mode, or null for standard mode
+ * @param {Object} attachment - The attachment data
+ */
+function writeAttachment(res, streamId, attachment) {
+ if (streamId) {
+ GenerationJobManager.emitChunk(streamId, { event: 'attachment', data: attachment });
+ } else {
+ res.write(`event: attachment\ndata: ${JSON.stringify(attachment)}\n\n`);
+ }
+}
/**
* Creates a function to handle search results and stream them as attachments
* @param {import('http').ServerResponse} res - The HTTP server response object
+ * @param {string | null} [streamId] - The stream ID for resumable mode, or null for standard mode
* @returns {{ onSearchResults: function(SearchResult, GraphRunnableConfig): void; onGetHighlights: function(string): void}} - Function that takes search results and returns or streams an attachment
*/
-function createOnSearchResults(res) {
+function createOnSearchResults(res, streamId = null) {
const context = {
sourceMap: new Map(),
searchResultData: undefined,
@@ -70,7 +86,7 @@ function createOnSearchResults(res) {
if (!res.headersSent) {
return attachment;
}
- res.write(`event: attachment\ndata: ${JSON.stringify(attachment)}\n\n`);
+ writeAttachment(res, streamId, attachment);
}
/**
@@ -92,7 +108,7 @@ function createOnSearchResults(res) {
}
const attachment = buildAttachment(context);
- res.write(`event: attachment\ndata: ${JSON.stringify(attachment)}\n\n`);
+ writeAttachment(res, streamId, attachment);
}
return {
diff --git a/api/server/services/UserService.js b/api/server/services/UserService.js
deleted file mode 100644
index 7cf2f832a3..0000000000
--- a/api/server/services/UserService.js
+++ /dev/null
@@ -1,183 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-const { encrypt, decrypt } = require('@librechat/api');
-const { ErrorTypes } = require('librechat-data-provider');
-const { updateUser } = require('~/models');
-const { Key } = require('~/db/models');
-
-/**
- * Updates the plugins for a user based on the action specified (install/uninstall).
- * @async
- * @param {Object} user - The user whose plugins are to be updated.
- * @param {string} pluginKey - The key of the plugin to install or uninstall.
- * @param {'install' | 'uninstall'} action - The action to perform, 'install' or 'uninstall'.
- * @returns {Promise} The result of the update operation.
- * @throws Logs the error internally if the update operation fails.
- * @description This function updates the plugin array of a user document based on the specified action.
- * It adds a plugin key to the plugins array for an 'install' action, and removes it for an 'uninstall' action.
- */
-const updateUserPluginsService = async (user, pluginKey, action) => {
- try {
- const userPlugins = user.plugins || [];
- if (action === 'install') {
- return await updateUser(user._id, { plugins: [...userPlugins, pluginKey] });
- } else if (action === 'uninstall') {
- return await updateUser(user._id, {
- plugins: userPlugins.filter((plugin) => plugin !== pluginKey),
- });
- }
- } catch (err) {
- logger.error('[updateUserPluginsService]', err);
- return err;
- }
-};
-
-/**
- * Retrieves and decrypts the key value for a given user identified by userId and identifier name.
- * @param {Object} params - The parameters object.
- * @param {string} params.userId - The unique identifier for the user.
- * @param {string} params.name - The name associated with the key.
- * @returns {Promise} The decrypted key value.
- * @throws {Error} Throws an error if the key is not found or if there is a problem during key retrieval.
- * @description This function searches for a user's key in the database using their userId and name.
- * If found, it decrypts the value of the key and returns it. If no key is found, it throws
- * an error indicating that there is no user key available.
- */
-const getUserKey = async ({ userId, name }) => {
- const keyValue = await Key.findOne({ userId, name }).lean();
- if (!keyValue) {
- throw new Error(
- JSON.stringify({
- type: ErrorTypes.NO_USER_KEY,
- }),
- );
- }
- return await decrypt(keyValue.value);
-};
-
-/**
- * Retrieves, decrypts, and parses the key values for a given user identified by userId and name.
- * @param {Object} params - The parameters object.
- * @param {string} params.userId - The unique identifier for the user.
- * @param {string} params.name - The name associated with the key.
- * @returns {Promise>} The decrypted and parsed key values.
- * @throws {Error} Throws an error if the key is invalid or if there is a problem during key value parsing.
- * @description This function retrieves a user's encrypted key using their userId and name, decrypts it,
- * and then attempts to parse the decrypted string into a JSON object. If the parsing fails,
- * it throws an error indicating that the user key is invalid.
- */
-const getUserKeyValues = async ({ userId, name }) => {
- let userValues = await getUserKey({ userId, name });
- try {
- userValues = JSON.parse(userValues);
- } catch (e) {
- logger.error('[getUserKeyValues]', e);
- throw new Error(
- JSON.stringify({
- type: ErrorTypes.INVALID_USER_KEY,
- }),
- );
- }
- return userValues;
-};
-
-/**
- * Retrieves the expiry information of a user's key identified by userId and name.
- * @async
- * @param {Object} params - The parameters object.
- * @param {string} params.userId - The unique identifier for the user.
- * @param {string} params.name - The name associated with the key.
- * @returns {Promise<{expiresAt: Date | null}>} The expiry date of the key or null if the key doesn't exist.
- * @description This function fetches a user's key from the database using their userId and name and
- * returns its expiry date. If the key is not found, it returns null for the expiry date.
- */
-const getUserKeyExpiry = async ({ userId, name }) => {
- const keyValue = await Key.findOne({ userId, name }).lean();
- if (!keyValue) {
- return { expiresAt: null };
- }
- return { expiresAt: keyValue.expiresAt || 'never' };
-};
-
-/**
- * Updates or inserts a new key for a given user identified by userId and name, with a specified value and expiry date.
- * @async
- * @param {Object} params - The parameters object.
- * @param {string} params.userId - The unique identifier for the user.
- * @param {string} params.name - The name associated with the key.
- * @param {string} params.value - The value to be encrypted and stored as the key's value.
- * @param {Date} params.expiresAt - The expiry date for the key [optional]
- * @returns {Promise} The updated or newly inserted key document.
- * @description This function either updates an existing user key or inserts a new one into the database,
- * after encrypting the provided value. It sets the provided expiry date for the key (or unsets for no expiry).
- */
-const updateUserKey = async ({ userId, name, value, expiresAt = null }) => {
- const encryptedValue = await encrypt(value);
- let updateObject = {
- userId,
- name,
- value: encryptedValue,
- };
- const updateQuery = { $set: updateObject };
- // add expiresAt to the update object if it's not null
- if (expiresAt) {
- updateObject.expiresAt = new Date(expiresAt);
- } else {
- // make sure to remove if already present
- updateQuery.$unset = { expiresAt };
- }
- return await Key.findOneAndUpdate({ userId, name }, updateQuery, {
- upsert: true,
- new: true,
- }).lean();
-};
-
-/**
- * Deletes a key or all keys for a given user identified by userId, optionally based on a specified name.
- * @async
- * @param {Object} params - The parameters object.
- * @param {string} params.userId - The unique identifier for the user.
- * @param {string} [params.name] - The name associated with the key to delete. If not provided and all is true, deletes all keys.
- * @param {boolean} [params.all=false] - Whether to delete all keys for the user.
- * @returns {Promise} The result of the deletion operation.
- * @description This function deletes a specific key or all keys for a user from the database.
- * If a name is provided and all is false, it deletes only the key with that name.
- * If all is true, it ignores the name and deletes all keys for the user.
- */
-const deleteUserKey = async ({ userId, name, all = false }) => {
- if (all) {
- return await Key.deleteMany({ userId });
- }
-
- await Key.findOneAndDelete({ userId, name }).lean();
-};
-
-/**
- * Checks if a user key has expired based on the provided expiration date and endpoint.
- * If the key has expired, it throws an Error with details including the type of error, the expiration date, and the endpoint.
- *
- * @param {string} expiresAt - The expiration date of the user key in a format that can be parsed by the Date constructor.
- * @param {string} endpoint - The endpoint associated with the user key to be checked.
- * @throws {Error} Throws an error if the user key has expired. The error message is a stringified JSON object
- * containing the type of error (`ErrorTypes.EXPIRED_USER_KEY`), the expiration date in the local string format, and the endpoint.
- */
-const checkUserKeyExpiry = (expiresAt, endpoint) => {
- const expiresAtDate = new Date(expiresAt);
- if (expiresAtDate < new Date()) {
- const errorMessage = JSON.stringify({
- type: ErrorTypes.EXPIRED_USER_KEY,
- expiredAt: expiresAtDate.toLocaleString(),
- endpoint,
- });
- throw new Error(errorMessage);
- }
-};
-
-module.exports = {
- getUserKey,
- updateUserKey,
- deleteUserKey,
- getUserKeyValues,
- getUserKeyExpiry,
- checkUserKeyExpiry,
- updateUserPluginsService,
-};
diff --git a/api/server/services/__tests__/ToolService.spec.js b/api/server/services/__tests__/ToolService.spec.js
new file mode 100644
index 0000000000..2f00bbc3d6
--- /dev/null
+++ b/api/server/services/__tests__/ToolService.spec.js
@@ -0,0 +1,149 @@
+const { AgentCapabilities, defaultAgentCapabilities } = require('librechat-data-provider');
+
+/**
+ * Tests for ToolService capability checking logic.
+ * The actual loadAgentTools function has many dependencies, so we test
+ * the capability checking logic in isolation.
+ */
+describe('ToolService - Capability Checking', () => {
+ describe('checkCapability logic', () => {
+ /**
+ * Simulates the checkCapability function from loadAgentTools
+ */
+ const createCheckCapability = (enabledCapabilities, logger = { warn: jest.fn() }) => {
+ return (capability) => {
+ const enabled = enabledCapabilities.has(capability);
+ if (!enabled) {
+ const isToolCapability = [
+ AgentCapabilities.file_search,
+ AgentCapabilities.execute_code,
+ AgentCapabilities.web_search,
+ ].includes(capability);
+ const suffix = isToolCapability ? ' despite configured tool.' : '.';
+ logger.warn(`Capability "${capability}" disabled${suffix}`);
+ }
+ return enabled;
+ };
+ };
+
+ it('should return true when capability is enabled', () => {
+ const enabledCapabilities = new Set([AgentCapabilities.deferred_tools]);
+ const checkCapability = createCheckCapability(enabledCapabilities);
+
+ expect(checkCapability(AgentCapabilities.deferred_tools)).toBe(true);
+ });
+
+ it('should return false when capability is not enabled', () => {
+ const enabledCapabilities = new Set([]);
+ const checkCapability = createCheckCapability(enabledCapabilities);
+
+ expect(checkCapability(AgentCapabilities.deferred_tools)).toBe(false);
+ });
+
+ it('should log warning with "despite configured tool" for tool capabilities', () => {
+ const logger = { warn: jest.fn() };
+ const enabledCapabilities = new Set([]);
+ const checkCapability = createCheckCapability(enabledCapabilities, logger);
+
+ checkCapability(AgentCapabilities.file_search);
+ expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('despite configured tool'));
+
+ logger.warn.mockClear();
+ checkCapability(AgentCapabilities.execute_code);
+ expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('despite configured tool'));
+
+ logger.warn.mockClear();
+ checkCapability(AgentCapabilities.web_search);
+ expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('despite configured tool'));
+ });
+
+ it('should log warning without "despite configured tool" for non-tool capabilities', () => {
+ const logger = { warn: jest.fn() };
+ const enabledCapabilities = new Set([]);
+ const checkCapability = createCheckCapability(enabledCapabilities, logger);
+
+ checkCapability(AgentCapabilities.deferred_tools);
+ expect(logger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('Capability "deferred_tools" disabled.'),
+ );
+ expect(logger.warn).not.toHaveBeenCalledWith(
+ expect.stringContaining('despite configured tool'),
+ );
+
+ logger.warn.mockClear();
+ checkCapability(AgentCapabilities.tools);
+ expect(logger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('Capability "tools" disabled.'),
+ );
+ expect(logger.warn).not.toHaveBeenCalledWith(
+ expect.stringContaining('despite configured tool'),
+ );
+
+ logger.warn.mockClear();
+ checkCapability(AgentCapabilities.actions);
+ expect(logger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('Capability "actions" disabled.'),
+ );
+ });
+
+ it('should not log warning when capability is enabled', () => {
+ const logger = { warn: jest.fn() };
+ const enabledCapabilities = new Set([
+ AgentCapabilities.deferred_tools,
+ AgentCapabilities.file_search,
+ ]);
+ const checkCapability = createCheckCapability(enabledCapabilities, logger);
+
+ checkCapability(AgentCapabilities.deferred_tools);
+ checkCapability(AgentCapabilities.file_search);
+
+ expect(logger.warn).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('defaultAgentCapabilities', () => {
+ it('should include deferred_tools capability by default', () => {
+ expect(defaultAgentCapabilities).toContain(AgentCapabilities.deferred_tools);
+ });
+
+ it('should include all expected default capabilities', () => {
+ expect(defaultAgentCapabilities).toContain(AgentCapabilities.execute_code);
+ expect(defaultAgentCapabilities).toContain(AgentCapabilities.file_search);
+ expect(defaultAgentCapabilities).toContain(AgentCapabilities.web_search);
+ expect(defaultAgentCapabilities).toContain(AgentCapabilities.artifacts);
+ expect(defaultAgentCapabilities).toContain(AgentCapabilities.actions);
+ expect(defaultAgentCapabilities).toContain(AgentCapabilities.context);
+ expect(defaultAgentCapabilities).toContain(AgentCapabilities.tools);
+ expect(defaultAgentCapabilities).toContain(AgentCapabilities.chain);
+ expect(defaultAgentCapabilities).toContain(AgentCapabilities.ocr);
+ });
+ });
+
+ describe('deferredToolsEnabled integration', () => {
+ it('should correctly determine deferredToolsEnabled from capabilities set', () => {
+ const createCheckCapability = (enabledCapabilities) => {
+ return (capability) => enabledCapabilities.has(capability);
+ };
+
+ // When deferred_tools is in capabilities
+ const withDeferred = new Set([AgentCapabilities.deferred_tools, AgentCapabilities.tools]);
+ const checkWithDeferred = createCheckCapability(withDeferred);
+ expect(checkWithDeferred(AgentCapabilities.deferred_tools)).toBe(true);
+
+ // When deferred_tools is NOT in capabilities
+ const withoutDeferred = new Set([AgentCapabilities.tools, AgentCapabilities.actions]);
+ const checkWithoutDeferred = createCheckCapability(withoutDeferred);
+ expect(checkWithoutDeferred(AgentCapabilities.deferred_tools)).toBe(false);
+ });
+
+ it('should use defaultAgentCapabilities when no capabilities configured', () => {
+ // Simulates the fallback behavior in loadAgentTools
+ const endpointsConfig = {}; // No capabilities configured
+ const enabledCapabilities = new Set(
+ endpointsConfig?.capabilities ?? defaultAgentCapabilities,
+ );
+
+ expect(enabledCapabilities.has(AgentCapabilities.deferred_tools)).toBe(true);
+ });
+ });
+});
diff --git a/api/server/services/initializeMCPs.js b/api/server/services/initializeMCPs.js
index 7fdb128683..c7f27acd0e 100644
--- a/api/server/services/initializeMCPs.js
+++ b/api/server/services/initializeMCPs.js
@@ -1,6 +1,7 @@
+const mongoose = require('mongoose');
const { logger } = require('@librechat/data-schemas');
const { mergeAppTools, getAppConfig } = require('./Config');
-const { createMCPManager } = require('~/config');
+const { createMCPServersRegistry, createMCPManager } = require('~/config');
/**
* Initialize MCP servers
@@ -8,21 +9,31 @@ const { createMCPManager } = require('~/config');
async function initializeMCPs() {
const appConfig = await getAppConfig();
const mcpServers = appConfig.mcpConfig;
- if (!mcpServers) {
- return;
- }
-
- const mcpManager = await createMCPManager(mcpServers);
try {
- const mcpTools = (await mcpManager.getAppToolFunctions()) || {};
- await mergeAppTools(mcpTools);
-
- logger.info(
- `MCP servers initialized successfully. Added ${Object.keys(mcpTools).length} MCP tools.`,
- );
+ createMCPServersRegistry(mongoose, appConfig?.mcpSettings?.allowedDomains);
} catch (error) {
- logger.error('Failed to initialize MCP servers:', error);
+ logger.error('[MCP] Failed to initialize MCPServersRegistry:', error);
+ throw error;
+ }
+
+ try {
+ const mcpManager = await createMCPManager(mcpServers || {});
+
+ if (mcpServers && Object.keys(mcpServers).length > 0) {
+ const mcpTools = (await mcpManager.getAppToolFunctions()) || {};
+ await mergeAppTools(mcpTools);
+ const serverCount = Object.keys(mcpServers).length;
+ const toolCount = Object.keys(mcpTools).length;
+ logger.info(
+ `[MCP] Initialized with ${serverCount} configured ${serverCount === 1 ? 'server' : 'servers'} and ${toolCount} ${toolCount === 1 ? 'tool' : 'tools'}.`,
+ );
+ } else {
+ logger.debug('[MCP] No servers configured. MCPManager ready for UI-based servers.');
+ }
+ } catch (error) {
+ logger.error('[MCP] Failed to initialize MCPManager:', error);
+ throw error;
}
}
diff --git a/api/server/services/initializeMCPs.spec.js b/api/server/services/initializeMCPs.spec.js
new file mode 100644
index 0000000000..d72fda0e00
--- /dev/null
+++ b/api/server/services/initializeMCPs.spec.js
@@ -0,0 +1,281 @@
+/**
+ * Tests for initializeMCPs.js
+ *
+ * These tests verify that MCPServersRegistry and MCPManager are ALWAYS initialized,
+ * even when no explicitly configured MCP servers exist. This is critical for the
+ * "Dynamic MCP Server Management" feature (introduced in `0.8.2-rc1` release) which
+ * allows users to add MCP servers via the UI without requiring explicit configuration.
+ *
+ * Bug fixed: Previously, MCPManager was only initialized when mcpServers existed
+ * in librechat.yaml, causing "MCPManager has not been initialized" errors when
+ * users tried to create MCP servers via the UI.
+ */
+
+// Mock dependencies before imports
+jest.mock('mongoose', () => ({
+ connection: { readyState: 1 },
+}));
+
+jest.mock('@librechat/data-schemas', () => ({
+ logger: {
+ debug: jest.fn(),
+ error: jest.fn(),
+ info: jest.fn(),
+ warn: jest.fn(),
+ },
+}));
+
+// Mock config functions
+const mockGetAppConfig = jest.fn();
+const mockMergeAppTools = jest.fn();
+
+jest.mock('./Config', () => ({
+ get getAppConfig() {
+ return mockGetAppConfig;
+ },
+ get mergeAppTools() {
+ return mockMergeAppTools;
+ },
+}));
+
+// Mock MCP singletons
+const mockCreateMCPServersRegistry = jest.fn();
+const mockCreateMCPManager = jest.fn();
+const mockMCPManagerInstance = {
+ getAppToolFunctions: jest.fn(),
+};
+
+jest.mock('~/config', () => ({
+ get createMCPServersRegistry() {
+ return mockCreateMCPServersRegistry;
+ },
+ get createMCPManager() {
+ return mockCreateMCPManager;
+ },
+}));
+
+const { logger } = require('@librechat/data-schemas');
+const initializeMCPs = require('./initializeMCPs');
+
+describe('initializeMCPs', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ // Default: successful initialization
+ mockCreateMCPServersRegistry.mockReturnValue(undefined);
+ mockCreateMCPManager.mockResolvedValue(mockMCPManagerInstance);
+ mockMCPManagerInstance.getAppToolFunctions.mockResolvedValue({});
+ mockMergeAppTools.mockResolvedValue(undefined);
+ });
+
+ describe('MCPServersRegistry initialization', () => {
+ it('should ALWAYS initialize MCPServersRegistry even without configured servers', async () => {
+ mockGetAppConfig.mockResolvedValue({
+ mcpConfig: null, // No configured servers
+ mcpSettings: { allowedDomains: ['localhost'] },
+ });
+
+ await initializeMCPs();
+
+ expect(mockCreateMCPServersRegistry).toHaveBeenCalledTimes(1);
+ expect(mockCreateMCPServersRegistry).toHaveBeenCalledWith(
+ expect.anything(), // mongoose
+ ['localhost'],
+ );
+ });
+
+ it('should pass allowedDomains from mcpSettings to registry', async () => {
+ const allowedDomains = ['localhost', '*.example.com', 'trusted-mcp.com'];
+ mockGetAppConfig.mockResolvedValue({
+ mcpConfig: null,
+ mcpSettings: { allowedDomains },
+ });
+
+ await initializeMCPs();
+
+ expect(mockCreateMCPServersRegistry).toHaveBeenCalledWith(expect.anything(), allowedDomains);
+ });
+
+ it('should handle undefined mcpSettings gracefully', async () => {
+ mockGetAppConfig.mockResolvedValue({
+ mcpConfig: null,
+ // mcpSettings is undefined
+ });
+
+ await initializeMCPs();
+
+ expect(mockCreateMCPServersRegistry).toHaveBeenCalledWith(expect.anything(), undefined);
+ });
+
+ it('should throw and log error if MCPServersRegistry initialization fails', async () => {
+ const registryError = new Error('Registry initialization failed');
+ mockCreateMCPServersRegistry.mockImplementation(() => {
+ throw registryError;
+ });
+ mockGetAppConfig.mockResolvedValue({ mcpConfig: null });
+
+ await expect(initializeMCPs()).rejects.toThrow('Registry initialization failed');
+ expect(logger.error).toHaveBeenCalledWith(
+ '[MCP] Failed to initialize MCPServersRegistry:',
+ registryError,
+ );
+ });
+ });
+
+ describe('MCPManager initialization', () => {
+ it('should ALWAYS initialize MCPManager even without configured servers', async () => {
+ mockGetAppConfig.mockResolvedValue({
+ mcpConfig: null, // No configured servers
+ });
+
+ await initializeMCPs();
+
+ // MCPManager should be created with empty object when no configured servers
+ expect(mockCreateMCPManager).toHaveBeenCalledTimes(1);
+ expect(mockCreateMCPManager).toHaveBeenCalledWith({});
+ });
+
+ it('should initialize MCPManager with configured servers when provided', async () => {
+ const mcpServers = {
+ 'test-server': { type: 'sse', url: 'http://localhost:3001/sse' },
+ 'local-server': { type: 'stdio', command: 'node', args: ['server.js'] },
+ };
+ mockGetAppConfig.mockResolvedValue({ mcpConfig: mcpServers });
+
+ await initializeMCPs();
+
+ expect(mockCreateMCPManager).toHaveBeenCalledWith(mcpServers);
+ });
+
+ it('should throw and log error if MCPManager initialization fails', async () => {
+ const managerError = new Error('Manager initialization failed');
+ mockCreateMCPManager.mockRejectedValue(managerError);
+ mockGetAppConfig.mockResolvedValue({ mcpConfig: null });
+
+ await expect(initializeMCPs()).rejects.toThrow('Manager initialization failed');
+ expect(logger.error).toHaveBeenCalledWith(
+ '[MCP] Failed to initialize MCPManager:',
+ managerError,
+ );
+ });
+ });
+
+ describe('Tool merging behavior', () => {
+ it('should NOT merge tools when no configured servers exist', async () => {
+ mockGetAppConfig.mockResolvedValue({
+ mcpConfig: null, // No configured servers
+ });
+
+ await initializeMCPs();
+
+ expect(mockMCPManagerInstance.getAppToolFunctions).not.toHaveBeenCalled();
+ expect(mockMergeAppTools).not.toHaveBeenCalled();
+ expect(logger.debug).toHaveBeenCalledWith(
+ '[MCP] No servers configured. MCPManager ready for UI-based servers.',
+ );
+ });
+
+ it('should NOT merge tools when mcpConfig is empty object', async () => {
+ mockGetAppConfig.mockResolvedValue({
+ mcpConfig: {}, // Empty object
+ });
+
+ await initializeMCPs();
+
+ expect(mockMCPManagerInstance.getAppToolFunctions).not.toHaveBeenCalled();
+ expect(mockMergeAppTools).not.toHaveBeenCalled();
+ expect(logger.debug).toHaveBeenCalledWith(
+ '[MCP] No servers configured. MCPManager ready for UI-based servers.',
+ );
+ });
+
+ it('should merge tools when configured servers exist', async () => {
+ const mcpServers = {
+ 'test-server': { type: 'sse', url: 'http://localhost:3001/sse' },
+ };
+ const mcpTools = {
+ tool1: jest.fn(),
+ tool2: jest.fn(),
+ };
+ mockGetAppConfig.mockResolvedValue({ mcpConfig: mcpServers });
+ mockMCPManagerInstance.getAppToolFunctions.mockResolvedValue(mcpTools);
+
+ await initializeMCPs();
+
+ expect(mockMCPManagerInstance.getAppToolFunctions).toHaveBeenCalledTimes(1);
+ expect(mockMergeAppTools).toHaveBeenCalledWith(mcpTools);
+ expect(logger.info).toHaveBeenCalledWith(
+ '[MCP] Initialized with 1 configured server and 2 tools.',
+ );
+ });
+
+ it('should handle null return from getAppToolFunctions', async () => {
+ const mcpServers = { 'test-server': { type: 'sse', url: 'http://localhost:3001' } };
+ mockGetAppConfig.mockResolvedValue({ mcpConfig: mcpServers });
+ mockMCPManagerInstance.getAppToolFunctions.mockResolvedValue(null);
+
+ await initializeMCPs();
+
+ // Should use empty object fallback
+ expect(mockMergeAppTools).toHaveBeenCalledWith({});
+ expect(logger.info).toHaveBeenCalledWith(
+ '[MCP] Initialized with 1 configured server and 0 tools.',
+ );
+ });
+ });
+
+ describe('Initialization order', () => {
+ it('should initialize Registry before Manager', async () => {
+ const callOrder = [];
+
+ mockCreateMCPServersRegistry.mockImplementation(() => {
+ callOrder.push('registry');
+ });
+ mockCreateMCPManager.mockImplementation(async () => {
+ callOrder.push('manager');
+ return mockMCPManagerInstance;
+ });
+ mockGetAppConfig.mockResolvedValue({ mcpConfig: null });
+
+ await initializeMCPs();
+
+ expect(callOrder).toEqual(['registry', 'manager']);
+ });
+
+ it('should not attempt MCPManager initialization if Registry fails', async () => {
+ mockCreateMCPServersRegistry.mockImplementation(() => {
+ throw new Error('Registry failed');
+ });
+ mockGetAppConfig.mockResolvedValue({ mcpConfig: null });
+
+ await expect(initializeMCPs()).rejects.toThrow('Registry failed');
+ expect(mockCreateMCPManager).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('UI-based MCP server management support', () => {
+ /**
+ * This test documents the critical fix:
+ * MCPManager must be initialized even without configured servers to support
+ * the "Dynamic MCP Server Management" feature where users create
+ * MCP servers via the UI.
+ */
+ it('should support UI-based server creation without explicit configuration', async () => {
+ // Scenario: User has no MCP servers in librechat.yaml but wants to
+ // add servers via the UI
+ mockGetAppConfig.mockResolvedValue({
+ mcpConfig: null,
+ mcpSettings: undefined,
+ });
+
+ await initializeMCPs();
+
+ // Both singletons must be initialized for UI-based management to work
+ expect(mockCreateMCPServersRegistry).toHaveBeenCalledTimes(1);
+ expect(mockCreateMCPManager).toHaveBeenCalledTimes(1);
+
+ // Verify manager was created with empty config (not null/undefined)
+ expect(mockCreateMCPManager).toHaveBeenCalledWith({});
+ });
+ });
+});
diff --git a/api/server/services/start/tools.js b/api/server/services/start/tools.js
index f139eaac4d..8dc8475f7f 100644
--- a/api/server/services/start/tools.js
+++ b/api/server/services/start/tools.js
@@ -5,7 +5,7 @@ const { Calculator } = require('@librechat/agents');
const { logger } = require('@librechat/data-schemas');
const { zodToJsonSchema } = require('zod-to-json-schema');
const { Tools, ImageVisionTool } = require('librechat-data-provider');
-const { getToolkitKey, oaiToolkit, ytToolkit } = require('@librechat/api');
+const { getToolkitKey, oaiToolkit, geminiToolkit } = require('@librechat/api');
const { toolkits } = require('~/app/clients/tools/manifest');
/**
@@ -83,7 +83,7 @@ function loadAndFormatTools({ directory, adminFilter = [], adminIncluded = [] })
const basicToolInstances = [
new Calculator(),
...Object.values(oaiToolkit),
- ...Object.values(ytToolkit),
+ ...Object.values(geminiToolkit),
];
for (const toolInstance of basicToolInstances) {
const formattedTool = formatToOpenAIAssistantTool(toolInstance);
@@ -107,22 +107,33 @@ function loadAndFormatTools({ directory, adminFilter = [], adminIncluded = [] })
}, {});
}
+/**
+ * Checks if a schema is a Zod schema by looking for the _def property
+ * @param {unknown} schema - The schema to check
+ * @returns {boolean} True if it's a Zod schema
+ */
+function isZodSchema(schema) {
+ return schema && typeof schema === 'object' && '_def' in schema;
+}
+
/**
* Formats a `StructuredTool` instance into a format that is compatible
* with OpenAI's ChatCompletionFunctions. It uses the `zodToJsonSchema`
* function to convert the schema of the `StructuredTool` into a JSON
* schema, which is then used as the parameters for the OpenAI function.
+ * If the schema is already a JSON schema, it is used directly.
*
* @param {StructuredTool} tool - The StructuredTool to format.
* @returns {FunctionTool} The OpenAI Assistant Tool.
*/
function formatToOpenAIAssistantTool(tool) {
+ const parameters = isZodSchema(tool.schema) ? zodToJsonSchema(tool.schema) : tool.schema;
return {
type: Tools.function,
[Tools.function]: {
name: tool.name,
description: tool.description,
- parameters: zodToJsonSchema(tool.schema),
+ parameters,
},
};
}
diff --git a/api/server/services/twoFactorService.js b/api/server/services/twoFactorService.js
index 4ac86a5549..cce24e2322 100644
--- a/api/server/services/twoFactorService.js
+++ b/api/server/services/twoFactorService.js
@@ -1,5 +1,5 @@
const { webcrypto } = require('node:crypto');
-const { hashBackupCode, decryptV3, decryptV2 } = require('@librechat/api');
+const { hashBackupCode, decryptV3, decryptV2 } = require('@librechat/data-schemas');
const { updateUser } = require('~/models');
// Base32 alphabet for TOTP secret encoding.
diff --git a/api/server/socialLogins.js b/api/server/socialLogins.js
index 0a89313ba9..a84c33bd52 100644
--- a/api/server/socialLogins.js
+++ b/api/server/socialLogins.js
@@ -1,8 +1,8 @@
const passport = require('passport');
const session = require('express-session');
-const { isEnabled } = require('@librechat/api');
-const { logger } = require('@librechat/data-schemas');
const { CacheKeys } = require('librechat-data-provider');
+const { isEnabled, shouldUseSecureCookie } = require('@librechat/api');
+const { logger, DEFAULT_SESSION_EXPIRY } = require('@librechat/data-schemas');
const {
openIdJwtLogin,
facebookLogin,
@@ -22,11 +22,16 @@ const { getLogStores } = require('~/cache');
*/
async function configureOpenId(app) {
logger.info('Configuring OpenID Connect...');
+ const sessionExpiry = Number(process.env.SESSION_EXPIRY) || DEFAULT_SESSION_EXPIRY;
const sessionOptions = {
secret: process.env.OPENID_SESSION_SECRET,
resave: false,
saveUninitialized: false,
store: getLogStores(CacheKeys.OPENID_SESSION),
+ cookie: {
+ maxAge: sessionExpiry,
+ secure: shouldUseSecureCookie(),
+ },
};
app.use(session(sessionOptions));
app.use(passport.session());
@@ -82,11 +87,16 @@ const configureSocialLogins = async (app) => {
process.env.SAML_SESSION_SECRET
) {
logger.info('Configuring SAML Connect...');
+ const sessionExpiry = Number(process.env.SESSION_EXPIRY) || DEFAULT_SESSION_EXPIRY;
const sessionOptions = {
secret: process.env.SAML_SESSION_SECRET,
resave: false,
saveUninitialized: false,
store: getLogStores(CacheKeys.SAML_SESSION),
+ cookie: {
+ maxAge: sessionExpiry,
+ secure: shouldUseSecureCookie(),
+ },
};
app.use(session(sessionOptions));
app.use(passport.session());
diff --git a/api/server/utils/handleText.js b/api/server/utils/handleText.js
index a798dc99bd..cce96feff4 100644
--- a/api/server/utils/handleText.js
+++ b/api/server/utils/handleText.js
@@ -1,3 +1,4 @@
+const partialRight = require('lodash/partialRight');
const {
Capabilities,
EModelEndpoint,
@@ -7,8 +8,7 @@ const {
defaultAssistantsVersion,
defaultAgentCapabilities,
} = require('librechat-data-provider');
-const { sendEvent } = require('@librechat/api');
-const partialRight = require('lodash/partialRight');
+const { sendEvent, isUserProvided } = require('@librechat/api');
const addSpaceIfNeeded = (text) => (text.length > 0 && !text.endsWith(' ') ? text + ' ' : text);
@@ -117,14 +117,6 @@ function formatAction(action) {
return formattedAction;
}
-/**
- * Checks if the provided value is 'user_provided'.
- *
- * @param {string} value - The value to check.
- * @returns {boolean} - Returns true if the value is 'user_provided', otherwise false.
- */
-const isUserProvided = (value) => value === 'user_provided';
-
/**
* Generate the configuration for a given key and base URL.
* @param {string} key
@@ -174,7 +166,6 @@ module.exports = {
handleText,
formatSteps,
formatAction,
- isUserProvided,
generateConfig,
addSpaceIfNeeded,
createOnProgress,
diff --git a/api/server/utils/import/importers-timestamp.spec.js b/api/server/utils/import/importers-timestamp.spec.js
index 2ce00de82b..c7665dfe25 100644
--- a/api/server/utils/import/importers-timestamp.spec.js
+++ b/api/server/utils/import/importers-timestamp.spec.js
@@ -243,6 +243,133 @@ describe('Import Timestamp Ordering', () => {
});
});
+ describe('ChatGPT Import - Timestamp Issues', () => {
+ test('should correct timestamp inversions (child before parent)', async () => {
+ // Simulate ChatGPT export with timestamp inversion (like tool call results)
+ const jsonData = [
+ {
+ title: 'Timestamp Inversion Test',
+ create_time: 1000,
+ mapping: {
+ 'root-node': {
+ id: 'root-node',
+ message: null,
+ parent: null,
+ children: ['parent-msg'],
+ },
+ 'parent-msg': {
+ id: 'parent-msg',
+ message: {
+ id: 'parent-msg',
+ author: { role: 'user' },
+ create_time: 1000.1, // Parent: 1000.1
+ content: { content_type: 'text', parts: ['Parent message'] },
+ metadata: {},
+ },
+ parent: 'root-node',
+ children: ['child-msg'],
+ },
+ 'child-msg': {
+ id: 'child-msg',
+ message: {
+ id: 'child-msg',
+ author: { role: 'assistant' },
+ create_time: 1000.095, // Child: 1000.095 (5ms BEFORE parent)
+ content: { content_type: 'text', parts: ['Child message'] },
+ metadata: {},
+ },
+ parent: 'parent-msg',
+ children: [],
+ },
+ },
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(jsonData);
+ await importer(jsonData, requestUserId, () => importBatchBuilder);
+
+ const savedMessages = importBatchBuilder.messages;
+ const parent = savedMessages.find((msg) => msg.text === 'Parent message');
+ const child = savedMessages.find((msg) => msg.text === 'Child message');
+
+ expect(parent).toBeDefined();
+ expect(child).toBeDefined();
+
+ // Child timestamp should be adjusted to be after parent
+ expect(new Date(child.createdAt).getTime()).toBeGreaterThan(
+ new Date(parent.createdAt).getTime(),
+ );
+ });
+
+ test('should use conv.create_time for null message timestamps', async () => {
+ const convCreateTime = 1500000000; // Conversation create time
+ const jsonData = [
+ {
+ title: 'Null Timestamp Test',
+ create_time: convCreateTime,
+ mapping: {
+ 'root-node': {
+ id: 'root-node',
+ message: null,
+ parent: null,
+ children: ['msg-with-null-time'],
+ },
+ 'msg-with-null-time': {
+ id: 'msg-with-null-time',
+ message: {
+ id: 'msg-with-null-time',
+ author: { role: 'user' },
+ create_time: null, // Null timestamp
+ content: { content_type: 'text', parts: ['Message with null time'] },
+ metadata: {},
+ },
+ parent: 'root-node',
+ children: ['msg-with-valid-time'],
+ },
+ 'msg-with-valid-time': {
+ id: 'msg-with-valid-time',
+ message: {
+ id: 'msg-with-valid-time',
+ author: { role: 'assistant' },
+ create_time: convCreateTime + 10, // Valid timestamp
+ content: { content_type: 'text', parts: ['Message with valid time'] },
+ metadata: {},
+ },
+ parent: 'msg-with-null-time',
+ children: [],
+ },
+ },
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(jsonData);
+ await importer(jsonData, requestUserId, () => importBatchBuilder);
+
+ const savedMessages = importBatchBuilder.messages;
+ const nullTimeMsg = savedMessages.find((msg) => msg.text === 'Message with null time');
+ const validTimeMsg = savedMessages.find((msg) => msg.text === 'Message with valid time');
+
+ expect(nullTimeMsg).toBeDefined();
+ expect(validTimeMsg).toBeDefined();
+
+ // Null timestamp should fall back to conv.create_time
+ expect(nullTimeMsg.createdAt).toEqual(new Date(convCreateTime * 1000));
+
+ // Child should still be after parent (timestamp adjustment)
+ expect(new Date(validTimeMsg.createdAt).getTime()).toBeGreaterThan(
+ new Date(nullTimeMsg.createdAt).getTime(),
+ );
+ });
+ });
+
describe('Comparison with Fork Functionality', () => {
test('fork functionality correctly handles timestamp issues (for comparison)', async () => {
const { cloneMessagesWithTimestamps } = require('./fork');
diff --git a/api/server/utils/import/importers.js b/api/server/utils/import/importers.js
index cb68946cc3..81a0f048df 100644
--- a/api/server/utils/import/importers.js
+++ b/api/server/utils/import/importers.js
@@ -13,8 +13,14 @@ const getLogStores = require('~/cache/getLogStores');
* @throws {Error} - If the import type is not supported.
*/
function getImporter(jsonData) {
- // For ChatGPT
+ // For array-based formats (ChatGPT or Claude)
if (Array.isArray(jsonData)) {
+ // Claude format has chat_messages array in each conversation
+ if (jsonData.length > 0 && jsonData[0]?.chat_messages) {
+ logger.info('Importing Claude conversation');
+ return importClaudeConvo;
+ }
+ // ChatGPT format has mapping object in each conversation
logger.info('Importing ChatGPT conversation');
return importChatGptConvo;
}
@@ -71,6 +77,111 @@ async function importChatBotUiConvo(
}
}
+/**
+ * Extracts text and thinking content from a Claude message.
+ * @param {Object} msg - Claude message object with content array and optional text field.
+ * @returns {{textContent: string, thinkingContent: string}} Extracted text and thinking content.
+ */
+function extractClaudeContent(msg) {
+ let textContent = '';
+ let thinkingContent = '';
+
+ for (const part of msg.content || []) {
+ if (part.type === 'text' && part.text) {
+ textContent += part.text;
+ } else if (part.type === 'thinking' && part.thinking) {
+ thinkingContent += part.thinking;
+ }
+ }
+
+ // Use the text field as fallback if content array is empty
+ if (!textContent && msg.text) {
+ textContent = msg.text;
+ }
+
+ return { textContent, thinkingContent };
+}
+
+/**
+ * Imports Claude conversations from provided JSON data.
+ * Claude export format: array of conversations with chat_messages array.
+ *
+ * @param {Array} jsonData - Array of Claude conversation objects to be imported.
+ * @param {string} requestUserId - The ID of the user who initiated the import process.
+ * @param {Function} builderFactory - Factory function to create a new import batch builder instance.
+ * @returns {Promise} Promise that resolves when all conversations have been imported.
+ */
+async function importClaudeConvo(
+ jsonData,
+ requestUserId,
+ builderFactory = createImportBatchBuilder,
+) {
+ try {
+ const importBatchBuilder = builderFactory(requestUserId);
+
+ for (const conv of jsonData) {
+ importBatchBuilder.startConversation(EModelEndpoint.anthropic);
+
+ let lastMessageId = Constants.NO_PARENT;
+ let lastTimestamp = null;
+
+ for (const msg of conv.chat_messages || []) {
+ const isCreatedByUser = msg.sender === 'human';
+ const messageId = uuidv4();
+
+ const { textContent, thinkingContent } = extractClaudeContent(msg);
+
+ // Skip empty messages
+ if (!textContent && !thinkingContent) {
+ continue;
+ }
+
+ // Parse timestamp, fallback to conversation create_time or current time
+ const messageTime = msg.created_at || conv.created_at;
+ let createdAt = messageTime ? new Date(messageTime) : new Date();
+
+ // Ensure timestamp is after the previous message.
+ // Messages are sorted by createdAt and buildTree expects parents to appear before children.
+ // This guards against any potential ordering issues in exports.
+ if (lastTimestamp && createdAt <= lastTimestamp) {
+ createdAt = new Date(lastTimestamp.getTime() + 1);
+ }
+ lastTimestamp = createdAt;
+
+ const message = {
+ messageId,
+ parentMessageId: lastMessageId,
+ text: textContent,
+ sender: isCreatedByUser ? 'user' : 'Claude',
+ isCreatedByUser,
+ user: requestUserId,
+ endpoint: EModelEndpoint.anthropic,
+ createdAt,
+ };
+
+ // Add content array with thinking if present
+ if (thinkingContent && !isCreatedByUser) {
+ message.content = [
+ { type: 'think', think: thinkingContent },
+ { type: 'text', text: textContent },
+ ];
+ }
+
+ importBatchBuilder.saveMessage(message);
+ lastMessageId = messageId;
+ }
+
+ const createdAt = conv.created_at ? new Date(conv.created_at) : new Date();
+ importBatchBuilder.finishConversation(conv.name || 'Imported Claude Chat', createdAt);
+ }
+
+ await importBatchBuilder.saveBatch();
+ logger.info(`user: ${requestUserId} | Claude conversation imported`);
+ } catch (error) {
+ logger.error(`user: ${requestUserId} | Error creating conversation from Claude file`, error);
+ }
+}
+
/**
* Imports a LibreChat conversation from JSON.
*
@@ -213,11 +324,11 @@ function processConversation(conv, importBatchBuilder, requestUserId) {
}
/**
- * Helper function to find the nearest non-system parent
+ * Helper function to find the nearest valid parent (skips system, reasoning_recap, and thoughts messages)
* @param {string} parentId - The ID of the parent message.
- * @returns {string} The ID of the nearest non-system parent message.
+ * @returns {string} The ID of the nearest valid parent message.
*/
- const findNonSystemParent = (parentId) => {
+ const findValidParent = (parentId) => {
if (!parentId || !messageMap.has(parentId)) {
return Constants.NO_PARENT;
}
@@ -227,14 +338,62 @@ function processConversation(conv, importBatchBuilder, requestUserId) {
return Constants.NO_PARENT;
}
- /* If parent is a system message, traverse up to find the nearest non-system parent */
- if (parentMapping.message.author?.role === 'system') {
- return findNonSystemParent(parentMapping.parent);
+ /* If parent is a system message, reasoning_recap, or thoughts, traverse up to find the nearest valid parent */
+ const contentType = parentMapping.message.content?.content_type;
+ const shouldSkip =
+ parentMapping.message.author?.role === 'system' ||
+ contentType === 'reasoning_recap' ||
+ contentType === 'thoughts';
+
+ if (shouldSkip) {
+ return findValidParent(parentMapping.parent);
}
return messageMap.get(parentId);
};
+ /**
+ * Helper function to find thinking content from parent chain (thoughts messages)
+ * @param {string} parentId - The ID of the parent message.
+ * @param {Set} visited - Set of already-visited IDs to prevent cycles.
+ * @returns {Array} The thinking content array (empty if not found).
+ */
+ const findThinkingContent = (parentId, visited = new Set()) => {
+ // Guard against circular references in malformed imports
+ if (!parentId || visited.has(parentId)) {
+ return [];
+ }
+ visited.add(parentId);
+
+ const parentMapping = conv.mapping[parentId];
+ if (!parentMapping?.message) {
+ return [];
+ }
+
+ const contentType = parentMapping.message.content?.content_type;
+
+ // If this is a thoughts message, extract the thinking content
+ if (contentType === 'thoughts') {
+ const thoughts = parentMapping.message.content.thoughts || [];
+ const thinkingText = thoughts
+ .map((t) => t.content || t.summary || '')
+ .filter(Boolean)
+ .join('\n\n');
+
+ if (thinkingText) {
+ return [{ type: 'think', think: thinkingText }];
+ }
+ return [];
+ }
+
+ // If this is reasoning_recap, look at its parent for thoughts
+ if (contentType === 'reasoning_recap') {
+ return findThinkingContent(parentMapping.parent, visited);
+ }
+
+ return [];
+ };
+
// Create and save messages using the mapped IDs
const messages = [];
for (const [id, mapping] of Object.entries(conv.mapping)) {
@@ -247,8 +406,20 @@ function processConversation(conv, importBatchBuilder, requestUserId) {
continue;
}
+ const contentType = mapping.message.content?.content_type;
+
+ // Skip thoughts messages - they will be merged into the response message
+ if (contentType === 'thoughts') {
+ continue;
+ }
+
+ // Skip reasoning_recap messages (just summaries like "Thought for 44s")
+ if (contentType === 'reasoning_recap') {
+ continue;
+ }
+
const newMessageId = messageMap.get(id);
- const parentMessageId = findNonSystemParent(mapping.parent);
+ const parentMessageId = findValidParent(mapping.parent);
const messageText = formatMessageText(mapping.message);
@@ -266,7 +437,12 @@ function processConversation(conv, importBatchBuilder, requestUserId) {
}
}
- messages.push({
+ // Use create_time from ChatGPT export to ensure proper message ordering
+ // For null timestamps, use the conversation's create_time as fallback, or current time as last resort
+ const messageTime = mapping.message.create_time || conv.create_time;
+ const createdAt = messageTime ? new Date(messageTime * 1000) : new Date();
+
+ const message = {
messageId: newMessageId,
parentMessageId,
text: messageText,
@@ -275,9 +451,23 @@ function processConversation(conv, importBatchBuilder, requestUserId) {
model,
user: requestUserId,
endpoint: EModelEndpoint.openAI,
- });
+ createdAt,
+ };
+
+ // For assistant messages, check if there's thinking content in the parent chain
+ if (!isCreatedByUser) {
+ const thinkingContent = findThinkingContent(mapping.parent);
+ if (thinkingContent.length > 0) {
+ // Combine thinking content with the text response
+ message.content = [...thinkingContent, { type: 'text', text: messageText }];
+ }
+ }
+
+ messages.push(message);
}
+ adjustTimestampsForOrdering(messages);
+
for (const message of messages) {
importBatchBuilder.saveMessage(message);
}
@@ -325,17 +515,18 @@ function processAssistantMessage(messageData, messageText) {
/**
* Formats the text content of a message based on its content type and author role.
* @param {ChatGPTMessage} messageData - The message data.
- * @returns {string} - The updated message text after processing.
+ * @returns {string} - The formatted message text.
*/
function formatMessageText(messageData) {
- const isText = messageData.content.content_type === 'text';
+ const contentType = messageData.content.content_type;
+ const isText = contentType === 'text';
let messageText = '';
if (isText && messageData.content.parts) {
messageText = messageData.content.parts.join(' ');
- } else if (messageData.content.content_type === 'code') {
+ } else if (contentType === 'code') {
messageText = `\`\`\`${messageData.content.language}\n${messageData.content.text}\n\`\`\``;
- } else if (messageData.content.content_type === 'execution_output') {
+ } else if (contentType === 'execution_output') {
messageText = `Execution Output:\n> ${messageData.content.text}`;
} else if (messageData.content.parts) {
for (const part of messageData.content.parts) {
@@ -357,4 +548,33 @@ function formatMessageText(messageData) {
return messageText;
}
+/**
+ * Adjusts message timestamps to ensure children always come after parents.
+ * Messages are sorted by createdAt and buildTree expects parents to appear before children.
+ * ChatGPT exports can have slight timestamp inversions (e.g., tool call results
+ * arriving a few ms before their parent). Uses multiple passes to handle cascading adjustments.
+ *
+ * @param {Array} messages - Array of message objects with messageId, parentMessageId, and createdAt.
+ */
+function adjustTimestampsForOrdering(messages) {
+ const timestampMap = new Map();
+ messages.forEach((msg) => timestampMap.set(msg.messageId, msg.createdAt));
+
+ let hasChanges = true;
+ while (hasChanges) {
+ hasChanges = false;
+ for (const message of messages) {
+ if (message.parentMessageId && message.parentMessageId !== Constants.NO_PARENT) {
+ const parentTimestamp = timestampMap.get(message.parentMessageId);
+ if (parentTimestamp && message.createdAt <= parentTimestamp) {
+ // Bump child timestamp to 1ms after parent
+ message.createdAt = new Date(parentTimestamp.getTime() + 1);
+ timestampMap.set(message.messageId, message.createdAt);
+ hasChanges = true;
+ }
+ }
+ }
+ }
+}
+
module.exports = { getImporter, processAssistantMessage };
diff --git a/api/server/utils/import/importers.spec.js b/api/server/utils/import/importers.spec.js
index 54b2dfea73..a695a31555 100644
--- a/api/server/utils/import/importers.spec.js
+++ b/api/server/utils/import/importers.spec.js
@@ -497,6 +497,262 @@ describe('importChatGptConvo', () => {
expect(userMsg.sender).toBe('user');
expect(userMsg.isCreatedByUser).toBe(true);
});
+
+ it('should merge thinking content into assistant message', async () => {
+ const testData = [
+ {
+ title: 'Thinking Content Test',
+ create_time: 1000,
+ update_time: 2000,
+ mapping: {
+ 'root-node': {
+ id: 'root-node',
+ message: null,
+ parent: null,
+ children: ['user-msg-1'],
+ },
+ 'user-msg-1': {
+ id: 'user-msg-1',
+ message: {
+ id: 'user-msg-1',
+ author: { role: 'user' },
+ create_time: 1,
+ content: { content_type: 'text', parts: ['What is 2+2?'] },
+ metadata: {},
+ },
+ parent: 'root-node',
+ children: ['thoughts-msg'],
+ },
+ 'thoughts-msg': {
+ id: 'thoughts-msg',
+ message: {
+ id: 'thoughts-msg',
+ author: { role: 'assistant' },
+ create_time: 2,
+ content: {
+ content_type: 'thoughts',
+ thoughts: [
+ { content: 'Let me think about this math problem.' },
+ { content: 'Adding 2 and 2 together gives 4.' },
+ ],
+ },
+ metadata: {},
+ },
+ parent: 'user-msg-1',
+ children: ['reasoning-recap-msg'],
+ },
+ 'reasoning-recap-msg': {
+ id: 'reasoning-recap-msg',
+ message: {
+ id: 'reasoning-recap-msg',
+ author: { role: 'assistant' },
+ create_time: 3,
+ content: {
+ content_type: 'reasoning_recap',
+ recap_text: 'Thought for 2 seconds',
+ },
+ metadata: {},
+ },
+ parent: 'thoughts-msg',
+ children: ['assistant-msg-1'],
+ },
+ 'assistant-msg-1': {
+ id: 'assistant-msg-1',
+ message: {
+ id: 'assistant-msg-1',
+ author: { role: 'assistant' },
+ create_time: 4,
+ content: { content_type: 'text', parts: ['The answer is 4.'] },
+ metadata: {},
+ },
+ parent: 'reasoning-recap-msg',
+ children: [],
+ },
+ },
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(testData);
+ await importer(testData, requestUserId, () => importBatchBuilder);
+
+ const savedMessages = importBatchBuilder.saveMessage.mock.calls.map((call) => call[0]);
+
+ // Should only have 2 messages: user message and assistant response
+ // (thoughts and reasoning_recap should be merged/skipped)
+ expect(savedMessages).toHaveLength(2);
+
+ const userMsg = savedMessages.find((msg) => msg.text === 'What is 2+2?');
+ const assistantMsg = savedMessages.find((msg) => msg.text === 'The answer is 4.');
+
+ expect(userMsg).toBeDefined();
+ expect(assistantMsg).toBeDefined();
+
+ // Assistant message should have content array with thinking block
+ expect(assistantMsg.content).toBeDefined();
+ expect(assistantMsg.content).toHaveLength(2);
+ expect(assistantMsg.content[0].type).toBe('think');
+ expect(assistantMsg.content[0].think).toContain('Let me think about this math problem.');
+ expect(assistantMsg.content[0].think).toContain('Adding 2 and 2 together gives 4.');
+ expect(assistantMsg.content[1].type).toBe('text');
+ expect(assistantMsg.content[1].text).toBe('The answer is 4.');
+
+ // Verify parent-child relationship is correct (skips thoughts and reasoning_recap)
+ expect(assistantMsg.parentMessageId).toBe(userMsg.messageId);
+ });
+
+ it('should skip reasoning_recap and thoughts messages as separate entries', async () => {
+ const testData = [
+ {
+ title: 'Skip Thinking Messages Test',
+ create_time: 1000,
+ update_time: 2000,
+ mapping: {
+ 'root-node': {
+ id: 'root-node',
+ message: null,
+ parent: null,
+ children: ['user-msg-1'],
+ },
+ 'user-msg-1': {
+ id: 'user-msg-1',
+ message: {
+ id: 'user-msg-1',
+ author: { role: 'user' },
+ create_time: 1,
+ content: { content_type: 'text', parts: ['Hello'] },
+ metadata: {},
+ },
+ parent: 'root-node',
+ children: ['thoughts-msg'],
+ },
+ 'thoughts-msg': {
+ id: 'thoughts-msg',
+ message: {
+ id: 'thoughts-msg',
+ author: { role: 'assistant' },
+ create_time: 2,
+ content: {
+ content_type: 'thoughts',
+ thoughts: [{ content: 'Thinking...' }],
+ },
+ metadata: {},
+ },
+ parent: 'user-msg-1',
+ children: ['reasoning-recap-msg'],
+ },
+ 'reasoning-recap-msg': {
+ id: 'reasoning-recap-msg',
+ message: {
+ id: 'reasoning-recap-msg',
+ author: { role: 'assistant' },
+ create_time: 3,
+ content: {
+ content_type: 'reasoning_recap',
+ recap_text: 'Thought for 1 second',
+ },
+ metadata: {},
+ },
+ parent: 'thoughts-msg',
+ children: ['assistant-msg-1'],
+ },
+ 'assistant-msg-1': {
+ id: 'assistant-msg-1',
+ message: {
+ id: 'assistant-msg-1',
+ author: { role: 'assistant' },
+ create_time: 4,
+ content: { content_type: 'text', parts: ['Hi there!'] },
+ metadata: {},
+ },
+ parent: 'reasoning-recap-msg',
+ children: [],
+ },
+ },
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(testData);
+ await importer(testData, requestUserId, () => importBatchBuilder);
+
+ const savedMessages = importBatchBuilder.saveMessage.mock.calls.map((call) => call[0]);
+
+ // Verify no messages have thoughts or reasoning_recap content types
+ const thoughtsMessages = savedMessages.filter(
+ (msg) =>
+ msg.text === '' || msg.text?.includes('Thinking...') || msg.text?.includes('Thought for'),
+ );
+ expect(thoughtsMessages).toHaveLength(0);
+
+ // Only user and assistant text messages should be saved
+ expect(savedMessages).toHaveLength(2);
+ expect(savedMessages.map((m) => m.text).sort()).toEqual(['Hello', 'Hi there!'].sort());
+ });
+
+ it('should set createdAt from ChatGPT create_time', async () => {
+ const testData = [
+ {
+ title: 'Timestamp Test',
+ create_time: 1000,
+ update_time: 2000,
+ mapping: {
+ 'root-node': {
+ id: 'root-node',
+ message: null,
+ parent: null,
+ children: ['user-msg-1'],
+ },
+ 'user-msg-1': {
+ id: 'user-msg-1',
+ message: {
+ id: 'user-msg-1',
+ author: { role: 'user' },
+ create_time: 1000,
+ content: { content_type: 'text', parts: ['Test message'] },
+ metadata: {},
+ },
+ parent: 'root-node',
+ children: ['assistant-msg-1'],
+ },
+ 'assistant-msg-1': {
+ id: 'assistant-msg-1',
+ message: {
+ id: 'assistant-msg-1',
+ author: { role: 'assistant' },
+ create_time: 2000,
+ content: { content_type: 'text', parts: ['Response'] },
+ metadata: {},
+ },
+ parent: 'user-msg-1',
+ children: [],
+ },
+ },
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(testData);
+ await importer(testData, requestUserId, () => importBatchBuilder);
+
+ const savedMessages = importBatchBuilder.saveMessage.mock.calls.map((call) => call[0]);
+
+ const userMsg = savedMessages.find((msg) => msg.text === 'Test message');
+ const assistantMsg = savedMessages.find((msg) => msg.text === 'Response');
+
+ // Verify createdAt is set from create_time (converted from Unix timestamp)
+ expect(userMsg.createdAt).toEqual(new Date(1000 * 1000));
+ expect(assistantMsg.createdAt).toEqual(new Date(2000 * 1000));
+ });
});
describe('importLibreChatConvo', () => {
@@ -1057,3 +1313,301 @@ describe('processAssistantMessage', () => {
expect(duration).toBeLessThan(100);
});
});
+
+describe('importClaudeConvo', () => {
+ it('should import basic Claude conversation correctly', async () => {
+ const jsonData = [
+ {
+ uuid: 'conv-123',
+ name: 'Test Conversation',
+ created_at: '2025-01-15T10:00:00.000Z',
+ chat_messages: [
+ {
+ uuid: 'msg-1',
+ sender: 'human',
+ created_at: '2025-01-15T10:00:01.000Z',
+ content: [{ type: 'text', text: 'Hello Claude' }],
+ },
+ {
+ uuid: 'msg-2',
+ sender: 'assistant',
+ created_at: '2025-01-15T10:00:02.000Z',
+ content: [{ type: 'text', text: 'Hello! How can I help you?' }],
+ },
+ ],
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+ jest.spyOn(importBatchBuilder, 'startConversation');
+ jest.spyOn(importBatchBuilder, 'finishConversation');
+
+ const importer = getImporter(jsonData);
+ await importer(jsonData, requestUserId, () => importBatchBuilder);
+
+ expect(importBatchBuilder.startConversation).toHaveBeenCalledWith(EModelEndpoint.anthropic);
+ expect(importBatchBuilder.saveMessage).toHaveBeenCalledTimes(2);
+ expect(importBatchBuilder.finishConversation).toHaveBeenCalledWith(
+ 'Test Conversation',
+ expect.any(Date),
+ );
+
+ const savedMessages = importBatchBuilder.saveMessage.mock.calls.map((call) => call[0]);
+
+ // Check user message
+ const userMsg = savedMessages.find((msg) => msg.text === 'Hello Claude');
+ expect(userMsg.isCreatedByUser).toBe(true);
+ expect(userMsg.sender).toBe('user');
+ expect(userMsg.endpoint).toBe(EModelEndpoint.anthropic);
+
+ // Check assistant message
+ const assistantMsg = savedMessages.find((msg) => msg.text === 'Hello! How can I help you?');
+ expect(assistantMsg.isCreatedByUser).toBe(false);
+ expect(assistantMsg.sender).toBe('Claude');
+ expect(assistantMsg.parentMessageId).toBe(userMsg.messageId);
+ });
+
+ it('should merge thinking content into assistant message', async () => {
+ const jsonData = [
+ {
+ uuid: 'conv-123',
+ name: 'Thinking Test',
+ created_at: '2025-01-15T10:00:00.000Z',
+ chat_messages: [
+ {
+ uuid: 'msg-1',
+ sender: 'human',
+ created_at: '2025-01-15T10:00:01.000Z',
+ content: [{ type: 'text', text: 'What is 2+2?' }],
+ },
+ {
+ uuid: 'msg-2',
+ sender: 'assistant',
+ created_at: '2025-01-15T10:00:02.000Z',
+ content: [
+ { type: 'thinking', thinking: 'Let me calculate this simple math problem.' },
+ { type: 'text', text: 'The answer is 4.' },
+ ],
+ },
+ ],
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(jsonData);
+ await importer(jsonData, requestUserId, () => importBatchBuilder);
+
+ const savedMessages = importBatchBuilder.saveMessage.mock.calls.map((call) => call[0]);
+ const assistantMsg = savedMessages.find((msg) => msg.text === 'The answer is 4.');
+
+ expect(assistantMsg.content).toBeDefined();
+ expect(assistantMsg.content).toHaveLength(2);
+ expect(assistantMsg.content[0].type).toBe('think');
+ expect(assistantMsg.content[0].think).toBe('Let me calculate this simple math problem.');
+ expect(assistantMsg.content[1].type).toBe('text');
+ expect(assistantMsg.content[1].text).toBe('The answer is 4.');
+ });
+
+ it('should not include model field (Claude exports do not contain model info)', async () => {
+ const jsonData = [
+ {
+ uuid: 'conv-123',
+ name: 'No Model Test',
+ created_at: '2025-01-15T10:00:00.000Z',
+ chat_messages: [
+ {
+ uuid: 'msg-1',
+ sender: 'human',
+ created_at: '2025-01-15T10:00:01.000Z',
+ content: [{ type: 'text', text: 'Hello' }],
+ },
+ ],
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(jsonData);
+ await importer(jsonData, requestUserId, () => importBatchBuilder);
+
+ const savedMessages = importBatchBuilder.saveMessage.mock.calls.map((call) => call[0]);
+ // Model should not be explicitly set (will use ImportBatchBuilder default)
+ expect(savedMessages[0]).not.toHaveProperty('model');
+ });
+
+ it('should correct timestamp inversions (child before parent)', async () => {
+ const jsonData = [
+ {
+ uuid: 'conv-123',
+ name: 'Timestamp Inversion Test',
+ created_at: '2025-01-15T10:00:00.000Z',
+ chat_messages: [
+ {
+ uuid: 'msg-1',
+ sender: 'human',
+ created_at: '2025-01-15T10:00:05.000Z', // Later timestamp
+ content: [{ type: 'text', text: 'First message' }],
+ },
+ {
+ uuid: 'msg-2',
+ sender: 'assistant',
+ created_at: '2025-01-15T10:00:02.000Z', // Earlier timestamp (inverted)
+ content: [{ type: 'text', text: 'Second message' }],
+ },
+ ],
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(jsonData);
+ await importer(jsonData, requestUserId, () => importBatchBuilder);
+
+ const savedMessages = importBatchBuilder.saveMessage.mock.calls.map((call) => call[0]);
+ const firstMsg = savedMessages.find((msg) => msg.text === 'First message');
+ const secondMsg = savedMessages.find((msg) => msg.text === 'Second message');
+
+ // Second message should have timestamp adjusted to be after first
+ expect(new Date(secondMsg.createdAt).getTime()).toBeGreaterThan(
+ new Date(firstMsg.createdAt).getTime(),
+ );
+ });
+
+ it('should use conversation create_time for null message timestamps', async () => {
+ const convCreateTime = '2025-01-15T10:00:00.000Z';
+ const jsonData = [
+ {
+ uuid: 'conv-123',
+ name: 'Null Timestamp Test',
+ created_at: convCreateTime,
+ chat_messages: [
+ {
+ uuid: 'msg-1',
+ sender: 'human',
+ created_at: null, // Null timestamp
+ content: [{ type: 'text', text: 'Message with null time' }],
+ },
+ ],
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(jsonData);
+ await importer(jsonData, requestUserId, () => importBatchBuilder);
+
+ const savedMessages = importBatchBuilder.saveMessage.mock.calls.map((call) => call[0]);
+ expect(savedMessages[0].createdAt).toEqual(new Date(convCreateTime));
+ });
+
+ it('should use text field as fallback when content array is empty', async () => {
+ const jsonData = [
+ {
+ uuid: 'conv-123',
+ name: 'Text Fallback Test',
+ created_at: '2025-01-15T10:00:00.000Z',
+ chat_messages: [
+ {
+ uuid: 'msg-1',
+ sender: 'human',
+ created_at: '2025-01-15T10:00:01.000Z',
+ text: 'Fallback text content',
+ content: [], // Empty content array
+ },
+ ],
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(jsonData);
+ await importer(jsonData, requestUserId, () => importBatchBuilder);
+
+ const savedMessages = importBatchBuilder.saveMessage.mock.calls.map((call) => call[0]);
+ expect(savedMessages[0].text).toBe('Fallback text content');
+ });
+
+ it('should skip empty messages', async () => {
+ const jsonData = [
+ {
+ uuid: 'conv-123',
+ name: 'Skip Empty Test',
+ created_at: '2025-01-15T10:00:00.000Z',
+ chat_messages: [
+ {
+ uuid: 'msg-1',
+ sender: 'human',
+ created_at: '2025-01-15T10:00:01.000Z',
+ content: [{ type: 'text', text: 'Valid message' }],
+ },
+ {
+ uuid: 'msg-2',
+ sender: 'assistant',
+ created_at: '2025-01-15T10:00:02.000Z',
+ content: [], // Empty content
+ text: '', // Empty text
+ },
+ {
+ uuid: 'msg-3',
+ sender: 'human',
+ created_at: '2025-01-15T10:00:03.000Z',
+ content: [{ type: 'text', text: 'Another valid message' }],
+ },
+ ],
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'saveMessage');
+
+ const importer = getImporter(jsonData);
+ await importer(jsonData, requestUserId, () => importBatchBuilder);
+
+ // Should only save 2 messages (empty one skipped)
+ expect(importBatchBuilder.saveMessage).toHaveBeenCalledTimes(2);
+ });
+
+ it('should use default name for unnamed conversations', async () => {
+ const jsonData = [
+ {
+ uuid: 'conv-123',
+ name: '', // Empty name
+ created_at: '2025-01-15T10:00:00.000Z',
+ chat_messages: [
+ {
+ uuid: 'msg-1',
+ sender: 'human',
+ created_at: '2025-01-15T10:00:01.000Z',
+ content: [{ type: 'text', text: 'Hello' }],
+ },
+ ],
+ },
+ ];
+
+ const requestUserId = 'user-123';
+ const importBatchBuilder = new ImportBatchBuilder(requestUserId);
+ jest.spyOn(importBatchBuilder, 'finishConversation');
+
+ const importer = getImporter(jsonData);
+ await importer(jsonData, requestUserId, () => importBatchBuilder);
+
+ expect(importBatchBuilder.finishConversation).toHaveBeenCalledWith(
+ 'Imported Claude Chat',
+ expect.any(Date),
+ );
+ });
+});
diff --git a/api/strategies/index.js b/api/strategies/index.js
index 725e04224a..9a1c58ad38 100644
--- a/api/strategies/index.js
+++ b/api/strategies/index.js
@@ -1,14 +1,14 @@
-const appleLogin = require('./appleStrategy');
+const { setupOpenId, getOpenIdConfig, getOpenIdEmail } = require('./openidStrategy');
+const openIdJwtLogin = require('./openIdJwtStrategy');
+const facebookLogin = require('./facebookStrategy');
+const discordLogin = require('./discordStrategy');
const passportLogin = require('./localStrategy');
const googleLogin = require('./googleStrategy');
const githubLogin = require('./githubStrategy');
-const discordLogin = require('./discordStrategy');
-const facebookLogin = require('./facebookStrategy');
-const { setupOpenId, getOpenIdConfig } = require('./openidStrategy');
-const jwtLogin = require('./jwtStrategy');
-const ldapLogin = require('./ldapStrategy');
const { setupSaml } = require('./samlStrategy');
-const openIdJwtLogin = require('./openIdJwtStrategy');
+const appleLogin = require('./appleStrategy');
+const ldapLogin = require('./ldapStrategy');
+const jwtLogin = require('./jwtStrategy');
module.exports = {
appleLogin,
@@ -20,6 +20,7 @@ module.exports = {
facebookLogin,
setupOpenId,
getOpenIdConfig,
+ getOpenIdEmail,
ldapLogin,
setupSaml,
openIdJwtLogin,
diff --git a/api/strategies/openIdJwtStrategy.js b/api/strategies/openIdJwtStrategy.js
index 998a918c30..83a40bf948 100644
--- a/api/strategies/openIdJwtStrategy.js
+++ b/api/strategies/openIdJwtStrategy.js
@@ -3,8 +3,9 @@ const jwksRsa = require('jwks-rsa');
const { logger } = require('@librechat/data-schemas');
const { HttpsProxyAgent } = require('https-proxy-agent');
const { SystemRoles } = require('librechat-data-provider');
+const { isEnabled, findOpenIDUser, math } = require('@librechat/api');
const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt');
-const { isEnabled, findOpenIDUser } = require('@librechat/api');
+const { getOpenIdEmail } = require('./openidStrategy');
const { updateUser, findUser } = require('~/models');
/**
@@ -27,9 +28,7 @@ const { updateUser, findUser } = require('~/models');
const openIdJwtLogin = (openIdConfig) => {
let jwksRsaOptions = {
cache: isEnabled(process.env.OPENID_JWKS_URL_CACHE_ENABLED) || true,
- cacheMaxAge: process.env.OPENID_JWKS_URL_CACHE_TIME
- ? eval(process.env.OPENID_JWKS_URL_CACHE_TIME)
- : 60000,
+ cacheMaxAge: math(process.env.OPENID_JWKS_URL_CACHE_TIME, 60000),
jwksUri: openIdConfig.serverMetadata().jwks_uri,
};
@@ -55,7 +54,7 @@ const openIdJwtLogin = (openIdConfig) => {
const { user, error, migration } = await findOpenIDUser({
findUser,
- email: payload?.email,
+ email: payload ? getOpenIdEmail(payload) : undefined,
openidId: payload?.sub,
idOnTheSource: payload?.oid,
strategyName: 'openIdJwtLogin',
@@ -83,14 +82,24 @@ const openIdJwtLogin = (openIdConfig) => {
await updateUser(user.id, updateData);
}
- const cookieHeader = req.headers.cookie;
- const parsedCookies = cookieHeader ? cookies.parse(cookieHeader) : {};
- const accessToken = parsedCookies.openid_access_token;
- const refreshToken = parsedCookies.refreshToken;
+ /** Read tokens from session (server-side) to avoid large cookie issues */
+ const sessionTokens = req.session?.openidTokens;
+ let accessToken = sessionTokens?.accessToken;
+ let idToken = sessionTokens?.idToken;
+ let refreshToken = sessionTokens?.refreshToken;
+
+ /** Fallback to cookies for backward compatibility */
+ if (!accessToken || !refreshToken || !idToken) {
+ const cookieHeader = req.headers.cookie;
+ const parsedCookies = cookieHeader ? cookies.parse(cookieHeader) : {};
+ accessToken = accessToken || parsedCookies.openid_access_token;
+ idToken = idToken || parsedCookies.openid_id_token;
+ refreshToken = refreshToken || parsedCookies.refreshToken;
+ }
user.federatedTokens = {
access_token: accessToken || rawToken,
- id_token: rawToken,
+ id_token: idToken,
refresh_token: refreshToken,
expires_at: payload.exp,
};
diff --git a/api/strategies/openIdJwtStrategy.spec.js b/api/strategies/openIdJwtStrategy.spec.js
new file mode 100644
index 0000000000..79af848046
--- /dev/null
+++ b/api/strategies/openIdJwtStrategy.spec.js
@@ -0,0 +1,347 @@
+const { SystemRoles } = require('librechat-data-provider');
+
+// --- Capture the verify callback from JwtStrategy ---
+let capturedVerifyCallback;
+jest.mock('passport-jwt', () => ({
+ Strategy: jest.fn((_opts, verifyCallback) => {
+ capturedVerifyCallback = verifyCallback;
+ return { name: 'jwt' };
+ }),
+ ExtractJwt: {
+ fromAuthHeaderAsBearerToken: jest.fn(() => 'mock-extractor'),
+ },
+}));
+jest.mock('jwks-rsa', () => ({
+ passportJwtSecret: jest.fn(() => 'mock-secret-provider'),
+}));
+jest.mock('https-proxy-agent', () => ({
+ HttpsProxyAgent: jest.fn(),
+}));
+jest.mock('@librechat/data-schemas', () => ({
+ logger: { info: jest.fn(), warn: jest.fn(), debug: jest.fn(), error: jest.fn() },
+}));
+jest.mock('@librechat/api', () => ({
+ isEnabled: jest.fn(() => false),
+ findOpenIDUser: jest.fn(),
+ math: jest.fn((val, fallback) => fallback),
+}));
+jest.mock('~/models', () => ({
+ findUser: jest.fn(),
+ updateUser: jest.fn(),
+}));
+jest.mock('~/server/services/Files/strategies', () => ({
+ getStrategyFunctions: jest.fn(() => ({
+ saveBuffer: jest.fn().mockResolvedValue('/fake/path/to/avatar.png'),
+ })),
+}));
+jest.mock('~/server/services/Config', () => ({
+ getAppConfig: jest.fn().mockResolvedValue({}),
+}));
+jest.mock('~/cache/getLogStores', () =>
+ jest.fn().mockReturnValue({ get: jest.fn(), set: jest.fn() }),
+);
+
+const { findOpenIDUser } = require('@librechat/api');
+const openIdJwtLogin = require('./openIdJwtStrategy');
+const { findUser, updateUser } = require('~/models');
+
+// Helper: build a mock openIdConfig
+const mockOpenIdConfig = {
+ serverMetadata: () => ({ jwks_uri: 'https://example.com/.well-known/jwks.json' }),
+};
+
+// Helper: invoke the captured verify callback
+async function invokeVerify(req, payload) {
+ return new Promise((resolve, reject) => {
+ capturedVerifyCallback(req, payload, (err, user, info) => {
+ if (err) {
+ return reject(err);
+ }
+ resolve({ user, info });
+ });
+ });
+}
+
+describe('openIdJwtStrategy – token source handling', () => {
+ const baseUser = {
+ _id: { toString: () => 'user-abc' },
+ role: SystemRoles.USER,
+ provider: 'openid',
+ };
+
+ const payload = { sub: 'oidc-123', email: 'test@example.com', exp: 9999999999 };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ findOpenIDUser.mockResolvedValue({ user: { ...baseUser }, error: null, migration: false });
+ updateUser.mockResolvedValue({});
+
+ // Initialize the strategy so capturedVerifyCallback is set
+ openIdJwtLogin(mockOpenIdConfig);
+ });
+
+ it('should read all tokens from session when available', async () => {
+ const req = {
+ headers: { authorization: 'Bearer raw-bearer-token' },
+ session: {
+ openidTokens: {
+ accessToken: 'session-access',
+ idToken: 'session-id',
+ refreshToken: 'session-refresh',
+ },
+ },
+ };
+
+ const { user } = await invokeVerify(req, payload);
+
+ expect(user.federatedTokens).toEqual({
+ access_token: 'session-access',
+ id_token: 'session-id',
+ refresh_token: 'session-refresh',
+ expires_at: payload.exp,
+ });
+ });
+
+ it('should fall back to cookies when session is absent', async () => {
+ const req = {
+ headers: {
+ authorization: 'Bearer raw-bearer-token',
+ cookie:
+ 'openid_access_token=cookie-access; openid_id_token=cookie-id; refreshToken=cookie-refresh',
+ },
+ };
+
+ const { user } = await invokeVerify(req, payload);
+
+ expect(user.federatedTokens).toEqual({
+ access_token: 'cookie-access',
+ id_token: 'cookie-id',
+ refresh_token: 'cookie-refresh',
+ expires_at: payload.exp,
+ });
+ });
+
+ it('should fall back to cookie for idToken only when session lacks it', async () => {
+ const req = {
+ headers: {
+ authorization: 'Bearer raw-bearer-token',
+ cookie: 'openid_id_token=cookie-id',
+ },
+ session: {
+ openidTokens: {
+ accessToken: 'session-access',
+ // idToken intentionally missing
+ refreshToken: 'session-refresh',
+ },
+ },
+ };
+
+ const { user } = await invokeVerify(req, payload);
+
+ expect(user.federatedTokens).toEqual({
+ access_token: 'session-access',
+ id_token: 'cookie-id',
+ refresh_token: 'session-refresh',
+ expires_at: payload.exp,
+ });
+ });
+
+ it('should use raw Bearer token as access_token fallback when neither session nor cookie has one', async () => {
+ const req = {
+ headers: {
+ authorization: 'Bearer raw-bearer-token',
+ cookie: 'openid_id_token=cookie-id; refreshToken=cookie-refresh',
+ },
+ };
+
+ const { user } = await invokeVerify(req, payload);
+
+ expect(user.federatedTokens.access_token).toBe('raw-bearer-token');
+ expect(user.federatedTokens.id_token).toBe('cookie-id');
+ expect(user.federatedTokens.refresh_token).toBe('cookie-refresh');
+ });
+
+ it('should set id_token to undefined when not available in session or cookies', async () => {
+ const req = {
+ headers: {
+ authorization: 'Bearer raw-bearer-token',
+ cookie: 'openid_access_token=cookie-access; refreshToken=cookie-refresh',
+ },
+ };
+
+ const { user } = await invokeVerify(req, payload);
+
+ expect(user.federatedTokens.access_token).toBe('cookie-access');
+ expect(user.federatedTokens.id_token).toBeUndefined();
+ expect(user.federatedTokens.refresh_token).toBe('cookie-refresh');
+ });
+
+ it('should keep id_token and access_token as distinct values from cookies', async () => {
+ const req = {
+ headers: {
+ authorization: 'Bearer raw-bearer-token',
+ cookie:
+ 'openid_access_token=the-access-token; openid_id_token=the-id-token; refreshToken=the-refresh',
+ },
+ };
+
+ const { user } = await invokeVerify(req, payload);
+
+ expect(user.federatedTokens.access_token).toBe('the-access-token');
+ expect(user.federatedTokens.id_token).toBe('the-id-token');
+ expect(user.federatedTokens.access_token).not.toBe(user.federatedTokens.id_token);
+ });
+});
+
+describe('openIdJwtStrategy – OPENID_EMAIL_CLAIM', () => {
+ const payload = {
+ sub: 'oidc-123',
+ email: 'test@example.com',
+ preferred_username: 'testuser',
+ upn: 'test@corp.example.com',
+ exp: 9999999999,
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ delete process.env.OPENID_EMAIL_CLAIM;
+
+ // Use real findOpenIDUser so it delegates to the findUser mock
+ const realFindOpenIDUser = jest.requireActual('@librechat/api').findOpenIDUser;
+ findOpenIDUser.mockImplementation(realFindOpenIDUser);
+
+ findUser.mockResolvedValue(null);
+ updateUser.mockResolvedValue({});
+
+ openIdJwtLogin(mockOpenIdConfig);
+ });
+
+ afterEach(() => {
+ delete process.env.OPENID_EMAIL_CLAIM;
+ });
+
+ it('should use the default email when OPENID_EMAIL_CLAIM is not set', async () => {
+ const existingUser = {
+ _id: 'user-id-1',
+ provider: 'openid',
+ openidId: payload.sub,
+ email: payload.email,
+ role: SystemRoles.USER,
+ };
+ findUser.mockImplementation(async (query) => {
+ if (query.$or && query.$or.some((c) => c.openidId === payload.sub)) {
+ return existingUser;
+ }
+ return null;
+ });
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledWith(
+ expect.objectContaining({
+ $or: expect.arrayContaining([{ openidId: payload.sub }]),
+ }),
+ );
+ });
+
+ it('should use OPENID_EMAIL_CLAIM when set for email lookup', async () => {
+ process.env.OPENID_EMAIL_CLAIM = 'upn';
+ findUser.mockResolvedValue(null);
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ const { user } = await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledTimes(2);
+ expect(findUser.mock.calls[0][0]).toMatchObject({
+ $or: expect.arrayContaining([{ openidId: payload.sub }]),
+ });
+ expect(findUser.mock.calls[1][0]).toEqual({ email: 'test@corp.example.com' });
+ expect(user).toBe(false);
+ });
+
+ it('should fall back to default chain when OPENID_EMAIL_CLAIM points to missing claim', async () => {
+ process.env.OPENID_EMAIL_CLAIM = 'nonexistent_claim';
+ findUser.mockResolvedValue(null);
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ const { user } = await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledWith({ email: payload.email });
+ expect(user).toBe(false);
+ });
+
+ it('should trim whitespace from OPENID_EMAIL_CLAIM', async () => {
+ process.env.OPENID_EMAIL_CLAIM = ' upn ';
+ findUser.mockResolvedValue(null);
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledWith({ email: 'test@corp.example.com' });
+ });
+
+ it('should ignore empty string OPENID_EMAIL_CLAIM and use default fallback', async () => {
+ process.env.OPENID_EMAIL_CLAIM = '';
+ findUser.mockResolvedValue(null);
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledWith({ email: payload.email });
+ });
+
+ it('should ignore whitespace-only OPENID_EMAIL_CLAIM and use default fallback', async () => {
+ process.env.OPENID_EMAIL_CLAIM = ' ';
+ findUser.mockResolvedValue(null);
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ await invokeVerify(req, payload);
+
+ expect(findUser).toHaveBeenCalledWith({ email: payload.email });
+ });
+
+ it('should resolve undefined email when payload is null', async () => {
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ const { user } = await invokeVerify(req, null);
+
+ expect(user).toBe(false);
+ });
+
+ it('should attempt email lookup via preferred_username fallback when email claim is absent', async () => {
+ const payloadNoEmail = {
+ sub: 'oidc-new-sub',
+ preferred_username: 'legacy@corp.com',
+ upn: 'legacy@corp.com',
+ exp: 9999999999,
+ };
+
+ const legacyUser = {
+ _id: 'legacy-db-id',
+ email: 'legacy@corp.com',
+ openidId: null,
+ role: SystemRoles.USER,
+ };
+
+ findUser.mockImplementation(async (query) => {
+ if (query.$or) {
+ return null;
+ }
+ if (query.email === 'legacy@corp.com') {
+ return legacyUser;
+ }
+ return null;
+ });
+
+ const req = { headers: { authorization: 'Bearer tok' }, session: {} };
+ const { user } = await invokeVerify(req, payloadNoEmail);
+
+ expect(findUser).toHaveBeenCalledTimes(2);
+ expect(findUser.mock.calls[1][0]).toEqual({ email: 'legacy@corp.com' });
+ expect(user).toBeTruthy();
+ expect(updateUser).toHaveBeenCalledWith(
+ 'legacy-db-id',
+ expect.objectContaining({ provider: 'openid', openidId: payloadNoEmail.sub }),
+ );
+ });
+});
diff --git a/api/strategies/openidStrategy.js b/api/strategies/openidStrategy.js
index 455ff1bd11..0ebdcb04e1 100644
--- a/api/strategies/openidStrategy.js
+++ b/api/strategies/openidStrategy.js
@@ -6,8 +6,8 @@ const client = require('openid-client');
const jwtDecode = require('jsonwebtoken/decode');
const { HttpsProxyAgent } = require('https-proxy-agent');
const { hashToken, logger } = require('@librechat/data-schemas');
-const { CacheKeys, ErrorTypes } = require('librechat-data-provider');
const { Strategy: OpenIDStrategy } = require('openid-client/passport');
+const { CacheKeys, ErrorTypes, SystemRoles } = require('librechat-data-provider');
const {
isEnabled,
logHeaders,
@@ -99,9 +99,14 @@ This violates RFC 7235 and may cause issues with strict OAuth clients. Removing
/** @typedef {Configuration | null} */
let openidConfig = null;
-//overload currenturl function because of express version 4 buggy req.host doesn't include port
-//More info https://github.com/panva/openid-client/pull/713
-
+/**
+ * Custom OpenID Strategy
+ *
+ * Note: Originally overrode currentUrl() to work around Express 4's req.host not including port.
+ * With Express 5, req.host now includes the port by default, but we continue to use DOMAIN_SERVER
+ * for consistency and explicit configuration control.
+ * More info: https://github.com/panva/openid-client/pull/713
+ */
class CustomOpenIDStrategy extends OpenIDStrategy {
currentUrl(req) {
const hostAndProtocol = process.env.DOMAIN_SERVER;
@@ -262,6 +267,34 @@ function getFullName(userinfo) {
return userinfo.username || userinfo.email;
}
+/**
+ * Resolves the user identifier from OpenID claims.
+ * Configurable via OPENID_EMAIL_CLAIM; defaults to: email -> preferred_username -> upn.
+ *
+ * @param {Object} userinfo - The user information object from OpenID Connect
+ * @returns {string|undefined} The resolved identifier string
+ */
+function getOpenIdEmail(userinfo) {
+ const claimKey = process.env.OPENID_EMAIL_CLAIM?.trim();
+ if (claimKey) {
+ const value = userinfo[claimKey];
+ if (typeof value === 'string' && value) {
+ return value;
+ }
+ if (value !== undefined && value !== null) {
+ logger.warn(
+ `[openidStrategy] OPENID_EMAIL_CLAIM="${claimKey}" resolved to a non-string value (type: ${typeof value}). Falling back to: email -> preferred_username -> upn.`,
+ );
+ } else {
+ logger.warn(
+ `[openidStrategy] OPENID_EMAIL_CLAIM="${claimKey}" not present in userinfo. Falling back to: email -> preferred_username -> upn.`,
+ );
+ }
+ }
+ const fallback = userinfo.email || userinfo.preferred_username || userinfo.upn;
+ return typeof fallback === 'string' ? fallback : undefined;
+}
+
/**
* Converts an input into a string suitable for a username.
* If the input is a string, it will be returned as is.
@@ -282,6 +315,367 @@ function convertToUsername(input, defaultValue = '') {
return defaultValue;
}
+/**
+ * Resolve Azure AD groups when group overage is in effect (groups moved to _claim_names/_claim_sources).
+ *
+ * NOTE: Microsoft recommends treating _claim_names/_claim_sources as a signal only and using Microsoft Graph
+ * to resolve group membership instead of calling the endpoint in _claim_sources directly.
+ *
+ * @param {string} accessToken - Access token with Microsoft Graph permissions
+ * @returns {Promise} Resolved group IDs or null on failure
+ * @see https://learn.microsoft.com/en-us/entra/identity-platform/access-token-claims-reference#groups-overage-claim
+ * @see https://learn.microsoft.com/en-us/graph/api/directoryobject-getmemberobjects
+ */
+async function resolveGroupsFromOverage(accessToken) {
+ try {
+ if (!accessToken) {
+ logger.error('[openidStrategy] Access token missing; cannot resolve group overage');
+ return null;
+ }
+
+ // Use /me/getMemberObjects so least-privileged delegated permission User.Read is sufficient
+ // when resolving the signed-in user's group membership.
+ const url = 'https://graph.microsoft.com/v1.0/me/getMemberObjects';
+
+ logger.debug(
+ `[openidStrategy] Detected group overage, resolving groups via Microsoft Graph getMemberObjects: ${url}`,
+ );
+
+ const fetchOptions = {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ securityEnabledOnly: false }),
+ };
+
+ if (process.env.PROXY) {
+ const { ProxyAgent } = undici;
+ fetchOptions.dispatcher = new ProxyAgent(process.env.PROXY);
+ }
+
+ const response = await undici.fetch(url, fetchOptions);
+ if (!response.ok) {
+ logger.error(
+ `[openidStrategy] Failed to resolve groups via Microsoft Graph getMemberObjects: HTTP ${response.status} ${response.statusText}`,
+ );
+ return null;
+ }
+
+ const data = await response.json();
+ const values = Array.isArray(data?.value) ? data.value : null;
+ if (!values) {
+ logger.error(
+ '[openidStrategy] Unexpected response format when resolving groups via Microsoft Graph getMemberObjects',
+ );
+ return null;
+ }
+ const groupIds = values.filter((id) => typeof id === 'string');
+
+ logger.debug(
+ `[openidStrategy] Successfully resolved ${groupIds.length} groups via Microsoft Graph getMemberObjects`,
+ );
+ return groupIds;
+ } catch (err) {
+ logger.error(
+ '[openidStrategy] Error resolving groups via Microsoft Graph getMemberObjects:',
+ err,
+ );
+ return null;
+ }
+}
+
+/**
+ * Process OpenID authentication tokenset and userinfo
+ * This is the core logic extracted from the passport strategy callback
+ * Can be reused by both the passport strategy and proxy authentication
+ *
+ * @param {Object} tokenset - The OpenID tokenset containing access_token, id_token, etc.
+ * @param {boolean} existingUsersOnly - If true, only existing users will be processed
+ * @returns {Promise} The authenticated user object with tokenset
+ */
+async function processOpenIDAuth(tokenset, existingUsersOnly = false) {
+ const claims = tokenset.claims ? tokenset.claims() : tokenset;
+ const userinfo = {
+ ...claims,
+ };
+
+ if (tokenset.access_token) {
+ const providerUserinfo = await getUserInfo(openidConfig, tokenset.access_token, claims.sub);
+ Object.assign(userinfo, providerUserinfo);
+ }
+
+ const appConfig = await getAppConfig();
+ const email = getOpenIdEmail(userinfo);
+ if (!isEmailDomainAllowed(email, appConfig?.registration?.allowedDomains)) {
+ logger.error(
+ `[OpenID Strategy] Authentication blocked - email domain not allowed [Identifier: ${email}]`,
+ );
+ throw new Error('Email domain not allowed');
+ }
+
+ const result = await findOpenIDUser({
+ findUser,
+ email: email,
+ openidId: claims.sub || userinfo.sub,
+ idOnTheSource: claims.oid || userinfo.oid,
+ strategyName: 'openidStrategy',
+ });
+ let user = result.user;
+ const error = result.error;
+
+ if (error) {
+ throw new Error(ErrorTypes.AUTH_FAILED);
+ }
+
+ const fullName = getFullName(userinfo);
+
+ const requiredRole = process.env.OPENID_REQUIRED_ROLE;
+ if (requiredRole) {
+ const requiredRoles = requiredRole
+ .split(',')
+ .map((role) => role.trim())
+ .filter(Boolean);
+ const requiredRoleParameterPath = process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH;
+ const requiredRoleTokenKind = process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND;
+
+ let decodedToken = '';
+ if (requiredRoleTokenKind === 'access' && tokenset.access_token) {
+ decodedToken = jwtDecode(tokenset.access_token);
+ } else if (requiredRoleTokenKind === 'id' && tokenset.id_token) {
+ decodedToken = jwtDecode(tokenset.id_token);
+ }
+
+ let roles = get(decodedToken, requiredRoleParameterPath);
+
+ // Handle Azure AD group overage for ID token groups: when hasgroups or _claim_* indicate overage,
+ // resolve groups via Microsoft Graph instead of relying on token group values.
+ if (
+ !Array.isArray(roles) &&
+ typeof roles !== 'string' &&
+ requiredRoleTokenKind === 'id' &&
+ requiredRoleParameterPath === 'groups' &&
+ decodedToken &&
+ (decodedToken.hasgroups ||
+ (decodedToken._claim_names?.groups &&
+ decodedToken._claim_sources?.[decodedToken._claim_names.groups]))
+ ) {
+ const overageGroups = await resolveGroupsFromOverage(tokenset.access_token);
+ if (overageGroups) {
+ roles = overageGroups;
+ }
+ }
+
+ if (!roles || (!Array.isArray(roles) && typeof roles !== 'string')) {
+ logger.error(
+ `[openidStrategy] Key '${requiredRoleParameterPath}' not found in ${requiredRoleTokenKind} token!`,
+ );
+ const rolesList =
+ requiredRoles.length === 1
+ ? `"${requiredRoles[0]}"`
+ : `one of: ${requiredRoles.map((r) => `"${r}"`).join(', ')}`;
+ throw new Error(`You must have ${rolesList} role to log in.`);
+ }
+
+ const roleValues = Array.isArray(roles) ? roles : roles.split(/[\s,]+/).filter(Boolean);
+
+ if (!requiredRoles.some((role) => roleValues.includes(role))) {
+ const rolesList =
+ requiredRoles.length === 1
+ ? `"${requiredRoles[0]}"`
+ : `one of: ${requiredRoles.map((r) => `"${r}"`).join(', ')}`;
+ throw new Error(`You must have ${rolesList} role to log in.`);
+ }
+ }
+
+ let username = '';
+ if (process.env.OPENID_USERNAME_CLAIM) {
+ username = userinfo[process.env.OPENID_USERNAME_CLAIM];
+ } else {
+ username = convertToUsername(
+ userinfo.preferred_username || userinfo.username || userinfo.email,
+ );
+ }
+
+ if (existingUsersOnly && !user) {
+ throw new Error('User does not exist');
+ }
+
+ if (!user) {
+ user = {
+ provider: 'openid',
+ openidId: userinfo.sub,
+ username,
+ email: email || '',
+ emailVerified: userinfo.email_verified || false,
+ name: fullName,
+ idOnTheSource: userinfo.oid,
+ };
+
+ const balanceConfig = getBalanceConfig(appConfig);
+ user = await createUser(user, balanceConfig, true, true);
+ } else {
+ user.provider = 'openid';
+ user.openidId = userinfo.sub;
+ user.username = username;
+ user.name = fullName;
+ user.idOnTheSource = userinfo.oid;
+ if (email && email !== user.email) {
+ user.email = email;
+ user.emailVerified = userinfo.email_verified || false;
+ }
+ }
+
+ const adminRole = process.env.OPENID_ADMIN_ROLE;
+ const adminRoleParameterPath = process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH;
+ const adminRoleTokenKind = process.env.OPENID_ADMIN_ROLE_TOKEN_KIND;
+
+ if (adminRole && adminRoleParameterPath && adminRoleTokenKind) {
+ let adminRoleObject;
+ switch (adminRoleTokenKind) {
+ case 'access':
+ adminRoleObject = jwtDecode(tokenset.access_token);
+ break;
+ case 'id':
+ adminRoleObject = jwtDecode(tokenset.id_token);
+ break;
+ case 'userinfo':
+ adminRoleObject = userinfo;
+ break;
+ default:
+ logger.error(
+ `[openidStrategy] Invalid admin role token kind: ${adminRoleTokenKind}. Must be one of 'access', 'id', or 'userinfo'.`,
+ );
+ throw new Error('Invalid admin role token kind');
+ }
+
+ const adminRoles = get(adminRoleObject, adminRoleParameterPath);
+ let adminRoleValues = [];
+ if (Array.isArray(adminRoles)) {
+ adminRoleValues = adminRoles;
+ } else if (typeof adminRoles === 'string') {
+ adminRoleValues = adminRoles.split(/[\s,]+/).filter(Boolean);
+ }
+
+ if (adminRoles && (adminRoles === true || adminRoleValues.includes(adminRole))) {
+ user.role = SystemRoles.ADMIN;
+ logger.info(`[openidStrategy] User ${username} is an admin based on role: ${adminRole}`);
+ } else if (user.role === SystemRoles.ADMIN) {
+ user.role = SystemRoles.USER;
+ logger.info(
+ `[openidStrategy] User ${username} demoted from admin - role no longer present in token`,
+ );
+ }
+ }
+
+ if (!!userinfo && userinfo.picture && !user.avatar?.includes('manual=true')) {
+ /** @type {string | undefined} */
+ const imageUrl = userinfo.picture;
+
+ let fileName;
+ if (crypto) {
+ fileName = (await hashToken(userinfo.sub)) + '.png';
+ } else {
+ fileName = userinfo.sub + '.png';
+ }
+
+ const imageBuffer = await downloadImage(
+ imageUrl,
+ openidConfig,
+ tokenset.access_token,
+ userinfo.sub,
+ );
+ if (imageBuffer) {
+ const { saveBuffer } = getStrategyFunctions(
+ appConfig?.fileStrategy ?? process.env.CDN_PROVIDER,
+ );
+ const imagePath = await saveBuffer({
+ fileName,
+ userId: user._id.toString(),
+ buffer: imageBuffer,
+ });
+ user.avatar = imagePath ?? '';
+ }
+ }
+
+ user = await updateUser(user._id, user);
+
+ logger.info(
+ `[openidStrategy] login success openidId: ${user.openidId} | email: ${user.email} | username: ${user.username} `,
+ {
+ user: {
+ openidId: user.openidId,
+ username: user.username,
+ email: user.email,
+ name: user.name,
+ },
+ },
+ );
+
+ return {
+ ...user,
+ tokenset,
+ federatedTokens: {
+ access_token: tokenset.access_token,
+ id_token: tokenset.id_token,
+ refresh_token: tokenset.refresh_token,
+ expires_at: tokenset.expires_at,
+ },
+ };
+}
+
+/**
+ * @param {boolean | undefined} [existingUsersOnly]
+ */
+function createOpenIDCallback(existingUsersOnly) {
+ return async (tokenset, done) => {
+ try {
+ const user = await processOpenIDAuth(tokenset, existingUsersOnly);
+ done(null, user);
+ } catch (err) {
+ if (err.message === 'Email domain not allowed') {
+ return done(null, false, { message: err.message });
+ }
+ if (err.message === ErrorTypes.AUTH_FAILED) {
+ return done(null, false, { message: err.message });
+ }
+ if (err.message && err.message.includes('role to log in')) {
+ return done(null, false, { message: err.message });
+ }
+ logger.error('[openidStrategy] login failed', err);
+ done(err);
+ }
+ };
+}
+
+/**
+ * Sets up the OpenID strategy specifically for admin authentication.
+ * @param {Configuration} openidConfig
+ */
+const setupOpenIdAdmin = (openidConfig) => {
+ try {
+ if (!openidConfig) {
+ throw new Error('OpenID configuration not initialized');
+ }
+
+ const openidAdminLogin = new CustomOpenIDStrategy(
+ {
+ config: openidConfig,
+ scope: process.env.OPENID_SCOPE,
+ usePKCE: isEnabled(process.env.OPENID_USE_PKCE),
+ clockTolerance: process.env.OPENID_CLOCK_TOLERANCE || 300,
+ callbackURL: process.env.DOMAIN_SERVER + '/api/admin/oauth/openid/callback',
+ },
+ createOpenIDCallback(true),
+ );
+
+ passport.use('openidAdmin', openidAdminLogin);
+ } catch (err) {
+ logger.error('[openidStrategy] setupOpenIdAdmin', err);
+ }
+};
+
/**
* Sets up the OpenID strategy for authentication.
* This function configures the OpenID client, handles proxy settings,
@@ -319,10 +713,6 @@ async function setupOpenId() {
},
);
- const requiredRole = process.env.OPENID_REQUIRED_ROLE;
- const requiredRoleParameterPath = process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH;
- const requiredRoleTokenKind = process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND;
- const usePKCE = isEnabled(process.env.OPENID_USE_PKCE);
logger.info(`[openidStrategy] OpenID authentication configuration`, {
generateNonce: shouldGenerateNonce,
reason: shouldGenerateNonce
@@ -330,241 +720,25 @@ async function setupOpenId() {
: 'OPENID_GENERATE_NONCE=false - Standard flow without explicit nonce or metadata',
});
- // Set of env variables that specify how to set if a user is an admin
- // If not set, all users will be treated as regular users
- const adminRole = process.env.OPENID_ADMIN_ROLE;
- const adminRoleParameterPath = process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH;
- const adminRoleTokenKind = process.env.OPENID_ADMIN_ROLE_TOKEN_KIND;
-
const openidLogin = new CustomOpenIDStrategy(
{
config: openidConfig,
scope: process.env.OPENID_SCOPE,
callbackURL: process.env.DOMAIN_SERVER + process.env.OPENID_CALLBACK_URL,
clockTolerance: process.env.OPENID_CLOCK_TOLERANCE || 300,
- usePKCE,
- },
- /**
- * @param {import('openid-client').TokenEndpointResponseHelpers} tokenset
- * @param {import('passport-jwt').VerifyCallback} done
- */
- async (tokenset, done) => {
- try {
- const claims = tokenset.claims();
- const userinfo = {
- ...claims,
- ...(await getUserInfo(openidConfig, tokenset.access_token, claims.sub)),
- };
-
- const appConfig = await getAppConfig();
- /** Azure AD sometimes doesn't return email, use preferred_username as fallback */
- const email = userinfo.email || userinfo.preferred_username || userinfo.upn;
- if (!isEmailDomainAllowed(email, appConfig?.registration?.allowedDomains)) {
- logger.error(
- `[OpenID Strategy] Authentication blocked - email domain not allowed [Email: ${email}]`,
- );
- return done(null, false, { message: 'Email domain not allowed' });
- }
-
- const result = await findOpenIDUser({
- findUser,
- email: email,
- openidId: claims.sub,
- idOnTheSource: claims.oid,
- strategyName: 'openidStrategy',
- });
- let user = result.user;
- const error = result.error;
-
- if (error) {
- return done(null, false, {
- message: ErrorTypes.AUTH_FAILED,
- });
- }
-
- const fullName = getFullName(userinfo);
-
- if (requiredRole) {
- const requiredRoles = requiredRole
- .split(',')
- .map((role) => role.trim())
- .filter(Boolean);
- let decodedToken = '';
- if (requiredRoleTokenKind === 'access') {
- decodedToken = jwtDecode(tokenset.access_token);
- } else if (requiredRoleTokenKind === 'id') {
- decodedToken = jwtDecode(tokenset.id_token);
- }
-
- let roles = get(decodedToken, requiredRoleParameterPath);
- if (!roles || (!Array.isArray(roles) && typeof roles !== 'string')) {
- logger.error(
- `[openidStrategy] Key '${requiredRoleParameterPath}' not found or invalid type in ${requiredRoleTokenKind} token!`,
- );
- const rolesList =
- requiredRoles.length === 1
- ? `"${requiredRoles[0]}"`
- : `one of: ${requiredRoles.map((r) => `"${r}"`).join(', ')}`;
- return done(null, false, {
- message: `You must have ${rolesList} role to log in.`,
- });
- }
-
- if (!requiredRoles.some((role) => roles.includes(role))) {
- const rolesList =
- requiredRoles.length === 1
- ? `"${requiredRoles[0]}"`
- : `one of: ${requiredRoles.map((r) => `"${r}"`).join(', ')}`;
- return done(null, false, {
- message: `You must have ${rolesList} role to log in.`,
- });
- }
- }
-
- let username = '';
- if (process.env.OPENID_USERNAME_CLAIM) {
- username = userinfo[process.env.OPENID_USERNAME_CLAIM];
- } else {
- username = convertToUsername(
- userinfo.preferred_username || userinfo.username || userinfo.email,
- );
- }
-
- if (!user) {
- user = {
- provider: 'openid',
- openidId: userinfo.sub,
- username,
- email: email || '',
- emailVerified: userinfo.email_verified || false,
- name: fullName,
- idOnTheSource: userinfo.oid,
- };
-
- const balanceConfig = getBalanceConfig(appConfig);
- user = await createUser(user, balanceConfig, true, true);
- } else {
- user.provider = 'openid';
- user.openidId = userinfo.sub;
- user.username = username;
- user.name = fullName;
- user.idOnTheSource = userinfo.oid;
- if (email && email !== user.email) {
- user.email = email;
- user.emailVerified = userinfo.email_verified || false;
- }
- }
-
- if (adminRole && adminRoleParameterPath && adminRoleTokenKind) {
- let adminRoleObject;
- switch (adminRoleTokenKind) {
- case 'access':
- adminRoleObject = jwtDecode(tokenset.access_token);
- break;
- case 'id':
- adminRoleObject = jwtDecode(tokenset.id_token);
- break;
- case 'userinfo':
- adminRoleObject = userinfo;
- break;
- default:
- logger.error(
- `[openidStrategy] Invalid admin role token kind: ${adminRoleTokenKind}. Must be one of 'access', 'id', or 'userinfo'.`,
- );
- return done(new Error('Invalid admin role token kind'));
- }
-
- const adminRoles = get(adminRoleObject, adminRoleParameterPath);
-
- // Accept 3 types of values for the object extracted from adminRoleParameterPath:
- // 1. A boolean value indicating if the user is an admin
- // 2. A string with a single role name
- // 3. An array of role names
-
- if (
- adminRoles &&
- (adminRoles === true ||
- adminRoles === adminRole ||
- (Array.isArray(adminRoles) && adminRoles.includes(adminRole)))
- ) {
- user.role = 'ADMIN';
- logger.info(
- `[openidStrategy] User ${username} is an admin based on role: ${adminRole}`,
- );
- } else if (user.role === 'ADMIN') {
- user.role = 'USER';
- logger.info(
- `[openidStrategy] User ${username} demoted from admin - role no longer present in token`,
- );
- }
- }
-
- if (!!userinfo && userinfo.picture && !user.avatar?.includes('manual=true')) {
- /** @type {string | undefined} */
- const imageUrl = userinfo.picture;
-
- let fileName;
- if (crypto) {
- fileName = (await hashToken(userinfo.sub)) + '.png';
- } else {
- fileName = userinfo.sub + '.png';
- }
-
- const imageBuffer = await downloadImage(
- imageUrl,
- openidConfig,
- tokenset.access_token,
- userinfo.sub,
- );
- if (imageBuffer) {
- const { saveBuffer } = getStrategyFunctions(
- appConfig?.fileStrategy ?? process.env.CDN_PROVIDER,
- );
- const imagePath = await saveBuffer({
- fileName,
- userId: user._id.toString(),
- buffer: imageBuffer,
- });
- user.avatar = imagePath ?? '';
- }
- }
-
- user = await updateUser(user._id, user);
-
- logger.info(
- `[openidStrategy] login success openidId: ${user.openidId} | email: ${user.email} | username: ${user.username} `,
- {
- user: {
- openidId: user.openidId,
- username: user.username,
- email: user.email,
- name: user.name,
- },
- },
- );
-
- done(null, {
- ...user,
- tokenset,
- federatedTokens: {
- access_token: tokenset.access_token,
- refresh_token: tokenset.refresh_token,
- expires_at: tokenset.expires_at,
- },
- });
- } catch (err) {
- logger.error('[openidStrategy] login failed', err);
- done(err);
- }
+ usePKCE: isEnabled(process.env.OPENID_USE_PKCE),
},
+ createOpenIDCallback(),
);
passport.use('openid', openidLogin);
+ setupOpenIdAdmin(openidConfig);
return openidConfig;
} catch (err) {
logger.error('[openidStrategy]', err);
return null;
}
}
+
/**
* @function getOpenIdConfig
* @description Returns the OpenID client instance.
@@ -581,4 +755,5 @@ function getOpenIdConfig() {
module.exports = {
setupOpenId,
getOpenIdConfig,
+ getOpenIdEmail,
};
diff --git a/api/strategies/openidStrategy.spec.js b/api/strategies/openidStrategy.spec.js
index 9ac22ff42f..485b77829e 100644
--- a/api/strategies/openidStrategy.spec.js
+++ b/api/strategies/openidStrategy.spec.js
@@ -1,3 +1,4 @@
+const undici = require('undici');
const fetch = require('node-fetch');
const jwtDecode = require('jsonwebtoken/decode');
const { ErrorTypes } = require('librechat-data-provider');
@@ -7,6 +8,10 @@ const { setupOpenId } = require('./openidStrategy');
// --- Mocks ---
jest.mock('node-fetch');
jest.mock('jsonwebtoken/decode');
+jest.mock('undici', () => ({
+ fetch: jest.fn(),
+ ProxyAgent: jest.fn(),
+}));
jest.mock('~/server/services/Files/strategies', () => ({
getStrategyFunctions: jest.fn(() => ({
saveBuffer: jest.fn().mockResolvedValue('/fake/path/to/avatar.png'),
@@ -64,21 +69,36 @@ jest.mock('openid-client', () => {
});
jest.mock('openid-client/passport', () => {
- let verifyCallback;
+ /** Store callbacks by strategy name - 'openid' and 'openidAdmin' */
+ const verifyCallbacks = {};
+ let lastVerifyCallback;
+
const mockStrategy = jest.fn((options, verify) => {
- verifyCallback = verify;
+ lastVerifyCallback = verify;
return { name: 'openid', options, verify };
});
return {
Strategy: mockStrategy,
- __getVerifyCallback: () => verifyCallback,
+ /** Get the last registered callback (for backward compatibility) */
+ __getVerifyCallback: () => lastVerifyCallback,
+ /** Store callback by name when passport.use is called */
+ __setVerifyCallback: (name, callback) => {
+ verifyCallbacks[name] = callback;
+ },
+ /** Get callback by strategy name */
+ __getVerifyCallbackByName: (name) => verifyCallbacks[name],
};
});
-// Mock passport
+// Mock passport - capture strategy name and callback
jest.mock('passport', () => ({
- use: jest.fn(),
+ use: jest.fn((name, strategy) => {
+ const passportMock = require('openid-client/passport');
+ if (strategy && strategy.verify) {
+ passportMock.__setVerifyCallback(name, strategy.verify);
+ }
+ }),
}));
describe('setupOpenId', () => {
@@ -132,6 +152,7 @@ describe('setupOpenId', () => {
process.env.OPENID_ADMIN_ROLE_TOKEN_KIND = 'id';
delete process.env.OPENID_USERNAME_CLAIM;
delete process.env.OPENID_NAME_CLAIM;
+ delete process.env.OPENID_EMAIL_CLAIM;
delete process.env.PROXY;
delete process.env.OPENID_USE_PKCE;
@@ -159,9 +180,10 @@ describe('setupOpenId', () => {
};
fetch.mockResolvedValue(fakeResponse);
- // Call the setup function and capture the verify callback
+ // Call the setup function and capture the verify callback for the regular 'openid' strategy
+ // (not 'openidAdmin' which requires existing users)
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
});
it('should create a new user with correct username when preferred_username claim exists', async () => {
@@ -344,6 +366,81 @@ describe('setupOpenId', () => {
expect(details.message).toBe('You must have "requiredRole" role to log in.');
});
+ it('should not treat substring matches in string roles as satisfying required role', async () => {
+ // Arrange – override required role to "read" then re-setup
+ process.env.OPENID_REQUIRED_ROLE = 'read';
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ // Token contains "bread" which *contains* "read" as a substring
+ jwtDecode.mockReturnValue({
+ roles: 'bread',
+ });
+
+ // Act
+ const { user, details } = await validate(tokenset);
+
+ // Assert – verify that substring match does not grant access
+ expect(user).toBe(false);
+ expect(details.message).toBe('You must have "read" role to log in.');
+ });
+
+ it('should allow login when roles claim is a space-separated string containing the required role', async () => {
+ // Arrange – IdP returns roles as a space-delimited string
+ jwtDecode.mockReturnValue({
+ roles: 'role1 role2 requiredRole',
+ });
+
+ // Act
+ const { user } = await validate(tokenset);
+
+ // Assert – login succeeds when required role is present after splitting
+ expect(user).toBeTruthy();
+ expect(createUser).toHaveBeenCalled();
+ });
+
+ it('should allow login when roles claim is a comma-separated string containing the required role', async () => {
+ // Arrange – IdP returns roles as a comma-delimited string
+ jwtDecode.mockReturnValue({
+ roles: 'role1,role2,requiredRole',
+ });
+
+ // Act
+ const { user } = await validate(tokenset);
+
+ // Assert – login succeeds when required role is present after splitting
+ expect(user).toBeTruthy();
+ expect(createUser).toHaveBeenCalled();
+ });
+
+ it('should allow login when roles claim is a mixed comma-and-space-separated string containing the required role', async () => {
+ // Arrange – IdP returns roles with comma-and-space delimiters
+ jwtDecode.mockReturnValue({
+ roles: 'role1, role2, requiredRole',
+ });
+
+ // Act
+ const { user } = await validate(tokenset);
+
+ // Assert – login succeeds when required role is present after splitting
+ expect(user).toBeTruthy();
+ expect(createUser).toHaveBeenCalled();
+ });
+
+ it('should reject login when roles claim is a space-separated string that does not contain the required role', async () => {
+ // Arrange – IdP returns a delimited string but required role is absent
+ jwtDecode.mockReturnValue({
+ roles: 'role1 role2 otherRole',
+ });
+
+ // Act
+ const { user, details } = await validate(tokenset);
+
+ // Assert – login is rejected with the correct error message
+ expect(user).toBe(false);
+ expect(details.message).toBe('You must have "requiredRole" role to log in.');
+ });
+
it('should allow login when single required role is present (backward compatibility)', async () => {
// Arrange – ensure single role configuration (as set in beforeEach)
// OPENID_REQUIRED_ROLE = 'requiredRole'
@@ -362,6 +459,292 @@ describe('setupOpenId', () => {
expect(createUser).toHaveBeenCalled();
});
+ describe('group overage and groups handling', () => {
+ it.each([
+ ['groups array contains required group', ['group-required', 'other-group'], true, undefined],
+ [
+ 'groups array missing required group',
+ ['other-group'],
+ false,
+ 'You must have "group-required" role to log in.',
+ ],
+ ['groups string equals required group', 'group-required', true, undefined],
+ [
+ 'groups string is other group',
+ 'other-group',
+ false,
+ 'You must have "group-required" role to log in.',
+ ],
+ ])(
+ 'uses groups claim directly when %s (no overage)',
+ async (_label, groupsClaim, expectedAllowed, expectedMessage) => {
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+
+ jwtDecode.mockReturnValue({
+ groups: groupsClaim,
+ permissions: ['admin'],
+ });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ const { user, details } = await validate(tokenset);
+
+ expect(undici.fetch).not.toHaveBeenCalled();
+ expect(Boolean(user)).toBe(expectedAllowed);
+ expect(details?.message).toBe(expectedMessage);
+ },
+ );
+
+ it.each([
+ ['token kind is not id', { kind: 'access', path: 'groups', decoded: { hasgroups: true } }],
+ ['parameter path is not groups', { kind: 'id', path: 'roles', decoded: { hasgroups: true } }],
+ ['decoded token is falsy', { kind: 'id', path: 'groups', decoded: null }],
+ [
+ 'no overage indicators in decoded token',
+ {
+ kind: 'id',
+ path: 'groups',
+ decoded: {
+ permissions: ['admin'],
+ },
+ },
+ ],
+ [
+ 'only _claim_names present (no _claim_sources)',
+ {
+ kind: 'id',
+ path: 'groups',
+ decoded: {
+ _claim_names: { groups: 'src1' },
+ permissions: ['admin'],
+ },
+ },
+ ],
+ [
+ 'only _claim_sources present (no _claim_names)',
+ {
+ kind: 'id',
+ path: 'groups',
+ decoded: {
+ _claim_sources: { src1: { endpoint: 'https://graph.windows.net/ignored' } },
+ permissions: ['admin'],
+ },
+ },
+ ],
+ ])('does not attempt overage resolution when %s', async (_label, cfg) => {
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = cfg.path;
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = cfg.kind;
+
+ jwtDecode.mockReturnValue(cfg.decoded);
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ const { user, details } = await validate(tokenset);
+
+ expect(undici.fetch).not.toHaveBeenCalled();
+ expect(user).toBe(false);
+ expect(details.message).toBe('You must have "group-required" role to log in.');
+ const { logger } = require('@librechat/data-schemas');
+ const expectedTokenKind = cfg.kind === 'access' ? 'access token' : 'id token';
+ expect(logger.error).toHaveBeenCalledWith(
+ expect.stringContaining(`Key '${cfg.path}' not found in ${expectedTokenKind}!`),
+ );
+ });
+ });
+
+ describe('resolving groups via Microsoft Graph', () => {
+ it('denies login and does not call Graph when access token is missing', async () => {
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+
+ const { logger } = require('@librechat/data-schemas');
+
+ jwtDecode.mockReturnValue({
+ hasgroups: true,
+ permissions: ['admin'],
+ });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ const tokensetWithoutAccess = {
+ ...tokenset,
+ access_token: undefined,
+ };
+
+ const { user, details } = await validate(tokensetWithoutAccess);
+
+ expect(user).toBe(false);
+ expect(details.message).toBe('You must have "group-required" role to log in.');
+
+ expect(undici.fetch).not.toHaveBeenCalled();
+ expect(logger.error).toHaveBeenCalledWith(
+ expect.stringContaining('Access token missing; cannot resolve group overage'),
+ );
+ });
+
+ it.each([
+ [
+ 'Graph returns HTTP error',
+ async () => ({
+ ok: false,
+ status: 403,
+ statusText: 'Forbidden',
+ json: async () => ({}),
+ }),
+ [
+ '[openidStrategy] Failed to resolve groups via Microsoft Graph getMemberObjects: HTTP 403 Forbidden',
+ ],
+ ],
+ [
+ 'Graph network error',
+ async () => {
+ throw new Error('network error');
+ },
+ [
+ '[openidStrategy] Error resolving groups via Microsoft Graph getMemberObjects:',
+ expect.any(Error),
+ ],
+ ],
+ [
+ 'Graph returns unexpected shape (no value)',
+ async () => ({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({}),
+ }),
+ [
+ '[openidStrategy] Unexpected response format when resolving groups via Microsoft Graph getMemberObjects',
+ ],
+ ],
+ [
+ 'Graph returns invalid value type',
+ async () => ({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({ value: 'not-an-array' }),
+ }),
+ [
+ '[openidStrategy] Unexpected response format when resolving groups via Microsoft Graph getMemberObjects',
+ ],
+ ],
+ ])(
+ 'denies login when overage resolution fails because %s',
+ async (_label, setupFetch, expectedErrorArgs) => {
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+
+ const { logger } = require('@librechat/data-schemas');
+
+ jwtDecode.mockReturnValue({
+ hasgroups: true,
+ permissions: ['admin'],
+ });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ undici.fetch.mockImplementation(setupFetch);
+
+ const { user, details } = await validate(tokenset);
+
+ expect(undici.fetch).toHaveBeenCalled();
+ expect(user).toBe(false);
+ expect(details.message).toBe('You must have "group-required" role to log in.');
+
+ expect(logger.error).toHaveBeenCalledWith(...expectedErrorArgs);
+ },
+ );
+
+ it.each([
+ [
+ 'hasgroups overage and Graph contains required group',
+ {
+ hasgroups: true,
+ },
+ ['group-required', 'some-other-group'],
+ true,
+ ],
+ [
+ '_claim_* overage and Graph contains required group',
+ {
+ _claim_names: { groups: 'src1' },
+ _claim_sources: { src1: { endpoint: 'https://graph.windows.net/ignored' } },
+ },
+ ['group-required', 'some-other-group'],
+ true,
+ ],
+ [
+ 'hasgroups overage and Graph does NOT contain required group',
+ {
+ hasgroups: true,
+ },
+ ['some-other-group'],
+ false,
+ ],
+ [
+ '_claim_* overage and Graph does NOT contain required group',
+ {
+ _claim_names: { groups: 'src1' },
+ _claim_sources: { src1: { endpoint: 'https://graph.windows.net/ignored' } },
+ },
+ ['some-other-group'],
+ false,
+ ],
+ ])(
+ 'resolves groups via Microsoft Graph when %s',
+ async (_label, decodedTokenValue, graphGroups, expectedAllowed) => {
+ process.env.OPENID_REQUIRED_ROLE = 'group-required';
+ process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'groups';
+ process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND = 'id';
+
+ const { logger } = require('@librechat/data-schemas');
+
+ jwtDecode.mockReturnValue(decodedTokenValue);
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ undici.fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ json: async () => ({
+ value: graphGroups,
+ }),
+ });
+
+ const { user } = await validate(tokenset);
+
+ expect(undici.fetch).toHaveBeenCalledWith(
+ 'https://graph.microsoft.com/v1.0/me/getMemberObjects',
+ expect.objectContaining({
+ method: 'POST',
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${tokenset.access_token}`,
+ }),
+ }),
+ );
+ expect(Boolean(user)).toBe(expectedAllowed);
+
+ expect(logger.debug).toHaveBeenCalledWith(
+ expect.stringContaining(
+ `Successfully resolved ${graphGroups.length} groups via Microsoft Graph getMemberObjects`,
+ ),
+ );
+ },
+ );
+ });
+
it('should attempt to download and save the avatar if picture is provided', async () => {
// Act
const { user } = await validate(tokenset);
@@ -389,7 +772,7 @@ describe('setupOpenId', () => {
// Arrange
process.env.OPENID_REQUIRED_ROLE = 'someRole,anotherRole,admin';
await setupOpenId(); // Re-initialize the strategy
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
jwtDecode.mockReturnValue({
roles: ['anotherRole', 'aThirdRole'],
});
@@ -406,7 +789,7 @@ describe('setupOpenId', () => {
// Arrange
process.env.OPENID_REQUIRED_ROLE = 'someRole,anotherRole,admin';
await setupOpenId(); // Re-initialize the strategy
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
jwtDecode.mockReturnValue({
roles: ['aThirdRole', 'aFourthRole'],
});
@@ -425,7 +808,7 @@ describe('setupOpenId', () => {
// Arrange
process.env.OPENID_REQUIRED_ROLE = ' someRole , anotherRole , admin ';
await setupOpenId(); // Re-initialize the strategy
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
jwtDecode.mockReturnValue({
roles: ['someRole'],
});
@@ -449,10 +832,11 @@ describe('setupOpenId', () => {
});
it('should attach federatedTokens to user object for token propagation', async () => {
- // Arrange - setup tokenset with access token, refresh token, and expiration
+ // Arrange - setup tokenset with access token, id token, refresh token, and expiration
const tokensetWithTokens = {
...tokenset,
access_token: 'mock_access_token_abc123',
+ id_token: 'mock_id_token_def456',
refresh_token: 'mock_refresh_token_xyz789',
expires_at: 1234567890,
};
@@ -464,16 +848,37 @@ describe('setupOpenId', () => {
expect(user.federatedTokens).toBeDefined();
expect(user.federatedTokens).toEqual({
access_token: 'mock_access_token_abc123',
+ id_token: 'mock_id_token_def456',
refresh_token: 'mock_refresh_token_xyz789',
expires_at: 1234567890,
});
});
+ it('should include id_token in federatedTokens distinct from access_token', async () => {
+ // Arrange - use different values for access_token and id_token
+ const tokensetWithTokens = {
+ ...tokenset,
+ access_token: 'the_access_token',
+ id_token: 'the_id_token',
+ refresh_token: 'the_refresh_token',
+ expires_at: 9999999999,
+ };
+
+ // Act
+ const { user } = await validate(tokensetWithTokens);
+
+ // Assert - id_token and access_token must be different values
+ expect(user.federatedTokens.access_token).toBe('the_access_token');
+ expect(user.federatedTokens.id_token).toBe('the_id_token');
+ expect(user.federatedTokens.id_token).not.toBe(user.federatedTokens.access_token);
+ });
+
it('should include tokenset along with federatedTokens', async () => {
// Arrange
const tokensetWithTokens = {
...tokenset,
access_token: 'test_access_token',
+ id_token: 'test_id_token',
refresh_token: 'test_refresh_token',
expires_at: 9999999999,
};
@@ -485,7 +890,9 @@ describe('setupOpenId', () => {
expect(user.tokenset).toBeDefined();
expect(user.federatedTokens).toBeDefined();
expect(user.tokenset.access_token).toBe('test_access_token');
+ expect(user.tokenset.id_token).toBe('test_id_token');
expect(user.federatedTokens.access_token).toBe('test_access_token');
+ expect(user.federatedTokens.id_token).toBe('test_id_token');
});
it('should set role to "ADMIN" if OPENID_ADMIN_ROLE is set and user has that role', async () => {
@@ -560,7 +967,7 @@ describe('setupOpenId', () => {
delete process.env.OPENID_ADMIN_ROLE_TOKEN_KIND;
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
// Simulate an existing admin user
const existingAdminUser = {
@@ -611,7 +1018,7 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
@@ -634,7 +1041,7 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
@@ -655,14 +1062,12 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user, details } = await validate(tokenset);
expect(logger.error).toHaveBeenCalledWith(
- expect.stringContaining(
- "Key 'resource_access.nonexistent.roles' not found or invalid type in id token!",
- ),
+ expect.stringContaining("Key 'resource_access.nonexistent.roles' not found in id token!"),
);
expect(user).toBe(false);
expect(details.message).toContain('role to log in');
@@ -680,12 +1085,12 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
expect(logger.error).toHaveBeenCalledWith(
- expect.stringContaining("Key 'org.team.roles' not found or invalid type in id token!"),
+ expect.stringContaining("Key 'org.team.roles' not found in id token!"),
);
expect(user).toBe(false);
});
@@ -709,7 +1114,7 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
@@ -739,7 +1144,7 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate({
...tokenset,
@@ -759,7 +1164,7 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
@@ -776,7 +1181,7 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
@@ -793,7 +1198,7 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
@@ -810,7 +1215,7 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
@@ -827,13 +1232,53 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
expect(user.role).toBeUndefined();
});
+ it('should grant admin when admin role claim is a space-separated string containing the admin role', async () => {
+ // Arrange – IdP returns admin roles as a space-delimited string
+ process.env.OPENID_ADMIN_ROLE = 'site-admin';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'app_roles';
+
+ jwtDecode.mockReturnValue({
+ roles: ['requiredRole'],
+ app_roles: 'user site-admin moderator',
+ });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ // Act
+ const { user } = await validate(tokenset);
+
+ // Assert – admin role is granted after splitting the delimited string
+ expect(user.role).toBe('ADMIN');
+ });
+
+ it('should not grant admin when admin role claim is a space-separated string that does not contain the admin role', async () => {
+ // Arrange – delimited string present but admin role is absent
+ process.env.OPENID_ADMIN_ROLE = 'site-admin';
+ process.env.OPENID_ADMIN_ROLE_PARAMETER_PATH = 'app_roles';
+
+ jwtDecode.mockReturnValue({
+ roles: ['requiredRole'],
+ app_roles: 'user moderator',
+ });
+
+ await setupOpenId();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
+
+ // Act
+ const { user } = await validate(tokenset);
+
+ // Assert – admin role is not granted
+ expect(user.role).toBeUndefined();
+ });
+
it('should handle nested path with special characters in keys', async () => {
process.env.OPENID_REQUIRED_ROLE = 'app-user';
process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH = 'resource_access.my-app-123.roles';
@@ -847,7 +1292,7 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
@@ -864,12 +1309,12 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
expect(logger.error).toHaveBeenCalledWith(
- expect.stringContaining("Key 'access.roles' not found or invalid type in id token!"),
+ expect.stringContaining("Key 'access.roles' not found in id token!"),
);
expect(user).toBe(false);
});
@@ -884,12 +1329,12 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
expect(logger.error).toHaveBeenCalledWith(
- expect.stringContaining("Key 'data.roles' not found or invalid type in id token!"),
+ expect.stringContaining("Key 'data.roles' not found in id token!"),
);
expect(user).toBe(false);
});
@@ -906,7 +1351,7 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
await expect(validate(tokenset)).rejects.toThrow('Invalid admin role token kind');
@@ -927,12 +1372,12 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user, details } = await validate(tokenset);
expect(logger.error).toHaveBeenCalledWith(
- expect.stringContaining("Key 'roles' not found or invalid type in id token!"),
+ expect.stringContaining("Key 'roles' not found in id token!"),
);
expect(user).toBe(false);
expect(details.message).toContain('role to log in');
@@ -948,14 +1393,92 @@ describe('setupOpenId', () => {
});
await setupOpenId();
- verifyCallback = require('openid-client/passport').__getVerifyCallback();
+ verifyCallback = require('openid-client/passport').__getVerifyCallbackByName('openid');
const { user } = await validate(tokenset);
expect(logger.error).toHaveBeenCalledWith(
- expect.stringContaining("Key 'roleCount' not found or invalid type in id token!"),
+ expect.stringContaining("Key 'roleCount' not found in id token!"),
);
expect(user).toBe(false);
});
});
+
+ describe('OPENID_EMAIL_CLAIM', () => {
+ it('should use the default email when OPENID_EMAIL_CLAIM is not set', async () => {
+ const { user } = await validate(tokenset);
+ expect(user.email).toBe('test@example.com');
+ });
+
+ it('should use the configured claim when OPENID_EMAIL_CLAIM is set', async () => {
+ process.env.OPENID_EMAIL_CLAIM = 'upn';
+ const userinfo = { ...tokenset.claims(), upn: 'user@corp.example.com' };
+
+ const { user } = await validate({ ...tokenset, claims: () => userinfo });
+
+ expect(user.email).toBe('user@corp.example.com');
+ expect(createUser).toHaveBeenCalledWith(
+ expect.objectContaining({ email: 'user@corp.example.com' }),
+ expect.anything(),
+ true,
+ true,
+ );
+ });
+
+ it('should fall back to preferred_username when email is missing and OPENID_EMAIL_CLAIM is not set', async () => {
+ const userinfo = { ...tokenset.claims() };
+ delete userinfo.email;
+
+ const { user } = await validate({ ...tokenset, claims: () => userinfo });
+
+ expect(user.email).toBe('testusername');
+ });
+
+ it('should fall back to upn when email and preferred_username are missing and OPENID_EMAIL_CLAIM is not set', async () => {
+ const userinfo = { ...tokenset.claims(), upn: 'user@corp.example.com' };
+ delete userinfo.email;
+ delete userinfo.preferred_username;
+
+ const { user } = await validate({ ...tokenset, claims: () => userinfo });
+
+ expect(user.email).toBe('user@corp.example.com');
+ });
+
+ it('should ignore empty string OPENID_EMAIL_CLAIM and use default fallback', async () => {
+ process.env.OPENID_EMAIL_CLAIM = '';
+
+ const { user } = await validate(tokenset);
+
+ expect(user.email).toBe('test@example.com');
+ });
+
+ it('should trim whitespace from OPENID_EMAIL_CLAIM and resolve correctly', async () => {
+ process.env.OPENID_EMAIL_CLAIM = ' upn ';
+ const userinfo = { ...tokenset.claims(), upn: 'user@corp.example.com' };
+
+ const { user } = await validate({ ...tokenset, claims: () => userinfo });
+
+ expect(user.email).toBe('user@corp.example.com');
+ });
+
+ it('should ignore whitespace-only OPENID_EMAIL_CLAIM and use default fallback', async () => {
+ process.env.OPENID_EMAIL_CLAIM = ' ';
+
+ const { user } = await validate(tokenset);
+
+ expect(user.email).toBe('test@example.com');
+ });
+
+ it('should fall back to default chain with warning when configured claim is missing from userinfo', async () => {
+ const { logger } = require('@librechat/data-schemas');
+ process.env.OPENID_EMAIL_CLAIM = 'nonexistent_claim';
+
+ const { user } = await validate(tokenset);
+
+ expect(user.email).toBe('test@example.com');
+ expect(logger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('OPENID_EMAIL_CLAIM="nonexistent_claim" not present in userinfo'),
+ );
+ });
+ });
});
diff --git a/api/test/.env.test.example b/api/test/.env.test.example
index 9b7a75a996..587a739cc3 100644
--- a/api/test/.env.test.example
+++ b/api/test/.env.test.example
@@ -11,3 +11,7 @@ OPENAI_API_KEY=your-api-key
BAN_VIOLATIONS=true
BAN_DURATION=7200000
BAN_INTERVAL=20
+
+# NODE_MAX_OLD_SPACE_SIZE is only used as a Docker build argument.
+# Node.js does NOT recognize this environment variable for heap size.
+NODE_MAX_OLD_SPACE_SIZE=6144
diff --git a/api/test/__mocks__/fetchEventSource.js b/api/test/__mocks__/fetchEventSource.js
deleted file mode 100644
index 8f6d3cc575..0000000000
--- a/api/test/__mocks__/fetchEventSource.js
+++ /dev/null
@@ -1,27 +0,0 @@
-jest.mock('@waylaidwanderer/fetch-event-source', () => ({
- fetchEventSource: jest
- .fn()
- .mockImplementation((url, { onopen, onmessage, onclose, onerror, error }) => {
- // Simulating the onopen event
- onopen && onopen({ status: 200 });
-
- // Simulating a few onmessage events
- onmessage &&
- onmessage({ data: JSON.stringify({ message: 'First message' }), event: 'message' });
- onmessage &&
- onmessage({ data: JSON.stringify({ message: 'Second message' }), event: 'message' });
- onmessage &&
- onmessage({ data: JSON.stringify({ message: 'Third message' }), event: 'message' });
-
- // Simulate the onclose event
- onclose && onclose();
-
- if (error) {
- // Simulate the onerror event
- onerror && onerror({ status: 500 });
- }
-
- // Return a Promise that resolves to simulate async behavior
- return Promise.resolve();
- }),
-}));
diff --git a/api/test/app/clients/tools/structured/OpenAIImageTools.test.js b/api/test/app/clients/tools/structured/OpenAIImageTools.test.js
new file mode 100644
index 0000000000..aa0726b916
--- /dev/null
+++ b/api/test/app/clients/tools/structured/OpenAIImageTools.test.js
@@ -0,0 +1,162 @@
+const OpenAI = require('openai');
+const createOpenAIImageTools = require('~/app/clients/tools/structured/OpenAIImageTools');
+
+jest.mock('openai');
+jest.mock('@librechat/data-schemas', () => ({
+ logger: {
+ warn: jest.fn(),
+ error: jest.fn(),
+ debug: jest.fn(),
+ },
+}));
+
+jest.mock('@librechat/api', () => ({
+ logAxiosError: jest.fn(),
+ oaiToolkit: {
+ image_gen_oai: {
+ name: 'image_gen_oai',
+ description: 'Generate an image',
+ schema: {},
+ },
+ image_edit_oai: {
+ name: 'image_edit_oai',
+ description: 'Edit an image',
+ schema: {},
+ },
+ },
+ extractBaseURL: jest.fn((url) => url),
+}));
+
+jest.mock('~/server/services/Files/strategies', () => ({
+ getStrategyFunctions: jest.fn(),
+}));
+
+jest.mock('~/models', () => ({
+ getFiles: jest.fn().mockResolvedValue([]),
+}));
+
+describe('OpenAIImageTools - IMAGE_GEN_OAI_MODEL environment variable', () => {
+ let originalEnv;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ originalEnv = { ...process.env };
+
+ process.env.IMAGE_GEN_OAI_API_KEY = 'test-api-key';
+
+ OpenAI.mockImplementation(() => ({
+ images: {
+ generate: jest.fn().mockResolvedValue({
+ data: [
+ {
+ b64_json: 'base64-encoded-image-data',
+ },
+ ],
+ }),
+ },
+ }));
+ });
+
+ afterEach(() => {
+ process.env = originalEnv;
+ });
+
+ it('should use default model "gpt-image-1" when IMAGE_GEN_OAI_MODEL is not set', async () => {
+ delete process.env.IMAGE_GEN_OAI_MODEL;
+
+ const [imageGenTool] = createOpenAIImageTools({
+ isAgent: true,
+ override: false,
+ req: { user: { id: 'test-user' } },
+ });
+
+ const mockGenerate = jest.fn().mockResolvedValue({
+ data: [
+ {
+ b64_json: 'base64-encoded-image-data',
+ },
+ ],
+ });
+
+ OpenAI.mockImplementation(() => ({
+ images: {
+ generate: mockGenerate,
+ },
+ }));
+
+ await imageGenTool.func({ prompt: 'test prompt' });
+
+ expect(mockGenerate).toHaveBeenCalledWith(
+ expect.objectContaining({
+ model: 'gpt-image-1',
+ }),
+ expect.any(Object),
+ );
+ });
+
+ it('should use "gpt-image-1.5" when IMAGE_GEN_OAI_MODEL is set to "gpt-image-1.5"', async () => {
+ process.env.IMAGE_GEN_OAI_MODEL = 'gpt-image-1.5';
+
+ const mockGenerate = jest.fn().mockResolvedValue({
+ data: [
+ {
+ b64_json: 'base64-encoded-image-data',
+ },
+ ],
+ });
+
+ OpenAI.mockImplementation(() => ({
+ images: {
+ generate: mockGenerate,
+ },
+ }));
+
+ const [imageGenTool] = createOpenAIImageTools({
+ isAgent: true,
+ override: false,
+ req: { user: { id: 'test-user' } },
+ });
+
+ await imageGenTool.func({ prompt: 'test prompt' });
+
+ expect(mockGenerate).toHaveBeenCalledWith(
+ expect.objectContaining({
+ model: 'gpt-image-1.5',
+ }),
+ expect.any(Object),
+ );
+ });
+
+ it('should use custom model name from IMAGE_GEN_OAI_MODEL environment variable', async () => {
+ process.env.IMAGE_GEN_OAI_MODEL = 'custom-image-model';
+
+ const mockGenerate = jest.fn().mockResolvedValue({
+ data: [
+ {
+ b64_json: 'base64-encoded-image-data',
+ },
+ ],
+ });
+
+ OpenAI.mockImplementation(() => ({
+ images: {
+ generate: mockGenerate,
+ },
+ }));
+
+ const [imageGenTool] = createOpenAIImageTools({
+ isAgent: true,
+ override: false,
+ req: { user: { id: 'test-user' } },
+ });
+
+ await imageGenTool.func({ prompt: 'test prompt' });
+
+ expect(mockGenerate).toHaveBeenCalledWith(
+ expect.objectContaining({
+ model: 'custom-image-model',
+ }),
+ expect.any(Object),
+ );
+ });
+});
diff --git a/api/test/app/clients/tools/util/fileSearch.test.js b/api/test/app/clients/tools/util/fileSearch.test.js
index 72353bd296..782e48f720 100644
--- a/api/test/app/clients/tools/util/fileSearch.test.js
+++ b/api/test/app/clients/tools/util/fileSearch.test.js
@@ -13,7 +13,7 @@ jest.mock('@librechat/data-schemas', () => ({
},
}));
-jest.mock('~/models/File', () => ({
+jest.mock('~/models', () => ({
getFiles: jest.fn().mockResolvedValue([]),
}));
diff --git a/api/test/services/Files/S3/crud.test.js b/api/test/services/Files/S3/crud.test.js
new file mode 100644
index 0000000000..c7b46fba4c
--- /dev/null
+++ b/api/test/services/Files/S3/crud.test.js
@@ -0,0 +1,876 @@
+const fs = require('fs');
+const fetch = require('node-fetch');
+const { Readable } = require('stream');
+const { FileSources } = require('librechat-data-provider');
+const {
+ PutObjectCommand,
+ GetObjectCommand,
+ HeadObjectCommand,
+ DeleteObjectCommand,
+} = require('@aws-sdk/client-s3');
+const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
+
+// Mock dependencies
+jest.mock('fs');
+jest.mock('node-fetch');
+jest.mock('@aws-sdk/s3-request-presigner');
+jest.mock('@aws-sdk/client-s3');
+
+jest.mock('@librechat/api', () => ({
+ initializeS3: jest.fn(),
+ deleteRagFile: jest.fn().mockResolvedValue(undefined),
+ isEnabled: jest.fn((val) => val === 'true'),
+}));
+
+jest.mock('@librechat/data-schemas', () => ({
+ logger: {
+ debug: jest.fn(),
+ info: jest.fn(),
+ warn: jest.fn(),
+ error: jest.fn(),
+ },
+}));
+
+const { initializeS3, deleteRagFile } = require('@librechat/api');
+const { logger } = require('@librechat/data-schemas');
+
+// Set env vars before requiring crud so module-level constants pick them up
+process.env.AWS_BUCKET_NAME = 'test-bucket';
+process.env.S3_URL_EXPIRY_SECONDS = '120';
+
+const {
+ saveBufferToS3,
+ saveURLToS3,
+ getS3URL,
+ deleteFileFromS3,
+ uploadFileToS3,
+ getS3FileStream,
+ refreshS3FileUrls,
+ refreshS3Url,
+ needsRefresh,
+ getNewS3URL,
+ extractKeyFromS3Url,
+} = require('~/server/services/Files/S3/crud');
+
+describe('S3 CRUD Operations', () => {
+ let mockS3Client;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ // Setup mock S3 client
+ mockS3Client = {
+ send: jest.fn(),
+ };
+ initializeS3.mockReturnValue(mockS3Client);
+ });
+
+ afterEach(() => {
+ delete process.env.S3_URL_EXPIRY_SECONDS;
+ delete process.env.S3_REFRESH_EXPIRY_MS;
+ delete process.env.AWS_BUCKET_NAME;
+ });
+
+ describe('saveBufferToS3', () => {
+ it('should upload a buffer to S3 and return a signed URL', async () => {
+ const mockBuffer = Buffer.from('test data');
+ const mockSignedUrl =
+ 'https://s3.amazonaws.com/test-bucket/images/user123/test.jpg?signature=abc';
+
+ mockS3Client.send.mockResolvedValue({});
+ getSignedUrl.mockResolvedValue(mockSignedUrl);
+
+ const result = await saveBufferToS3({
+ userId: 'user123',
+ buffer: mockBuffer,
+ fileName: 'test.jpg',
+ basePath: 'images',
+ });
+
+ expect(mockS3Client.send).toHaveBeenCalledWith(expect.any(PutObjectCommand));
+ expect(result).toBe(mockSignedUrl);
+ });
+
+ it('should use default basePath if not provided', async () => {
+ const mockBuffer = Buffer.from('test data');
+ const mockSignedUrl =
+ 'https://s3.amazonaws.com/test-bucket/images/user123/test.jpg?signature=abc';
+
+ mockS3Client.send.mockResolvedValue({});
+ getSignedUrl.mockResolvedValue(mockSignedUrl);
+
+ await saveBufferToS3({
+ userId: 'user123',
+ buffer: mockBuffer,
+ fileName: 'test.jpg',
+ });
+
+ expect(getSignedUrl).toHaveBeenCalled();
+ });
+
+ it('should handle S3 upload errors', async () => {
+ const mockBuffer = Buffer.from('test data');
+ const error = new Error('S3 upload failed');
+
+ mockS3Client.send.mockRejectedValue(error);
+
+ await expect(
+ saveBufferToS3({
+ userId: 'user123',
+ buffer: mockBuffer,
+ fileName: 'test.jpg',
+ }),
+ ).rejects.toThrow('S3 upload failed');
+
+ expect(logger.error).toHaveBeenCalledWith(
+ '[saveBufferToS3] Error uploading buffer to S3:',
+ 'S3 upload failed',
+ );
+ });
+ });
+
+ describe('getS3URL', () => {
+ it('should return a signed URL for a file', async () => {
+ const mockSignedUrl =
+ 'https://s3.amazonaws.com/test-bucket/images/user123/file.pdf?signature=xyz';
+ getSignedUrl.mockResolvedValue(mockSignedUrl);
+
+ const result = await getS3URL({
+ userId: 'user123',
+ fileName: 'file.pdf',
+ basePath: 'documents',
+ });
+
+ expect(result).toBe(mockSignedUrl);
+ expect(getSignedUrl).toHaveBeenCalledWith(
+ mockS3Client,
+ expect.any(GetObjectCommand),
+ expect.objectContaining({ expiresIn: 120 }),
+ );
+ });
+
+ it('should add custom filename to Content-Disposition header', async () => {
+ const mockSignedUrl =
+ 'https://s3.amazonaws.com/test-bucket/images/user123/file.pdf?signature=xyz';
+ getSignedUrl.mockResolvedValue(mockSignedUrl);
+
+ await getS3URL({
+ userId: 'user123',
+ fileName: 'file.pdf',
+ customFilename: 'custom-name.pdf',
+ });
+
+ expect(getSignedUrl).toHaveBeenCalled();
+ });
+
+ it('should add custom content type', async () => {
+ const mockSignedUrl =
+ 'https://s3.amazonaws.com/test-bucket/images/user123/file.pdf?signature=xyz';
+ getSignedUrl.mockResolvedValue(mockSignedUrl);
+
+ await getS3URL({
+ userId: 'user123',
+ fileName: 'file.pdf',
+ contentType: 'application/pdf',
+ });
+
+ expect(getSignedUrl).toHaveBeenCalled();
+ });
+
+ it('should handle errors when getting signed URL', async () => {
+ const error = new Error('Failed to sign URL');
+ getSignedUrl.mockRejectedValue(error);
+
+ await expect(
+ getS3URL({
+ userId: 'user123',
+ fileName: 'file.pdf',
+ }),
+ ).rejects.toThrow('Failed to sign URL');
+
+ expect(logger.error).toHaveBeenCalledWith(
+ '[getS3URL] Error getting signed URL from S3:',
+ 'Failed to sign URL',
+ );
+ });
+ });
+
+ describe('saveURLToS3', () => {
+ it('should fetch a file from URL and save to S3', async () => {
+ const mockBuffer = Buffer.from('downloaded data');
+ const mockResponse = {
+ buffer: jest.fn().mockResolvedValue(mockBuffer),
+ };
+ const mockSignedUrl =
+ 'https://s3.amazonaws.com/test-bucket/images/user123/downloaded.jpg?signature=abc';
+
+ fetch.mockResolvedValue(mockResponse);
+ mockS3Client.send.mockResolvedValue({});
+ getSignedUrl.mockResolvedValue(mockSignedUrl);
+
+ const result = await saveURLToS3({
+ userId: 'user123',
+ URL: 'https://example.com/image.jpg',
+ fileName: 'downloaded.jpg',
+ });
+
+ expect(fetch).toHaveBeenCalledWith('https://example.com/image.jpg');
+ expect(mockS3Client.send).toHaveBeenCalled();
+ expect(result).toBe(mockSignedUrl);
+ });
+
+ it('should handle fetch errors', async () => {
+ const error = new Error('Network error');
+ fetch.mockRejectedValue(error);
+
+ await expect(
+ saveURLToS3({
+ userId: 'user123',
+ URL: 'https://example.com/image.jpg',
+ fileName: 'downloaded.jpg',
+ }),
+ ).rejects.toThrow('Network error');
+
+ expect(logger.error).toHaveBeenCalled();
+ });
+ });
+
+ describe('deleteFileFromS3', () => {
+ const mockReq = {
+ user: { id: 'user123' },
+ };
+
+ it('should delete a file from S3', async () => {
+ const mockFile = {
+ filepath: 'https://s3.amazonaws.com/test-bucket/images/user123/file.jpg',
+ file_id: 'file123',
+ };
+
+ // Mock HeadObject to verify file exists
+ mockS3Client.send
+ .mockResolvedValueOnce({}) // First HeadObject - exists
+ .mockResolvedValueOnce({}) // DeleteObject
+ .mockRejectedValueOnce({ name: 'NotFound' }); // Second HeadObject - deleted
+
+ await deleteFileFromS3(mockReq, mockFile);
+
+ expect(deleteRagFile).toHaveBeenCalledWith({ userId: 'user123', file: mockFile });
+ expect(mockS3Client.send).toHaveBeenCalledWith(expect.any(HeadObjectCommand));
+ expect(mockS3Client.send).toHaveBeenCalledWith(expect.any(DeleteObjectCommand));
+ });
+
+ it('should handle file not found gracefully', async () => {
+ const mockFile = {
+ filepath: 'https://s3.amazonaws.com/test-bucket/images/user123/nonexistent.jpg',
+ file_id: 'file123',
+ };
+
+ mockS3Client.send.mockRejectedValue({ name: 'NotFound' });
+
+ await deleteFileFromS3(mockReq, mockFile);
+
+ expect(logger.warn).toHaveBeenCalled();
+ });
+
+ it('should throw error if user ID does not match', async () => {
+ const mockFile = {
+ filepath: 'https://s3.amazonaws.com/test-bucket/images/different-user/file.jpg',
+ file_id: 'file123',
+ };
+
+ await expect(deleteFileFromS3(mockReq, mockFile)).rejects.toThrow('User ID mismatch');
+ expect(logger.error).toHaveBeenCalled();
+ });
+
+ it('should handle NoSuchKey error', async () => {
+ const mockFile = {
+ filepath: 'https://s3.amazonaws.com/test-bucket/images/user123/file.jpg',
+ file_id: 'file123',
+ };
+
+ mockS3Client.send
+ .mockResolvedValueOnce({}) // HeadObject - exists
+ .mockRejectedValueOnce({ code: 'NoSuchKey' }); // DeleteObject fails
+
+ await deleteFileFromS3(mockReq, mockFile);
+
+ expect(logger.debug).toHaveBeenCalled();
+ });
+ });
+
+ describe('uploadFileToS3', () => {
+ const mockReq = {
+ user: { id: 'user123' },
+ };
+
+ it('should upload a file from disk to S3', async () => {
+ const mockFile = {
+ path: '/tmp/upload.jpg',
+ originalname: 'photo.jpg',
+ };
+ const mockStats = { size: 1024 };
+ const mockSignedUrl =
+ 'https://s3.amazonaws.com/test-bucket/images/user123/file123__photo.jpg?signature=xyz';
+
+ fs.promises = { stat: jest.fn().mockResolvedValue(mockStats) };
+ fs.createReadStream = jest.fn().mockReturnValue(new Readable());
+ mockS3Client.send.mockResolvedValue({});
+ getSignedUrl.mockResolvedValue(mockSignedUrl);
+
+ const result = await uploadFileToS3({
+ req: mockReq,
+ file: mockFile,
+ file_id: 'file123',
+ basePath: 'images',
+ });
+
+ expect(result).toEqual({
+ filepath: mockSignedUrl,
+ bytes: 1024,
+ });
+ expect(fs.createReadStream).toHaveBeenCalledWith('/tmp/upload.jpg');
+ expect(mockS3Client.send).toHaveBeenCalledWith(expect.any(PutObjectCommand));
+ });
+
+ it('should handle upload errors and clean up temp file', async () => {
+ const mockFile = {
+ path: '/tmp/upload.jpg',
+ originalname: 'photo.jpg',
+ };
+ const error = new Error('Upload failed');
+
+ fs.promises = {
+ stat: jest.fn().mockResolvedValue({ size: 1024 }),
+ unlink: jest.fn().mockResolvedValue(),
+ };
+ fs.createReadStream = jest.fn().mockReturnValue(new Readable());
+ mockS3Client.send.mockRejectedValue(error);
+
+ await expect(
+ uploadFileToS3({
+ req: mockReq,
+ file: mockFile,
+ file_id: 'file123',
+ }),
+ ).rejects.toThrow('Upload failed');
+
+ expect(logger.error).toHaveBeenCalledWith(
+ '[uploadFileToS3] Error streaming file to S3:',
+ error,
+ );
+ });
+ });
+
+ describe('getS3FileStream', () => {
+ it('should return a readable stream for a file', async () => {
+ const mockStream = new Readable();
+ const mockResponse = { Body: mockStream };
+
+ mockS3Client.send.mockResolvedValue(mockResponse);
+
+ const result = await getS3FileStream(
+ {},
+ 'https://s3.amazonaws.com/test-bucket/images/user123/file.pdf',
+ );
+
+ expect(result).toBe(mockStream);
+ expect(mockS3Client.send).toHaveBeenCalledWith(expect.any(GetObjectCommand));
+ });
+
+ it('should handle errors when retrieving stream', async () => {
+ const error = new Error('Stream error');
+ mockS3Client.send.mockRejectedValue(error);
+
+ await expect(getS3FileStream({}, 'images/user123/file.pdf')).rejects.toThrow('Stream error');
+ expect(logger.error).toHaveBeenCalled();
+ });
+ });
+
+ describe('needsRefresh', () => {
+ it('should return false for non-signed URLs', () => {
+ const url = 'https://example.com/proxy/file.jpg';
+ const result = needsRefresh(url, 3600);
+ expect(result).toBe(false);
+ });
+
+ it('should return true for expired signed URLs', () => {
+ const now = new Date();
+ const past = new Date(now.getTime() - 3600 * 1000); // 1 hour ago
+ const dateStr = past
+ .toISOString()
+ .replace(/[-:]/g, '')
+ .replace(/\.\d{3}/, '');
+
+ const url = `https://s3.amazonaws.com/bucket/key?X-Amz-Signature=abc&X-Amz-Date=${dateStr}&X-Amz-Expires=60`;
+ const result = needsRefresh(url, 60);
+ expect(result).toBe(true);
+ });
+
+ it('should return false for URLs that are not close to expiration', () => {
+ const now = new Date();
+ const recent = new Date(now.getTime() - 10 * 1000); // 10 seconds ago
+ const dateStr = recent
+ .toISOString()
+ .replace(/[-:]/g, '')
+ .replace(/\.\d{3}/, '');
+
+ const url = `https://s3.amazonaws.com/bucket/key?X-Amz-Signature=abc&X-Amz-Date=${dateStr}&X-Amz-Expires=7200`;
+ const result = needsRefresh(url, 60);
+ expect(result).toBe(false);
+ });
+
+ it('should use custom refresh expiry when S3_REFRESH_EXPIRY_MS is set', () => {
+ process.env.S3_REFRESH_EXPIRY_MS = '30000'; // 30 seconds
+
+ const now = new Date();
+ const recent = new Date(now.getTime() - 31 * 1000); // 31 seconds ago
+ const dateStr = recent
+ .toISOString()
+ .replace(/[-:]/g, '')
+ .replace(/\.\d{3}/, '');
+
+ const url = `https://s3.amazonaws.com/bucket/key?X-Amz-Signature=abc&X-Amz-Date=${dateStr}&X-Amz-Expires=7200`;
+
+ // Need to reload the module to pick up the env var change
+ jest.resetModules();
+ const { needsRefresh: needsRefreshReloaded } = require('~/server/services/Files/S3/crud');
+
+ const result = needsRefreshReloaded(url, 60);
+ expect(result).toBe(true);
+ });
+
+ it('should return true for malformed URLs', () => {
+ const url = 'not-a-valid-url';
+ const result = needsRefresh(url, 3600);
+ expect(result).toBe(true);
+ });
+ });
+
+ describe('getNewS3URL', () => {
+ it('should generate a new URL from an existing S3 URL', async () => {
+ const currentURL =
+ 'https://s3.amazonaws.com/test-bucket/images/user123/file.jpg?signature=old';
+ const newURL = 'https://s3.amazonaws.com/test-bucket/images/user123/file.jpg?signature=new';
+
+ getSignedUrl.mockResolvedValue(newURL);
+
+ const result = await getNewS3URL(currentURL);
+
+ expect(result).toBe(newURL);
+ expect(getSignedUrl).toHaveBeenCalled();
+ });
+
+ it('should return undefined for invalid URLs', async () => {
+ const result = await getNewS3URL('invalid-url');
+ expect(result).toBeUndefined();
+ });
+
+ it('should handle errors gracefully', async () => {
+ const currentURL = 'https://s3.amazonaws.com/test-bucket/images/user123/file.jpg';
+ getSignedUrl.mockRejectedValue(new Error('Failed'));
+
+ const result = await getNewS3URL(currentURL);
+
+ expect(result).toBeUndefined();
+ expect(logger.error).toHaveBeenCalledWith('Error getting new S3 URL:', expect.any(Error));
+ });
+
+ it('should construct GetObjectCommand with correct key (no bucket name duplication)', async () => {
+ const currentURL =
+ 'https://s3.amazonaws.com/my-bucket/images/user123/file.jpg?X-Amz-Signature=old';
+ getSignedUrl.mockResolvedValue(
+ 'https://s3.amazonaws.com/test-bucket/images/user123/file.jpg?signature=new',
+ );
+
+ await getNewS3URL(currentURL);
+
+ expect(GetObjectCommand).toHaveBeenCalledWith(
+ expect.objectContaining({ Key: 'images/user123/file.jpg' }),
+ );
+ });
+ });
+
+ describe('refreshS3FileUrls', () => {
+ it('should refresh expired URLs for multiple files', async () => {
+ const now = new Date();
+ const past = new Date(now.getTime() - 3600 * 1000);
+ const dateStr = past
+ .toISOString()
+ .replace(/[-:]/g, '')
+ .replace(/\.\d{3}/, '');
+
+ const files = [
+ {
+ file_id: 'file1',
+ source: FileSources.s3,
+ filepath: `https://s3.amazonaws.com/bucket/images/user123/file1.jpg?X-Amz-Signature=abc&X-Amz-Date=${dateStr}&X-Amz-Expires=60`,
+ },
+ {
+ file_id: 'file2',
+ source: FileSources.s3,
+ filepath: `https://s3.amazonaws.com/bucket/images/user123/file2.jpg?X-Amz-Signature=def&X-Amz-Date=${dateStr}&X-Amz-Expires=60`,
+ },
+ ];
+
+ const newURL1 = 'https://s3.amazonaws.com/bucket/images/user123/file1.jpg?signature=new1';
+ const newURL2 = 'https://s3.amazonaws.com/bucket/images/user123/file2.jpg?signature=new2';
+
+ getSignedUrl.mockResolvedValueOnce(newURL1).mockResolvedValueOnce(newURL2);
+
+ const mockBatchUpdate = jest.fn().mockResolvedValue();
+
+ const result = await refreshS3FileUrls(files, mockBatchUpdate, 60);
+
+ expect(result[0].filepath).toBe(newURL1);
+ expect(result[1].filepath).toBe(newURL2);
+ expect(mockBatchUpdate).toHaveBeenCalledWith([
+ { file_id: 'file1', filepath: newURL1 },
+ { file_id: 'file2', filepath: newURL2 },
+ ]);
+ });
+
+ it('should skip non-S3 files', async () => {
+ const files = [
+ {
+ file_id: 'file1',
+ source: 'local',
+ filepath: '/local/path/file.jpg',
+ },
+ ];
+
+ const mockBatchUpdate = jest.fn();
+
+ const result = await refreshS3FileUrls(files, mockBatchUpdate);
+
+ expect(result).toEqual(files);
+ expect(mockBatchUpdate).not.toHaveBeenCalled();
+ });
+
+ it('should handle empty or invalid input', async () => {
+ const mockBatchUpdate = jest.fn();
+
+ const result1 = await refreshS3FileUrls(null, mockBatchUpdate);
+ expect(result1).toBe(null);
+
+ const result2 = await refreshS3FileUrls([], mockBatchUpdate);
+ expect(result2).toEqual([]);
+
+ expect(mockBatchUpdate).not.toHaveBeenCalled();
+ });
+
+ it('should handle errors for individual files gracefully', async () => {
+ const now = new Date();
+ const past = new Date(now.getTime() - 3600 * 1000);
+ const dateStr = past
+ .toISOString()
+ .replace(/[-:]/g, '')
+ .replace(/\.\d{3}/, '');
+
+ const files = [
+ {
+ file_id: 'file1',
+ source: FileSources.s3,
+ filepath: `https://s3.amazonaws.com/bucket/images/user123/file1.jpg?X-Amz-Signature=abc&X-Amz-Date=${dateStr}&X-Amz-Expires=60`,
+ },
+ ];
+
+ getSignedUrl.mockRejectedValue(new Error('Failed to refresh'));
+ const mockBatchUpdate = jest.fn();
+
+ await refreshS3FileUrls(files, mockBatchUpdate, 60);
+
+ expect(logger.error).toHaveBeenCalledWith('Error getting new S3 URL:', expect.any(Error));
+ expect(mockBatchUpdate).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('refreshS3Url', () => {
+ it('should refresh an expired S3 URL', async () => {
+ const now = new Date();
+ const past = new Date(now.getTime() - 3600 * 1000);
+ const dateStr = past
+ .toISOString()
+ .replace(/[-:]/g, '')
+ .replace(/\.\d{3}/, '');
+
+ const fileObj = {
+ source: FileSources.s3,
+ filepath: `https://s3.amazonaws.com/bucket/images/user123/file.jpg?X-Amz-Signature=abc&X-Amz-Date=${dateStr}&X-Amz-Expires=60`,
+ };
+
+ const newURL = 'https://s3.amazonaws.com/bucket/images/user123/file.jpg?signature=new';
+ getSignedUrl.mockResolvedValue(newURL);
+
+ const result = await refreshS3Url(fileObj, 60);
+
+ expect(result).toBe(newURL);
+ });
+
+ it('should return original URL if not expired', async () => {
+ const fileObj = {
+ source: FileSources.s3,
+ filepath: 'https://example.com/proxy/file.jpg',
+ };
+
+ const result = await refreshS3Url(fileObj, 3600);
+
+ expect(result).toBe(fileObj.filepath);
+ expect(getSignedUrl).not.toHaveBeenCalled();
+ });
+
+ it('should return empty string for null input', async () => {
+ const result = await refreshS3Url(null);
+ expect(result).toBe('');
+ });
+
+ it('should return original URL for non-S3 files', async () => {
+ const fileObj = {
+ source: 'local',
+ filepath: '/local/path/file.jpg',
+ };
+
+ const result = await refreshS3Url(fileObj);
+
+ expect(result).toBe(fileObj.filepath);
+ });
+
+ it('should handle errors and return original URL', async () => {
+ const now = new Date();
+ const past = new Date(now.getTime() - 3600 * 1000);
+ const dateStr = past
+ .toISOString()
+ .replace(/[-:]/g, '')
+ .replace(/\.\d{3}/, '');
+
+ const fileObj = {
+ source: FileSources.s3,
+ filepath: `https://s3.amazonaws.com/bucket/images/user123/file.jpg?X-Amz-Signature=abc&X-Amz-Date=${dateStr}&X-Amz-Expires=60`,
+ };
+
+ getSignedUrl.mockRejectedValue(new Error('Refresh failed'));
+
+ const result = await refreshS3Url(fileObj, 60);
+
+ expect(result).toBe(fileObj.filepath);
+ expect(logger.error).toHaveBeenCalled();
+ });
+ });
+
+ describe('extractKeyFromS3Url', () => {
+ it('should extract key from a full S3 URL', () => {
+ const url = 'https://s3.amazonaws.com/test-bucket/images/user123/file.jpg';
+ const result = extractKeyFromS3Url(url);
+ expect(result).toBe('images/user123/file.jpg');
+ });
+
+ it('should extract key from a signed S3 URL with query parameters', () => {
+ const url =
+ 'https://s3.amazonaws.com/test-bucket/documents/user456/report.pdf?X-Amz-Signature=abc123&X-Amz-Date=20260107';
+ const result = extractKeyFromS3Url(url);
+ expect(result).toBe('documents/user456/report.pdf');
+ });
+
+ it('should extract key from S3 URL with different domain format', () => {
+ const url = 'https://test-bucket.s3.amazonaws.com/uploads/user789/image.png';
+ const result = extractKeyFromS3Url(url);
+ expect(result).toBe('uploads/user789/image.png');
+ });
+
+ it('should return key as-is if already properly formatted (3+ parts, no http)', () => {
+ const key = 'images/user123/file.jpg';
+ const result = extractKeyFromS3Url(key);
+ expect(result).toBe('images/user123/file.jpg');
+ });
+
+ it('should handle key with leading slash by removing it', () => {
+ const key = '/images/user123/file.jpg';
+ const result = extractKeyFromS3Url(key);
+ expect(result).toBe('images/user123/file.jpg');
+ });
+
+ it('should handle simple key without slashes', () => {
+ const key = 'simple-file.txt';
+ const result = extractKeyFromS3Url(key);
+ expect(result).toBe('simple-file.txt');
+ });
+
+ it('should handle key with only two parts', () => {
+ const key = 'folder/file.txt';
+ const result = extractKeyFromS3Url(key);
+ expect(result).toBe('folder/file.txt');
+ });
+
+ it('should throw error for empty input', () => {
+ expect(() => extractKeyFromS3Url('')).toThrow('Invalid input: URL or key is empty');
+ });
+
+ it('should throw error for null input', () => {
+ expect(() => extractKeyFromS3Url(null)).toThrow('Invalid input: URL or key is empty');
+ });
+
+ it('should throw error for undefined input', () => {
+ expect(() => extractKeyFromS3Url(undefined)).toThrow('Invalid input: URL or key is empty');
+ });
+
+ it('should handle URLs with encoded characters', () => {
+ const url = 'https://s3.amazonaws.com/test-bucket/images/user123/my%20file%20name.jpg';
+ const result = extractKeyFromS3Url(url);
+ expect(result).toBe('images/user123/my%20file%20name.jpg');
+ });
+
+ it('should handle deep nested paths', () => {
+ const url = 'https://s3.amazonaws.com/bucket/a/b/c/d/e/f/file.jpg';
+ const result = extractKeyFromS3Url(url);
+ expect(result).toBe('a/b/c/d/e/f/file.jpg');
+ });
+
+ it('should log debug message when extracting from URL', () => {
+ const url = 'https://s3.amazonaws.com/bucket/images/user123/file.jpg';
+ extractKeyFromS3Url(url);
+ expect(logger.debug).toHaveBeenCalledWith(
+ expect.stringContaining('[extractKeyFromS3Url] fileUrlOrKey:'),
+ );
+ });
+
+ it('should log fallback debug message for non-URL input', () => {
+ const key = 'simple-file.txt';
+ extractKeyFromS3Url(key);
+ expect(logger.debug).toHaveBeenCalledWith(
+ expect.stringContaining('[extractKeyFromS3Url] FALLBACK'),
+ );
+ });
+
+ it('should handle valid URLs that contain only a bucket', () => {
+ const url = 'https://s3.amazonaws.com/test-bucket/';
+ const result = extractKeyFromS3Url(url);
+ expect(logger.warn).toHaveBeenCalledWith(
+ expect.stringContaining(
+ '[extractKeyFromS3Url] Extracted key is empty after removing bucket name from URL: https://s3.amazonaws.com/test-bucket/',
+ ),
+ );
+ expect(result).toBe('');
+ });
+
+ it('should handle invalid URLs that contain only a bucket', () => {
+ const url = 'https://s3.amazonaws.com/test-bucket';
+ const result = extractKeyFromS3Url(url);
+ expect(logger.warn).toHaveBeenCalledWith(
+ expect.stringContaining(
+ '[extractKeyFromS3Url] Unable to extract key from path-style URL: https://s3.amazonaws.com/test-bucket',
+ ),
+ );
+ expect(result).toBe('');
+ });
+
+ // https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html
+
+ // Path-style requests
+ // https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access
+ // https://s3.region-code.amazonaws.com/bucket-name/key-name
+ it('should handle formatted according to Path-style regional endpoint', () => {
+ const url = 'https://s3.us-west-2.amazonaws.com/amzn-s3-demo-bucket1/dogs/puppy.jpg';
+ const result = extractKeyFromS3Url(url);
+ expect(result).toBe('dogs/puppy.jpg');
+ });
+
+ // virtual host style
+ // https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#virtual-hosted-style-access
+ // https://bucket-name.s3.region-code.amazonaws.com/key-name
+ it('should handle formatted according to Virtual-hosted–style Regional endpoint', () => {
+ const url = 'https://amzn-s3-demo-bucket1.s3.us-west-2.amazonaws.com/dogs/puppy.png';
+ const result = extractKeyFromS3Url(url);
+ expect(result).toBe('dogs/puppy.png');
+ });
+
+ // Legacy endpoints
+ // https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#VirtualHostingBackwardsCompatibility
+
+ // s3‐Region
+ // https://bucket-name.s3-region-code.amazonaws.com
+ it('should handle formatted according to s3‐Region', () => {
+ const url = 'https://amzn-s3-demo-bucket1.s3-us-west-2.amazonaws.com/puppy.png';
+ const result = extractKeyFromS3Url(url);
+ expect(result).toBe('puppy.png');
+
+ const testcase2 = 'https://amzn-s3-demo-bucket1.s3-us-west-2.amazonaws.com/cats/kitten.png';
+ const result2 = extractKeyFromS3Url(testcase2);
+ expect(result2).toBe('cats/kitten.png');
+ });
+
+ // Legacy global endpoint
+ // bucket-name.s3.amazonaws.com
+ it('should handle formatted according to Legacy global endpoint', () => {
+ const url = 'https://amzn-s3-demo-bucket1.s3.amazonaws.com/dogs/puppy.png';
+ const result = extractKeyFromS3Url(url);
+ expect(result).toBe('dogs/puppy.png');
+ });
+
+ it('should handle malformed URL and log error', () => {
+ const malformedUrl = 'https://invalid url with spaces.com/key';
+ const result = extractKeyFromS3Url(malformedUrl);
+
+ expect(logger.error).toHaveBeenCalledWith(
+ expect.stringContaining('[extractKeyFromS3Url] Error parsing URL:'),
+ );
+ expect(logger.error).toHaveBeenCalledWith(expect.stringContaining(malformedUrl));
+
+ expect(result).toBe(malformedUrl);
+ });
+
+ it('should return empty string for regional path-style URL with only bucket (no key)', () => {
+ const url = 'https://s3.us-west-2.amazonaws.com/my-bucket';
+ const result = extractKeyFromS3Url(url);
+ expect(result).toBe('');
+ expect(logger.warn).toHaveBeenCalledWith(
+ expect.stringContaining('[extractKeyFromS3Url] Unable to extract key from path-style URL:'),
+ );
+ });
+
+ it('should not log error when given a plain S3 key (non-URL input)', () => {
+ extractKeyFromS3Url('images/user123/file.jpg');
+ expect(logger.error).not.toHaveBeenCalled();
+ });
+
+ it('should strip bucket from custom endpoint URLs (MinIO, R2, etc.) using bucketName', () => {
+ // bucketName is the module-level const 'test-bucket', set before require at top of file
+ expect(
+ extractKeyFromS3Url('https://minio.example.com/test-bucket/images/user123/file.jpg'),
+ ).toBe('images/user123/file.jpg');
+ expect(
+ extractKeyFromS3Url(
+ 'https://abc123.r2.cloudflarestorage.com/test-bucket/images/user123/avatar.png',
+ ),
+ ).toBe('images/user123/avatar.png');
+ });
+
+ it('should use endpoint base path when AWS_ENDPOINT_URL and AWS_FORCE_PATH_STYLE are set', () => {
+ process.env.AWS_BUCKET_NAME = 'test-bucket';
+ process.env.AWS_ENDPOINT_URL = 'https://minio.example.com';
+ process.env.AWS_FORCE_PATH_STYLE = 'true';
+ jest.resetModules();
+ const { extractKeyFromS3Url: fn } = require('~/server/services/Files/S3/crud');
+
+ expect(fn('https://minio.example.com/test-bucket/images/user123/file.jpg')).toBe(
+ 'images/user123/file.jpg',
+ );
+
+ delete process.env.AWS_ENDPOINT_URL;
+ delete process.env.AWS_FORCE_PATH_STYLE;
+ });
+
+ it('should handle endpoint with a base path', () => {
+ process.env.AWS_BUCKET_NAME = 'test-bucket';
+ process.env.AWS_ENDPOINT_URL = 'https://example.com/storage/';
+ process.env.AWS_FORCE_PATH_STYLE = 'true';
+ jest.resetModules();
+ const { extractKeyFromS3Url: fn } = require('~/server/services/Files/S3/crud');
+
+ expect(fn('https://example.com/storage/test-bucket/images/user123/file.jpg')).toBe(
+ 'images/user123/file.jpg',
+ );
+
+ delete process.env.AWS_ENDPOINT_URL;
+ delete process.env.AWS_FORCE_PATH_STYLE;
+ });
+ });
+});
diff --git a/api/typedefs.js b/api/typedefs.js
index b6385c69a9..5200e7fd0e 100644
--- a/api/typedefs.js
+++ b/api/typedefs.js
@@ -1264,12 +1264,6 @@
* @memberof typedefs
*/
-/**
- * @exports OpenAISpecClient
- * @typedef {import('./app/clients/OpenAIClient')} OpenAISpecClient
- * @memberof typedefs
- */
-
/**
* @exports TAgentClient
* @typedef {import('./server/controllers/agents/client')} TAgentClient
@@ -1498,13 +1492,11 @@
* @typedef {Object} EndpointServiceConfig
* @property {string} openAIApiKey - The API key for OpenAI.
* @property {string} azureOpenAIApiKey - The API key for Azure OpenAI.
- * @property {boolean} useAzurePlugins - Flag to indicate if Azure plugins are used.
* @property {boolean} userProvidedOpenAI - Flag to indicate if OpenAI API key is user provided.
* @property {string} googleKey - The Palm key.
* @property {boolean|{userProvide: boolean}} [openAI] - Flag to indicate if OpenAI endpoint is user provided, or its configuration.
* @property {boolean|{userProvide: boolean}} [assistant] - Flag to indicate if Assistant endpoint is user provided, or its configuration.
* @property {boolean|{userProvide: boolean}} [azureOpenAI] - Flag to indicate if Azure OpenAI endpoint is user provided, or its configuration.
- * @property {boolean|{userProvide: boolean}} [chatGPTBrowser] - Flag to indicate if ChatGPT Browser endpoint is user provided, or its configuration.
* @property {boolean|{userProvide: boolean}} [anthropic] - Flag to indicate if Anthropic endpoint is user provided, or its configuration.
* @property {boolean|{userProvide: boolean}} [google] - Flag to indicate if Google endpoint is user provided, or its configuration.
* @property {boolean|{userProvide: boolean, userProvideURL: boolean, name: string}} [custom] - Custom Endpoint configuration.
@@ -1519,23 +1511,12 @@
* @memberof typedefs
*/
-/**
- * @exports GptPlugins
- * @typedef {Object} GptPlugins
- * @property {Plugin[]} plugins - An array of plugins available.
- * @property {string[]} availableAgents - Available agents, 'classic' or 'functions'.
- * @property {boolean} userProvide - A flag indicating if the user has provided the data.
- * @property {boolean} azure - A flag indicating if azure plugins are used.
- * @memberof typedefs
- */
-
/**
* @exports DefaultConfig
* @typedef {Object} DefaultConfig
* @property {boolean|{userProvide: boolean}} [openAI] - Flag to indicate if OpenAI endpoint is user provided, or its configuration.
* @property {boolean|{userProvide: boolean}} [assistant] - Flag to indicate if Assistant endpoint is user provided, or its configuration.
* @property {boolean|{userProvide: boolean}} [azureOpenAI] - Flag to indicate if Azure OpenAI endpoint is user provided, or its configuration.
- * @property {boolean|{userProvide: boolean}} [chatGPTBrowser] - Flag to indicate if ChatGPT Browser endpoint is user provided, or its configuration.
* @property {boolean|{userProvide: boolean}} [anthropic] - Flag to indicate if Anthropic endpoint is user provided, or its configuration.
* @property {boolean|{userProvide: boolean}} [google] - Flag to indicate if Google endpoint is user provided, or its configuration.
* @property {boolean|{userProvide: boolean, userProvideURL: boolean, name: string}} [custom] - Custom Endpoint configuration.
diff --git a/api/utils/deriveBaseURL.js b/api/utils/deriveBaseURL.js
deleted file mode 100644
index 982c2c8c2e..0000000000
--- a/api/utils/deriveBaseURL.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-
-/**
- * Extracts the base URL from the provided URL.
- * @param {string} fullURL - The full URL.
- * @returns {string} The base URL.
- */
-function deriveBaseURL(fullURL) {
- try {
- const parsedUrl = new URL(fullURL);
- const protocol = parsedUrl.protocol;
- const hostname = parsedUrl.hostname;
- const port = parsedUrl.port;
-
- // Check if the parsed URL components are meaningful
- if (!protocol || !hostname) {
- return fullURL;
- }
-
- // Reconstruct the base URL
- return `${protocol}//${hostname}${port ? `:${port}` : ''}`;
- } catch (error) {
- logger.error('Failed to derive base URL', error);
- return fullURL; // Return the original URL in case of any exception
- }
-}
-
-module.exports = deriveBaseURL;
diff --git a/api/utils/deriveBaseURL.spec.js b/api/utils/deriveBaseURL.spec.js
deleted file mode 100644
index 50f64257fe..0000000000
--- a/api/utils/deriveBaseURL.spec.js
+++ /dev/null
@@ -1,74 +0,0 @@
-const axios = require('axios');
-const deriveBaseURL = require('./deriveBaseURL');
-jest.mock('@librechat/api', () => {
- const originalUtils = jest.requireActual('@librechat/api');
- return {
- ...originalUtils,
- processModelData: jest.fn((...args) => {
- return originalUtils.processModelData(...args);
- }),
- };
-});
-
-jest.mock('axios');
-jest.mock('~/cache/getLogStores', () =>
- jest.fn().mockImplementation(() => ({
- get: jest.fn().mockResolvedValue(undefined),
- set: jest.fn().mockResolvedValue(true),
- })),
-);
-jest.mock('~/config', () => ({
- logger: {
- error: jest.fn(),
- },
-}));
-
-axios.get.mockResolvedValue({
- data: {
- data: [{ id: 'model-1' }, { id: 'model-2' }],
- },
-});
-
-describe('deriveBaseURL', () => {
- it('should extract the base URL correctly from a full URL with a port', () => {
- const fullURL = 'https://example.com:8080/path?query=123';
- const baseURL = deriveBaseURL(fullURL);
- expect(baseURL).toEqual('https://example.com:8080');
- });
-
- it('should extract the base URL correctly from a full URL without a port', () => {
- const fullURL = 'https://example.com/path?query=123';
- const baseURL = deriveBaseURL(fullURL);
- expect(baseURL).toEqual('https://example.com');
- });
-
- it('should handle URLs using the HTTP protocol', () => {
- const fullURL = 'http://example.com:3000/path?query=123';
- const baseURL = deriveBaseURL(fullURL);
- expect(baseURL).toEqual('http://example.com:3000');
- });
-
- it('should return only the protocol and hostname if no port is specified', () => {
- const fullURL = 'http://example.com/path?query=123';
- const baseURL = deriveBaseURL(fullURL);
- expect(baseURL).toEqual('http://example.com');
- });
-
- it('should handle URLs with uncommon protocols', () => {
- const fullURL = 'ftp://example.com:2121/path?query=123';
- const baseURL = deriveBaseURL(fullURL);
- expect(baseURL).toEqual('ftp://example.com:2121');
- });
-
- it('should handle edge case where URL ends with a slash', () => {
- const fullURL = 'https://example.com/';
- const baseURL = deriveBaseURL(fullURL);
- expect(baseURL).toEqual('https://example.com');
- });
-
- it('should return the original URL if the URL is invalid', () => {
- const invalidURL = 'htp:/example.com:8080';
- const result = deriveBaseURL(invalidURL);
- expect(result).toBe(invalidURL);
- });
-});
diff --git a/api/utils/findMessageContent.js b/api/utils/findMessageContent.js
deleted file mode 100644
index 6aeed1a395..0000000000
--- a/api/utils/findMessageContent.js
+++ /dev/null
@@ -1,35 +0,0 @@
-const { logger } = require('@librechat/data-schemas');
-
-function findContent(obj) {
- if (obj && typeof obj === 'object') {
- if ('kwargs' in obj && 'content' in obj.kwargs) {
- return obj.kwargs.content;
- }
- for (let key in obj) {
- let content = findContent(obj[key]);
- if (content) {
- return content;
- }
- }
- }
- return null;
-}
-
-function findMessageContent(message) {
- let startIndex = Math.min(message.indexOf('{'), message.indexOf('['));
- let jsonString = message.substring(startIndex);
-
- let jsonObjectOrArray;
- try {
- jsonObjectOrArray = JSON.parse(jsonString);
- } catch (error) {
- logger.error('[findMessageContent] Failed to parse JSON:', error);
- return null;
- }
-
- let content = findContent(jsonObjectOrArray);
-
- return content;
-}
-
-module.exports = findMessageContent;
diff --git a/api/utils/index.js b/api/utils/index.js
deleted file mode 100644
index dc5f3a6737..0000000000
--- a/api/utils/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-const deriveBaseURL = require('./deriveBaseURL');
-const extractBaseURL = require('./extractBaseURL');
-const findMessageContent = require('./findMessageContent');
-
-module.exports = {
- deriveBaseURL,
- extractBaseURL,
- findMessageContent,
-};
diff --git a/api/utils/tokens.spec.js b/api/utils/tokens.spec.js
index 3336a0f82d..efbd962a8c 100644
--- a/api/utils/tokens.spec.js
+++ b/api/utils/tokens.spec.js
@@ -1,3 +1,4 @@
+/** Note: No hard-coded values should be used in this file. */
const { EModelEndpoint } = require('librechat-data-provider');
const {
maxTokensMap,
@@ -278,6 +279,12 @@ describe('getModelMaxTokens', () => {
expect(getModelMaxTokens('gemini-3', EModelEndpoint.google)).toBe(
maxTokensMap[EModelEndpoint.google]['gemini-3'],
);
+ expect(getModelMaxTokens('gemini-3.1-pro-preview', EModelEndpoint.google)).toBe(
+ maxTokensMap[EModelEndpoint.google]['gemini-3.1'],
+ );
+ expect(getModelMaxTokens('gemini-3.1-pro-preview-customtools', EModelEndpoint.google)).toBe(
+ maxTokensMap[EModelEndpoint.google]['gemini-3.1'],
+ );
expect(getModelMaxTokens('gemini-2.5-pro', EModelEndpoint.google)).toBe(
maxTokensMap[EModelEndpoint.google]['gemini-2.5-pro'],
);
@@ -626,41 +633,45 @@ describe('matchModelName', () => {
describe('Meta Models Tests', () => {
describe('getModelMaxTokens', () => {
test('should return correct tokens for LLaMa 2 models', () => {
- expect(getModelMaxTokens('llama2')).toBe(4000);
- expect(getModelMaxTokens('llama2.70b')).toBe(4000);
- expect(getModelMaxTokens('llama2-13b')).toBe(4000);
- expect(getModelMaxTokens('llama2-70b')).toBe(4000);
+ const llama2Tokens = maxTokensMap[EModelEndpoint.openAI]['llama2'];
+ expect(getModelMaxTokens('llama2')).toBe(llama2Tokens);
+ expect(getModelMaxTokens('llama2.70b')).toBe(llama2Tokens);
+ expect(getModelMaxTokens('llama2-13b')).toBe(llama2Tokens);
+ expect(getModelMaxTokens('llama2-70b')).toBe(llama2Tokens);
});
test('should return correct tokens for LLaMa 3 models', () => {
- expect(getModelMaxTokens('llama3')).toBe(8000);
- expect(getModelMaxTokens('llama3.8b')).toBe(8000);
- expect(getModelMaxTokens('llama3.70b')).toBe(8000);
- expect(getModelMaxTokens('llama3-8b')).toBe(8000);
- expect(getModelMaxTokens('llama3-70b')).toBe(8000);
+ const llama3Tokens = maxTokensMap[EModelEndpoint.openAI]['llama3'];
+ expect(getModelMaxTokens('llama3')).toBe(llama3Tokens);
+ expect(getModelMaxTokens('llama3.8b')).toBe(llama3Tokens);
+ expect(getModelMaxTokens('llama3.70b')).toBe(llama3Tokens);
+ expect(getModelMaxTokens('llama3-8b')).toBe(llama3Tokens);
+ expect(getModelMaxTokens('llama3-70b')).toBe(llama3Tokens);
});
test('should return correct tokens for LLaMa 3.1 models', () => {
- expect(getModelMaxTokens('llama3.1:8b')).toBe(127500);
- expect(getModelMaxTokens('llama3.1:70b')).toBe(127500);
- expect(getModelMaxTokens('llama3.1:405b')).toBe(127500);
- expect(getModelMaxTokens('llama3-1-8b')).toBe(127500);
- expect(getModelMaxTokens('llama3-1-70b')).toBe(127500);
- expect(getModelMaxTokens('llama3-1-405b')).toBe(127500);
+ const llama31Tokens = maxTokensMap[EModelEndpoint.openAI]['llama3.1:8b'];
+ expect(getModelMaxTokens('llama3.1:8b')).toBe(llama31Tokens);
+ expect(getModelMaxTokens('llama3.1:70b')).toBe(llama31Tokens);
+ expect(getModelMaxTokens('llama3.1:405b')).toBe(llama31Tokens);
+ expect(getModelMaxTokens('llama3-1-8b')).toBe(llama31Tokens);
+ expect(getModelMaxTokens('llama3-1-70b')).toBe(llama31Tokens);
+ expect(getModelMaxTokens('llama3-1-405b')).toBe(llama31Tokens);
});
test('should handle partial matches for Meta models', () => {
- // Test with full model names
- expect(getModelMaxTokens('meta/llama3.1:405b')).toBe(127500);
- expect(getModelMaxTokens('meta/llama3.1:70b')).toBe(127500);
- expect(getModelMaxTokens('meta/llama3.1:8b')).toBe(127500);
- expect(getModelMaxTokens('meta/llama3-1-8b')).toBe(127500);
+ const llama31Tokens = maxTokensMap[EModelEndpoint.openAI]['llama3.1:8b'];
+ const llama3Tokens = maxTokensMap[EModelEndpoint.openAI]['llama3'];
+ const llama2Tokens = maxTokensMap[EModelEndpoint.openAI]['llama2'];
+ expect(getModelMaxTokens('meta/llama3.1:405b')).toBe(llama31Tokens);
+ expect(getModelMaxTokens('meta/llama3.1:70b')).toBe(llama31Tokens);
+ expect(getModelMaxTokens('meta/llama3.1:8b')).toBe(llama31Tokens);
+ expect(getModelMaxTokens('meta/llama3-1-8b')).toBe(llama31Tokens);
- // Test base versions
- expect(getModelMaxTokens('meta/llama3.1')).toBe(127500);
- expect(getModelMaxTokens('meta/llama3-1')).toBe(127500);
- expect(getModelMaxTokens('meta/llama3')).toBe(8000);
- expect(getModelMaxTokens('meta/llama2')).toBe(4000);
+ expect(getModelMaxTokens('meta/llama3.1')).toBe(llama31Tokens);
+ expect(getModelMaxTokens('meta/llama3-1')).toBe(llama31Tokens);
+ expect(getModelMaxTokens('meta/llama3')).toBe(llama3Tokens);
+ expect(getModelMaxTokens('meta/llama2')).toBe(llama2Tokens);
});
test('should match Deepseek model variations', () => {
@@ -678,18 +689,33 @@ describe('Meta Models Tests', () => {
);
});
- test('should return 128000 context tokens for all DeepSeek models', () => {
- expect(getModelMaxTokens('deepseek-chat')).toBe(128000);
- expect(getModelMaxTokens('deepseek-reasoner')).toBe(128000);
- expect(getModelMaxTokens('deepseek-r1')).toBe(128000);
- expect(getModelMaxTokens('deepseek-v3')).toBe(128000);
- expect(getModelMaxTokens('deepseek.r1')).toBe(128000);
+ test('should return correct context tokens for all DeepSeek models', () => {
+ const deepseekChatTokens = maxTokensMap[EModelEndpoint.openAI]['deepseek-chat'];
+ expect(getModelMaxTokens('deepseek-chat')).toBe(deepseekChatTokens);
+ expect(getModelMaxTokens('deepseek-reasoner')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['deepseek-reasoner'],
+ );
+ expect(getModelMaxTokens('deepseek-r1')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['deepseek-r1'],
+ );
+ expect(getModelMaxTokens('deepseek-v3')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['deepseek'],
+ );
+ expect(getModelMaxTokens('deepseek.r1')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['deepseek.r1'],
+ );
});
test('should handle DeepSeek models with provider prefixes', () => {
- expect(getModelMaxTokens('deepseek/deepseek-chat')).toBe(128000);
- expect(getModelMaxTokens('openrouter/deepseek-reasoner')).toBe(128000);
- expect(getModelMaxTokens('openai/deepseek-v3')).toBe(128000);
+ expect(getModelMaxTokens('deepseek/deepseek-chat')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['deepseek-chat'],
+ );
+ expect(getModelMaxTokens('openrouter/deepseek-reasoner')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['deepseek-reasoner'],
+ );
+ expect(getModelMaxTokens('openai/deepseek-v3')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['deepseek'],
+ );
});
});
@@ -728,30 +754,38 @@ describe('Meta Models Tests', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
test('should return correct max output tokens for deepseek-chat', () => {
- expect(getModelMaxOutputTokens('deepseek-chat')).toBe(8000);
- expect(getModelMaxOutputTokens('deepseek-chat', EModelEndpoint.openAI)).toBe(8000);
- expect(getModelMaxOutputTokens('deepseek-chat', EModelEndpoint.custom)).toBe(8000);
+ const expected = maxOutputTokensMap[EModelEndpoint.openAI]['deepseek-chat'];
+ expect(getModelMaxOutputTokens('deepseek-chat')).toBe(expected);
+ expect(getModelMaxOutputTokens('deepseek-chat', EModelEndpoint.openAI)).toBe(expected);
+ expect(getModelMaxOutputTokens('deepseek-chat', EModelEndpoint.custom)).toBe(expected);
});
test('should return correct max output tokens for deepseek-reasoner', () => {
- expect(getModelMaxOutputTokens('deepseek-reasoner')).toBe(64000);
- expect(getModelMaxOutputTokens('deepseek-reasoner', EModelEndpoint.openAI)).toBe(64000);
- expect(getModelMaxOutputTokens('deepseek-reasoner', EModelEndpoint.custom)).toBe(64000);
+ const expected = maxOutputTokensMap[EModelEndpoint.openAI]['deepseek-reasoner'];
+ expect(getModelMaxOutputTokens('deepseek-reasoner')).toBe(expected);
+ expect(getModelMaxOutputTokens('deepseek-reasoner', EModelEndpoint.openAI)).toBe(expected);
+ expect(getModelMaxOutputTokens('deepseek-reasoner', EModelEndpoint.custom)).toBe(expected);
});
test('should return correct max output tokens for deepseek-r1', () => {
- expect(getModelMaxOutputTokens('deepseek-r1')).toBe(64000);
- expect(getModelMaxOutputTokens('deepseek-r1', EModelEndpoint.openAI)).toBe(64000);
+ const expected = maxOutputTokensMap[EModelEndpoint.openAI]['deepseek-r1'];
+ expect(getModelMaxOutputTokens('deepseek-r1')).toBe(expected);
+ expect(getModelMaxOutputTokens('deepseek-r1', EModelEndpoint.openAI)).toBe(expected);
});
test('should return correct max output tokens for deepseek base pattern', () => {
- expect(getModelMaxOutputTokens('deepseek')).toBe(8000);
- expect(getModelMaxOutputTokens('deepseek-v3')).toBe(8000);
+ const expected = maxOutputTokensMap[EModelEndpoint.openAI]['deepseek'];
+ expect(getModelMaxOutputTokens('deepseek')).toBe(expected);
+ expect(getModelMaxOutputTokens('deepseek-v3')).toBe(expected);
});
test('should handle DeepSeek models with provider prefixes for max output tokens', () => {
- expect(getModelMaxOutputTokens('deepseek/deepseek-chat')).toBe(8000);
- expect(getModelMaxOutputTokens('openrouter/deepseek-reasoner')).toBe(64000);
+ expect(getModelMaxOutputTokens('deepseek/deepseek-chat')).toBe(
+ maxOutputTokensMap[EModelEndpoint.openAI]['deepseek-chat'],
+ );
+ expect(getModelMaxOutputTokens('openrouter/deepseek-reasoner')).toBe(
+ maxOutputTokensMap[EModelEndpoint.openAI]['deepseek-reasoner'],
+ );
});
});
@@ -796,68 +830,90 @@ describe('Meta Models Tests', () => {
describe('Grok Model Tests - Tokens', () => {
describe('getModelMaxTokens', () => {
test('should return correct tokens for Grok vision models', () => {
- expect(getModelMaxTokens('grok-2-vision-1212')).toBe(32768);
- expect(getModelMaxTokens('grok-2-vision')).toBe(32768);
- expect(getModelMaxTokens('grok-2-vision-latest')).toBe(32768);
+ const grok2VisionTokens = maxTokensMap[EModelEndpoint.openAI]['grok-2-vision'];
+ expect(getModelMaxTokens('grok-2-vision-1212')).toBe(grok2VisionTokens);
+ expect(getModelMaxTokens('grok-2-vision')).toBe(grok2VisionTokens);
+ expect(getModelMaxTokens('grok-2-vision-latest')).toBe(grok2VisionTokens);
});
test('should return correct tokens for Grok beta models', () => {
- expect(getModelMaxTokens('grok-vision-beta')).toBe(8192);
- expect(getModelMaxTokens('grok-beta')).toBe(131072);
+ expect(getModelMaxTokens('grok-vision-beta')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['grok-vision-beta'],
+ );
+ expect(getModelMaxTokens('grok-beta')).toBe(maxTokensMap[EModelEndpoint.openAI]['grok-beta']);
});
test('should return correct tokens for Grok text models', () => {
- expect(getModelMaxTokens('grok-2-1212')).toBe(131072);
- expect(getModelMaxTokens('grok-2')).toBe(131072);
- expect(getModelMaxTokens('grok-2-latest')).toBe(131072);
+ const grok2Tokens = maxTokensMap[EModelEndpoint.openAI]['grok-2'];
+ expect(getModelMaxTokens('grok-2-1212')).toBe(grok2Tokens);
+ expect(getModelMaxTokens('grok-2')).toBe(grok2Tokens);
+ expect(getModelMaxTokens('grok-2-latest')).toBe(grok2Tokens);
});
test('should return correct tokens for Grok 3 series models', () => {
- expect(getModelMaxTokens('grok-3')).toBe(131072);
- expect(getModelMaxTokens('grok-3-fast')).toBe(131072);
- expect(getModelMaxTokens('grok-3-mini')).toBe(131072);
- expect(getModelMaxTokens('grok-3-mini-fast')).toBe(131072);
+ expect(getModelMaxTokens('grok-3')).toBe(maxTokensMap[EModelEndpoint.openAI]['grok-3']);
+ expect(getModelMaxTokens('grok-3-fast')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['grok-3-fast'],
+ );
+ expect(getModelMaxTokens('grok-3-mini')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['grok-3-mini'],
+ );
+ expect(getModelMaxTokens('grok-3-mini-fast')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['grok-3-mini-fast'],
+ );
});
test('should return correct tokens for Grok 4 model', () => {
- expect(getModelMaxTokens('grok-4-0709')).toBe(256000);
+ expect(getModelMaxTokens('grok-4-0709')).toBe(maxTokensMap[EModelEndpoint.openAI]['grok-4']);
});
test('should return correct tokens for Grok 4 Fast and Grok 4.1 Fast models', () => {
- expect(getModelMaxTokens('grok-4-fast')).toBe(2000000);
- expect(getModelMaxTokens('grok-4-1-fast-reasoning')).toBe(2000000);
- expect(getModelMaxTokens('grok-4-1-fast-non-reasoning')).toBe(2000000);
+ const grok4FastTokens = maxTokensMap[EModelEndpoint.openAI]['grok-4-fast'];
+ const grok41FastTokens = maxTokensMap[EModelEndpoint.openAI]['grok-4-1-fast'];
+ expect(getModelMaxTokens('grok-4-fast')).toBe(grok4FastTokens);
+ expect(getModelMaxTokens('grok-4-1-fast-reasoning')).toBe(grok41FastTokens);
+ expect(getModelMaxTokens('grok-4-1-fast-non-reasoning')).toBe(grok41FastTokens);
});
test('should return correct tokens for Grok Code Fast model', () => {
- expect(getModelMaxTokens('grok-code-fast-1')).toBe(256000);
+ expect(getModelMaxTokens('grok-code-fast-1')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['grok-code-fast'],
+ );
});
test('should handle partial matches for Grok models with prefixes', () => {
- // Vision models should match before general models
- expect(getModelMaxTokens('xai/grok-2-vision-1212')).toBe(32768);
- expect(getModelMaxTokens('xai/grok-2-vision')).toBe(32768);
- expect(getModelMaxTokens('xai/grok-2-vision-latest')).toBe(32768);
- // Beta models
- expect(getModelMaxTokens('xai/grok-vision-beta')).toBe(8192);
- expect(getModelMaxTokens('xai/grok-beta')).toBe(131072);
- // Text models
- expect(getModelMaxTokens('xai/grok-2-1212')).toBe(131072);
- expect(getModelMaxTokens('xai/grok-2')).toBe(131072);
- expect(getModelMaxTokens('xai/grok-2-latest')).toBe(131072);
- // Grok 3 models
- expect(getModelMaxTokens('xai/grok-3')).toBe(131072);
- expect(getModelMaxTokens('xai/grok-3-fast')).toBe(131072);
- expect(getModelMaxTokens('xai/grok-3-mini')).toBe(131072);
- expect(getModelMaxTokens('xai/grok-3-mini-fast')).toBe(131072);
- // Grok 4 model
- expect(getModelMaxTokens('xai/grok-4-0709')).toBe(256000);
- // Grok 4 Fast and 4.1 Fast models
- expect(getModelMaxTokens('xai/grok-4-fast')).toBe(2000000);
- expect(getModelMaxTokens('xai/grok-4-1-fast-reasoning')).toBe(2000000);
- expect(getModelMaxTokens('xai/grok-4-1-fast-non-reasoning')).toBe(2000000);
- // Grok Code Fast model
- expect(getModelMaxTokens('xai/grok-code-fast-1')).toBe(256000);
+ const grok2VisionTokens = maxTokensMap[EModelEndpoint.openAI]['grok-2-vision'];
+ const grokVisionBetaTokens = maxTokensMap[EModelEndpoint.openAI]['grok-vision-beta'];
+ const grokBetaTokens = maxTokensMap[EModelEndpoint.openAI]['grok-beta'];
+ const grok2Tokens = maxTokensMap[EModelEndpoint.openAI]['grok-2'];
+ const grok3Tokens = maxTokensMap[EModelEndpoint.openAI]['grok-3'];
+ const grok4Tokens = maxTokensMap[EModelEndpoint.openAI]['grok-4'];
+ const grok4FastTokens = maxTokensMap[EModelEndpoint.openAI]['grok-4-fast'];
+ const grok41FastTokens = maxTokensMap[EModelEndpoint.openAI]['grok-4-1-fast'];
+ const grokCodeFastTokens = maxTokensMap[EModelEndpoint.openAI]['grok-code-fast'];
+ expect(getModelMaxTokens('xai/grok-2-vision-1212')).toBe(grok2VisionTokens);
+ expect(getModelMaxTokens('xai/grok-2-vision')).toBe(grok2VisionTokens);
+ expect(getModelMaxTokens('xai/grok-2-vision-latest')).toBe(grok2VisionTokens);
+ expect(getModelMaxTokens('xai/grok-vision-beta')).toBe(grokVisionBetaTokens);
+ expect(getModelMaxTokens('xai/grok-beta')).toBe(grokBetaTokens);
+ expect(getModelMaxTokens('xai/grok-2-1212')).toBe(grok2Tokens);
+ expect(getModelMaxTokens('xai/grok-2')).toBe(grok2Tokens);
+ expect(getModelMaxTokens('xai/grok-2-latest')).toBe(grok2Tokens);
+ expect(getModelMaxTokens('xai/grok-3')).toBe(grok3Tokens);
+ expect(getModelMaxTokens('xai/grok-3-fast')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['grok-3-fast'],
+ );
+ expect(getModelMaxTokens('xai/grok-3-mini')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['grok-3-mini'],
+ );
+ expect(getModelMaxTokens('xai/grok-3-mini-fast')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['grok-3-mini-fast'],
+ );
+ expect(getModelMaxTokens('xai/grok-4-0709')).toBe(grok4Tokens);
+ expect(getModelMaxTokens('xai/grok-4-fast')).toBe(grok4FastTokens);
+ expect(getModelMaxTokens('xai/grok-4-1-fast-reasoning')).toBe(grok41FastTokens);
+ expect(getModelMaxTokens('xai/grok-4-1-fast-non-reasoning')).toBe(grok41FastTokens);
+ expect(getModelMaxTokens('xai/grok-code-fast-1')).toBe(grokCodeFastTokens);
});
});
@@ -1062,46 +1118,251 @@ describe('Claude Model Tests', () => {
expect(matchModelName(model, EModelEndpoint.anthropic)).toBe(expectedModel);
});
});
+
+ it('should return correct context length for Claude Opus 4.6 (1M)', () => {
+ expect(getModelMaxTokens('claude-opus-4-6', EModelEndpoint.anthropic)).toBe(
+ maxTokensMap[EModelEndpoint.anthropic]['claude-opus-4-6'],
+ );
+ expect(getModelMaxTokens('claude-opus-4-6')).toBe(
+ maxTokensMap[EModelEndpoint.anthropic]['claude-opus-4-6'],
+ );
+ });
+
+ it('should return correct max output tokens for Claude Opus 4.6 (128K)', () => {
+ const { getModelMaxOutputTokens } = require('@librechat/api');
+ expect(getModelMaxOutputTokens('claude-opus-4-6', EModelEndpoint.anthropic)).toBe(
+ maxOutputTokensMap[EModelEndpoint.anthropic]['claude-opus-4-6'],
+ );
+ });
+
+ it('should handle Claude Opus 4.6 model name variations', () => {
+ const modelVariations = [
+ 'claude-opus-4-6',
+ 'claude-opus-4-6-20250801',
+ 'claude-opus-4-6-latest',
+ 'anthropic/claude-opus-4-6',
+ 'claude-opus-4-6/anthropic',
+ 'claude-opus-4-6-preview',
+ ];
+
+ modelVariations.forEach((model) => {
+ const modelKey = findMatchingPattern(model, maxTokensMap[EModelEndpoint.anthropic]);
+ expect(modelKey).toBe('claude-opus-4-6');
+ expect(getModelMaxTokens(model, EModelEndpoint.anthropic)).toBe(
+ maxTokensMap[EModelEndpoint.anthropic]['claude-opus-4-6'],
+ );
+ });
+ });
+
+ it('should match model names correctly for Claude Opus 4.6', () => {
+ const modelVariations = [
+ 'claude-opus-4-6',
+ 'claude-opus-4-6-20250801',
+ 'claude-opus-4-6-latest',
+ 'anthropic/claude-opus-4-6',
+ 'claude-opus-4-6/anthropic',
+ 'claude-opus-4-6-preview',
+ ];
+
+ modelVariations.forEach((model) => {
+ expect(matchModelName(model, EModelEndpoint.anthropic)).toBe('claude-opus-4-6');
+ });
+ });
+
+ it('should return correct context length for Claude Sonnet 4.6 (1M)', () => {
+ expect(getModelMaxTokens('claude-sonnet-4-6', EModelEndpoint.anthropic)).toBe(
+ maxTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4-6'],
+ );
+ expect(getModelMaxTokens('claude-sonnet-4-6')).toBe(
+ maxTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4-6'],
+ );
+ });
+
+ it('should return correct max output tokens for Claude Sonnet 4.6 (64K)', () => {
+ const { getModelMaxOutputTokens } = require('@librechat/api');
+ expect(getModelMaxOutputTokens('claude-sonnet-4-6', EModelEndpoint.anthropic)).toBe(
+ maxOutputTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4-6'],
+ );
+ });
+
+ it('should handle Claude Sonnet 4.6 model name variations', () => {
+ const modelVariations = [
+ 'claude-sonnet-4-6',
+ 'claude-sonnet-4-6-20260101',
+ 'claude-sonnet-4-6-latest',
+ 'anthropic/claude-sonnet-4-6',
+ 'claude-sonnet-4-6/anthropic',
+ 'claude-sonnet-4-6-preview',
+ ];
+
+ modelVariations.forEach((model) => {
+ const modelKey = findMatchingPattern(model, maxTokensMap[EModelEndpoint.anthropic]);
+ expect(modelKey).toBe('claude-sonnet-4-6');
+ expect(getModelMaxTokens(model, EModelEndpoint.anthropic)).toBe(
+ maxTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4-6'],
+ );
+ });
+ });
+
+ it('should match model names correctly for Claude Sonnet 4.6', () => {
+ const modelVariations = [
+ 'claude-sonnet-4-6',
+ 'claude-sonnet-4-6-20260101',
+ 'claude-sonnet-4-6-latest',
+ 'anthropic/claude-sonnet-4-6',
+ 'claude-sonnet-4-6/anthropic',
+ 'claude-sonnet-4-6-preview',
+ ];
+
+ modelVariations.forEach((model) => {
+ expect(matchModelName(model, EModelEndpoint.anthropic)).toBe('claude-sonnet-4-6');
+ });
+ });
});
-describe('Kimi Model Tests', () => {
+describe('Moonshot/Kimi Model Tests', () => {
describe('getModelMaxTokens', () => {
- test('should return correct tokens for Kimi models', () => {
- expect(getModelMaxTokens('kimi')).toBe(131000);
- expect(getModelMaxTokens('kimi-k2')).toBe(131000);
- expect(getModelMaxTokens('kimi-vl')).toBe(131000);
+ test('should return correct tokens for kimi-k2.5 (multi-modal)', () => {
+ expect(getModelMaxTokens('kimi-k2.5')).toBe(maxTokensMap[EModelEndpoint.openAI]['kimi-k2.5']);
+ expect(getModelMaxTokens('kimi-k2.5-latest')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2.5'],
+ );
});
- test('should return correct tokens for Kimi models with provider prefix', () => {
- expect(getModelMaxTokens('moonshotai/kimi-k2')).toBe(131000);
- expect(getModelMaxTokens('moonshotai/kimi')).toBe(131000);
- expect(getModelMaxTokens('moonshotai/kimi-vl')).toBe(131000);
+ test('should return correct tokens for kimi-k2 series models', () => {
+ expect(getModelMaxTokens('kimi')).toBe(maxTokensMap[EModelEndpoint.openAI]['kimi']);
+ expect(getModelMaxTokens('kimi-k2')).toBe(maxTokensMap[EModelEndpoint.openAI]['kimi-k2']);
+ expect(getModelMaxTokens('kimi-k2-turbo')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2-turbo'],
+ );
+ expect(getModelMaxTokens('kimi-k2-turbo-preview')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2-turbo-preview'],
+ );
+ expect(getModelMaxTokens('kimi-k2-0905')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2-0905'],
+ );
+ expect(getModelMaxTokens('kimi-k2-0905-preview')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2-0905-preview'],
+ );
+ expect(getModelMaxTokens('kimi-k2-thinking')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2-thinking'],
+ );
+ expect(getModelMaxTokens('kimi-k2-thinking-turbo')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2-thinking-turbo'],
+ );
});
- test('should handle partial matches for Kimi models', () => {
- expect(getModelMaxTokens('kimi-k2-latest')).toBe(131000);
- expect(getModelMaxTokens('kimi-vl-preview')).toBe(131000);
- expect(getModelMaxTokens('kimi-2024')).toBe(131000);
+ test('should return correct tokens for kimi-k2-0711 (smaller context)', () => {
+ expect(getModelMaxTokens('kimi-k2-0711')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2-0711'],
+ );
+ expect(getModelMaxTokens('kimi-k2-0711-preview')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2-0711-preview'],
+ );
+ });
+
+ test('should return correct tokens for kimi-latest', () => {
+ expect(getModelMaxTokens('kimi-latest')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-latest'],
+ );
+ });
+
+ test('should return correct tokens for moonshot-v1 series models', () => {
+ expect(getModelMaxTokens('moonshot')).toBe(maxTokensMap[EModelEndpoint.openAI]['moonshot']);
+ expect(getModelMaxTokens('moonshot-v1')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1'],
+ );
+ expect(getModelMaxTokens('moonshot-v1-auto')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-auto'],
+ );
+ expect(getModelMaxTokens('moonshot-v1-8k')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-8k'],
+ );
+ expect(getModelMaxTokens('moonshot-v1-8k-vision')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-8k-vision'],
+ );
+ expect(getModelMaxTokens('moonshot-v1-8k-vision-preview')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-8k-vision-preview'],
+ );
+ expect(getModelMaxTokens('moonshot-v1-32k')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-32k'],
+ );
+ expect(getModelMaxTokens('moonshot-v1-32k-vision')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-32k-vision'],
+ );
+ expect(getModelMaxTokens('moonshot-v1-32k-vision-preview')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-32k-vision-preview'],
+ );
+ expect(getModelMaxTokens('moonshot-v1-128k')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-128k'],
+ );
+ expect(getModelMaxTokens('moonshot-v1-128k-vision')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-128k-vision'],
+ );
+ expect(getModelMaxTokens('moonshot-v1-128k-vision-preview')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-128k-vision-preview'],
+ );
+ });
+
+ test('should return correct tokens for Bedrock moonshot models', () => {
+ expect(getModelMaxTokens('moonshot.kimi', EModelEndpoint.bedrock)).toBe(
+ maxTokensMap[EModelEndpoint.bedrock]['moonshot.kimi'],
+ );
+ expect(getModelMaxTokens('moonshot.kimi-k2', EModelEndpoint.bedrock)).toBe(
+ maxTokensMap[EModelEndpoint.bedrock]['moonshot.kimi-k2'],
+ );
+ expect(getModelMaxTokens('moonshot.kimi-k2.5', EModelEndpoint.bedrock)).toBe(
+ maxTokensMap[EModelEndpoint.bedrock]['moonshot.kimi-k2.5'],
+ );
+ expect(getModelMaxTokens('moonshot.kimi-k2-thinking', EModelEndpoint.bedrock)).toBe(
+ maxTokensMap[EModelEndpoint.bedrock]['moonshot.kimi-k2-thinking'],
+ );
+ expect(getModelMaxTokens('moonshot.kimi-k2-0711', EModelEndpoint.bedrock)).toBe(
+ maxTokensMap[EModelEndpoint.bedrock]['moonshot.kimi-k2-0711'],
+ );
+ });
+
+ test('should handle Moonshot/Kimi models with provider prefixes', () => {
+ expect(getModelMaxTokens('openrouter/kimi-k2')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2'],
+ );
+ expect(getModelMaxTokens('openrouter/kimi-k2.5')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2.5'],
+ );
+ expect(getModelMaxTokens('openrouter/kimi-k2-turbo')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['kimi-k2-turbo'],
+ );
+ expect(getModelMaxTokens('openrouter/moonshot-v1-128k')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-128k'],
+ );
});
});
describe('matchModelName', () => {
test('should match exact Kimi model names', () => {
expect(matchModelName('kimi')).toBe('kimi');
- expect(matchModelName('kimi-k2')).toBe('kimi');
- expect(matchModelName('kimi-vl')).toBe('kimi');
+ expect(matchModelName('kimi-k2')).toBe('kimi-k2');
+ expect(matchModelName('kimi-k2.5')).toBe('kimi-k2.5');
+ expect(matchModelName('kimi-k2-turbo')).toBe('kimi-k2-turbo');
+ expect(matchModelName('kimi-k2-0711')).toBe('kimi-k2-0711');
+ });
+
+ test('should match moonshot model names', () => {
+ expect(matchModelName('moonshot')).toBe('moonshot');
+ expect(matchModelName('moonshot-v1-8k')).toBe('moonshot-v1-8k');
+ expect(matchModelName('moonshot-v1-32k')).toBe('moonshot-v1-32k');
+ expect(matchModelName('moonshot-v1-128k')).toBe('moonshot-v1-128k');
});
test('should match Kimi model variations with provider prefix', () => {
- expect(matchModelName('moonshotai/kimi')).toBe('kimi');
- expect(matchModelName('moonshotai/kimi-k2')).toBe('kimi');
- expect(matchModelName('moonshotai/kimi-vl')).toBe('kimi');
+ expect(matchModelName('openrouter/kimi')).toBe('kimi');
+ expect(matchModelName('openrouter/kimi-k2')).toBe('kimi-k2');
+ expect(matchModelName('openrouter/kimi-k2.5')).toBe('kimi-k2.5');
});
test('should match Kimi model variations with suffixes', () => {
- expect(matchModelName('kimi-k2-latest')).toBe('kimi');
- expect(matchModelName('kimi-vl-preview')).toBe('kimi');
- expect(matchModelName('kimi-2024')).toBe('kimi');
+ expect(matchModelName('kimi-k2-latest')).toBe('kimi-k2');
+ expect(matchModelName('kimi-k2.5-preview')).toBe('kimi-k2.5');
});
});
});
@@ -1224,44 +1485,80 @@ describe('Qwen3 Model Tests', () => {
describe('GLM Model Tests (Zhipu AI)', () => {
describe('getModelMaxTokens', () => {
test('should return correct tokens for GLM models', () => {
- expect(getModelMaxTokens('glm-4.6')).toBe(200000);
- expect(getModelMaxTokens('glm-4.5v')).toBe(66000);
- expect(getModelMaxTokens('glm-4.5-air')).toBe(131000);
- expect(getModelMaxTokens('glm-4.5')).toBe(131000);
- expect(getModelMaxTokens('glm-4-32b')).toBe(128000);
- expect(getModelMaxTokens('glm-4')).toBe(128000);
- expect(getModelMaxTokens('glm4')).toBe(128000);
+ expect(getModelMaxTokens('glm-4.6')).toBe(maxTokensMap[EModelEndpoint.openAI]['glm-4.6']);
+ expect(getModelMaxTokens('glm-4.5v')).toBe(maxTokensMap[EModelEndpoint.openAI]['glm-4.5v']);
+ expect(getModelMaxTokens('glm-4.5-air')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5-air'],
+ );
+ expect(getModelMaxTokens('glm-4.5')).toBe(maxTokensMap[EModelEndpoint.openAI]['glm-4.5']);
+ expect(getModelMaxTokens('glm-4-32b')).toBe(maxTokensMap[EModelEndpoint.openAI]['glm-4-32b']);
+ expect(getModelMaxTokens('glm-4')).toBe(maxTokensMap[EModelEndpoint.openAI]['glm-4']);
+ expect(getModelMaxTokens('glm4')).toBe(maxTokensMap[EModelEndpoint.openAI]['glm4']);
});
test('should handle partial matches for GLM models with provider prefixes', () => {
- expect(getModelMaxTokens('z-ai/glm-4.6')).toBe(200000);
- expect(getModelMaxTokens('z-ai/glm-4.5')).toBe(131000);
- expect(getModelMaxTokens('z-ai/glm-4.5-air')).toBe(131000);
- expect(getModelMaxTokens('z-ai/glm-4.5v')).toBe(66000);
- expect(getModelMaxTokens('z-ai/glm-4-32b')).toBe(128000);
+ expect(getModelMaxTokens('z-ai/glm-4.6')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.6'],
+ );
+ expect(getModelMaxTokens('z-ai/glm-4.5')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5'],
+ );
+ expect(getModelMaxTokens('z-ai/glm-4.5-air')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5-air'],
+ );
+ expect(getModelMaxTokens('z-ai/glm-4.5v')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5v'],
+ );
+ expect(getModelMaxTokens('z-ai/glm-4-32b')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4-32b'],
+ );
- expect(getModelMaxTokens('zai/glm-4.6')).toBe(200000);
- expect(getModelMaxTokens('zai/glm-4.5')).toBe(131000);
- expect(getModelMaxTokens('zai/glm-4.5-air')).toBe(131000);
- expect(getModelMaxTokens('zai/glm-4.5v')).toBe(66000);
+ expect(getModelMaxTokens('zai/glm-4.6')).toBe(maxTokensMap[EModelEndpoint.openAI]['glm-4.6']);
+ expect(getModelMaxTokens('zai/glm-4.5')).toBe(maxTokensMap[EModelEndpoint.openAI]['glm-4.5']);
+ expect(getModelMaxTokens('zai/glm-4.5-air')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5-air'],
+ );
+ expect(getModelMaxTokens('zai/glm-4.5v')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5v'],
+ );
- expect(getModelMaxTokens('zai-org/GLM-4.6')).toBe(200000);
- expect(getModelMaxTokens('zai-org/GLM-4.5')).toBe(131000);
- expect(getModelMaxTokens('zai-org/GLM-4.5-Air')).toBe(131000);
- expect(getModelMaxTokens('zai-org/GLM-4.5V')).toBe(66000);
- expect(getModelMaxTokens('zai-org/GLM-4-32B-0414')).toBe(128000);
+ expect(getModelMaxTokens('zai-org/GLM-4.6')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.6'],
+ );
+ expect(getModelMaxTokens('zai-org/GLM-4.5')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5'],
+ );
+ expect(getModelMaxTokens('zai-org/GLM-4.5-Air')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5-air'],
+ );
+ expect(getModelMaxTokens('zai-org/GLM-4.5V')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5v'],
+ );
+ expect(getModelMaxTokens('zai-org/GLM-4-32B-0414')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4-32b'],
+ );
});
test('should handle GLM model variations with suffixes', () => {
- expect(getModelMaxTokens('glm-4.6-fp8')).toBe(200000);
- expect(getModelMaxTokens('zai-org/GLM-4.6-FP8')).toBe(200000);
- expect(getModelMaxTokens('zai-org/GLM-4.5-Air-FP8')).toBe(131000);
+ expect(getModelMaxTokens('glm-4.6-fp8')).toBe(maxTokensMap[EModelEndpoint.openAI]['glm-4.6']);
+ expect(getModelMaxTokens('zai-org/GLM-4.6-FP8')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.6'],
+ );
+ expect(getModelMaxTokens('zai-org/GLM-4.5-Air-FP8')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5-air'],
+ );
});
test('should prioritize more specific GLM patterns', () => {
- expect(getModelMaxTokens('glm-4.5-air-custom')).toBe(131000);
- expect(getModelMaxTokens('glm-4.5-custom')).toBe(131000);
- expect(getModelMaxTokens('glm-4.5v-custom')).toBe(66000);
+ expect(getModelMaxTokens('glm-4.5-air-custom')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5-air'],
+ );
+ expect(getModelMaxTokens('glm-4.5-custom')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5'],
+ );
+ expect(getModelMaxTokens('glm-4.5v-custom')).toBe(
+ maxTokensMap[EModelEndpoint.openAI]['glm-4.5v'],
+ );
});
});
diff --git a/bun.lock b/bun.lock
index 5eae2093a4..c6a5dd01a1 100644
--- a/bun.lock
+++ b/bun.lock
@@ -36,28 +36,24 @@
},
"api": {
"name": "@librechat/backend",
- "version": "0.8.1-rc2",
+ "version": "0.8.300",
"dependencies": {
- "@anthropic-ai/sdk": "^0.52.0",
+ "@aws-sdk/client-bedrock-runtime": "^3.941.0",
"@aws-sdk/client-s3": "^3.758.0",
"@aws-sdk/s3-request-presigner": "^3.758.0",
"@azure/identity": "^4.7.0",
"@azure/search-documents": "^12.0.0",
"@azure/storage-blob": "^12.27.0",
- "@google/generative-ai": "^0.24.0",
"@googleapis/youtube": "^20.0.0",
"@keyv/redis": "^4.3.3",
"@langchain/core": "^0.3.79",
- "@langchain/google-genai": "^0.2.13",
- "@langchain/google-vertexai": "^0.2.13",
- "@langchain/textsplitters": "^0.1.0",
- "@librechat/agents": "^3.0.36",
+ "@librechat/agents": "^3.0.50",
"@librechat/api": "*",
"@librechat/data-schemas": "*",
"@microsoft/microsoft-graph-client": "^3.0.7",
- "@modelcontextprotocol/sdk": "^1.21.0",
+ "@modelcontextprotocol/sdk": "^1.24.3",
"@node-saml/passport-saml": "^5.1.0",
- "@waylaidwanderer/fetch-event-source": "^3.0.1",
+ "@smithy/node-http-handler": "^4.4.5",
"axios": "^1.12.1",
"bcryptjs": "^2.4.3",
"compression": "^1.8.1",
@@ -68,15 +64,14 @@
"dedent": "^1.5.3",
"dotenv": "^16.0.3",
"eventsource": "^3.0.2",
- "express": "^4.21.2",
+ "express": "^5.1.0",
"express-mongo-sanitize": "^2.2.0",
- "express-rate-limit": "^7.4.1",
+ "express-rate-limit": "^8.2.1",
"express-session": "^1.18.2",
"express-static-gzip": "^2.2.0",
"file-type": "^18.7.0",
"firebase": "^11.0.2",
"form-data": "^4.0.4",
- "googleapis": "^126.0.1",
"handlebars": "^4.7.7",
"https-proxy-agent": "^7.0.6",
"ioredis": "^5.3.2",
@@ -129,7 +124,7 @@
},
"client": {
"name": "@librechat/frontend",
- "version": "0.8.1-rc2",
+ "version": "0.8.300",
"dependencies": {
"@ariakit/react": "^0.4.15",
"@ariakit/react-core": "^0.4.17",
@@ -141,10 +136,10 @@
"@marsidev/react-turnstile": "^1.1.0",
"@mcp-ui/client": "^5.7.0",
"@radix-ui/react-accordion": "^1.1.2",
- "@radix-ui/react-alert-dialog": "^1.0.2",
+ "@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-checkbox": "^1.0.3",
"@radix-ui/react-collapsible": "^1.0.3",
- "@radix-ui/react-dialog": "^1.0.2",
+ "@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-hover-card": "^1.0.5",
"@radix-ui/react-icons": "^1.3.0",
@@ -259,7 +254,7 @@
},
"packages/api": {
"name": "@librechat/api",
- "version": "1.7.0",
+ "version": "1.7.23",
"devDependencies": {
"@babel/preset-env": "^7.21.5",
"@babel/preset-react": "^7.18.6",
@@ -298,14 +293,14 @@
"@azure/storage-blob": "^12.27.0",
"@keyv/redis": "^4.3.3",
"@langchain/core": "^0.3.79",
- "@librechat/agents": "^3.0.36",
+ "@librechat/agents": "^3.0.50",
"@librechat/data-schemas": "*",
- "@modelcontextprotocol/sdk": "^1.21.0",
+ "@modelcontextprotocol/sdk": "^1.24.3",
"axios": "^1.12.1",
"connect-redis": "^8.1.0",
"diff": "^7.0.0",
"eventsource": "^3.0.2",
- "express": "^4.21.2",
+ "express": "^5.1.0",
"express-session": "^1.18.2",
"firebase": "^11.0.2",
"form-data": "^4.0.4",
@@ -326,21 +321,33 @@
},
"packages/client": {
"name": "@librechat/client",
- "version": "0.4.1",
+ "version": "0.4.52",
"devDependencies": {
+ "@babel/core": "^7.28.5",
+ "@babel/preset-env": "^7.28.5",
+ "@babel/preset-react": "^7.28.5",
+ "@babel/preset-typescript": "^7.28.5",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^29.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-replace": "^5.0.5",
- "@rollup/plugin-terser": "^0.4.4",
"@tanstack/react-query": "^4.28.0",
+ "@tanstack/react-table": "^8.21.3",
+ "@tanstack/react-virtual": "^3.13.13",
+ "@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^14.0.0",
+ "@types/jest": "^29.5.14",
"@types/react": "^18.2.11",
"@types/react-dom": "^18.2.4",
+ "babel-jest": "^30.2.0",
"caniuse-lite": "^1.0.30001741",
"concat-with-sourcemaps": "^1.1.0",
"i18next": "^24.2.3",
+ "identity-obj-proxy": "^3.0.0",
+ "jest": "^30.2.0",
+ "jest-environment-jsdom": "^30.2.0",
"jotai": "^2.12.5",
+ "lucide-react": "^0.525.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^15.4.0",
@@ -359,10 +366,10 @@
"@dicebear/core": "^9.2.2",
"@headlessui/react": "^2.1.2",
"@radix-ui/react-accordion": "^1.2.11",
- "@radix-ui/react-alert-dialog": "^1.0.2",
+ "@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-checkbox": "^1.0.3",
"@radix-ui/react-collapsible": "^1.1.11",
- "@radix-ui/react-dialog": "^1.0.2",
+ "@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-hover-card": "^1.0.5",
"@radix-ui/react-icons": "^1.3.0",
@@ -402,7 +409,7 @@
},
"packages/data-provider": {
"name": "librechat-data-provider",
- "version": "0.8.200",
+ "version": "0.8.300",
"dependencies": {
"axios": "^1.12.1",
"dayjs": "^1.11.13",
@@ -440,7 +447,7 @@
},
"packages/data-schemas": {
"name": "@librechat/data-schemas",
- "version": "0.0.31",
+ "version": "0.0.36",
"devDependencies": {
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^29.0.0",
@@ -486,11 +493,11 @@
"packages": {
"@aashutoshrathi/word-wrap": ["@aashutoshrathi/word-wrap@1.2.6", "", {}, "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA=="],
- "@adobe/css-tools": ["@adobe/css-tools@4.3.3", "", {}, "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ=="],
+ "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="],
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
- "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.52.0", "", { "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-d4c+fg+xy9e46c8+YnrrgIQR45CZlAi7PwdzIfDXDM6ACxEZli1/fxhURsq30ZpMZy6LvSkr41jGq5aF5TD7rQ=="],
+ "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.65.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-zIdPOcrCVEI8t3Di40nH4z9EoeyGZfXbYSvWdDLsB/KkaSYMnEgC7gmcgWu83g2NTn1ZTpbMvpdttWDGGIk6zw=="],
"@apideck/better-ajv-errors": ["@apideck/better-ajv-errors@0.3.6", "", { "dependencies": { "json-schema": "^0.4.0", "jsonpointer": "^5.0.0", "leven": "^3.1.0" }, "peerDependencies": { "ajv": ">=8" } }, "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA=="],
@@ -500,6 +507,8 @@
"@ariakit/react-core": ["@ariakit/react-core@0.4.17", "", { "dependencies": { "@ariakit/core": "0.4.15", "@floating-ui/dom": "^1.0.0", "use-sync-external-store": "^1.2.0" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-kFF6n+gC/5CRQIyaMTFoBPio2xUe0k9rZhMNdUobWRmc/twfeLVkODx+8UVYaNyKilTge8G0JFqwvFKku/jKEw=="],
+ "@asamuzakjp/css-color": ["@asamuzakjp/css-color@3.2.0", "", { "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "lru-cache": "^10.4.3" } }, "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw=="],
+
"@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="],
"@aws-crypto/crc32c": ["@aws-crypto/crc32c@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag=="],
@@ -516,7 +525,7 @@
"@aws-sdk/client-bedrock-agent-runtime": ["@aws-sdk/client-bedrock-agent-runtime@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/credential-provider-node": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/eventstream-serde-browser": "^4.2.4", "@smithy/eventstream-serde-config-resolver": "^4.3.4", "@smithy/eventstream-serde-node": "^4.2.4", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-k2UeG/+Ka74jztHDzYNrpNLDSsMCst+ph3+e7uAX5Jmo40tVKa+sVu4DkV3BIXuktc6jqM1ewtfPNug79kN6JQ=="],
- "@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/credential-provider-node": "3.927.0", "@aws-sdk/eventstream-handler-node": "3.922.0", "@aws-sdk/middleware-eventstream": "3.922.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/middleware-websocket": "3.922.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/token-providers": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/eventstream-serde-browser": "^4.2.4", "@smithy/eventstream-serde-config-resolver": "^4.3.4", "@smithy/eventstream-serde-node": "^4.2.4", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-glNCCATcVd2F1SGOw3LiXKtBZzmaJhNAzPttZKM44kak6P2njz67QUP08v9qb4VDPq4Yvu/Mvu1C/Q7Wsw8z9g=="],
+ "@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.952.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-node": "3.952.0", "@aws-sdk/eventstream-handler-node": "3.936.0", "@aws-sdk/middleware-eventstream": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/middleware-websocket": "3.936.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/token-providers": "3.952.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Xc1xqIz/OdFd23UQ6cvROD+3tfvDpp5dabMqUYXFiKlk5psMNM9xhzLwWK7DE1tr1ra/dui77w8JOiLA1dC7AA=="],
"@aws-sdk/client-cognito-identity": ["@aws-sdk/client-cognito-identity@3.623.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/client-sso-oidc": "3.623.0", "@aws-sdk/core": "3.623.0", "@aws-sdk/credential-provider-node": "3.623.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", "@aws-sdk/middleware-user-agent": "3.620.0", "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", "@aws-sdk/util-endpoints": "3.614.0", "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", "@smithy/core": "^2.3.2", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-retry": "^3.0.14", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", "@smithy/util-defaults-mode-browser": "^3.0.14", "@smithy/util-defaults-mode-node": "^3.0.14", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-kGYnTzXTMGdjko5+GZ1PvWvfXA7quiOp5iMo5gbh5b55pzIdc918MHN0pvaqplVGWYlaFJF4YzxUT5Nbxd7Xeg=="],
@@ -538,6 +547,8 @@
"@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.623.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", "@aws-sdk/credential-provider-http": "3.622.0", "@aws-sdk/credential-provider-process": "3.620.1", "@aws-sdk/credential-provider-sso": "3.623.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/property-provider": "^3.1.3", "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-kvXA1SwGneqGzFwRZNpESitnmaENHGFFuuTvgGwtMe7mzXWuA/LkXdbiHmdyAzOo0iByKTCD8uetuwh3CXy4Pw=="],
+ "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.952.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-jL9zc+e+7sZeJrHzYKK9GOjl1Ktinh0ORU3cM2uRBi7fuH/0zV9pdMN8PQnGXz0i4tJaKcZ1lrE4V0V6LB9NQg=="],
+
"@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.758.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.758.0", "@aws-sdk/credential-provider-http": "3.758.0", "@aws-sdk/credential-provider-ini": "3.758.0", "@aws-sdk/credential-provider-process": "3.758.0", "@aws-sdk/credential-provider-sso": "3.758.0", "@aws-sdk/credential-provider-web-identity": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/credential-provider-imds": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-+DaMv63wiq7pJrhIQzZYMn4hSarKiizDoJRvyR7WGhnn0oQ/getX9Z0VNCV3i7lIFoLNTb7WMmQ9k7+z/uD5EQ=="],
"@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.620.1", "", { "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg=="],
@@ -548,11 +559,11 @@
"@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.623.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.623.0", "@aws-sdk/client-sso": "3.623.0", "@aws-sdk/credential-provider-cognito-identity": "3.623.0", "@aws-sdk/credential-provider-env": "3.620.1", "@aws-sdk/credential-provider-http": "3.622.0", "@aws-sdk/credential-provider-ini": "3.623.0", "@aws-sdk/credential-provider-node": "3.623.0", "@aws-sdk/credential-provider-process": "3.620.1", "@aws-sdk/credential-provider-sso": "3.623.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/property-provider": "^3.1.3", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-abtlH1hkVWAkzuOX79Q47l0ztWOV2Q7l7J4JwQgzEQm7+zCk5iUAiwqKyDzr+ByCyo4I3IWFjy+e1gBdL7rXQQ=="],
- "@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/eventstream-codec": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-DTKHeH1Bk17zSdoa5qXPGwCmZXuhQReqXOVW2/jIVX8NGVvnraH7WppGPlQxBjFtwSSwVTgzH2NVPgediQphNA=="],
+ "@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/eventstream-codec": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-4zIbhdRmol2KosIHmU31ATvNP0tkJhDlRj9GuawVJoEnMvJA1pd2U3SRdiOImJU3j8pT46VeS4YMmYxfjGHByg=="],
"@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@aws-sdk/util-arn-parser": "3.723.0", "@smithy/node-config-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-config-provider": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-etC7G18aF7KdZguW27GE/wpbrNmYLVT755EsFc8kXpZj8D6AFKxc7OuveinJmiy0bYXAMspJUWsF6CrGpOw6CQ=="],
- "@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-qDHi3NxIZCOh10aKcDPz58qlt7xtTXTMHGv7N2uVWeb7gAhk/KGerHLukY6SFAID5FJ246Le14h2blQOHi9U2Q=="],
+ "@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-XQSH8gzLkk8CDUDxyt4Rdm9owTpRIPdtg2yw9Y2Wl5iSI55YQSiC3x8nM3c4Y4WqReJprunFPK225ZUDoYCfZA=="],
"@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-P38/v1l6HjuB2aFUewt7ueAW5IvKkFcv5dalPtbMGRhLeyivBOHwbCyuRKgVs7z7ClTpu9EaViEGki2jEQqEsQ=="],
@@ -572,9 +583,9 @@
"@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@smithy/core": "^3.1.5", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-iNyehQXtQlj69JCgfaOssgZD4HeYGOwxcaKeG6F+40cwBjTAi0+Ph1yfDwqk2qiBPIRWJ/9l2LodZbxiBqgrwg=="],
- "@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/util-format-url": "3.922.0", "@smithy/eventstream-codec": "^4.2.4", "@smithy/eventstream-serde-browser": "^4.2.4", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-cBGDpMORc2lkpsSWJJkXes1lduPeUo58TIjMuC66TK134o8Wc+EsSutInxZXAT031BVWoyddhW9dBZJ1ybQQ2Q=="],
+ "@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/util-format-url": "3.936.0", "@smithy/eventstream-codec": "^4.2.5", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-bPe3rqeugyj/MmjP0yBSZox2v1Wa8Dv39KN+RxVbQroLO8VUitBo6xyZ0oZebhZ5sASwSg58aDcMlX0uFLQnTA=="],
- "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.758.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-retry": "^4.0.7", "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.7", "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-YZ5s7PSvyF3Mt2h1EQulCG93uybprNGbBkPmVuy/HMMfbFTt4iL3SbKjxqvOZelm86epFfj7pvK7FliI2WOEcg=="],
+ "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.952.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-OtuirjxuOqZyDcI0q4WtoyWfkq3nSnbH41JwJQsXJefduWcww1FQe5TL1JfYCU7seUxHzK8rg2nFxUBuqUlZtg=="],
"@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ=="],
@@ -582,7 +593,7 @@
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.758.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", "@smithy/signature-v4": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-0RPCo8fYJcrenJ6bRtiUbFOSgQ1CX/GpvwtLU2Fam1tS9h2klKK8d74caeV6A1mIUvBU7bhyQ0wMGlwMtn3EYw=="],
- "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.614.0", "", { "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "peerDependencies": { "@aws-sdk/client-sso-oidc": "^3.614.0" } }, "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw=="],
+ "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.952.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-IpQVC9WOeXQlCEcFVNXWDIKy92CH1Az37u9K0H3DF/HT56AjhyDVKQQfHUy00nt7bHFe3u0K5+zlwErBeKy5ZA=="],
"@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
@@ -600,7 +611,7 @@
"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Zrjxi5qwGEcUsJ0ru7fRtW74WcTS0rbLcehoFB+rN1GRi2hbLcFaYs4PwVA5diLeAJH0gszv3x4Hr/S87MfbKQ=="],
- "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.1.1", "", {}, "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA=="],
+ "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="],
"@axe-core/playwright": ["@axe-core/playwright@4.10.1", "", { "dependencies": { "axe-core": "~4.10.2" }, "peerDependencies": { "playwright-core": ">= 1.0.0" } }, "sha512-EV5t39VV68kuAfMKqb/RL+YjYKhfuGim9rgIaQ6Vntb2HgaCaau0h98Y3WEUqW1+PbdzxDtDNjFAipbtZuBmEA=="],
@@ -780,6 +791,8 @@
"@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg=="],
+ "@babel/plugin-transform-explicit-resource-management": ["@babel/plugin-transform-explicit-resource-management@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ=="],
+
"@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.26.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ=="],
"@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww=="],
@@ -1228,6 +1241,8 @@
"@headlessui/react": ["@headlessui/react@2.2.4", "", { "dependencies": { "@floating-ui/react": "^0.26.16", "@react-aria/focus": "^3.20.2", "@react-aria/interactions": "^3.25.0", "@tanstack/react-virtual": "^3.13.9", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-lz+OGcAH1dK93rgSMzXmm1qKOJkBUqZf1L4M8TWLNplftQD3IkoEDdUFNfAn4ylsN6WOTVtWaLmvmaHOUk1dTA=="],
+ "@hono/node-server": ["@hono/node-server@1.19.7", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw=="],
+
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
"@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="],
@@ -1292,7 +1307,9 @@
"@jest/diff-sequences": ["@jest/diff-sequences@30.0.1", "", {}, "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw=="],
- "@jest/environment": ["@jest/environment@29.7.0", "", { "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "jest-mock": "^29.7.0" } }, "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw=="],
+ "@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="],
+
+ "@jest/environment-jsdom-abstract": ["@jest/environment-jsdom-abstract@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/jsdom": "^21.1.7", "@types/node": "*", "jest-mock": "30.2.0", "jest-util": "30.2.0" }, "peerDependencies": { "canvas": "^3.0.0", "jsdom": "*" }, "optionalPeers": ["canvas"] }, "sha512-kazxw2L9IPuZpQ0mEt9lu9Z98SqR74xcagANmMBU16X0lS23yPc0+S6hGLUz8kVRlomZEs/5S/Zlpqwf5yu6OQ=="],
"@jest/expect": ["@jest/expect@30.2.0", "", { "dependencies": { "expect": "30.2.0", "jest-snapshot": "30.2.0" } }, "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA=="],
@@ -1388,7 +1405,7 @@
"@lezer/lr": ["@lezer/lr@1.4.2", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA=="],
- "@librechat/agents": ["@librechat/agents@3.0.36", "", { "dependencies": { "@langchain/anthropic": "^0.3.26", "@langchain/aws": "^0.1.15", "@langchain/core": "^0.3.79", "@langchain/deepseek": "^0.0.2", "@langchain/google-genai": "^0.2.18", "@langchain/google-vertexai": "^0.2.18", "@langchain/langgraph": "^0.4.9", "@langchain/mistralai": "^0.2.1", "@langchain/openai": "0.5.18", "@langchain/textsplitters": "^0.1.0", "@langchain/xai": "^0.0.3", "@langfuse/langchain": "^4.3.0", "@langfuse/otel": "^4.3.0", "@langfuse/tracing": "^4.3.0", "@opentelemetry/sdk-node": "^0.207.0", "axios": "^1.12.1", "cheerio": "^1.0.0", "dotenv": "^16.4.7", "https-proxy-agent": "^7.0.6", "mathjs": "^15.1.0", "nanoid": "^3.3.7", "openai": "5.8.2" } }, "sha512-52+uNiG0X2B4TZX03ldFRvqtJrExnntEFQV5UfA38+2sNbYgPm4lcdKyAHr9OTPdmmtbmDY/gKKguRiUzLVL2g=="],
+ "@librechat/agents": ["@librechat/agents@3.0.50", "", { "dependencies": { "@langchain/anthropic": "^0.3.26", "@langchain/aws": "^0.1.15", "@langchain/core": "^0.3.79", "@langchain/deepseek": "^0.0.2", "@langchain/google-genai": "^0.2.18", "@langchain/google-vertexai": "^0.2.18", "@langchain/langgraph": "^0.4.9", "@langchain/mistralai": "^0.2.1", "@langchain/openai": "0.5.18", "@langchain/textsplitters": "^0.1.0", "@langchain/xai": "^0.0.3", "@langfuse/langchain": "^4.3.0", "@langfuse/otel": "^4.3.0", "@langfuse/tracing": "^4.3.0", "@opentelemetry/sdk-node": "^0.207.0", "axios": "^1.12.1", "cheerio": "^1.0.0", "dotenv": "^16.4.7", "https-proxy-agent": "^7.0.6", "mathjs": "^15.1.0", "nanoid": "^3.3.7", "openai": "5.8.2" } }, "sha512-oovj3BsP/QoxPbWFAc71Ddplwd9BT8ucfYs+n+kiR37aCWtvxdvL9/XldRYfnaq9boNE324njQJyqc8v8AAPFQ=="],
"@librechat/api": ["@librechat/api@workspace:packages/api"],
@@ -1408,7 +1425,7 @@
"@mistralai/mistralai": ["@mistralai/mistralai@1.10.0", "", { "dependencies": { "zod": "^3.20.0", "zod-to-json-schema": "^3.24.1" } }, "sha512-tdIgWs4Le8vpvPiUEWne6tK0qbVc+jMenujnvTqOjogrJUsCSQhus0tHTU1avDDh5//Rq2dFgP9mWRAdIEoBqg=="],
- "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.21.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" } }, "sha512-YFBsXJMFCyI1zP98u7gezMFKX4lgu/XpoZJk7ufI6UlFKXLj2hAMUuRlQX/nrmIPOmhRrG6tw2OQ2ZA/ZlXYpQ=="],
+ "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.25.0", "", { "dependencies": { "@hono/node-server": "^1.19.7", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-z0Zhn/LmQ3yz91dEfd5QgS7DpSjA4pk+3z2++zKgn5L6iDFM9QapsVoAQSbKLvlrFsZk9+ru6yHHWNq2lCYJKQ=="],
"@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.3.1", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-6nZrq5kfAz0POWyhljnbWQQJQ5uT8oE2ddX303q1uY0tWsivWKgBDXBBvuFPwOqRRalXJuVO9EjOdVtuhLX0zg=="],
@@ -1530,7 +1547,7 @@
"@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collapsible": "1.1.11", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-l3W5D54emV2ues7jjeG1xcyN7S3jnK3zE2zHqgn0CmMsy9lNJwmgcrmaxS+7ipw15FAivzKNzH3d5EcGoFKw0A=="],
- "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.0.5", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-dialog": "1.0.5", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-OrVIOcZL0tl6xibeuGt5/+UxoT2N27KCFOPjFyfXMnchxSHZ/OW7cCX2nGlIYJrbHK/fczPcFzAwvNBB6XBNMA=="],
+ "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="],
"@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA=="],
@@ -1544,17 +1561,17 @@
"@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
- "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.0.5", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-dismissable-layer": "1.0.5", "@radix-ui/react-focus-guards": "1.0.1", "@radix-ui/react-focus-scope": "1.0.4", "@radix-ui/react-id": "1.0.1", "@radix-ui/react-portal": "1.0.4", "@radix-ui/react-presence": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-slot": "1.0.2", "@radix-ui/react-use-controllable-state": "1.0.1", "aria-hidden": "^1.1.1", "react-remove-scroll": "2.5.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q=="],
+ "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="],
"@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
- "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.0.5", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1", "@radix-ui/react-use-escape-keydown": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g=="],
+ "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
"@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.1", "", { "dependencies": { "@radix-ui/primitive": "1.1.0", "@radix-ui/react-compose-refs": "1.1.0", "@radix-ui/react-context": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-menu": "2.1.1", "@radix-ui/react-primitive": "2.0.0", "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ=="],
- "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA=="],
+ "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
- "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.0.4", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA=="],
+ "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
"@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.0.7", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-dismissable-layer": "1.0.5", "@radix-ui/react-popper": "1.1.3", "@radix-ui/react-portal": "1.0.4", "@radix-ui/react-presence": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-controllable-state": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-OcUN2FU0YpmajD/qkph3XzMcK/NmSk9hGWnjV68p6QiZMgILugusgQwnLSDs3oFSJYGKf3Y49zgFedhGh04k9A=="],
@@ -1570,7 +1587,7 @@
"@radix-ui/react-popper": ["@radix-ui/react-popper@1.1.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.0.3", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1", "@radix-ui/react-use-layout-effect": "1.0.1", "@radix-ui/react-use-rect": "1.0.1", "@radix-ui/react-use-size": "1.0.1", "@radix-ui/rect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w=="],
- "@radix-ui/react-portal": ["@radix-ui/react-portal@1.0.4", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q=="],
+ "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
"@radix-ui/react-presence": ["@radix-ui/react-presence@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-use-layout-effect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg=="],
@@ -1602,7 +1619,7 @@
"@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
- "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg=="],
+ "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
"@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
@@ -1732,7 +1749,7 @@
"@sinonjs/fake-timers": ["@sinonjs/fake-timers@10.3.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.0" } }, "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA=="],
- "@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@smithy/abort-controller": ["@smithy/abort-controller@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-P7JD4J+wxHMpGxqIg6SHno2tPkZbBUBLbPpR5/T1DEUvw/mEaINBMaPFZNM7lA+ToSCZ36j6nMHa+5kej+fhGg=="],
"@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw=="],
@@ -1744,7 +1761,7 @@
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@3.2.0", "", { "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "tslib": "^2.6.2" } }, "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA=="],
- "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
+ "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.6", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-OZfsI+YRG26XZik/jKMMg37acnBSbUiK/8nETW3uM3mLj+0tMmFXdHQw1e5WEd/IHN8BGOh3te91SNDe2o4RHg=="],
"@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.4", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-d5T7ZS3J/r8P/PDjgmCcutmNxnSRvPH1U6iHeXjzI50sMr78GLmFcrczLw33Ap92oEKqa4CLrkAPeSSOqvGdUA=="],
@@ -1780,13 +1797,13 @@
"@smithy/node-config-provider": ["@smithy/node-config-provider@4.0.1", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ=="],
- "@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+ "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.6", "", { "dependencies": { "@smithy/abort-controller": "^4.2.6", "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-Gsb9jf4ido5BhPfani4ggyrKDd3ZK+vTFWmUaZeFg5G3E5nhFmqiTzAIbHqmPs1sARuJawDiGMGR/nY+Gw6+aQ=="],
"@smithy/property-provider": ["@smithy/property-provider@3.1.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g=="],
"@smithy/protocol-http": ["@smithy/protocol-http@5.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3sfFd2MAzVt0Q/klOmjFi3oIkxczHs0avbwrfn1aBqtc23WqQSmjvk77MBw9WkEQcwbOYIX5/2z4ULj8DuxSsw=="],
- "@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-MeM9fTAiD3HvoInK/aA8mgJaKQDvm8N0dKy6EiFaCfgpovQr4CaOkJC28XqlSRABM+sHdSQXbC8NZ0DShBMHqg=="],
"@smithy/querystring-parser": ["@smithy/querystring-parser@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw=="],
@@ -1848,17 +1865,17 @@
"@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@4.36.1", "", { "dependencies": { "@tanstack/match-sorter-utils": "^8.7.0", "superjson": "^1.10.0", "use-sync-external-store": "^1.2.0" }, "peerDependencies": { "@tanstack/react-query": "^4.36.1", "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-WYku83CKP3OevnYSG8Y/QO9g0rT75v1om5IvcWUwiUZJ4LanYGLVCZ8TdFG5jfsq4Ej/lu2wwDAULEUnRIMBSw=="],
- "@tanstack/react-table": ["@tanstack/react-table@8.11.7", "", { "dependencies": { "@tanstack/table-core": "8.11.7" }, "peerDependencies": { "react": ">=16", "react-dom": ">=16" } }, "sha512-ZbzfMkLjxUTzNPBXJYH38pv2VpC9WUA+Qe5USSHEBz0dysDTv4z/ARI3csOed/5gmlmrPzVUN3UXGuUMbod3Jg=="],
+ "@tanstack/react-table": ["@tanstack/react-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww=="],
- "@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.12", "", { "dependencies": { "@tanstack/virtual-core": "3.13.12" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA=="],
+ "@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.13", "", { "dependencies": { "@tanstack/virtual-core": "3.13.13" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-4o6oPMDvQv+9gMi8rE6gWmsOjtUZUYIJHv7EB+GblyYdi8U6OqLl8rhHWIUZSL1dUU2dPwTdTgybCKf9EjIrQg=="],
- "@tanstack/table-core": ["@tanstack/table-core@8.11.7", "", {}, "sha512-N3ksnkbPbsF3PjubuZCB/etTqvctpXWRHIXTmYfJFnhynQKjeZu8BCuHvdlLPpumKbA+bjY4Ay9AELYLOXPWBg=="],
+ "@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="],
- "@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.12", "", {}, "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA=="],
+ "@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.13", "", {}, "sha512-uQFoSdKKf5S8k51W5t7b2qpfkyIbdHMzAn+AMQvHPxKUPeo1SsGaA4JRISQT87jm28b7z8OEqPcg1IOZagQHcA=="],
"@testing-library/dom": ["@testing-library/dom@9.3.4", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.1.3", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" } }, "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ=="],
- "@testing-library/jest-dom": ["@testing-library/jest-dom@5.17.0", "", { "dependencies": { "@adobe/css-tools": "^4.0.1", "@babel/runtime": "^7.9.2", "@types/testing-library__jest-dom": "^5.9.1", "aria-query": "^5.0.0", "chalk": "^3.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.5.6", "lodash": "^4.17.15", "redent": "^3.0.0" } }, "sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg=="],
+ "@testing-library/jest-dom": ["@testing-library/jest-dom@6.9.1", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="],
"@testing-library/react": ["@testing-library/react@14.3.1", "", { "dependencies": { "@babel/runtime": "^7.12.5", "@testing-library/dom": "^9.0.0", "@types/react-dom": "^18.0.0" }, "peerDependencies": { "react": "^18.0.0", "react-dom": "^18.0.0" } }, "sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ=="],
@@ -1926,7 +1943,7 @@
"@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="],
- "@types/jsdom": ["@types/jsdom@20.0.1", "", { "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", "parse5": "^7.0.0" } }, "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ=="],
+ "@types/jsdom": ["@types/jsdom@21.1.7", "", { "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", "parse5": "^7.0.0" } }, "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA=="],
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
@@ -2064,8 +2081,6 @@
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="],
- "@waylaidwanderer/fetch-event-source": ["@waylaidwanderer/fetch-event-source@3.0.1", "", {}, "sha512-gkc7vmBW9uulRj7tY30/1D8iBrpcgphBpI+e7LP744x/hAzaQxUuyF+n4O5dctKx+dE3i4BFuCWMEz9fAx2jlQ=="],
-
"@webassemblyjs/ast": ["@webassemblyjs/ast@1.12.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg=="],
"@webassemblyjs/floating-point-hex-parser": ["@webassemblyjs/floating-point-hex-parser@1.11.6", "", {}, "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw=="],
@@ -2110,7 +2125,7 @@
"abstract-logging": ["abstract-logging@2.0.1", "", {}, "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="],
- "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="],
+ "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
"acorn": ["acorn@8.15.0", "", { "bin": "bin/acorn" }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
@@ -2122,7 +2137,7 @@
"acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="],
- "agent-base": ["agent-base@7.1.3", "", {}, "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw=="],
+ "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
@@ -2154,8 +2169,6 @@
"array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="],
- "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="],
-
"array-includes": ["array-includes@3.1.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" } }, "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ=="],
"array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="],
@@ -2250,7 +2263,7 @@
"bn.js": ["bn.js@4.12.1", "", {}, "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg=="],
- "body-parser": ["body-parser@1.20.3", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g=="],
+ "body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
@@ -2414,7 +2427,7 @@
"constants-browserify": ["constants-browserify@1.0.0", "", {}, "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ=="],
- "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="],
+ "content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
@@ -2424,7 +2437,7 @@
"cookie-parser": ["cookie-parser@1.4.7", "", { "dependencies": { "cookie": "0.7.2", "cookie-signature": "1.0.6" } }, "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw=="],
- "cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="],
+ "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
"cookiejar": ["cookiejar@2.1.4", "", {}, "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="],
@@ -2492,7 +2505,7 @@
"cssom": ["cssom@0.5.0", "", {}, "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw=="],
- "cssstyle": ["cssstyle@2.3.0", "", { "dependencies": { "cssom": "~0.3.6" } }, "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A=="],
+ "cssstyle": ["cssstyle@4.6.0", "", { "dependencies": { "@asamuzakjp/css-color": "^3.2.0", "rrweb-cssom": "^0.8.0" } }, "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
@@ -2502,7 +2515,7 @@
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
- "data-urls": ["data-urls@3.0.2", "", { "dependencies": { "abab": "^2.0.6", "whatwg-mimetype": "^3.0.0", "whatwg-url": "^11.0.0" } }, "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ=="],
+ "data-urls": ["data-urls@5.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" } }, "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg=="],
"data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="],
@@ -2576,7 +2589,7 @@
"doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="],
- "dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="],
+ "dom-accessibility-api": ["dom-accessibility-api@0.6.3", "", {}, "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w=="],
"dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="],
@@ -2742,11 +2755,11 @@
"export-from-json": ["export-from-json@1.7.4", "", {}, "sha512-FjmpluvZS2PTYyhkoMfQoyEJMfe2bfAyNpa5Apa6C9n7SWUWyJkG/VFnzERuj3q9Jjo3iwBjwVsDQ7Z7sczthA=="],
- "express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="],
+ "express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
"express-mongo-sanitize": ["express-mongo-sanitize@2.2.0", "", {}, "sha512-PZBs5nwhD6ek9ZuP+W2xmpvcrHwXZxD5GdieX2dsjPbAbH4azOkrHbycBud2QRU+YQF1CT+pki/lZGedHgo/dQ=="],
- "express-rate-limit": ["express-rate-limit@7.5.0", "", { "peerDependencies": { "express": "^4.11 || 5 || ^5.0.0-beta.1" } }, "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg=="],
+ "express-rate-limit": ["express-rate-limit@8.2.1", "", { "dependencies": { "ip-address": "10.0.1" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g=="],
"express-session": ["express-session@1.18.2", "", { "dependencies": { "cookie": "0.7.2", "cookie-signature": "1.0.7", "debug": "2.6.9", "depd": "~2.0.0", "on-headers": "~1.1.0", "parseurl": "~1.3.3", "safe-buffer": "5.2.1", "uid-safe": "~2.1.5" } }, "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A=="],
@@ -2804,7 +2817,7 @@
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
- "finalhandler": ["finalhandler@1.3.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ=="],
+ "finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
"find-cache-dir": ["find-cache-dir@3.3.2", "", { "dependencies": { "commondir": "^1.0.1", "make-dir": "^3.0.2", "pkg-dir": "^4.1.0" } }, "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig=="],
@@ -2840,7 +2853,7 @@
"framer-motion": ["framer-motion@12.23.9", "", { "dependencies": { "motion-dom": "^12.23.9", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid"] }, "sha512-TqEHXj8LWfQSKqfdr5Y4mYltYLw96deu6/K9kGDd+ysqRJPNwF9nb5mZcrLmybHbU7gcJ+HQar41U3UTGanbbQ=="],
- "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="],
+ "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
"fs-extra": ["fs-extra@11.3.2", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A=="],
@@ -2898,8 +2911,6 @@
"google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
- "googleapis": ["googleapis@126.0.1", "", { "dependencies": { "google-auth-library": "^9.0.0", "googleapis-common": "^7.0.0" } }, "sha512-4N8LLi+hj6ytK3PhE52KcM8iSGhJjtXnCDYB4fp6l+GdLbYz4FoDmx074WqMbl7iYMDN87vqD/8drJkhxW92mQ=="],
-
"googleapis-common": ["googleapis-common@7.0.1", "", { "dependencies": { "extend": "^3.0.2", "gaxios": "^6.0.3", "google-auth-library": "^9.0.0", "qs": "^6.7.0", "url-template": "^2.0.8", "uuid": "^9.0.0" } }, "sha512-mgt5zsd7zj5t5QXvDanjWguMdHAcJmmDrF9RkInCecNsyV7S7YtGqm5v2IWONNID88osb7zmx5FtrAP12JfD0w=="],
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
@@ -2962,11 +2973,13 @@
"hoist-non-react-statics": ["hoist-non-react-statics@3.3.2", "", { "dependencies": { "react-is": "^16.7.0" } }, "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="],
+ "hono": ["hono@4.11.1", "", {}, "sha512-KsFcH0xxHes0J4zaQgWbYwmz3UPOOskdqZmItstUG93+Wk1ePBLkLGwbP9zlmh1BFUiL8Qp+Xfu9P7feJWpGNg=="],
+
"hookified": ["hookified@1.12.1", "", {}, "sha512-xnKGl+iMIlhrZmGHB729MqlmPoWBznctSQTYCpFKqNsCgimJQmithcW0xSQMMFzYnV2iKUh25alswn6epgxS0Q=="],
"htm": ["htm@3.1.1", "", {}, "sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ=="],
- "html-encoding-sniffer": ["html-encoding-sniffer@3.0.0", "", { "dependencies": { "whatwg-encoding": "^2.0.0" } }, "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA=="],
+ "html-encoding-sniffer": ["html-encoding-sniffer@4.0.0", "", { "dependencies": { "whatwg-encoding": "^3.1.1" } }, "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ=="],
"html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="],
@@ -3040,6 +3053,8 @@
"ioredis": ["ioredis@5.3.2", "", { "dependencies": { "@ioredis/commands": "^1.1.1", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA=="],
+ "ip-address": ["ip-address@10.0.1", "", {}, "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA=="],
+
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
"is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
@@ -3182,7 +3197,7 @@
"jest-each": ["jest-each@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "chalk": "^4.1.2", "jest-util": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ=="],
- "jest-environment-jsdom": ["jest-environment-jsdom@29.7.0", "", { "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/jsdom": "^20.0.0", "@types/node": "*", "jest-mock": "^29.7.0", "jest-util": "^29.7.0", "jsdom": "^20.0.0" }, "peerDependencies": { "canvas": "^2.5.0" }, "optionalPeers": ["canvas"] }, "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA=="],
+ "jest-environment-jsdom": ["jest-environment-jsdom@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/environment-jsdom-abstract": "30.2.0", "@types/jsdom": "^21.1.7", "@types/node": "*", "jsdom": "^26.1.0" }, "peerDependencies": { "canvas": "^3.0.0" }, "optionalPeers": ["canvas"] }, "sha512-zbBTiqr2Vl78pKp/laGBREYzbZx9ZtqPjOK4++lL4BNDhxRnahg51HtoDrk9/VjIy9IthNEWdKVd7H5bqBhiWQ=="],
"jest-environment-node": ["jest-environment-node@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0" } }, "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA=="],
@@ -3226,7 +3241,7 @@
"jiti": ["jiti@1.21.0", "", { "bin": "bin/jiti.js" }, "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q=="],
- "jose": ["jose@4.15.5", "", {}, "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg=="],
+ "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
"jotai": ["jotai@2.12.5", "", { "peerDependencies": { "@types/react": ">=17.0.0", "react": ">=17.0.0" } }, "sha512-G8m32HW3lSmcz/4mbqx0hgJIQ0ekndKWiYP7kWVKi0p6saLXdSoye+FZiOFyonnd7Q482LCzm8sMDl7Ar1NWDw=="],
@@ -3238,7 +3253,7 @@
"js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
- "jsdom": ["jsdom@20.0.3", "", { "dependencies": { "abab": "^2.0.6", "acorn": "^8.8.1", "acorn-globals": "^7.0.0", "cssom": "^0.5.0", "cssstyle": "^2.3.0", "data-urls": "^3.0.2", "decimal.js": "^10.4.2", "domexception": "^4.0.0", "escodegen": "^2.0.0", "form-data": "^4.0.0", "html-encoding-sniffer": "^3.0.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.1", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.2", "parse5": "^7.1.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^4.1.2", "w3c-xmlserializer": "^4.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^2.0.0", "whatwg-mimetype": "^3.0.0", "whatwg-url": "^11.0.0", "ws": "^8.11.0", "xml-name-validator": "^4.0.0" }, "peerDependencies": { "canvas": "^2.5.0" }, "optionalPeers": ["canvas"] }, "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ=="],
+ "jsdom": ["jsdom@26.1.0", "", { "dependencies": { "cssstyle": "^4.2.1", "data-urls": "^5.0.0", "decimal.js": "^10.5.0", "html-encoding-sniffer": "^4.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.16", "parse5": "^7.2.1", "rrweb-cssom": "^0.8.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^5.1.1", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.1.1", "ws": "^8.18.0", "xml-name-validator": "^5.0.0" }, "peerDependencies": { "canvas": "^3.0.0" }, "optionalPeers": ["canvas"] }, "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg=="],
"jsesc": ["jsesc@3.1.0", "", { "bin": "bin/jsesc" }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
@@ -3254,9 +3269,11 @@
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
+ "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="],
+
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
- "json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
+ "json5": ["json5@2.2.3", "", { "bin": "lib/cli.js" }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
"jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
@@ -3428,7 +3445,7 @@
"mdn-data": ["mdn-data@2.0.14", "", {}, "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="],
- "media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="],
+ "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
"meilisearch": ["meilisearch@0.38.0", "", { "dependencies": { "cross-fetch": "^3.1.6" } }, "sha512-bHaq8nYxSKw9/Qslq1Zes5g9tHgFkxy/I9o8942wv2PqlNOT0CzptIkh/x98N52GikoSZOXSQkgt6oMjtf5uZw=="],
@@ -3436,7 +3453,7 @@
"memorystore": ["memorystore@1.6.7", "", { "dependencies": { "debug": "^4.3.0", "lru-cache": "^4.0.3" } }, "sha512-OZnmNY/NDrKohPQ+hxp0muBcBKrzKNtHr55DbqSx9hLsYVNnomSAMRAtI7R64t3gf3ID7tHQA7mG4oL3Hu9hdw=="],
- "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="],
+ "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
@@ -3512,9 +3529,9 @@
"mime": ["mime@3.0.0", "", { "bin": "cli.js" }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
- "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
+ "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
- "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
+ "mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
"mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
@@ -3608,7 +3625,7 @@
"nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
- "nwsapi": ["nwsapi@2.2.7", "", {}, "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ=="],
+ "nwsapi": ["nwsapi@2.2.23", "", {}, "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ=="],
"oauth": ["oauth@0.10.0", "", {}, "sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q=="],
@@ -3730,7 +3747,7 @@
"path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="],
- "path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="],
+ "path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="],
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
@@ -3940,7 +3957,7 @@
"qrcode.react": ["qrcode.react@4.2.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA=="],
- "qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="],
+ "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
"querystring-es3": ["querystring-es3@0.2.1", "", {}, "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA=="],
@@ -3994,7 +4011,7 @@
"react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
- "react-remove-scroll": ["react-remove-scroll@2.5.5", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.3", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", "use-callback-ref": "^1.3.0", "use-sidecar": "^1.1.2" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw=="],
+ "react-remove-scroll": ["react-remove-scroll@2.7.1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA=="],
"react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
@@ -4114,6 +4131,8 @@
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
+ "rrweb-cssom": ["rrweb-cssom@0.8.0", "", {}, "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw=="],
+
"run-applescript": ["run-applescript@7.0.0", "", {}, "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
@@ -4144,11 +4163,11 @@
"semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
- "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="],
+ "send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
"serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="],
- "serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="],
+ "serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
"set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="],
@@ -4350,6 +4369,10 @@
"tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="],
+ "tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="],
+
+ "tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="],
+
"tmpl": ["tmpl@1.0.5", "", {}, "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw=="],
"to-buffer": ["to-buffer@1.2.1", "", { "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", "typed-array-buffer": "^1.0.3" } }, "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ=="],
@@ -4364,7 +4387,7 @@
"touch": ["touch@3.1.0", "", { "dependencies": { "nopt": "~1.0.10" }, "bin": { "nodetouch": "bin/nodetouch.js" } }, "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA=="],
- "tough-cookie": ["tough-cookie@4.1.3", "", { "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", "universalify": "^0.2.0", "url-parse": "^1.5.3" } }, "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw=="],
+ "tough-cookie": ["tough-cookie@5.1.2", "", { "dependencies": { "tldts": "^6.1.32" } }, "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A=="],
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
@@ -4398,7 +4421,7 @@
"type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
- "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="],
+ "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
"typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="],
@@ -4526,7 +4549,7 @@
"w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="],
- "w3c-xmlserializer": ["w3c-xmlserializer@4.0.0", "", { "dependencies": { "xml-name-validator": "^4.0.0" } }, "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw=="],
+ "w3c-xmlserializer": ["w3c-xmlserializer@5.0.0", "", { "dependencies": { "xml-name-validator": "^5.0.0" } }, "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA=="],
"walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="],
@@ -4546,7 +4569,7 @@
"websocket-extensions": ["websocket-extensions@0.1.4", "", {}, "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="],
- "whatwg-encoding": ["whatwg-encoding@2.0.0", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg=="],
+ "whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="],
"whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="],
@@ -4620,7 +4643,7 @@
"xml-encryption": ["xml-encryption@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.5", "escape-html": "^1.0.3", "xpath": "0.0.32" } }, "sha512-PV7qnYpoAMXbf1kvQkqMScLeQpjCMixddAKq9PtqVrho8HnYbBOWNfG0kA4R7zxQDo7w9kiYAyzS/ullAyO55Q=="],
- "xml-name-validator": ["xml-name-validator@4.0.0", "", {}, "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw=="],
+ "xml-name-validator": ["xml-name-validator@5.0.0", "", {}, "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg=="],
"xml2js": ["xml2js@0.6.2", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="],
@@ -4658,6 +4681,16 @@
"@apideck/better-ajv-errors/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
+ "@asamuzakjp/css-color/@csstools/css-calc": ["@csstools/css-calc@2.1.4", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ=="],
+
+ "@asamuzakjp/css-color/@csstools/css-color-parser": ["@csstools/css-color-parser@3.1.0", "", { "dependencies": { "@csstools/color-helpers": "^5.1.0", "@csstools/css-calc": "^2.1.4" }, "peerDependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA=="],
+
+ "@asamuzakjp/css-color/@csstools/css-parser-algorithms": ["@csstools/css-parser-algorithms@3.0.5", "", { "peerDependencies": { "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ=="],
+
+ "@asamuzakjp/css-color/@csstools/css-tokenizer": ["@csstools/css-tokenizer@3.0.4", "", {}, "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw=="],
+
+ "@asamuzakjp/css-color/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
+
"@aws-crypto/crc32/@aws-sdk/types": ["@aws-sdk/types@3.609.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q=="],
"@aws-crypto/crc32c/@aws-sdk/types": ["@aws-sdk/types@3.609.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q=="],
@@ -4742,57 +4775,63 @@
"@aws-sdk/client-bedrock-agent-runtime/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.927.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.927.0", "@aws-sdk/credential-provider-http": "3.927.0", "@aws-sdk/credential-provider-ini": "3.927.0", "@aws-sdk/credential-provider-process": "3.927.0", "@aws-sdk/credential-provider-sso": "3.927.0", "@aws-sdk/credential-provider-web-identity": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-M6BLrI+WHQ7PUY1aYu2OkI/KEz9aca+05zyycACk7cnlHlZaQ3vTFd0xOqF+A1qaenQBuxApOTs7Z21pnPUo9Q=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.952.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-ini": "3.952.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.952.0", "@aws-sdk/credential-provider-web-identity": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pj7nidLrb3Dz9llcUPh6N0Yv1dBYTS9xJqi8u0kI8D5sn72HJMB+fIOhcDQVXXAw/dpVolOAH9FOAbog5JDAMg=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.948.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Qa8Zj+EAqA0VlAVvxpRnpBpIWJI9KUwaioY1vkeNVwXPlNaz9y9zCKVM9iU9OZ5HXpoUg6TnhATAHXHAE8+QsQ=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.7", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/nested-clients": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-JRdaprkZjZ6EY4WVwsZaEjPUj9W9vqlSaFDm4oD+IbwlY4GjAXuUQK6skKcvVyoOsSTvJp/CaveSws2FiWUp9Q=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/types": ["@aws-sdk/types@3.922.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-eLA6XjVobAUAMivvM7DBL79mnHyrm+32TkXNWZua5mnxF+6kQCfblKKJvxMZLGosO53/Ex46ogim8IY5Nbqv2w=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/config-resolver": ["@smithy/config-resolver@4.4.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/types": "^4.10.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-s3U5ChS21DwU54kMmZ0UJumoS5cg0+rGVZvN6f5Lp6EbAVi0ZyP+qDSHdewfmXKUgNK1j3z45JyzulkDukrjAA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/core": ["@smithy/core@3.19.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.7", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-stream": "^4.5.7", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-Y9oHXpBcXQgYHOcAEmxjkDilUbSTkgKjoHYed3WaYUH8jngq8lPWDBSpjHblJ9uOgBdy5mh3pzebrScDdYr29w=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.6", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-6OiaAaEbLB6dEkRbQyNzFSJv5HDvly3Mc6q/qcPd2uS/g3szR8wAIkh7UndAFKfMypNSTuZ6eCBmgCLR5LacTg=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-xP5YXbOVRVN8A4pDnSUkEUsL9fYFU6VNhxo8tgr13YnMbf3Pn4xVr+hSyLVjS1Frfi1Uk03ET5Bwml4+0CeYEw=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.6", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-jhH7nJuaOpnTFcuZpWK9dqb6Ge2yGi1okTo0W6wkJrfwAm2vwmO74tF1v07JmrSyHBcKLQATEexclJw9K1Vj7w=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/hash-node": ["@smithy/hash-node@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-k3Dy9VNR37wfMh2/1RHkFf/e0rMyN0pjY0FdyY6ItJRjENYyVPRMwad6ZR1S9HFm6tTuIOd9pqKBmtJ4VHxvxg=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-E4t/V/q2T46RY21fpfznd1iSLTvCXKNKo4zJ1QuEFN4SE9gKfu2vb6bgq35LpufkQ+SETWIC7ZAf2GGvTlBaMQ=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.6", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-0cjqjyfj+Gls30ntq45SsBtqF3dfJQCeqQPyGz58Pk8OgrAr5YiB7ZvDzjCA94p4r6DCI4qLm7FKobqBjf515w=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.0", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-serde": "^4.2.7", "@smithy/node-config-provider": "^4.3.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-M6qWfUNny6NFNy8amrCGIb9TfOMUkHVtg9bHtEFGRgfH7A7AtPpn/fcrToGPjVDK1ECuMVvqGQOXcZxmu9K+7A=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.16", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/protocol-http": "^5.3.6", "@smithy/service-error-classification": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-retry": "^4.2.6", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-XPpNhNRzm3vhYm7YCsyw3AtmWggJbg1wNGAoqb7NBYr5XA5isMRv14jgbYyUV6IvbTBFZQdf2QpeW43LrRdStQ=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-JSbALU3G+JS4kyBZPqnJ3hxIYwOVRV7r9GNQMS6j5VsQDo5+Es5nddLfr9TQlxZLNHPvKSh+XSB0OuWGfSWFcA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.6", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-fYEyL59Qe82Ha1p97YQTMEQPJYmBS+ux76foqluaTVWoG9Px5J53w6NvXZNE3wP7lIicLDF7Vj1Em18XTX7fsA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
+
+ "@aws-sdk/client-bedrock-runtime/@smithy/smithy-client": ["@smithy/smithy-client@4.10.1", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-endpoint": "^4.4.0", "@smithy/middleware-stack": "^4.2.6", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-stream": "^4.5.7", "tslib": "^2.6.2" } }, "sha512-1ovWdxzYprhq+mWqiGZlt3kF69LJthuQcfY9BIyHx9MywTFKzFapluku1QXoaBB43GCsLDxNqS+1v30ure69AA=="],
+
+ "@aws-sdk/client-bedrock-runtime/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
+
+ "@aws-sdk/client-bedrock-runtime/@smithy/url-parser": ["@smithy/url-parser@4.2.6", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tVoyzJ2vXp4R3/aeV4EQjBDmCuWxRa8eo3KybL7Xv4wEM16nObYh7H1sNfcuLWHAAAzb0RVyxUz1S3sGj4X+Tg=="],
"@aws-sdk/client-bedrock-runtime/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
@@ -4800,15 +4839,17 @@
"@aws-sdk/client-bedrock-runtime/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.15", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-LiZQVAg/oO8kueX4c+oMls5njaD2cRLXRfcjlTYjhIqmwHnCwkQO5B3dMQH0c5PACILxGAQf6Mxsq7CjlDc76A=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.18", "", { "dependencies": { "@smithy/config-resolver": "^4.4.4", "@smithy/credential-provider-imds": "^4.2.6", "@smithy/node-config-provider": "^4.3.6", "@smithy/property-provider": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-Kw2J+KzYm9C9Z9nY6+W0tEnoZOofstVCMTshli9jhQbQCy64rueGfKzPfuFBnVUqZD9JobxTh2DzHmPkp/Va/Q=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-v60VNM2+mPvgHCBXEfMCYrQ0RepP6u6xvbAkMenfe4Mi872CqNkJzgcnQL837e8NdeDxBgrWQRTluKq5Lqdhfg=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/util-middleware": ["@smithy/util-middleware@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/util-retry": ["@smithy/util-retry@4.2.6", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-x7CeDQLPQ9cb6xN7fRJEjlP9NyGW/YeXWc4j/RUhg4I+H60F0PEeRc2c/z3rm9zmsdiMFzpV/rT+4UHW6KM1SA=="],
+
+ "@aws-sdk/client-bedrock-runtime/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
"@aws-sdk/client-bedrock-runtime/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
@@ -4950,6 +4991,8 @@
"@aws-sdk/client-kendra/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
+ "@aws-sdk/client-s3/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+
"@aws-sdk/client-sso/@aws-sdk/core": ["@aws-sdk/core@3.623.0", "", { "dependencies": { "@smithy/core": "^2.3.2", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-8Toq3X6trX/67obSdh4K0MFQY4f132bEbr1i0YPDWk/O3KdBt12mLC/sW3aVRnlIs110XMuX9yrWWqJ8fDW10g=="],
"@aws-sdk/client-sso/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.620.0", "", { "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/protocol-http": "^4.1.0", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg=="],
@@ -5122,6 +5165,18 @@
"@aws-sdk/credential-provider-ini/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
+
+ "@aws-sdk/credential-provider-login/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
+
+ "@aws-sdk/credential-provider-login/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
+
+ "@aws-sdk/credential-provider-login/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
+
+ "@aws-sdk/credential-provider-login/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
+
+ "@aws-sdk/credential-provider-login/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
+
"@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/property-provider": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-N27eFoRrO6MeUNumtNHDW9WOiwfd59LPXPqDrIa3kWL/s+fOKFHb9xIcF++bAwtcZnAxKkgpDCUP+INNZskE+w=="],
"@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/property-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-stream": "^4.1.2", "tslib": "^2.6.2" } }, "sha512-Xt9/U8qUCiw1hihztWkNeIR+arg6P+yda10OuCHX6kFVx3auTlU7+hCqs3UxqniGU4dguHuftf3mRpi5/GJ33Q=="],
@@ -5144,6 +5199,8 @@
"@aws-sdk/credential-provider-process/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
+ "@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.614.0", "", { "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "peerDependencies": { "@aws-sdk/client-sso-oidc": "^3.614.0" } }, "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw=="],
+
"@aws-sdk/credential-provider-sso/@aws-sdk/types": ["@aws-sdk/types@3.609.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q=="],
"@aws-sdk/credential-provider-sso/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
@@ -5160,184 +5217,146 @@
"@aws-sdk/credential-providers/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
- "@aws-sdk/eventstream-handler-node/@aws-sdk/types": ["@aws-sdk/types@3.922.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-eLA6XjVobAUAMivvM7DBL79mnHyrm+32TkXNWZua5mnxF+6kQCfblKKJvxMZLGosO53/Ex46ogim8IY5Nbqv2w=="],
+ "@aws-sdk/eventstream-handler-node/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
- "@aws-sdk/middleware-bucket-endpoint/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
+ "@aws-sdk/eventstream-handler-node/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
- "@aws-sdk/middleware-bucket-endpoint/@smithy/node-config-provider": ["@smithy/node-config-provider@4.0.1", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ=="],
+ "@aws-sdk/middleware-eventstream/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
- "@aws-sdk/middleware-eventstream/@aws-sdk/types": ["@aws-sdk/types@3.922.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-eLA6XjVobAUAMivvM7DBL79mnHyrm+32TkXNWZua5mnxF+6kQCfblKKJvxMZLGosO53/Ex46ogim8IY5Nbqv2w=="],
+ "@aws-sdk/middleware-eventstream/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
- "@aws-sdk/middleware-expect-continue/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
+ "@aws-sdk/middleware-eventstream/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core": ["@aws-sdk/core@3.758.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/core": "^3.1.5", "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/signature-v4": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-middleware": "^4.0.1", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg=="],
+ "@aws-sdk/middleware-websocket/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
+ "@aws-sdk/middleware-websocket/@aws-sdk/util-format-url": ["@aws-sdk/util-format-url@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/querystring-builder": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-MS5eSEtDUFIAMHrJaMERiHAvDPdfxc/T869ZjDNFAIiZhyc037REw0aoTNeimNXDNy2txRNZJaAUn/kE4RwN+g=="],
- "@aws-sdk/middleware-flexible-checksums/@smithy/node-config-provider": ["@smithy/node-config-provider@4.0.1", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ=="],
+ "@aws-sdk/middleware-websocket/@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.6", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-6OiaAaEbLB6dEkRbQyNzFSJv5HDvly3Mc6q/qcPd2uS/g3szR8wAIkh7UndAFKfMypNSTuZ6eCBmgCLR5LacTg=="],
- "@aws-sdk/middleware-flexible-checksums/@smithy/util-stream": ["@smithy/util-stream@4.1.2", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw=="],
+ "@aws-sdk/middleware-websocket/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
- "@aws-sdk/middleware-flexible-checksums/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
+ "@aws-sdk/middleware-websocket/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
- "@aws-sdk/middleware-location-constraint/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
+ "@aws-sdk/middleware-websocket/@smithy/signature-v4": ["@smithy/signature-v4@5.3.6", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA=="],
- "@aws-sdk/middleware-sdk-s3/@aws-sdk/core": ["@aws-sdk/core@3.758.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/core": "^3.1.5", "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/signature-v4": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-middleware": "^4.0.1", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg=="],
+ "@aws-sdk/middleware-websocket/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
- "@aws-sdk/middleware-sdk-s3/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
+ "@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/core": ["@smithy/core@3.1.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA=="],
+ "@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/node-config-provider": ["@smithy/node-config-provider@4.0.1", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ=="],
+ "@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/smithy-client": ["@smithy/smithy-client@4.1.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-stack": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-stream": "^4.1.2", "tslib": "^2.6.2" } }, "sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw=="],
+ "@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.948.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Qa8Zj+EAqA0VlAVvxpRnpBpIWJI9KUwaioY1vkeNVwXPlNaz9y9zCKVM9iU9OZ5HXpoUg6TnhATAHXHAE8+QsQ=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/util-config-provider": ["@smithy/util-config-provider@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w=="],
+ "@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.7", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/util-stream": ["@smithy/util-stream@4.1.2", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw=="],
+ "@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
+ "@aws-sdk/nested-clients/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
- "@aws-sdk/middleware-ssec/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
+ "@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="],
- "@aws-sdk/middleware-websocket/@aws-sdk/types": ["@aws-sdk/types@3.922.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-eLA6XjVobAUAMivvM7DBL79mnHyrm+32TkXNWZua5mnxF+6kQCfblKKJvxMZLGosO53/Ex46ogim8IY5Nbqv2w=="],
+ "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="],
- "@aws-sdk/middleware-websocket/@aws-sdk/util-format-url": ["@aws-sdk/util-format-url@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-UYLWPvZEd6TYilNkrQrIeXh2bXZsY3ighYErSEjD24f3JQhg0XdXoR/QHIE8licHu2qFrTRM6yi9LH1GY6X0cg=="],
+ "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ=="],
- "@aws-sdk/middleware-websocket/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+ "@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/types": "^4.10.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-s3U5ChS21DwU54kMmZ0UJumoS5cg0+rGVZvN6f5Lp6EbAVi0ZyP+qDSHdewfmXKUgNK1j3z45JyzulkDukrjAA=="],
- "@aws-sdk/nested-clients/@aws-sdk/core": ["@aws-sdk/core@3.758.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/core": "^3.1.5", "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/signature-v4": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-middleware": "^4.0.1", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-0RswbdR9jt/XKemaLNuxi2gGr4xGlHyGxkTdhSQzCyUe9A9OPCoLl3rIESRguQEech+oJnbHk/wuiwHqTuP9sg=="],
+ "@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.19.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.7", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-stream": "^4.5.7", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-Y9oHXpBcXQgYHOcAEmxjkDilUbSTkgKjoHYed3WaYUH8jngq8lPWDBSpjHblJ9uOgBdy5mh3pzebrScDdYr29w=="],
- "@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw=="],
+ "@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
- "@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w=="],
+ "@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-k3Dy9VNR37wfMh2/1RHkFf/e0rMyN0pjY0FdyY6ItJRjENYyVPRMwad6ZR1S9HFm6tTuIOd9pqKBmtJ4VHxvxg=="],
- "@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA=="],
+ "@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-E4t/V/q2T46RY21fpfznd1iSLTvCXKNKo4zJ1QuEFN4SE9gKfu2vb6bgq35LpufkQ+SETWIC7ZAf2GGvTlBaMQ=="],
- "@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.758.0", "", { "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@smithy/core": "^3.1.5", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-iNyehQXtQlj69JCgfaOssgZD4HeYGOwxcaKeG6F+40cwBjTAi0+Ph1yfDwqk2qiBPIRWJ/9l2LodZbxiBqgrwg=="],
+ "@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.6", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-0cjqjyfj+Gls30ntq45SsBtqF3dfJQCeqQPyGz58Pk8OgrAr5YiB7ZvDzjCA94p4r6DCI4qLm7FKobqBjf515w=="],
- "@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ=="],
+ "@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.0", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-serde": "^4.2.7", "@smithy/node-config-provider": "^4.3.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-M6qWfUNny6NFNy8amrCGIb9TfOMUkHVtg9bHtEFGRgfH7A7AtPpn/fcrToGPjVDK1ECuMVvqGQOXcZxmu9K+7A=="],
- "@aws-sdk/nested-clients/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
+ "@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.16", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/protocol-http": "^5.3.6", "@smithy/service-error-classification": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-retry": "^4.2.6", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-XPpNhNRzm3vhYm7YCsyw3AtmWggJbg1wNGAoqb7NBYr5XA5isMRv14jgbYyUV6IvbTBFZQdf2QpeW43LrRdStQ=="],
- "@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.743.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", "@smithy/util-endpoints": "^3.0.1", "tslib": "^2.6.2" } }, "sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw=="],
+ "@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
- "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.734.0", "", { "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng=="],
+ "@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-JSbALU3G+JS4kyBZPqnJ3hxIYwOVRV7r9GNQMS6j5VsQDo5+Es5nddLfr9TQlxZLNHPvKSh+XSB0OuWGfSWFcA=="],
- "@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.758.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-A5EZw85V6WhoKMV2hbuFRvb9NPlxEErb4HPO6/SPXYY4QrjprIzScHxikqcWv1w4J3apB1wto9LPU3IMsYtfrw=="],
+ "@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.6", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-fYEyL59Qe82Ha1p97YQTMEQPJYmBS+ux76foqluaTVWoG9Px5J53w6NvXZNE3wP7lIicLDF7Vj1Em18XTX7fsA=="],
- "@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.0.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-config-provider": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ=="],
+ "@aws-sdk/nested-clients/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
- "@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.1.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA=="],
+ "@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.10.1", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-endpoint": "^4.4.0", "@smithy/middleware-stack": "^4.2.6", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-stream": "^4.5.7", "tslib": "^2.6.2" } }, "sha512-1ovWdxzYprhq+mWqiGZlt3kF69LJthuQcfY9BIyHx9MywTFKzFapluku1QXoaBB43GCsLDxNqS+1v30ure69AA=="],
- "@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA=="],
+ "@aws-sdk/nested-clients/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
- "@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w=="],
+ "@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.6", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tVoyzJ2vXp4R3/aeV4EQjBDmCuWxRa8eo3KybL7Xv4wEM16nObYh7H1sNfcuLWHAAAzb0RVyxUz1S3sGj4X+Tg=="],
- "@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ=="],
+ "@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
- "@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ=="],
+ "@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
- "@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.0.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-serde": "^4.0.2", "@smithy/node-config-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg=="],
+ "@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
- "@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.0.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/service-error-classification": "^4.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "tslib": "^2.6.2", "uuid": "^9.0.1" } }, "sha512-58j9XbUPLkqAcV1kHzVX/kAR16GT+j7DUZJqwzsxh1jtz7G82caZiGyyFgUvogVfNTg3TeAOIJepGc8TXF4AVQ=="],
+ "@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.15", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-LiZQVAg/oO8kueX4c+oMls5njaD2cRLXRfcjlTYjhIqmwHnCwkQO5B3dMQH0c5PACILxGAQf6Mxsq7CjlDc76A=="],
- "@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
+ "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.18", "", { "dependencies": { "@smithy/config-resolver": "^4.4.4", "@smithy/credential-provider-imds": "^4.2.6", "@smithy/node-config-provider": "^4.3.6", "@smithy/property-provider": "^4.2.6", "@smithy/smithy-client": "^4.10.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-Kw2J+KzYm9C9Z9nY6+W0tEnoZOofstVCMTshli9jhQbQCy64rueGfKzPfuFBnVUqZD9JobxTh2DzHmPkp/Va/Q=="],
- "@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA=="],
+ "@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-v60VNM2+mPvgHCBXEfMCYrQ0RepP6u6xvbAkMenfe4Mi872CqNkJzgcnQL837e8NdeDxBgrWQRTluKq5Lqdhfg=="],
- "@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.0.1", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ=="],
+ "@aws-sdk/nested-clients/@smithy/util-middleware": ["@smithy/util-middleware@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg=="],
- "@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+ "@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.6", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-x7CeDQLPQ9cb6xN7fRJEjlP9NyGW/YeXWc4j/RUhg4I+H60F0PEeRc2c/z3rm9zmsdiMFzpV/rT+4UHW6KM1SA=="],
- "@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.1.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-stack": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-stream": "^4.1.2", "tslib": "^2.6.2" } }, "sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw=="],
+ "@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
- "@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.0.1", "", { "dependencies": { "@smithy/querystring-parser": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g=="],
+ "@aws-sdk/token-providers/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
- "@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="],
+ "@aws-sdk/token-providers/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="],
- "@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA=="],
+ "@aws-sdk/token-providers/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
- "@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg=="],
+ "@aws-sdk/token-providers/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
- "@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.0.7", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-CZgDDrYHLv0RUElOsmZtAnp1pIjwDVCSuZWOPhIOBvG36RDfX1Q9+6lS61xBf+qqvHoqRjHxgINeQz47cYFC2Q=="],
-
- "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.0.7", "", { "dependencies": { "@smithy/config-resolver": "^4.0.1", "@smithy/credential-provider-imds": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-79fQW3hnfCdrfIi1soPbK3zmooRFnLpSx3Vxi6nUlqaaQeC5dm8plt4OTNDNqEEEDkvKghZSaoti684dQFVrGQ=="],
-
- "@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.0.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA=="],
-
- "@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.0.1", "", { "dependencies": { "@smithy/service-error-classification": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw=="],
-
- "@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
-
- "@aws-sdk/region-config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w=="],
-
- "@aws-sdk/s3-request-presigner/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
-
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.0.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-serde": "^4.0.2", "@smithy/node-config-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg=="],
-
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client": ["@smithy/smithy-client@4.1.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-stack": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-stream": "^4.1.2", "tslib": "^2.6.2" } }, "sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw=="],
-
- "@aws-sdk/signature-v4-multi-region/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
-
- "@aws-sdk/token-providers/@aws-sdk/types": ["@aws-sdk/types@3.609.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q=="],
-
- "@aws-sdk/token-providers/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
-
- "@aws-sdk/token-providers/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/util-format-url/@aws-sdk/types": ["@aws-sdk/types@3.734.0", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg=="],
+ "@aws-sdk/token-providers/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
"@aws-sdk/util-format-url/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
"@azure/core-http-compat/@azure/abort-controller": ["@azure/abort-controller@1.1.0", "", { "dependencies": { "tslib": "^2.2.0" } }, "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw=="],
- "@azure/core-rest-pipeline/https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
-
"@azure/core-xml/fast-xml-parser": ["fast-xml-parser@5.0.9", "", { "dependencies": { "strnum": "^2.0.5" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-2mBwCiuW3ycKQQ6SOesSB8WeF+fIGb6I/GG5vU5/XEptwFFhp9PE8b9O7fbs2dpq9fXn4ULR3UsfydNUCntf5A=="],
- "@azure/msal-node/uuid": ["uuid@8.3.2", "", { "bin": "dist/bin/uuid" }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
-
- "@babel/core/json5": ["json5@2.2.3", "", { "bin": "lib/cli.js" }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
-
- "@babel/core/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@babel/helper-compilation-targets/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
"@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
- "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
- "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
- "@babel/helper-create-regexp-features-plugin/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
"@babel/plugin-transform-classes/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
+ "@babel/plugin-transform-explicit-resource-management/@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="],
+
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.8", "", { "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.5.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg=="],
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.9.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.5.0", "core-js-compat": "^3.34.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg=="],
"@babel/plugin-transform-runtime/babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.5.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.5.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg=="],
- "@babel/plugin-transform-runtime/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.23.10", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-replace-supers": "^7.22.20", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw=="],
- "@babel/preset-env/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"@babel/preset-typescript/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.23.3", "", { "dependencies": { "@babel/helper-module-transforms": "^7.23.3", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-simple-access": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA=="],
+ "@codesandbox/sandpack-client/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
+
"@csstools/css-color-parser/@csstools/color-helpers": ["@csstools/color-helpers@4.0.0", "", {}, "sha512-wjyXB22/h2OvxAr3jldPB7R7kjTUEzopvjitS8jWtyd8fN6xJ8vy1HnHu0ZNfEkqpBJgQ76Q+sBDshWcMvTa/w=="],
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
+ "@headlessui/react/@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.12", "", { "dependencies": { "@tanstack/virtual-core": "3.13.12" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA=="],
+
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
@@ -5364,7 +5383,15 @@
"@jest/core/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "@jest/environment/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
+ "@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
+
+ "@jest/environment/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
+
+ "@jest/environment-jsdom-abstract/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
+
+ "@jest/environment-jsdom-abstract/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
+
+ "@jest/environment-jsdom-abstract/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
"@jest/expect/expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="],
@@ -5372,12 +5399,8 @@
"@jest/fake-timers/jest-message-util": ["jest-message-util@29.7.0", "", { "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w=="],
- "@jest/globals/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="],
-
"@jest/globals/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
- "@jest/pattern/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="],
-
"@jest/reporters/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@jest/reporters/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
@@ -5386,8 +5409,6 @@
"@jest/reporters/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "@jest/snapshot-utils/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="],
-
"@jest/source-map/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"@jest/test-sequencer/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
@@ -5404,7 +5425,7 @@
"@jridgewell/source-map/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
- "@langchain/anthropic/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.65.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-zIdPOcrCVEI8t3Di40nH4z9EoeyGZfXbYSvWdDLsB/KkaSYMnEgC7gmcgWu83g2NTn1ZTpbMvpdttWDGGIk6zw=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/credential-provider-node": "3.927.0", "@aws-sdk/eventstream-handler-node": "3.922.0", "@aws-sdk/middleware-eventstream": "3.922.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/middleware-websocket": "3.922.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/token-providers": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/eventstream-serde-browser": "^4.2.4", "@smithy/eventstream-serde-config-resolver": "^4.3.4", "@smithy/eventstream-serde-node": "^4.2.4", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-glNCCATcVd2F1SGOw3LiXKtBZzmaJhNAzPttZKM44kak6P2njz67QUP08v9qb4VDPq4Yvu/Mvu1C/Q7Wsw8z9g=="],
"@langchain/aws/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.927.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.927.0", "@aws-sdk/credential-provider-http": "3.927.0", "@aws-sdk/credential-provider-ini": "3.927.0", "@aws-sdk/credential-provider-process": "3.927.0", "@aws-sdk/credential-provider-sso": "3.927.0", "@aws-sdk/credential-provider-web-identity": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-M6BLrI+WHQ7PUY1aYu2OkI/KEz9aca+05zyycACk7cnlHlZaQ3vTFd0xOqF+A1qaenQBuxApOTs7Z21pnPUo9Q=="],
@@ -5424,17 +5445,35 @@
"@langchain/mistralai/uuid": ["uuid@10.0.0", "", { "bin": "dist/bin/uuid" }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="],
- "@librechat/agents/https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
+ "@librechat/client/@babel/preset-env": ["@babel/preset-env@7.28.5", "", { "dependencies": { "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.27.1", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg=="],
+
+ "@librechat/client/@babel/preset-react": ["@babel/preset-react@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ=="],
+
+ "@librechat/client/@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="],
+
+ "@librechat/frontend/@babel/preset-env": ["@babel/preset-env@7.28.5", "", { "dependencies": { "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.27.1", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg=="],
+
+ "@librechat/frontend/@babel/preset-react": ["@babel/preset-react@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ=="],
+
+ "@librechat/frontend/@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="],
"@librechat/frontend/@react-spring/web": ["@react-spring/web@9.7.5", "", { "dependencies": { "@react-spring/animated": "~9.7.5", "@react-spring/core": "~9.7.5", "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ=="],
+ "@librechat/frontend/@testing-library/jest-dom": ["@testing-library/jest-dom@5.17.0", "", { "dependencies": { "@adobe/css-tools": "^4.0.1", "@babel/runtime": "^7.9.2", "@types/testing-library__jest-dom": "^5.9.1", "aria-query": "^5.0.0", "chalk": "^3.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.5.6", "lodash": "^4.17.15", "redent": "^3.0.0" } }, "sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg=="],
+
"@librechat/frontend/framer-motion": ["framer-motion@11.18.2", "", { "dependencies": { "motion-dom": "^11.18.1", "motion-utils": "^11.18.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid"] }, "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w=="],
+ "@librechat/frontend/jest-environment-jsdom": ["jest-environment-jsdom@29.7.0", "", { "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/jsdom": "^20.0.0", "@types/node": "*", "jest-mock": "^29.7.0", "jest-util": "^29.7.0", "jsdom": "^20.0.0" }, "peerDependencies": { "canvas": "^2.5.0" }, "optionalPeers": ["canvas"] }, "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA=="],
+
"@librechat/frontend/lucide-react": ["lucide-react@0.394.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0" } }, "sha512-PzTbJ0bsyXRhH59k5qe7MpTd5MxlpYZUcM9kGSwvPGAfnn0J6FElDwu2EX6Vuh//F7y60rcVJiFQ7EK9DCMgfw=="],
+ "@mcp-ui/client/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.21.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" } }, "sha512-YFBsXJMFCyI1zP98u7gezMFKX4lgu/XpoZJk7ufI6UlFKXLj2hAMUuRlQX/nrmIPOmhRrG6tw2OQ2ZA/ZlXYpQ=="],
+
"@modelcontextprotocol/sdk/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
- "@modelcontextprotocol/sdk/express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
+ "@modelcontextprotocol/sdk/express-rate-limit": ["express-rate-limit@7.5.0", "", { "peerDependencies": { "express": "^4.11 || 5 || ^5.0.0-beta.1" } }, "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg=="],
+
+ "@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.0", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ=="],
"@node-saml/node-saml/@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="],
@@ -5442,69 +5481,13 @@
"@node-saml/passport-saml/passport": ["passport@0.7.0", "", { "dependencies": { "passport-strategy": "1.x.x", "pause": "0.0.1", "utils-merge": "^1.0.1" } }, "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ=="],
- "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-transformer": "0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw=="],
-
- "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.207.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA=="],
-
- "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg=="],
-
- "@opentelemetry/exporter-logs-otlp-http/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/exporter-logs-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-transformer": "0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw=="],
-
- "@opentelemetry/exporter-logs-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.207.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA=="],
-
- "@opentelemetry/exporter-logs-otlp-http/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg=="],
-
- "@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-transformer": "0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw=="],
-
- "@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.207.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA=="],
-
- "@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg=="],
-
- "@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-transformer": "0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw=="],
-
- "@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.207.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA=="],
-
- "@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-transformer": "0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw=="],
-
- "@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.207.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA=="],
-
- "@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-transformer": "0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw=="],
-
- "@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.207.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA=="],
-
- "@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-transformer": "0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw=="],
-
- "@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.207.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA=="],
-
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.208.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-transformer": "0.208.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-gMd39gIfVb2OgxldxUtOwGJYSH8P1kVFFlJLuut32L6KgUC4gl1dMhn+YC2mGn0bDOiQYSk/uHOdSjuKp58vvA=="],
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.208.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.208.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.208.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-DCFPY8C6lAQHUNkzcNT9R+qYExvsk6C5Bto2pbNxgicpcSWbe2WHShLxkOxIdNcBiYPdVHv/e7vH7K6TI+C+fQ=="],
- "@opentelemetry/instrumentation/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-transformer": "0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw=="],
-
- "@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.207.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA=="],
-
- "@opentelemetry/otlp-transformer/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/otlp-transformer/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg=="],
-
"@opentelemetry/sdk-node/@opentelemetry/exporter-trace-otlp-http": ["@opentelemetry/exporter-trace-otlp-http@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-exporter-base": "0.207.0", "@opentelemetry/otlp-transformer": "0.207.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-HSRBzXHIC7C8UfPQdu15zEEoBGv0yWkhEwxqgPCHVUKUQ9NLHVGXkVrf65Uaj7UwmAkC1gQfkuVYvLlD//AnUQ=="],
- "@radix-ui/react-alert-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw=="],
-
- "@radix-ui/react-alert-dialog/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
-
- "@radix-ui/react-alert-dialog/@radix-ui/react-context": ["@radix-ui/react-context@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg=="],
-
- "@radix-ui/react-alert-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="],
-
- "@radix-ui/react-alert-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
+ "@radix-ui/react-alert-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
"@radix-ui/react-arrow/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="],
@@ -5518,41 +5501,13 @@
"@radix-ui/react-checkbox/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA=="],
- "@radix-ui/react-collapsible/@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="],
-
- "@radix-ui/react-collapsible/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@radix-ui/react-collapsible/@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
-
- "@radix-ui/react-collapsible/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
-
"@radix-ui/react-collapsible/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA=="],
- "@radix-ui/react-collapsible/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
+ "@radix-ui/react-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
- "@radix-ui/react-collapsible/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
+ "@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
- "@radix-ui/react-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-context": ["@radix-ui/react-context@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-id": ["@radix-ui/react-id@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-layout-effect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA=="],
-
- "@radix-ui/react-dismissable-layer/@radix-ui/primitive": ["@radix-ui/primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw=="],
-
- "@radix-ui/react-dismissable-layer/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
-
- "@radix-ui/react-dismissable-layer/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="],
-
- "@radix-ui/react-dismissable-layer/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
+ "@radix-ui/react-dismissable-layer/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
"@radix-ui/react-dropdown-menu/@radix-ui/primitive": ["@radix-ui/primitive@1.1.0", "", {}, "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA=="],
@@ -5566,26 +5521,20 @@
"@radix-ui/react-dropdown-menu/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw=="],
- "@radix-ui/react-focus-scope/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
-
- "@radix-ui/react-focus-scope/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="],
-
- "@radix-ui/react-focus-scope/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
-
"@radix-ui/react-hover-card/@radix-ui/primitive": ["@radix-ui/primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw=="],
"@radix-ui/react-hover-card/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
"@radix-ui/react-hover-card/@radix-ui/react-context": ["@radix-ui/react-context@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg=="],
+ "@radix-ui/react-hover-card/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.0.5", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1", "@radix-ui/react-use-escape-keydown": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g=="],
+
+ "@radix-ui/react-hover-card/@radix-ui/react-portal": ["@radix-ui/react-portal@1.0.4", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q=="],
+
"@radix-ui/react-hover-card/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="],
"@radix-ui/react-hover-card/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA=="],
- "@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
"@radix-ui/react-menu/@radix-ui/primitive": ["@radix-ui/primitive@1.1.0", "", {}, "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA=="],
"@radix-ui/react-menu/@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.0", "@radix-ui/react-context": "1.1.0", "@radix-ui/react-primitive": "2.0.0", "@radix-ui/react-slot": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw=="],
@@ -5618,20 +5567,32 @@
"@radix-ui/react-menu/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
+ "@radix-ui/react-menu/react-remove-scroll": ["react-remove-scroll@2.5.5", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.3", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", "use-callback-ref": "^1.3.0", "use-sidecar": "^1.1.2" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw=="],
+
"@radix-ui/react-popover/@radix-ui/primitive": ["@radix-ui/primitive@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw=="],
"@radix-ui/react-popover/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
"@radix-ui/react-popover/@radix-ui/react-context": ["@radix-ui/react-context@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg=="],
+ "@radix-ui/react-popover/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.0.5", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1", "@radix-ui/react-use-escape-keydown": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g=="],
+
+ "@radix-ui/react-popover/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA=="],
+
+ "@radix-ui/react-popover/@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.0.4", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA=="],
+
"@radix-ui/react-popover/@radix-ui/react-id": ["@radix-ui/react-id@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-layout-effect": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ=="],
+ "@radix-ui/react-popover/@radix-ui/react-portal": ["@radix-ui/react-portal@1.0.4", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q=="],
+
"@radix-ui/react-popover/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="],
"@radix-ui/react-popover/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
"@radix-ui/react-popover/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA=="],
+ "@radix-ui/react-popover/react-remove-scroll": ["react-remove-scroll@2.5.5", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.3", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", "use-callback-ref": "^1.3.0", "use-sidecar": "^1.1.2" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw=="],
+
"@radix-ui/react-popper/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
"@radix-ui/react-popper/@radix-ui/react-context": ["@radix-ui/react-context@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg=="],
@@ -5642,8 +5603,6 @@
"@radix-ui/react-popper/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ=="],
- "@radix-ui/react-portal/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="],
-
"@radix-ui/react-presence/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
"@radix-ui/react-presence/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ=="],
@@ -5652,108 +5611,24 @@
"@radix-ui/react-progress/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
- "@radix-ui/react-radio-group/@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="],
-
- "@radix-ui/react-radio-group/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@radix-ui/react-radio-group/@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
-
- "@radix-ui/react-radio-group/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
-
"@radix-ui/react-radio-group/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA=="],
- "@radix-ui/react-radio-group/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
- "@radix-ui/react-radio-group/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
-
"@radix-ui/react-radio-group/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
"@radix-ui/react-radio-group/@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="],
- "@radix-ui/react-roving-focus/@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
-
- "@radix-ui/react-select/@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="],
-
- "@radix-ui/react-select/@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="],
-
- "@radix-ui/react-select/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@radix-ui/react-select/@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
-
- "@radix-ui/react-select/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
-
"@radix-ui/react-select/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ=="],
"@radix-ui/react-select/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA=="],
- "@radix-ui/react-select/@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
-
- "@radix-ui/react-select/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
-
"@radix-ui/react-select/@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.7", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ=="],
- "@radix-ui/react-select/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
-
- "@radix-ui/react-select/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
- "@radix-ui/react-select/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-select/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
-
- "@radix-ui/react-select/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
"@radix-ui/react-select/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
- "@radix-ui/react-select/react-remove-scroll": ["react-remove-scroll@2.7.1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA=="],
-
- "@radix-ui/react-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
- "@radix-ui/react-slider/@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="],
-
- "@radix-ui/react-slider/@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="],
-
- "@radix-ui/react-slider/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@radix-ui/react-slider/@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
-
- "@radix-ui/react-slider/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
-
- "@radix-ui/react-slider/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
- "@radix-ui/react-slider/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
-
- "@radix-ui/react-slider/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
"@radix-ui/react-slider/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
"@radix-ui/react-slider/@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="],
- "@radix-ui/react-switch/@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="],
-
- "@radix-ui/react-switch/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@radix-ui/react-switch/@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
-
- "@radix-ui/react-switch/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
- "@radix-ui/react-switch/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
-
"@radix-ui/react-switch/@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
"@radix-ui/react-switch/@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="],
@@ -5780,6 +5655,10 @@
"@radix-ui/react-toast/@radix-ui/react-context": ["@radix-ui/react-context@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg=="],
+ "@radix-ui/react-toast/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.0.5", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-callback-ref": "1.0.1", "@radix-ui/react-use-escape-keydown": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g=="],
+
+ "@radix-ui/react-toast/@radix-ui/react-portal": ["@radix-ui/react-portal@1.0.4", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q=="],
+
"@radix-ui/react-toast/@radix-ui/react-primitive": ["@radix-ui/react-primitive@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-slot": "1.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g=="],
"@radix-ui/react-toast/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
@@ -5790,16 +5669,8 @@
"@radix-ui/react-toast/@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-primitive": "1.0.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA=="],
- "@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-use-effect-event/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-use-escape-keydown/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
-
"@radix-ui/react-use-size/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ=="],
- "@radix-ui/react-visually-hidden/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
"@rollup/plugin-babel/@rollup/pluginutils": ["@rollup/pluginutils@3.1.0", "", { "dependencies": { "@types/estree": "0.0.39", "estree-walker": "^1.0.1", "picomatch": "^2.2.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0" } }, "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg=="],
"@rollup/plugin-babel/rollup": ["rollup@2.79.2", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ=="],
@@ -5810,9 +5681,7 @@
"@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
- "@smithy/chunked-blob-reader-native/@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="],
-
- "@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w=="],
+ "@smithy/abort-controller/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
"@smithy/credential-provider-imds/@smithy/node-config-provider": ["@smithy/node-config-provider@3.1.4", "", { "dependencies": { "@smithy/property-provider": "^3.1.3", "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ=="],
@@ -5820,31 +5689,37 @@
"@smithy/credential-provider-imds/@smithy/url-parser": ["@smithy/url-parser@3.0.3", "", { "dependencies": { "@smithy/querystring-parser": "^3.0.3", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A=="],
- "@smithy/hash-stream-node/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
+ "@smithy/eventstream-codec/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
- "@smithy/md5-js/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
+ "@smithy/eventstream-serde-universal/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
+
+ "@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
"@smithy/middleware-retry/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
"@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
+ "@smithy/node-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
+
+ "@smithy/node-http-handler/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
+
"@smithy/property-provider/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
+ "@smithy/querystring-builder/@smithy/types": ["@smithy/types@4.10.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-K9mY7V/f3Ul+/Gz4LJANZ3vJ/yiBIwCyxe0sPT4vNJK63Srvd+Yk1IzP0t+nE7XFSpIGtzR71yljtnqpUTYFlQ=="],
+
"@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@smithy/signature-v4/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
- "@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
-
"@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
"@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.0.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg=="],
"@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
- "@smithy/util-waiter/@smithy/abort-controller": ["@smithy/abort-controller@4.0.4", "", { "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" } }, "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA=="],
+ "@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
- "@surma/rollup-plugin-off-main-thread/json5": ["json5@2.2.3", "", { "bin": "lib/cli.js" }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
+ "@smithy/util-waiter/@smithy/abort-controller": ["@smithy/abort-controller@4.0.4", "", { "dependencies": { "@smithy/types": "^4.3.1", "tslib": "^2.6.2" } }, "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA=="],
"@surma/rollup-plugin-off-main-thread/magic-string": ["magic-string@0.25.9", "", { "dependencies": { "sourcemap-codec": "^1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="],
@@ -5852,12 +5727,10 @@
"@testing-library/dom/aria-query": ["aria-query@5.1.3", "", { "dependencies": { "deep-equal": "^2.0.5" } }, "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ=="],
+ "@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="],
+
"@testing-library/dom/pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="],
- "@testing-library/jest-dom/aria-query": ["aria-query@5.1.3", "", { "dependencies": { "deep-equal": "^2.0.5" } }, "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ=="],
-
- "@testing-library/jest-dom/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="],
-
"@types/mdast/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
"@types/testing-library__jest-dom/@types/jest": ["@types/jest@29.5.12", "", { "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" } }, "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw=="],
@@ -5870,7 +5743,7 @@
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="],
- "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
+ "accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
"ajv-formats/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
@@ -5880,16 +5753,8 @@
"babel-jest/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"babel-plugin-root-import/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
-
- "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
-
- "body-parser/raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="],
-
"browser-resolve/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
"browserify-rsa/bn.js": ["bn.js@5.2.2", "", {}, "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw=="],
@@ -5908,40 +5773,30 @@
"cli-truncate/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
- "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
-
"cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"colorspace/color": ["color@3.2.1", "", { "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" } }, "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA=="],
+ "compressible/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
+
"compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
+ "cookie-parser/cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="],
+
"create-ecdh/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="],
"cssnano/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
"cssnano/yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="],
- "cssstyle/cssom": ["cssom@0.3.8", "", {}, "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="],
-
- "data-urls/whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
-
- "data-urls/whatwg-url": ["whatwg-url@11.0.0", "", { "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" } }, "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ=="],
+ "data-urls/whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="],
"diffie-hellman/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="],
"domexception/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
- "encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
-
- "encoding-sniffer/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
-
- "encoding-sniffer/whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="],
-
"error-ex/is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
- "eslint/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
-
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-import-resolver-node/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
@@ -5950,33 +5805,23 @@
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
- "eslint-plugin-react/doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="],
-
- "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
- "espree/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
-
"execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
"expect/jest-message-util": ["jest-message-util@29.7.0", "", { "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w=="],
- "express/cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="],
-
- "express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
-
"express-session/cookie-signature": ["cookie-signature@1.0.7", "", {}, "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="],
"express-session/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
+ "express-static-gzip/serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="],
+
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
- "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
-
"flat-cache/keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
- "foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
+ "form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"gaxios/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
@@ -5988,6 +5833,8 @@
"googleapis-common/gaxios": ["gaxios@6.2.0", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9" } }, "sha512-H6+bHeoEAU5D6XNc6mPKeN5dLZqEDs9Gpk6I+SZBEzK5So58JVrHPmevNi35fRl1J9Y5TaeLW0kYx3pCJ1U2mQ=="],
+ "googleapis-common/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="],
+
"googleapis-common/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
"gtoken/gaxios": ["gaxios@6.2.0", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9" } }, "sha512-H6+bHeoEAU5D6XNc6mPKeN5dLZqEDs9Gpk6I+SZBEzK5So58JVrHPmevNi35fRl1J9Y5TaeLW0kYx3pCJ1U2mQ=="],
@@ -6012,16 +5859,10 @@
"hast-util-parse-selector/@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="],
- "hast-util-to-jsx-runtime/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
-
- "hast-util-to-jsx-runtime/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
"hast-util-to-text/@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="],
"hast-util-to-text/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
- "hast-util-whitespace/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
-
"hastscript/@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="],
"hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
@@ -6048,8 +5889,6 @@
"jest-changed-files/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
- "jest-circus/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="],
-
"jest-circus/jest-matcher-utils": ["jest-matcher-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "jest-diff": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg=="],
"jest-circus/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
@@ -6074,10 +5913,6 @@
"jest-each/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
- "jest-environment-jsdom/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
-
- "jest-environment-node/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="],
-
"jest-environment-node/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
"jest-environment-node/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
@@ -6102,14 +5937,10 @@
"jest-resolve/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "jest-runner/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="],
-
"jest-runner/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
"jest-runner/source-map-support": ["source-map-support@0.5.13", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w=="],
- "jest-runtime/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="],
-
"jest-runtime/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
"jest-runtime/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
@@ -6150,15 +5981,11 @@
"jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
- "jsdom/http-proxy-agent": ["http-proxy-agent@5.0.0", "", { "dependencies": { "@tootallnate/once": "2", "agent-base": "6", "debug": "4" } }, "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w=="],
-
- "jsdom/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
+ "jsdom/decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="],
"jsdom/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
- "jsdom/whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
-
- "jsdom/whatwg-url": ["whatwg-url@11.0.0", "", { "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" } }, "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ=="],
+ "jsdom/whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="],
"jsonwebtoken/jws": ["jws@3.2.2", "", { "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA=="],
@@ -6166,6 +5993,8 @@
"jwks-rsa/@types/express": ["@types/express@4.17.21", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ=="],
+ "jwks-rsa/jose": ["jose@4.15.5", "", {}, "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg=="],
+
"katex/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="],
"keyv-file/@keyv/serialize": ["@keyv/serialize@1.0.3", "", { "dependencies": { "buffer": "^6.0.3" } }, "sha512-qnEovoOp5Np2JDGonIDL6Ayihw0RhnRh6vxPuHo4RDn1UOzwEo4AeIfpL6UGIrsceWrCMiVPgwRjbHu4vYFc3g=="],
@@ -6178,6 +6007,12 @@
"ldapauth-fork/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
+ "librechat-data-provider/@babel/preset-env": ["@babel/preset-env@7.28.5", "", { "dependencies": { "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.27.1", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg=="],
+
+ "librechat-data-provider/@babel/preset-react": ["@babel/preset-react@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ=="],
+
+ "librechat-data-provider/@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="],
+
"lint-staged/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
"log-update/ansi-escapes": ["ansi-escapes@7.0.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw=="],
@@ -6186,74 +6021,32 @@
"log-update/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
- "log-update/wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="],
-
"lowlight/@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="],
"lru-cache/yallist": ["yallist@2.1.2", "", {}, "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="],
"lru-memoizer/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
- "make-dir/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"mathjs/fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="],
- "mdast-util-directive/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-directive/unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
-
"mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
- "mdast-util-find-and-replace/unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
-
- "mdast-util-find-and-replace/unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
-
- "mdast-util-from-markdown/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-from-markdown/unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "mdast-util-math/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
-
"mdast-util-math/unist-util-remove-position": ["unist-util-remove-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q=="],
- "mdast-util-mdx-expression/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
-
- "mdast-util-mdx-jsx/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
-
- "mdast-util-mdx-jsx/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
"mdast-util-mdx-jsx/unist-util-remove-position": ["unist-util-remove-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q=="],
- "mdast-util-mdx-jsx/unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "mdast-util-mdx-jsx/vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
-
- "mdast-util-mdxjs-esm/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
-
- "mdast-util-phrasing/unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
-
- "mdast-util-to-hast/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
-
- "mdast-util-to-hast/unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="],
-
- "mdast-util-to-hast/vfile": ["vfile@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg=="],
-
- "mdast-util-to-markdown/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-to-markdown/unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="],
-
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"miller-rabin/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="],
"mongodb-connection-string-url/whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="],
- "mongodb-memory-server-core/https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
-
"mongodb-memory-server-core/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"multer/mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": "bin/cmd.js" }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="],
+ "multer/type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="],
+
"node-stdlib-browser/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
"node-stdlib-browser/pkg-dir": ["pkg-dir@5.0.0", "", { "dependencies": { "find-up": "^5.0.0" } }, "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA=="],
@@ -6310,8 +6103,6 @@
"pretty-format/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
- "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
@@ -6340,30 +6131,12 @@
"rehype-katex/unist-util-visit": ["unist-util-visit@4.1.2", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", "unist-util-visit-parents": "^5.1.1" } }, "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg=="],
- "remark-directive/unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
-
- "remark-gfm/unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
-
- "remark-math/unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
-
- "remark-parse/unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
-
- "remark-rehype/@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
-
- "remark-rehype/unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
-
- "remark-rehype/vfile": ["vfile@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg=="],
-
- "remark-stringify/unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
-
"remark-supersub/unist-util-visit": ["unist-util-visit@4.1.2", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", "unist-util-visit-parents": "^5.1.1" } }, "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg=="],
"resolve-cwd/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
"restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
- "restore-cursor/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
-
"rollup-plugin-postcss/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
"rollup-plugin-typescript2/@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="],
@@ -6374,16 +6147,8 @@
"rollup-pluginutils/estree-walker": ["estree-walker@0.6.1", "", {}, "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="],
- "router/path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="],
-
"schema-utils/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
- "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
-
- "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
-
- "send/mime": ["mime@1.6.0", "", { "bin": "cli.js" }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="],
-
"sharp/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"simple-update-notifier/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
@@ -6394,12 +6159,12 @@
"stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="],
+ "static-browser-server/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
+
"string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
- "string-width-cjs/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
-
"string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
"stylehacks/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
@@ -6410,6 +6175,8 @@
"superagent/mime": ["mime@2.6.0", "", { "bin": "cli.js" }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="],
+ "superagent/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="],
+
"svgo/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="],
"svgo/css-select": ["css-select@4.3.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" } }, "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ=="],
@@ -6418,8 +6185,6 @@
"tailwindcss/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
- "tailwindcss/object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="],
-
"tailwindcss/postcss-load-config": ["postcss-load-config@4.0.2", "", { "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" } }, "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ=="],
"tailwindcss/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
@@ -6438,49 +6203,37 @@
"tinyglobby/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
- "tough-cookie/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
-
- "tough-cookie/universalify": ["universalify@0.2.0", "", {}, "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="],
-
"ts-node/diff": ["diff@4.0.2", "", {}, "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="],
+ "tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
+
+ "unified/vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
+
"unist-util-find-after/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
"unist-util-find-after/unist-util-is": ["unist-util-is@5.2.1", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw=="],
- "unist-util-position/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
"unist-util-remove-position/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
"unist-util-remove-position/unist-util-visit": ["unist-util-visit@4.1.2", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", "unist-util-visit-parents": "^5.1.1" } }, "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg=="],
"uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
- "url/punycode": ["punycode@1.4.1", "", {}, "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="],
+ "url/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="],
"v8-to-istanbul/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
"vasync/verror": ["verror@1.10.0", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw=="],
- "vfile/vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
-
"vfile-location/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
"vfile-location/vfile": ["vfile@5.3.7", "", { "dependencies": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", "unist-util-stringify-position": "^3.0.0", "vfile-message": "^3.0.0" } }, "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g=="],
- "vfile-message/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "vfile-message/unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "vite/fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
-
- "vite/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
"webpack/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
"webpack/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="],
- "whatwg-encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
+ "webpack/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"winston-daily-rotate-file/winston-transport": ["winston-transport@4.7.0", "", { "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", "triple-beam": "^1.3.0" } }, "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg=="],
@@ -6508,10 +6261,6 @@
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
- "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
-
- "write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
-
"xml-crypto/xpath": ["xpath@0.0.33", "", {}, "sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA=="],
"xml-encryption/xpath": ["xpath@0.0.32", "", {}, "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw=="],
@@ -6520,6 +6269,8 @@
"@apideck/better-ajv-errors/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
+ "@asamuzakjp/css-color/@csstools/css-color-parser/@csstools/color-helpers": ["@csstools/color-helpers@5.1.0", "", {}, "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA=="],
+
"@aws-crypto/crc32/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
"@aws-crypto/crc32c/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
@@ -6554,14 +6305,14 @@
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/nested-clients": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Oh/aFYjZQsIiZ2PQEgTNvqEE/mmOYxZKZzXV86qrU3jBUfUUBvprUZc684nBqJbSKPwM5jCZtxiRYh+IrZDE7A=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/types": ["@aws-sdk/types@3.922.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-eLA6XjVobAUAMivvM7DBL79mnHyrm+32TkXNWZua5mnxF+6kQCfblKKJvxMZLGosO53/Ex46ogim8IY5Nbqv2w=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-YVNMjhdz2pVto5bRdux7GMs0x1m0Afz3OcQy/4Yf9DH4fWOtroGH7uLvs7ZmDyoBJzLdegtIPpXrpJOZWvUXdw=="],
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
+ "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.1.1", "", {}, "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA=="],
+
"@aws-sdk/client-bedrock-agent-runtime/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
"@aws-sdk/client-bedrock-agent-runtime/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
@@ -6598,196 +6349,94 @@
"@aws-sdk/client-bedrock-agent-runtime/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-bAllBpmaWINpf0brXQWh/hjkBctapknZPYb3FJRlBHytEGHi7TpgqBXi8riT0tc6RVWChhnw58rQz22acOmBuw=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.6", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-jEvb8C7tuRBFhe8vZY9vm9z6UQnbP85IMEt3Qiz0dxAd341Hgu0lOzMv5mSKQ5yBnTLq+t3FPKgD9tIiHLqxSQ=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VR2V6dRELmzwAsCpK4GqxUi6UW5WNhAXS9F9AzWi5jvijwJo3nH92YNJUP4quMpgFZxJHEWyXLWgPjh9u0zYOA=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/credential-provider-env": "3.927.0", "@aws-sdk/credential-provider-http": "3.927.0", "@aws-sdk/credential-provider-process": "3.927.0", "@aws-sdk/credential-provider-sso": "3.927.0", "@aws-sdk/credential-provider-web-identity": "3.927.0", "@aws-sdk/nested-clients": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-WvliaKYT7bNLiryl/FsZyUwRGBo/CWtboekZWvSfloAb+0SKFXWjmxt3z+Y260aoaPm/LIzEyslDHfxqR9xCJQ=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-inF09lh9SlHj63Vmr5d+LmwPXZc2IbK8lAruhOr3KLsZAIHEgHgGPXWDC2ukTEMzg0pkexQ6FOhXXad6klK4RA=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-rvqdZIN3TRhLKssufN5G2EWLMBct3ZebOBdwr0tuOoPEdaYflyXYYUScu+Beb541CKfXaFnEOlZokq12r7EPcQ=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.952.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-login": "3.952.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.952.0", "@aws-sdk/credential-provider-web-identity": "3.952.0", "@aws-sdk/nested-clients": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-N5B15SwzMkZ8/LLopNksTlPEWWZn5tbafZAUfMY5Xde4rSHGWmv5H/ws2M3P8L0X77E2wKnOJsNmu+GsArBreQ=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.927.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.927.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/token-providers": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-XrCuncze/kxZE6WYEWtNMGtrJvJtyhUqav4xQQ9PJcNjxCUYiIRv7Gwkt7cuwJ1HS+akQj+JiZmljAg97utfDw=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-WpanFbHe08SP1hAJNeDdBDVz9SGgMu/gc0XJ9u3uNpW99nKZjDpvPRAdW7WLA4K6essMjxWkguIGNOpij6Do2Q=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/nested-clients": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Oh/aFYjZQsIiZ2PQEgTNvqEE/mmOYxZKZzXV86qrU3jBUfUUBvprUZc684nBqJbSKPwM5jCZtxiRYh+IrZDE7A=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.952.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.948.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/token-providers": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-1CQdP5RzxeXuEfytbAD5TgreY1c9OacjtCdO8+n9m05tpzBABoNBof0hcjzw1dtrWFH7deyUgfwCl1TAN3yBWQ=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/types": ["@aws-sdk/types@3.922.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-eLA6XjVobAUAMivvM7DBL79mnHyrm+32TkXNWZua5mnxF+6kQCfblKKJvxMZLGosO53/Ex46ogim8IY5Nbqv2w=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.952.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.952.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-5hJbfaZdHDAP8JlwplNbXJAat9Vv7L0AbTZzkbPIgjHhC3vrMf5r3a6I1HWFp5i5pXo7J45xyuf5uQGZJxJlCg=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-YVNMjhdz2pVto5bRdux7GMs0x1m0Afz3OcQy/4Yf9DH4fWOtroGH7uLvs7ZmDyoBJzLdegtIPpXrpJOZWvUXdw=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/property-provider": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-xBmawExyTzOjbhzkZwg+vVm/khg28kG+rj2sbGlULjFd1jI70sv/cbpaR0Ev4Yfd6CpDUDRMe64cTqR//wAOyA=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
"@aws-sdk/client-bedrock-runtime/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.6", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-olIfZ230B64TvPD6b0tPvrEp2eB0FkyL3KvDlqF4RVmIc/kn3orzXnV6DTQdOOW5UU+M5zKY3/BU47X420/oPw=="],
+
+ "@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-node/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.6", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-olIfZ230B64TvPD6b0tPvrEp2eB0FkyL3KvDlqF4RVmIc/kn3orzXnV6DTQdOOW5UU+M5zKY3/BU47X420/oPw=="],
"@aws-sdk/client-bedrock-runtime/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0" } }, "sha512-Q73XBrzJlGTut2nf5RglSntHKgAG0+KiTJdO5QQblLfr4TdliGwIAha1iZIjwisc3rA5ulzqwwsYC6xrclxVQg=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-YmWxl32SQRw/kIRccSOxzS/Ib8/b5/f9ex0r5PR40jRJg8X1wgM3KrR2In+8zvOGVhRSXgvyQpw9yOSlmfmSnA=="],
"@aws-sdk/client-bedrock-runtime/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-YVNMjhdz2pVto5bRdux7GMs0x1m0Afz3OcQy/4Yf9DH4fWOtroGH7uLvs7ZmDyoBJzLdegtIPpXrpJOZWvUXdw=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/property-provider": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-xBmawExyTzOjbhzkZwg+vVm/khg28kG+rj2sbGlULjFd1jI70sv/cbpaR0Ev4Yfd6CpDUDRMe64cTqR//wAOyA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
- "@aws-sdk/client-bedrock-runtime/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
+ "@aws-sdk/client-bedrock-runtime/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0" } }, "sha512-Q73XBrzJlGTut2nf5RglSntHKgAG0+KiTJdO5QQblLfr4TdliGwIAha1iZIjwisc3rA5ulzqwwsYC6xrclxVQg=="],
"@aws-sdk/client-bedrock-runtime/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@aws-sdk/client-bedrock-runtime/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@4.1.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "@smithy/protocol-http": "^4.1.0", "@smithy/types": "^3.3.0", "@smithy/util-hex-encoding": "^3.0.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-uri-escape": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag=="],
- "@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
"@aws-sdk/client-cognito-identity/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-host-header/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-host-header/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-logger/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-recursion-detection/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-recursion-detection/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-user-agent/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-user-agent/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/region-config-resolver/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@aws-sdk/region-config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ=="],
- "@aws-sdk/client-cognito-identity/@aws-sdk/region-config-resolver/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/util-endpoints/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/util-user-agent-browser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/util-user-agent-node/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/config-resolver/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ=="],
- "@aws-sdk/client-cognito-identity/@smithy/config-resolver/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/core/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/core/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/core/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/fetch-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw=="],
- "@aws-sdk/client-cognito-identity/@smithy/fetch-http-handler/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/hash-node/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
- "@aws-sdk/client-cognito-identity/@smithy/hash-node/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/invalid-dependency/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/middleware-content-length/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/middleware-content-length/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/client-cognito-identity/@smithy/middleware-endpoint/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/middleware-endpoint/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/middleware-retry/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0" } }, "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ=="],
- "@aws-sdk/client-cognito-identity/@smithy/middleware-retry/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/middleware-retry/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
"@aws-sdk/client-cognito-identity/@smithy/middleware-retry/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
- "@aws-sdk/client-cognito-identity/@smithy/middleware-serde/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/middleware-stack/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/client-cognito-identity/@smithy/node-config-provider/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@3.1.1", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ=="],
- "@aws-sdk/client-cognito-identity/@smithy/node-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw=="],
- "@aws-sdk/client-cognito-identity/@smithy/node-http-handler/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/smithy-client/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/smithy-client/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@3.1.3", "", { "dependencies": { "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/types": "^3.3.0", "@smithy/util-base64": "^3.0.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-hex-encoding": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw=="],
"@aws-sdk/client-cognito-identity/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ=="],
- "@aws-sdk/client-cognito-identity/@smithy/url-parser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
- "@aws-sdk/client-cognito-identity/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/util-defaults-mode-browser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/util-defaults-mode-node/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/util-endpoints/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0" } }, "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ=="],
- "@aws-sdk/client-cognito-identity/@smithy/util-retry/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
"@aws-sdk/client-kendra/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
@@ -6806,14 +6455,14 @@
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/nested-clients": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Oh/aFYjZQsIiZ2PQEgTNvqEE/mmOYxZKZzXV86qrU3jBUfUUBvprUZc684nBqJbSKPwM5jCZtxiRYh+IrZDE7A=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/types": ["@aws-sdk/types@3.922.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-eLA6XjVobAUAMivvM7DBL79mnHyrm+32TkXNWZua5mnxF+6kQCfblKKJvxMZLGosO53/Ex46ogim8IY5Nbqv2w=="],
-
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-YVNMjhdz2pVto5bRdux7GMs0x1m0Afz3OcQy/4Yf9DH4fWOtroGH7uLvs7ZmDyoBJzLdegtIPpXrpJOZWvUXdw=="],
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
+ "@aws-sdk/client-kendra/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.1.1", "", {}, "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA=="],
+
"@aws-sdk/client-kendra/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
"@aws-sdk/client-kendra/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
@@ -6850,292 +6499,88 @@
"@aws-sdk/client-kendra/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/client-sso-oidc/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
+ "@aws-sdk/client-s3/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+
+ "@aws-sdk/client-s3/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
"@aws-sdk/client-sso-oidc/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@4.1.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "@smithy/protocol-http": "^4.1.0", "@smithy/types": "^3.3.0", "@smithy/util-hex-encoding": "^3.0.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-uri-escape": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag=="],
- "@aws-sdk/client-sso-oidc/@aws-sdk/core/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
"@aws-sdk/client-sso-oidc/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/client-sso-oidc/@aws-sdk/middleware-host-header/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/middleware-host-header/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/middleware-logger/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/middleware-recursion-detection/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/middleware-recursion-detection/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/middleware-user-agent/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/middleware-user-agent/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/region-config-resolver/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@aws-sdk/region-config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ=="],
- "@aws-sdk/client-sso-oidc/@aws-sdk/region-config-resolver/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/util-endpoints/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/util-user-agent-browser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/util-user-agent-node/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/config-resolver/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ=="],
- "@aws-sdk/client-sso-oidc/@smithy/config-resolver/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/core/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/core/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/core/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/fetch-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw=="],
- "@aws-sdk/client-sso-oidc/@smithy/fetch-http-handler/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/hash-node/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
- "@aws-sdk/client-sso-oidc/@smithy/hash-node/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/invalid-dependency/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/middleware-content-length/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/middleware-content-length/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/client-sso-oidc/@smithy/middleware-endpoint/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/middleware-endpoint/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/middleware-retry/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0" } }, "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ=="],
- "@aws-sdk/client-sso-oidc/@smithy/middleware-retry/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/middleware-retry/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
"@aws-sdk/client-sso-oidc/@smithy/middleware-retry/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
- "@aws-sdk/client-sso-oidc/@smithy/middleware-serde/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/middleware-stack/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/client-sso-oidc/@smithy/node-config-provider/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@3.1.1", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ=="],
- "@aws-sdk/client-sso-oidc/@smithy/node-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw=="],
- "@aws-sdk/client-sso-oidc/@smithy/node-http-handler/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/smithy-client/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/smithy-client/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@3.1.3", "", { "dependencies": { "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/types": "^3.3.0", "@smithy/util-base64": "^3.0.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-hex-encoding": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw=="],
"@aws-sdk/client-sso-oidc/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ=="],
- "@aws-sdk/client-sso-oidc/@smithy/url-parser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
- "@aws-sdk/client-sso-oidc/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/util-defaults-mode-browser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/util-defaults-mode-node/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/util-endpoints/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0" } }, "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ=="],
- "@aws-sdk/client-sso-oidc/@smithy/util-retry/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
- "@aws-sdk/client-sso/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-sso/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@4.1.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "@smithy/protocol-http": "^4.1.0", "@smithy/types": "^3.3.0", "@smithy/util-hex-encoding": "^3.0.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-uri-escape": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag=="],
- "@aws-sdk/client-sso/@aws-sdk/core/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-sso/@aws-sdk/middleware-host-header/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/middleware-host-header/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/middleware-logger/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/middleware-recursion-detection/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/middleware-recursion-detection/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/middleware-user-agent/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/middleware-user-agent/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/region-config-resolver/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@aws-sdk/region-config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ=="],
- "@aws-sdk/client-sso/@aws-sdk/region-config-resolver/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-sso/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/util-endpoints/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/util-user-agent-browser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@aws-sdk/util-user-agent-node/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/config-resolver/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ=="],
- "@aws-sdk/client-sso/@smithy/config-resolver/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-sso/@smithy/core/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso/@smithy/core/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/core/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-sso/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw=="],
- "@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/hash-node/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
- "@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-sso/@smithy/invalid-dependency/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/middleware-content-length/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso/@smithy/middleware-content-length/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/client-sso/@smithy/middleware-endpoint/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/middleware-endpoint/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
- "@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0" } }, "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ=="],
- "@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
-
"@aws-sdk/client-sso/@smithy/middleware-retry/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
- "@aws-sdk/client-sso/@smithy/middleware-serde/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/middleware-stack/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/client-sso/@smithy/node-config-provider/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@3.1.1", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ=="],
- "@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw=="],
- "@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/smithy-client/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/client-sso/@smithy/smithy-client/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@3.1.3", "", { "dependencies": { "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/types": "^3.3.0", "@smithy/util-base64": "^3.0.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-hex-encoding": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw=="],
"@aws-sdk/client-sso/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ=="],
- "@aws-sdk/client-sso/@smithy/url-parser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
- "@aws-sdk/client-sso/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-sso/@smithy/util-defaults-mode-browser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/util-defaults-mode-node/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/util-endpoints/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0" } }, "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ=="],
- "@aws-sdk/client-sso/@smithy/util-retry/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
- "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-env/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-http/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw=="],
- "@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64": ["@smithy/util-base64@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ=="],
"@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@3.1.1", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ=="],
- "@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
"@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw=="],
- "@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@3.1.0", "", { "dependencies": { "@smithy/middleware-serde": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/shared-ini-file-loader": "^3.1.4", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" } }, "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw=="],
"@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA=="],
- "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/protocol-http": ["@smithy/protocol-http@4.1.0", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA=="],
-
- "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ=="],
"@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
@@ -7144,145 +6589,97 @@
"@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
- "@aws-sdk/credential-provider-ini/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="],
- "@aws-sdk/credential-provider-ini/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core": ["@smithy/core@3.19.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.7", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-stream": "^4.5.7", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-Y9oHXpBcXQgYHOcAEmxjkDilUbSTkgKjoHYed3WaYUH8jngq8lPWDBSpjHblJ9uOgBdy5mh3pzebrScDdYr29w=="],
+
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.6", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-fYEyL59Qe82Ha1p97YQTMEQPJYmBS+ux76foqluaTVWoG9Px5J53w6NvXZNE3wP7lIicLDF7Vj1Em18XTX7fsA=="],
+
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.6", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA=="],
+
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.1", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-endpoint": "^4.4.0", "@smithy/middleware-stack": "^4.2.6", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-stream": "^4.5.7", "tslib": "^2.6.2" } }, "sha512-1ovWdxzYprhq+mWqiGZlt3kF69LJthuQcfY9BIyHx9MywTFKzFapluku1QXoaBB43GCsLDxNqS+1v30ure69AA=="],
+
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
+
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg=="],
+
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
+
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.758.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-retry": "^4.0.7", "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.7", "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-YZ5s7PSvyF3Mt2h1EQulCG93uybprNGbBkPmVuy/HMMfbFTt4iL3SbKjxqvOZelm86epFfj7pvK7FliI2WOEcg=="],
"@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.758.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-retry": "^4.0.7", "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.7", "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-BoGO6IIWrLyLxQG6txJw6RT2urmbtlwfggapNCrNPyYjlXpzTSJhBYjndg7TpDATFd0SXL0zm8y/tXsUXNkdYQ=="],
"@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.758.0", "", { "dependencies": { "@aws-sdk/nested-clients": "3.758.0", "@aws-sdk/types": "3.734.0", "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-ckptN1tNrIfQUaGWm/ayW1ddG+imbKN7HHhjFdS4VfItsP0QQOB0+Ov+tpgb4MoNR4JaUghMIVStjIeHN2ks1w=="],
- "@aws-sdk/credential-provider-process/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-process/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-sso/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-sso/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-web-identity/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.758.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-retry": "^4.0.7", "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.7", "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-YZ5s7PSvyF3Mt2h1EQulCG93uybprNGbBkPmVuy/HMMfbFTt4iL3SbKjxqvOZelm86epFfj7pvK7FliI2WOEcg=="],
"@aws-sdk/credential-providers/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/credential-providers/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/middleware-bucket-endpoint/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
-
- "@aws-sdk/middleware-bucket-endpoint/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
-
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/core": ["@smithy/core@3.1.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA=="],
-
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
-
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.1.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-stack": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-stream": "^4.1.2", "tslib": "^2.6.2" } }, "sha512-UYDolNg6h2O0L+cJjtgSyKKvEKCOa/8FHYJnBobyeoeWDmNpXjwOAtw16ezyeu1ETuuLEOZbrynK0ZY1Lx9Jbw=="],
-
- "@aws-sdk/middleware-flexible-checksums/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
-
- "@aws-sdk/middleware-flexible-checksums/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
-
- "@aws-sdk/middleware-flexible-checksums/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA=="],
-
- "@aws-sdk/middleware-flexible-checksums/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
-
- "@aws-sdk/middleware-flexible-checksums/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="],
-
- "@aws-sdk/middleware-flexible-checksums/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
-
- "@aws-sdk/middleware-flexible-checksums/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
-
- "@aws-sdk/middleware-sdk-s3/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.0.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-serde": "^4.0.2", "@smithy/node-config-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
-
- "@aws-sdk/middleware-sdk-s3/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
-
- "@aws-sdk/middleware-websocket/@aws-sdk/util-format-url/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/middleware-websocket/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
+ "@aws-sdk/middleware-websocket/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.6", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-olIfZ230B64TvPD6b0tPvrEp2eB0FkyL3KvDlqF4RVmIc/kn3orzXnV6DTQdOOW5UU+M5zKY3/BU47X420/oPw=="],
"@aws-sdk/middleware-websocket/@smithy/fetch-http-handler/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
- "@aws-sdk/nested-clients/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
+ "@aws-sdk/middleware-websocket/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/nested-clients/@aws-sdk/region-config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w=="],
+ "@aws-sdk/middleware-websocket/@smithy/signature-v4/@smithy/util-middleware": ["@smithy/util-middleware@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg=="],
- "@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w=="],
+ "@aws-sdk/middleware-websocket/@smithy/signature-v4/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
- "@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.1.2", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw=="],
+ "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="],
- "@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/nested-clients/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
- "@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
+ "@aws-sdk/nested-clients/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.6", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA=="],
- "@aws-sdk/nested-clients/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
+ "@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
- "@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0" } }, "sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA=="],
+ "@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
- "@aws-sdk/nested-clients/@smithy/middleware-retry/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
+ "@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/nested-clients/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
+ "@aws-sdk/nested-clients/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
- "@aws-sdk/nested-clients/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
+ "@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0" } }, "sha512-Q73XBrzJlGTut2nf5RglSntHKgAG0+KiTJdO5QQblLfr4TdliGwIAha1iZIjwisc3rA5ulzqwwsYC6xrclxVQg=="],
- "@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@aws-sdk/nested-clients/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
- "@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/nested-clients/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.1", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tph+oQYPbpN6NamF030hx1gb5YN2Plog+GLaRHpoEDwp8+ZPG26rIJvStG9hkWzN2HBn3HcWg0sHeB0tmkYzqA=="],
- "@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.1.2", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw=="],
+ "@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
- "@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw=="],
+ "@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-YmWxl32SQRw/kIRccSOxzS/Ib8/b5/f9ex0r5PR40jRJg8X1wgM3KrR2In+8zvOGVhRSXgvyQpw9yOSlmfmSnA=="],
- "@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
+ "@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
+ "@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
- "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.0.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg=="],
+ "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.6", "@smithy/property-provider": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-xBmawExyTzOjbhzkZwg+vVm/khg28kG+rj2sbGlULjFd1jI70sv/cbpaR0Ev4Yfd6CpDUDRMe64cTqR//wAOyA=="],
- "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
+ "@aws-sdk/nested-clients/@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-a/tGSLPtaia2krbRdwR4xbZKO8lU67DjMk/jfY4QKt4PRlKML+2tL/gmAuhNdFDioO6wOq0sXkfnddNFH9mNUA=="],
- "@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0" } }, "sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA=="],
+ "@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0" } }, "sha512-Q73XBrzJlGTut2nf5RglSntHKgAG0+KiTJdO5QQblLfr4TdliGwIAha1iZIjwisc3rA5ulzqwwsYC6xrclxVQg=="],
- "@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
+ "@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core": ["@smithy/core@3.1.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core": ["@smithy/core@3.19.0", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.7", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-stream": "^4.5.7", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-Y9oHXpBcXQgYHOcAEmxjkDilUbSTkgKjoHYed3WaYUH8jngq8lPWDBSpjHblJ9uOgBdy5mh3pzebrScDdYr29w=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/node-config-provider": ["@smithy/node-config-provider@4.0.1", "", { "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.6", "", { "dependencies": { "@smithy/property-provider": "^4.2.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-fYEyL59Qe82Ha1p97YQTMEQPJYmBS+ux76foqluaTVWoG9Px5J53w6NvXZNE3wP7lIicLDF7Vj1Em18XTX7fsA=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/protocol-http": ["@smithy/protocol-http@5.3.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qLRZzP2+PqhE3OSwvY2jpBbP0WKTZ9opTsn+6IWYI0SKVpbG+imcfNxXPq9fj5XeaUTr7odpsNpK6dmoiM1gJQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.0.1", "", { "dependencies": { "@smithy/querystring-parser": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.6", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.6", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-P1TXDHuQMadTMTOBv4oElZMURU4uyEhxhHfn+qOc2iofW9Rd4sZtBGx58Lzk112rIGVEYZT8eUMK4NftpewpRA=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core": ["@smithy/core@3.1.5", "", { "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-middleware": "^4.0.1", "@smithy/util-stream": "^4.1.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-HLclGWPkCsekQgsyzxLhCQLa8THWXtB5PxyYN+2O6nkyLt550KQKTlbV2D1/j5dNIQapAZM1+qFnpBFxZQkgCA=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.10.1", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-endpoint": "^4.4.0", "@smithy/middleware-stack": "^4.2.6", "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "@smithy/util-stream": "^4.5.7", "tslib": "^2.6.2" } }, "sha512-1ovWdxzYprhq+mWqiGZlt3kF69LJthuQcfY9BIyHx9MywTFKzFapluku1QXoaBB43GCsLDxNqS+1v30ure69AA=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.1.2", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-middleware": ["@smithy/util-middleware@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-qrvXUkxBSAFomM3/OEMuDVwjh4wtqK8D2uDZPShzIqOylPst6gor2Cdp6+XrH4dyksAWq/bE2aSDYBTTnj0Rxg=="],
- "@aws-sdk/token-providers/@aws-sdk/types/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/token-providers/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@azure/core-rest-pipeline/https-proxy-agent/agent-base": ["agent-base@7.1.3", "", {}, "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
"@azure/core-xml/fast-xml-parser/strnum": ["strnum@2.0.5", "", {}, "sha512-YAT3K/sgpCUxhxNMrrdhtod3jckkpYwH6JAuwmUdXZsmzH1wUyzTMrrK2wYCEEqlKwrWDd35NeuUkbBy/1iK+Q=="],
@@ -7292,8 +6689,6 @@
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
- "@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs3/core-js-compat": ["core-js-compat@3.35.1", "", { "dependencies": { "browserslist": "^4.22.2" } }, "sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw=="],
@@ -7308,29 +6703,25 @@
"@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
- "@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
+ "@headlessui/react/@tanstack/react-virtual/@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.12", "", {}, "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA=="],
- "@isaacs/cliui/string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
-
- "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.0.1", "", {}, "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="],
+ "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
- "@isaacs/cliui/wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
-
"@istanbuljs/load-nyc-config/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="],
"@istanbuljs/load-nyc-config/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
- "@jest/console/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "@jest/core/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "@jest/core/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"@jest/core/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "@jest/environment/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
+ "@jest/environment-jsdom-abstract/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
+
+ "@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
+
+ "@jest/environment/@jest/fake-timers/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
+
+ "@jest/environment/jest-mock/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
"@jest/expect/expect/@jest/expect-utils": ["@jest/expect-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0" } }, "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA=="],
@@ -7344,19 +6735,85 @@
"@jest/fake-timers/jest-message-util/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
- "@jest/globals/@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
-
"@jest/globals/jest-mock/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
"@jest/reporters/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@jest/reporters/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
- "@jest/reporters/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
- "@jest/snapshot-utils/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/eventstream-codec": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-DTKHeH1Bk17zSdoa5qXPGwCmZXuhQReqXOVW2/jIVX8NGVvnraH7WppGPlQxBjFtwSSwVTgzH2NVPgediQphNA=="],
- "@jest/transform/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-qDHi3NxIZCOh10aKcDPz58qlt7xtTXTMHGv7N2uVWeb7gAhk/KGerHLukY6SFAID5FJ246Le14h2blQOHi9U2Q=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/util-format-url": "3.922.0", "@smithy/eventstream-codec": "^4.2.4", "@smithy/eventstream-serde-browser": "^4.2.4", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-cBGDpMORc2lkpsSWJJkXes1lduPeUo58TIjMuC66TK134o8Wc+EsSutInxZXAT031BVWoyddhW9dBZJ1ybQQ2Q=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/nested-clients": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-JRdaprkZjZ6EY4WVwsZaEjPUj9W9vqlSaFDm4oD+IbwlY4GjAXuUQK6skKcvVyoOsSTvJp/CaveSws2FiWUp9Q=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/types": ["@aws-sdk/types@3.922.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-eLA6XjVobAUAMivvM7DBL79mnHyrm+32TkXNWZua5mnxF+6kQCfblKKJvxMZLGosO53/Ex46ogim8IY5Nbqv2w=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-bAllBpmaWINpf0brXQWh/hjkBctapknZPYb3FJRlBHytEGHi7TpgqBXi8riT0tc6RVWChhnw58rQz22acOmBuw=="],
@@ -7384,7 +6841,269 @@
"@langchain/google-gauth/google-auth-library/gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="],
- "@librechat/agents/https-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.28.5", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.14", "", { "dependencies": { "@babel/compat-data": "^7.27.7", "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="],
+
+ "@librechat/client/@babel/preset-env/core-js-compat": ["core-js-compat@3.47.0", "", { "dependencies": { "browserslist": "^4.28.0" } }, "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ=="],
+
+ "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="],
+
+ "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/types": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw=="],
+
+ "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.27.1", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q=="],
+
+ "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA=="],
+
+ "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
+
+ "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.28.5", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.14", "", { "dependencies": { "@babel/compat-data": "^7.27.7", "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="],
+
+ "@librechat/frontend/@babel/preset-env/core-js-compat": ["core-js-compat@3.47.0", "", { "dependencies": { "browserslist": "^4.28.0" } }, "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ=="],
+
+ "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="],
+
+ "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/types": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw=="],
+
+ "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.27.1", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q=="],
+
+ "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA=="],
+
+ "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
+
+ "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA=="],
"@librechat/frontend/@react-spring/web/@react-spring/animated": ["@react-spring/animated@9.7.5", "", { "dependencies": { "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg=="],
@@ -7394,100 +7113,60 @@
"@librechat/frontend/@react-spring/web/@react-spring/types": ["@react-spring/types@9.7.5", "", {}, "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g=="],
+ "@librechat/frontend/@testing-library/jest-dom/@adobe/css-tools": ["@adobe/css-tools@4.3.3", "", {}, "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ=="],
+
+ "@librechat/frontend/@testing-library/jest-dom/aria-query": ["aria-query@5.1.3", "", { "dependencies": { "deep-equal": "^2.0.5" } }, "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ=="],
+
+ "@librechat/frontend/@testing-library/jest-dom/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="],
+
+ "@librechat/frontend/@testing-library/jest-dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="],
+
"@librechat/frontend/framer-motion/motion-dom": ["motion-dom@11.18.1", "", { "dependencies": { "motion-utils": "^11.18.1" } }, "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw=="],
"@librechat/frontend/framer-motion/motion-utils": ["motion-utils@11.18.1", "", {}, "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA=="],
+ "@librechat/frontend/jest-environment-jsdom/@jest/environment": ["@jest/environment@29.7.0", "", { "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "jest-mock": "^29.7.0" } }, "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw=="],
+
+ "@librechat/frontend/jest-environment-jsdom/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
+
+ "@librechat/frontend/jest-environment-jsdom/@types/jsdom": ["@types/jsdom@20.0.1", "", { "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", "parse5": "^7.0.0" } }, "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom": ["jsdom@20.0.3", "", { "dependencies": { "abab": "^2.0.6", "acorn": "^8.8.1", "acorn-globals": "^7.0.0", "cssom": "^0.5.0", "cssstyle": "^2.3.0", "data-urls": "^3.0.2", "decimal.js": "^10.4.2", "domexception": "^4.0.0", "escodegen": "^2.0.0", "form-data": "^4.0.0", "html-encoding-sniffer": "^3.0.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.1", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.2", "parse5": "^7.1.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^4.1.2", "w3c-xmlserializer": "^4.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^2.0.0", "whatwg-mimetype": "^3.0.0", "whatwg-url": "^11.0.0", "ws": "^8.11.0", "xml-name-validator": "^4.0.0" }, "peerDependencies": { "canvas": "^2.5.0" }, "optionalPeers": ["canvas"] }, "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ=="],
+
+ "@mcp-ui/client/@modelcontextprotocol/sdk/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
+
+ "@mcp-ui/client/@modelcontextprotocol/sdk/express-rate-limit": ["express-rate-limit@7.5.0", "", { "peerDependencies": { "express": "^4.11 || 5 || ^5.0.0-beta.1" } }, "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg=="],
+
"@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
- "@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
-
- "@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
-
- "@modelcontextprotocol/sdk/express/content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
-
- "@modelcontextprotocol/sdk/express/cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
-
- "@modelcontextprotocol/sdk/express/finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
-
- "@modelcontextprotocol/sdk/express/fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
-
- "@modelcontextprotocol/sdk/express/merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
-
- "@modelcontextprotocol/sdk/express/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
-
- "@modelcontextprotocol/sdk/express/qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
-
- "@modelcontextprotocol/sdk/express/send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
-
- "@modelcontextprotocol/sdk/express/serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
-
- "@modelcontextprotocol/sdk/express/type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
-
"@node-saml/passport-saml/@types/express/@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A=="],
"@node-saml/passport-saml/@types/express/@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="],
- "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/sdk-logs/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg=="],
-
- "@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/otlp-transformer/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/otlp-transformer/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg=="],
-
- "@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/otlp-transformer/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/otlp-transformer/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg=="],
-
- "@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/otlp-transformer/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg=="],
-
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.208.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg=="],
"@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.208.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.208.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-QlAyL1jRpOeaqx7/leG1vJMp84g0xKP6gJmfELBpnI4O/9xPX+Hu5m1POk9Kl+veNkyth5t19hRlN6tNY1sjbA=="],
- "@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/otlp-transformer/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
-
- "@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/otlp-transformer/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg=="],
-
- "@opentelemetry/sdk-node/@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.207.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/otlp-transformer": "0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw=="],
-
- "@opentelemetry/sdk-node/@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.207.0", "@opentelemetry/sdk-metrics": "2.2.0", "@opentelemetry/sdk-trace-base": "2.2.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA=="],
-
"@radix-ui/react-arrow/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
"@radix-ui/react-checkbox/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
"@radix-ui/react-checkbox/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
- "@radix-ui/react-collapsible/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
-
- "@radix-ui/react-dismissable-layer/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
-
"@radix-ui/react-dropdown-menu/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@radix-ui/react-dropdown-menu/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw=="],
"@radix-ui/react-dropdown-menu/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
- "@radix-ui/react-focus-scope/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
+ "@radix-ui/react-hover-card/@radix-ui/react-dismissable-layer/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
+
+ "@radix-ui/react-hover-card/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg=="],
"@radix-ui/react-hover-card/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
"@radix-ui/react-hover-card/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
- "@radix-ui/react-label/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
"@radix-ui/react-menu/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw=="],
"@radix-ui/react-menu/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
@@ -7508,34 +7187,20 @@
"@radix-ui/react-menu/@radix-ui/react-roving-focus/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw=="],
+ "@radix-ui/react-popover/@radix-ui/react-dismissable-layer/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
+
+ "@radix-ui/react-popover/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg=="],
+
+ "@radix-ui/react-popover/@radix-ui/react-focus-scope/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
+
"@radix-ui/react-popover/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ=="],
"@radix-ui/react-popover/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ=="],
"@radix-ui/react-popper/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
- "@radix-ui/react-portal/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
-
"@radix-ui/react-progress/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ=="],
- "@radix-ui/react-radio-group/@radix-ui/react-presence/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-radio-group/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-radio-group/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-radio-group/@radix-ui/react-use-size/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-roving-focus/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-select/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
-
"@radix-ui/react-select/@radix-ui/react-popper/@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
"@radix-ui/react-select/@radix-ui/react-popper/@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="],
@@ -7544,18 +7209,6 @@
"@radix-ui/react-select/@radix-ui/react-popper/@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
- "@radix-ui/react-separator/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-slider/@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-slider/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-switch/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-switch/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-switch/@radix-ui/react-use-size/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
"@radix-ui/react-tabs/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ=="],
"@radix-ui/react-tabs/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
@@ -7570,9 +7223,9 @@
"@radix-ui/react-toast/@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
- "@radix-ui/react-toast/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
+ "@radix-ui/react-toast/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.0.3", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-use-callback-ref": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg=="],
- "@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
+ "@radix-ui/react-toast/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
"@rollup/plugin-babel/@rollup/pluginutils/@types/estree": ["@types/estree@0.0.39", "", {}, "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="],
@@ -7580,31 +7233,15 @@
"@rollup/plugin-babel/@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
- "@smithy/chunked-blob-reader-native/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
-
- "@smithy/chunked-blob-reader-native/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
-
"@smithy/credential-provider-imds/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@smithy/credential-provider-imds/@smithy/node-config-provider/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@smithy/credential-provider-imds/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ=="],
- "@smithy/credential-provider-imds/@smithy/url-parser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@smithy/hash-stream-node/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
-
- "@smithy/md5-js/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
-
"@smithy/signature-v4/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@testing-library/dom/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
+ "@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
- "@testing-library/dom/pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="],
-
- "@testing-library/jest-dom/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
-
- "@testing-library/jest-dom/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
+ "@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
"@types/winston/winston/logform": ["logform@2.6.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ=="],
@@ -7614,8 +7251,6 @@
"ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
- "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
-
"browserify-sign/readable-stream/core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
"browserify-sign/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
@@ -7630,33 +7265,27 @@
"cli-truncate/string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
- "cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
-
- "cliui/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
-
"cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"colorspace/color/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
- "data-urls/whatwg-url/tr46": ["tr46@3.0.0", "", { "dependencies": { "punycode": "^2.1.1" } }, "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA=="],
+ "data-urls/whatwg-url/tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="],
"data-urls/whatwg-url/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
- "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
-
"expect/jest-message-util/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
"expect/jest-message-util/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
"express-session/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
- "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
+ "express-static-gzip/serve-static/send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="],
"filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
- "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
+ "form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"gaxios/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
@@ -7674,24 +7303,18 @@
"hast-util-from-html/vfile/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
- "hast-util-from-html/vfile/is-buffer": ["is-buffer@2.0.5", "", {}, "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="],
-
"hast-util-from-html/vfile/unist-util-stringify-position": ["unist-util-stringify-position@3.0.3", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg=="],
"hast-util-from-html/vfile-message/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
"hast-util-from-html/vfile-message/unist-util-stringify-position": ["unist-util-stringify-position@3.0.3", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg=="],
- "hast-util-from-parse5/vfile/is-buffer": ["is-buffer@2.0.5", "", {}, "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="],
-
"hast-util-from-parse5/vfile/unist-util-stringify-position": ["unist-util-stringify-position@3.0.3", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg=="],
"hast-util-from-parse5/vfile/vfile-message": ["vfile-message@3.1.4", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^3.0.0" } }, "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw=="],
"hast-util-parse-selector/@types/hast/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
- "hast-util-whitespace/@types/hast/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
-
"hastscript/@types/hast/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
"istanbul-lib-report/make-dir/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
@@ -7710,165 +7333,197 @@
"jest-changed-files/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
- "jest-changed-files/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "jest-circus/@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
-
- "jest-circus/@jest/environment/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
-
- "jest-circus/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "jest-circus/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"jest-circus/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "jest-cli/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
"jest-config/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"jest-config/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
- "jest-config/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "jest-config/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"jest-config/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "jest-diff/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"jest-diff/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "jest-each/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "jest-each/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"jest-each/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "jest-environment-jsdom/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
-
"jest-environment-node/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
- "jest-environment-node/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "jest-haste-map/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "jest-leak-detector/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"jest-leak-detector/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "jest-message-util/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"jest-message-util/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"jest-mock/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
- "jest-resolve/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "jest-runner/@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="],
-
- "jest-runner/@jest/environment/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
-
- "jest-runner/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
"jest-runtime/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
"jest-runtime/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"jest-runtime/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
- "jest-runtime/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
"jest-snapshot/expect/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="],
- "jest-snapshot/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "jest-snapshot/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"jest-snapshot/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"jest-snapshot/synckit/@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="],
"jest-util/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
- "jest-validate/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"jest-validate/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "jest-watcher/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
- "jest-worker/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
"jest-worker/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
- "jsdom/http-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
-
- "jsdom/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
-
- "jsdom/whatwg-url/tr46": ["tr46@3.0.0", "", { "dependencies": { "punycode": "^2.1.1" } }, "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA=="],
+ "jsdom/whatwg-url/tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="],
"jsonwebtoken/jws/jwa": ["jwa@1.4.1", "", { "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA=="],
"jwks-rsa/@types/express/@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.28.5", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.14", "", { "dependencies": { "@babel/compat-data": "^7.27.7", "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="],
+
+ "librechat-data-provider/@babel/preset-env/core-js-compat": ["core-js-compat@3.47.0", "", { "dependencies": { "browserslist": "^4.28.0" } }, "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ=="],
+
+ "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="],
+
+ "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/types": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw=="],
+
+ "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.27.1", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q=="],
+
+ "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA=="],
+
+ "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
+
+ "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA=="],
+
"log-update/slice-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
"log-update/slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.0.0", "", { "dependencies": { "get-east-asian-width": "^1.0.0" } }, "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA=="],
"log-update/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
- "log-update/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
-
- "log-update/wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
-
"lowlight/@types/hast/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
- "lru-memoizer/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
-
- "mdast-util-directive/unist-util-visit-parents/unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
-
- "mdast-util-find-and-replace/unist-util-is/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-find-and-replace/unist-util-visit-parents/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-math/@types/hast/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
-
- "mdast-util-math/unist-util-remove-position/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-math/unist-util-remove-position/unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="],
-
- "mdast-util-mdx-expression/@types/hast/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-mdx-jsx/unist-util-remove-position/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-mdx-jsx/unist-util-remove-position/unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="],
-
- "mdast-util-mdxjs-esm/@types/hast/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-phrasing/unist-util-is/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-to-hast/@types/hast/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-to-hast/unist-util-visit/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-to-hast/unist-util-visit/unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
-
- "mdast-util-to-hast/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
-
- "mdast-util-to-hast/vfile/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "mdast-util-to-hast/vfile/unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "mdast-util-to-hast/vfile/vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
-
- "mdast-util-to-markdown/unist-util-visit/unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
-
- "mdast-util-to-markdown/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
-
"mongodb-connection-string-url/whatwg-url/tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="],
"mongodb-connection-string-url/whatwg-url/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
- "mongodb-memory-server-core/https-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
+ "multer/type-is/media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="],
+
+ "multer/type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"pbkdf2/ripemd160/hash-base": ["hash-base@2.0.2", "", { "dependencies": { "inherits": "^2.0.1" } }, "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw=="],
@@ -7894,8 +7549,6 @@
"rehype-highlight/unified/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
- "rehype-highlight/unified/is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
-
"rehype-highlight/unified/vfile": ["vfile@5.3.7", "", { "dependencies": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", "unist-util-stringify-position": "^3.0.0", "vfile-message": "^3.0.0" } }, "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g=="],
"rehype-highlight/unist-util-visit/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
@@ -7912,48 +7565,6 @@
"rehype-katex/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@5.1.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" } }, "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg=="],
- "remark-directive/unified/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "remark-directive/unified/is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
-
- "remark-directive/unified/vfile": ["vfile@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg=="],
-
- "remark-gfm/unified/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "remark-gfm/unified/is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
-
- "remark-gfm/unified/vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
-
- "remark-math/unified/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "remark-math/unified/is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
-
- "remark-math/unified/vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
-
- "remark-parse/unified/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "remark-parse/unified/is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
-
- "remark-parse/unified/vfile": ["vfile@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg=="],
-
- "remark-rehype/@types/hast/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "remark-rehype/unified/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "remark-rehype/unified/is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
-
- "remark-rehype/vfile/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "remark-rehype/vfile/unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "remark-rehype/vfile/vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
-
- "remark-stringify/unified/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "remark-stringify/unified/is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
-
- "remark-stringify/unified/vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
-
"remark-supersub/unist-util-visit/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
"remark-supersub/unist-util-visit/unist-util-is": ["unist-util-is@5.2.1", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw=="],
@@ -7964,8 +7575,6 @@
"schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
- "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
-
"stylehacks/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
"sucrase/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
@@ -7984,10 +7593,6 @@
"unist-util-remove-position/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@5.1.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" } }, "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg=="],
- "vasync/verror/core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
-
- "vfile-location/vfile/is-buffer": ["is-buffer@2.0.5", "", {}, "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="],
-
"vfile-location/vfile/unist-util-stringify-position": ["unist-util-stringify-position@3.0.3", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg=="],
"vfile-location/vfile/vfile-message": ["vfile-message@3.1.4", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^3.0.0" } }, "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw=="],
@@ -7996,6 +7601,8 @@
"webpack/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="],
+ "webpack/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
+
"winston-daily-rotate-file/winston-transport/logform": ["logform@2.6.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ=="],
"workbox-build/@babel/preset-env/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ=="],
@@ -8110,8 +7717,6 @@
"workbox-build/@babel/preset-env/core-js-compat": ["core-js-compat@3.35.1", "", { "dependencies": { "browserslist": "^4.22.2" } }, "sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw=="],
- "workbox-build/@babel/preset-env/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"workbox-build/@rollup/plugin-replace/@rollup/pluginutils": ["@rollup/pluginutils@3.1.0", "", { "dependencies": { "@types/estree": "0.0.39", "estree-walker": "^1.0.1", "picomatch": "^2.2.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0" } }, "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg=="],
"workbox-build/@rollup/plugin-replace/magic-string": ["magic-string@0.25.9", "", { "dependencies": { "sourcemap-codec": "^1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="],
@@ -8120,10 +7725,6 @@
"workbox-build/source-map/whatwg-url": ["whatwg-url@7.1.0", "", { "dependencies": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", "webidl-conversions": "^4.0.2" } }, "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg=="],
- "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
-
- "wrap-ansi-cjs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
-
"wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
@@ -8136,38 +7737,16 @@
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-O+e+jo6ei7U/BA7lhT4mmPCWmeR9dFgGUHVwCwJ5c/nCaSaHQ+cb7j2h8WPXERu0LhPSFyj1aD5dk3jFIwNlbg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/nested-clients": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-JRdaprkZjZ6EY4WVwsZaEjPUj9W9vqlSaFDm4oD+IbwlY4GjAXuUQK6skKcvVyoOsSTvJp/CaveSws2FiWUp9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@aws-sdk/client-bedrock-agent-runtime/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
@@ -8180,37 +7759,9 @@
"@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-O+e+jo6ei7U/BA7lhT4mmPCWmeR9dFgGUHVwCwJ5c/nCaSaHQ+cb7j2h8WPXERu0LhPSFyj1aD5dk3jFIwNlbg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/nested-clients": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-JRdaprkZjZ6EY4WVwsZaEjPUj9W9vqlSaFDm4oD+IbwlY4GjAXuUQK6skKcvVyoOsSTvJp/CaveSws2FiWUp9Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
+ "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iWjchXy8bIAVBUsKnbfKYXRwhLgRg3EqCQ5FTr3JbR+QR75rZm4ZOYXlvHGztVTmtAZ+PQVA1Y4zO7v7N87C0A=="],
"@aws-sdk/client-bedrock-runtime/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
@@ -8226,80 +7777,32 @@
"@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
- "@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/signature-v4/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
"@aws-sdk/client-cognito-identity/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/client-cognito-identity/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/middleware-retry/@smithy/service-error-classification/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/node-config-provider/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/node-http-handler/@smithy/abort-controller/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
- "@aws-sdk/client-cognito-identity/@smithy/smithy-client/@smithy/util-stream/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
"@aws-sdk/client-cognito-identity/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ=="],
- "@aws-sdk/client-cognito-identity/@smithy/smithy-client/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/url-parser/@smithy/querystring-parser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/client-cognito-identity/@smithy/util-retry/@smithy/service-error-classification/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-cognito-identity/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
"@aws-sdk/client-kendra/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-O+e+jo6ei7U/BA7lhT4mmPCWmeR9dFgGUHVwCwJ5c/nCaSaHQ+cb7j2h8WPXERu0LhPSFyj1aD5dk3jFIwNlbg=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/nested-clients": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-JRdaprkZjZ6EY4WVwsZaEjPUj9W9vqlSaFDm4oD+IbwlY4GjAXuUQK6skKcvVyoOsSTvJp/CaveSws2FiWUp9Q=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
-
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
"@aws-sdk/client-kendra/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@aws-sdk/client-kendra/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
@@ -8316,44 +7819,18 @@
"@aws-sdk/client-sso-oidc/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
- "@aws-sdk/client-sso-oidc/@aws-sdk/core/@smithy/signature-v4/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-sso-oidc/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
"@aws-sdk/client-sso-oidc/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/client-sso-oidc/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/middleware-retry/@smithy/service-error-classification/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/node-config-provider/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/node-http-handler/@smithy/abort-controller/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
- "@aws-sdk/client-sso-oidc/@smithy/smithy-client/@smithy/util-stream/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
"@aws-sdk/client-sso-oidc/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ=="],
- "@aws-sdk/client-sso-oidc/@smithy/smithy-client/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/url-parser/@smithy/querystring-parser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/client-sso-oidc/@smithy/util-retry/@smithy/service-error-classification/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso-oidc/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
"@aws-sdk/client-sso/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
@@ -8362,56 +7839,26 @@
"@aws-sdk/client-sso/@aws-sdk/core/@smithy/signature-v4/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
- "@aws-sdk/client-sso/@aws-sdk/core/@smithy/signature-v4/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-sso/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
-
- "@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
"@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/client-sso/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/service-error-classification/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/node-config-provider/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/abort-controller/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
- "@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
"@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ=="],
- "@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
- "@aws-sdk/client-sso/@smithy/url-parser/@smithy/querystring-parser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/client-sso/@smithy/util-retry/@smithy/service-error-classification/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/client-sso/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
"@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
"@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
- "@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/abort-controller/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg=="],
"@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA=="],
@@ -8420,91 +7867,83 @@
"@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@3.1.4", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ=="],
- "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@3.0.3", "", { "dependencies": { "@smithy/querystring-parser": "^3.0.3", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A=="],
"@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/util-middleware": ["@smithy/util-middleware@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw=="],
- "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-stack/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
-
- "@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@3.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="],
-
"@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/credential-providers/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.0.6", "", { "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-serde": "^4.0.2", "@smithy/node-config-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-middleware": "^4.0.1", "tslib": "^2.6.2" } }, "sha512-ftpmkTHIFqgaFugcjzLZv3kzPEFsBFSnq1JsIkr2mwFzCraZVhQk2gqN51OOeRxqhbPTkRFj39Qd2V91E/mQxg=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/middleware-flexible-checksums/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.0", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-serde": "^4.2.7", "@smithy/node-config-provider": "^4.3.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-M6qWfUNny6NFNy8amrCGIb9TfOMUkHVtg9bHtEFGRgfH7A7AtPpn/fcrToGPjVDK1ECuMVvqGQOXcZxmu9K+7A=="],
- "@aws-sdk/middleware-flexible-checksums/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-JSbALU3G+JS4kyBZPqnJ3hxIYwOVRV7r9GNQMS6j5VsQDo5+Es5nddLfr9TQlxZLNHPvKSh+XSB0OuWGfSWFcA=="],
- "@aws-sdk/middleware-flexible-checksums/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.0.1", "", { "dependencies": { "@smithy/querystring-parser": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.758.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/middleware-retry": "^4.0.7", "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.7", "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-YZ5s7PSvyF3Mt2h1EQulCG93uybprNGbBkPmVuy/HMMfbFTt4iL3SbKjxqvOZelm86epFfj7pvK7FliI2WOEcg=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
"@aws-sdk/middleware-websocket/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@aws-sdk/middleware-websocket/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
- "@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
+ "@aws-sdk/middleware-websocket/@smithy/signature-v4/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+ "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
- "@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
+ "@aws-sdk/nested-clients/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+ "@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+ "@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA=="],
+ "@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.1.2", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-44PKEqQ303d3rlQuiDpcCcu//hV8sn+u2JBo84dWCE0rvgeiVl0IlLMagbU++o0jCWhYCsHaAt9wZuZqNe05Hw=="],
+ "@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
+ "@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/signature-v4/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.0", "", { "dependencies": { "@smithy/core": "^3.19.0", "@smithy/middleware-serde": "^4.2.7", "@smithy/node-config-provider": "^4.3.6", "@smithy/shared-ini-file-loader": "^4.4.1", "@smithy/types": "^4.10.0", "@smithy/url-parser": "^4.2.6", "@smithy/util-middleware": "^4.2.6", "tslib": "^2.6.2" } }, "sha512-M6qWfUNny6NFNy8amrCGIb9TfOMUkHVtg9bHtEFGRgfH7A7AtPpn/fcrToGPjVDK1ECuMVvqGQOXcZxmu9K+7A=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-JSbALU3G+JS4kyBZPqnJ3hxIYwOVRV7r9GNQMS6j5VsQDo5+Es5nddLfr9TQlxZLNHPvKSh+XSB0OuWGfSWFcA=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.7", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.7", "@smithy/node-http-handler": "^4.4.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Uuy4S5Aj4oF6k1z+i2OtIBJUns4mlg29Ph4S+CqjR+f4XXpSFVgTCYLzMszHJTicYDBxKFtwq2/QSEDSS5l02A=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
@@ -8514,31 +7953,67 @@
"@babel/plugin-transform-runtime/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
- "@isaacs/cliui/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.0.1", "", {}, "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="],
-
- "@isaacs/cliui/wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.0.1", "", {}, "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="],
-
"@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
- "@jest/environment/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
-
"@jest/expect/expect/jest-matcher-utils/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="],
- "@jest/expect/expect/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
"@jest/fake-timers/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
- "@jest/globals/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
-
- "@jest/globals/@jest/environment/@jest/fake-timers/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="],
-
- "@jest/globals/jest-mock/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
-
"@jest/reporters/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"@jest/reporters/glob/path-scurry/lru-cache": ["lru-cache@10.2.0", "", {}, "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="],
- "@jest/snapshot-utils/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/eventstream-handler-node/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.1.1", "", {}, "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@aws-sdk/util-format-url": ["@aws-sdk/util-format-url@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-UYLWPvZEd6TYilNkrQrIeXh2bXZsY3ighYErSEjD24f3JQhg0XdXoR/QHIE8licHu2qFrTRM6yi9LH1GY6X0cg=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.8.1", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aV8blR9RBDKrOlZVgjOdmOibTC2sBXNiT7WA558b4MPdsLTV6sbyc1WIE9QiIuYMJjYtnPLciefoqSW8Gi+MZQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.3.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-y5ozxeQ9omVjbnJo9dtTsdXj9BEvGx2X8xvRgKnV+/7wLBuYJQL6dOa/qMY6omyHi7yjt1OA97jZLoVRYi8lxA=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-YVNMjhdz2pVto5bRdux7GMs0x1m0Afz3OcQy/4Yf9DH4fWOtroGH7uLvs7ZmDyoBJzLdegtIPpXrpJOZWvUXdw=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-g2DHo08IhxV5GdY3Cpt/jr0mkTlAD39EJKN27Jb5N8Fb5qt8KG39wVKTXiTRCmHHou7lbXR8nKVU14/aRUf86w=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core": ["@aws-sdk/core@3.927.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws-sdk/xml-builder": "3.921.0", "@smithy/core": "^3.17.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/signature-v4": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-QOtR9QdjNeC7bId3fc/6MnqoEezvQ2Fk+x6F+Auf7NhOxwYAtB1nvh0k3+gJHWVGpfxN1I8keahRZd79U68/ag=="],
@@ -8572,48 +8047,176 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
- "@langchain/google-gauth/google-auth-library/gaxios/https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
-
"@langchain/google-gauth/google-auth-library/gaxios/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
"@langchain/google-gauth/google-auth-library/gaxios/rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": "dist/esm/bin.mjs" }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-for-of/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-spread/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
+
+ "@librechat/client/@babel/preset-env/core-js-compat/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
+
+ "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-jsx/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-react/@babel/plugin-transform-react-pure-annotations/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-for-of/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-spread/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
+
+ "@librechat/frontend/@babel/preset-env/core-js-compat/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
+
+ "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-jsx/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-react/@babel/plugin-transform-react-pure-annotations/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
"@librechat/frontend/@react-spring/web/@react-spring/shared/@react-spring/rafz": ["@react-spring/rafz@9.7.5", "", {}, "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw=="],
- "@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
+ "@librechat/frontend/@testing-library/jest-dom/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
- "@modelcontextprotocol/sdk/express/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
+ "@librechat/frontend/@testing-library/jest-dom/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
- "@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
+ "@librechat/frontend/jest-environment-jsdom/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/cssstyle": ["cssstyle@2.3.0", "", { "dependencies": { "cssom": "~0.3.6" } }, "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/data-urls": ["data-urls@3.0.2", "", { "dependencies": { "abab": "^2.0.6", "whatwg-mimetype": "^3.0.0", "whatwg-url": "^11.0.0" } }, "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/html-encoding-sniffer": ["html-encoding-sniffer@3.0.0", "", { "dependencies": { "whatwg-encoding": "^2.0.0" } }, "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/http-proxy-agent": ["http-proxy-agent@5.0.0", "", { "dependencies": { "@tootallnate/once": "2", "agent-base": "6", "debug": "4" } }, "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/nwsapi": ["nwsapi@2.2.7", "", {}, "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/tough-cookie": ["tough-cookie@4.1.3", "", { "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", "universalify": "^0.2.0", "url-parse": "^1.5.3" } }, "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/w3c-xmlserializer": ["w3c-xmlserializer@4.0.0", "", { "dependencies": { "xml-name-validator": "^4.0.0" } }, "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/whatwg-encoding": ["whatwg-encoding@2.0.0", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/whatwg-url": ["whatwg-url@11.0.0", "", { "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" } }, "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/xml-name-validator": ["xml-name-validator@4.0.0", "", {}, "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw=="],
+
+ "@mcp-ui/client/@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
+
+ "@node-saml/passport-saml/@types/express/@types/express-serve-static-core/@types/qs": ["@types/qs@6.9.17", "", {}, "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ=="],
"@radix-ui/react-arrow/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
- "@radix-ui/react-label/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@radix-ui/react-portal/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
-
"@radix-ui/react-progress/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
- "@radix-ui/react-separator/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
"@radix-ui/react-tabs/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.1", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw=="],
"@radix-ui/react-tabs/@radix-ui/react-roving-focus/@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/react-compose-refs": "1.0.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg=="],
- "@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@smithy/chunked-blob-reader-native/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
-
- "@smithy/credential-provider-imds/@smithy/node-config-provider/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@smithy/credential-provider-imds/@smithy/url-parser/@smithy/querystring-parser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@smithy/hash-stream-node/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
-
- "@smithy/md5-js/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
-
- "@testing-library/jest-dom/chalk/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
-
"cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"colorspace/color/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
@@ -8622,6 +8225,14 @@
"expect/jest-message-util/@jest/types/@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
+ "express-static-gzip/serve-static/send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
+
+ "express-static-gzip/serve-static/send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
+
+ "express-static-gzip/serve-static/send/fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="],
+
+ "express-static-gzip/serve-static/send/mime": ["mime@1.6.0", "", { "bin": "cli.js" }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="],
+
"google-auth-library/gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.0", "", { "dependencies": { "debug": "^4.3.4" } }, "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg=="],
"googleapis-common/gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.0", "", { "dependencies": { "debug": "^4.3.4" } }, "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg=="],
@@ -8630,18 +8241,12 @@
"jest-changed-files/execa/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
- "jest-circus/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
-
"jest-config/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"jest-config/glob/path-scurry/lru-cache": ["lru-cache@10.2.0", "", {}, "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="],
- "jest-environment-jsdom/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
-
"jest-mock/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
- "jest-runner/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="],
-
"jest-runtime/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"jest-runtime/glob/path-scurry/lru-cache": ["lru-cache@10.2.0", "", {}, "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="],
@@ -8650,40 +8255,76 @@
"jsdom/whatwg-url/tr46/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
- "log-update/wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
- "mdast-util-math/unist-util-remove-position/unist-util-visit/unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
- "mdast-util-math/unist-util-remove-position/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="],
- "mdast-util-mdx-jsx/unist-util-remove-position/unist-util-visit/unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
- "mdast-util-mdx-jsx/unist-util-remove-position/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-for-of/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-optional-chaining/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-spread/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="],
+
+ "librechat-data-provider/@babel/preset-env/core-js-compat/browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": "cli.js" }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="],
+
+ "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-jsx/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-react/@babel/plugin-transform-react-pure-annotations/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
+
+ "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
"mongodb-connection-string-url/whatwg-url/tr46/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
- "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
+ "multer/type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
- "rehype-highlight/unified/vfile/is-buffer": ["is-buffer@2.0.5", "", {}, "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="],
+ "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
"rehype-highlight/unified/vfile/unist-util-stringify-position": ["unist-util-stringify-position@3.0.3", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg=="],
"rehype-highlight/unified/vfile/vfile-message": ["vfile-message@3.1.4", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^3.0.0" } }, "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw=="],
- "remark-directive/unified/vfile/unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "remark-directive/unified/vfile/vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
-
- "remark-gfm/unified/vfile/vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
-
- "remark-math/unified/vfile/vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
-
- "remark-parse/unified/vfile/unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "remark-parse/unified/vfile/vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
-
- "remark-stringify/unified/vfile/vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
-
"sucrase/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"sucrase/glob/path-scurry/lru-cache": ["lru-cache@10.2.0", "", {}, "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="],
@@ -8720,8 +8361,6 @@
"workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
- "workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
"workbox-build/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.5.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q=="],
@@ -8740,915 +8379,111 @@
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@aws-sdk/client-bedrock-agent-runtime/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-cognito-identity/@aws-sdk/core/@smithy/signature-v4/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
-
- "@aws-sdk/client-cognito-identity/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
-
"@aws-sdk/client-cognito-identity/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
"@aws-sdk/client-kendra/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.927.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.927.0", "@aws-sdk/middleware-host-header": "3.922.0", "@aws-sdk/middleware-logger": "3.922.0", "@aws-sdk/middleware-recursion-detection": "3.922.0", "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/region-config-resolver": "3.925.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@aws-sdk/util-user-agent-browser": "3.922.0", "@aws-sdk/util-user-agent-node": "3.927.0", "@smithy/config-resolver": "^4.4.2", "@smithy/core": "^3.17.2", "@smithy/fetch-http-handler": "^5.3.5", "@smithy/hash-node": "^4.2.4", "@smithy/invalid-dependency": "^4.2.4", "@smithy/middleware-content-length": "^4.2.4", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-retry": "^4.4.6", "@smithy/middleware-serde": "^4.2.4", "@smithy/middleware-stack": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/node-http-handler": "^4.4.4", "@smithy/protocol-http": "^5.3.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.5", "@smithy/util-defaults-mode-node": "^4.2.8", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Oy6w7+fzIdr10DhF/HpfVLy6raZFTdiE7pxS1rvpuj2JgxzW2y6urm2sYf3eLOpMiHyuG4xUBwFiJpU9CCEvJA=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
"@aws-sdk/client-kendra/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@aws-sdk/client-kendra/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-sso-oidc/@aws-sdk/core/@smithy/signature-v4/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
-
- "@aws-sdk/client-sso-oidc/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
-
"@aws-sdk/client-sso-oidc/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/client-sso/@aws-sdk/core/@smithy/signature-v4/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@3.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" } }, "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA=="],
-
- "@aws-sdk/client-sso/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
-
"@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
"@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
- "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/node-config-provider/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
"@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@3.0.3", "", { "dependencies": { "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } }, "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ=="],
- "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
- "@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@3.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.0.2", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.0.1", "", { "dependencies": { "@smithy/querystring-parser": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.6", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tVoyzJ2vXp4R3/aeV4EQjBDmCuWxRa8eo3KybL7Xv4wEM16nObYh7H1sNfcuLWHAAAzb0RVyxUz1S3sGj4X+Tg=="],
- "@aws-sdk/middleware-sdk-s3/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
+
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
"@aws-sdk/middleware-websocket/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+ "@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
- "@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+ "@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.0.1", "", { "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA=="],
+ "@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.0.3", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-dYCLeINNbYdvmMLtW0VdhW1biXt+PPCGazzT5ZjKw46mOtdgToQEwjqZSS9/EN8+tNs/RO0cEWG044+YZs97aA=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/util-base64": ["@smithy/util-base64@4.0.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-PFMVHVPgtFECeu4iZ+4SX6VOQT0+dIpm4jSPLLL6JLSkp9RohGqKBKD0cbiXdeIFS08Forp0UHI6kc0gIHenSA=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.0.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.6", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.6", "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-tVoyzJ2vXp4R3/aeV4EQjBDmCuWxRa8eo3KybL7Xv4wEM16nObYh7H1sNfcuLWHAAAzb0RVyxUz1S3sGj4X+Tg=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.6", "@smithy/querystring-builder": "^4.2.6", "@smithy/types": "^4.10.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-fcVap4QwqmzQwQK9QU3keeEpCzTjnP9NJ171vI7GnD7nbkAIcP9biZhDUx88uRH9BabSsQDS0unUps88uZvFIQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@babel/plugin-transform-runtime/babel-plugin-polyfill-corejs3/core-js-compat/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
"@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
- "@jest/expect/expect/jest-matcher-utils/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
-
"@jest/expect/expect/jest-matcher-utils/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
- "@jest/globals/@jest/environment/@jest/fake-timers/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@aws-sdk/util-format-url/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.921.0", "", { "dependencies": { "@smithy/types": "^4.8.1", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-LVHg0jgjyicKKvpNIEMXIMr1EBViESxcPkqfOlT+X1FkmUMTNZEEVF18tOJg4m4hV5vxtkWcqtr4IEeWa1C41Q=="],
@@ -9924,20 +8759,336 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
- "@langchain/google-gauth/google-auth-library/gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
-
"@langchain/google-gauth/google-auth-library/gaxios/rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+ "@librechat/client/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
+
+ "@librechat/client/@babel/preset-env/core-js-compat/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+
+ "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/client/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+ "@librechat/frontend/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
+
+ "@librechat/frontend/@babel/preset-env/core-js-compat/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+
+ "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "@librechat/frontend/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "@librechat/frontend/@testing-library/jest-dom/chalk/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
+
+ "@librechat/frontend/jest-environment-jsdom/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/cssstyle/cssom": ["cssom@0.3.8", "", {}, "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/http-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/tough-cookie/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/tough-cookie/universalify": ["universalify@0.2.0", "", {}, "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="],
+
+ "@librechat/frontend/jest-environment-jsdom/jsdom/whatwg-url/tr46": ["tr46@3.0.0", "", { "dependencies": { "punycode": "^2.1.1" } }, "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA=="],
+
"expect/jest-message-util/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
+ "express-static-gzip/serve-static/send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-async-to-generator/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-object-super/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
+
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+ "librechat-data-provider/@babel/preset-env/babel-plugin-polyfill-regenerator/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
+
+ "librechat-data-provider/@babel/preset-env/core-js-compat/browserslist/update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+
+ "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
+
+ "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
+
+ "librechat-data-provider/@babel/preset-typescript/@babel/plugin-transform-typescript/@babel/helper-create-class-features-plugin/@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
+
"pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
- "remark-gfm/unified/vfile/vfile-message/unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "remark-math/unified/vfile/vfile-message/unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "remark-stringify/unified/vfile/vfile-message/unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
"svgo/css-select/domutils/dom-serializer/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="],
"workbox-build/@babel/preset-env/@babel/plugin-transform-async-generator-functions/@babel/helper-remap-async-to-generator/@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.22.20", "", { "dependencies": { "@babel/helper-function-name": "^7.22.5", "@babel/template": "^7.22.15", "@babel/types": "^7.22.19" } }, "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw=="],
@@ -9952,8 +9103,6 @@
"workbox-build/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-properties/@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"workbox-build/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.23.0", "", { "dependencies": { "@babel/types": "^7.23.0" } }, "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA=="],
"workbox-build/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw=="],
@@ -9962,8 +9111,6 @@
"workbox-build/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-class-static-block/@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"workbox-build/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.23.0", "", { "dependencies": { "@babel/types": "^7.23.0" } }, "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA=="],
"workbox-build/@babel/preset-env/@babel/plugin-transform-classes/@babel/helper-replace-supers/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw=="],
@@ -9980,8 +9127,6 @@
"workbox-build/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-methods/@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"workbox-build/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.23.0", "", { "dependencies": { "@babel/types": "^7.23.0" } }, "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA=="],
"workbox-build/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw=="],
@@ -9990,8 +9135,6 @@
"workbox-build/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.22.5", "", { "dependencies": { "@babel/types": "^7.22.5" } }, "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q=="],
- "workbox-build/@babel/preset-env/@babel/plugin-transform-private-property-in-object/@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
"workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs2/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
"workbox-build/@babel/preset-env/babel-plugin-polyfill-corejs3/@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.8", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="],
@@ -10002,777 +9145,27 @@
"workbox-build/source-map/whatwg-url/tr46/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
"@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
"@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-YmWxl32SQRw/kIRccSOxzS/Ib8/b5/f9ex0r5PR40jRJg8X1wgM3KrR2In+8zvOGVhRSXgvyQpw9yOSlmfmSnA=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
+ "@aws-sdk/credential-provider-login/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
+ "@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.6", "", { "dependencies": { "@smithy/types": "^4.10.0", "tslib": "^2.6.2" } }, "sha512-YmWxl32SQRw/kIRccSOxzS/Ib8/b5/f9ex0r5PR40jRJg8X1wgM3KrR2In+8zvOGVhRSXgvyQpw9yOSlmfmSnA=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@aws-sdk/token-providers/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-HPquFgBnq/KqKRVkiuCt97PmWbKtxQ5iUNLEc6FIviqOoZTmaYG3EDsIbuFBz9C4RHJU4FKLmHL2bL3FEId6AA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-AkvYO6b80FBm5/kk2E636zNNcNgjztNNUxpqVx+huyGn9ZqGTzS4kLqW2hO6CBe5APzVtPCtiQsXL24nzuOlAg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@aws/lambda-invoke-store": "^0.1.1", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-TtSCEDonV/9R0VhVlCpxZbp/9sxQvTTRKzIf8LxW3uXpby6Wl8IxEciBJlxmSkoqxh542WRcko7NYODlvL/gDA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.927.0", "", { "dependencies": { "@aws-sdk/core": "3.927.0", "@aws-sdk/types": "3.922.0", "@aws-sdk/util-endpoints": "3.922.0", "@smithy/core": "^3.17.2", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-sv6St9EgEka6E7y19UMCsttFBZ8tsmz2sstgRd7LztlX3wJynpeDUhq0gtedguG1lGZY/gDf832k5dqlRLUk7g=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.925.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/config-resolver": "^4.4.2", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-FOthcdF9oDb1pfQBRCfWPZhJZT5wqpvdAS5aJzB1WDZ+6EuaAhLzLH/fW1slDunIqq1PSQGG3uSnVglVVOvPHQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-endpoints": "^3.2.4", "tslib": "^2.6.2" } }, "sha512-4ZdQCSuNMY8HMlR1YN4MRDdXuKd+uQTeKIr5/pIM+g3TjInZoj8imvXudjcrFGA63UF3t92YVTkBq88mg58RXQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.922.0", "", { "dependencies": { "@aws-sdk/types": "3.922.0", "@smithy/types": "^4.8.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-qOJAERZ3Plj1st7M4Q5henl5FRpE30uLm6L9edZqZXGR6c7ry9jzexWamWVpQ4H4xVAVmiO9dIEBAfbq4mduOA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.927.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.927.0", "@aws-sdk/types": "3.922.0", "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-5Ty+29jBTHg1mathEhLJavzA7A7vmhephRYGenFzo8rApLZh+c+MCAqjddSjdDzcf5FH+ydGGnIrj4iIfbZIMQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node": ["@smithy/hash-node@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kKU0gVhx/ppVMntvUOZE7WRMFW86HuaxLwvqileBEjL7PoILI8/djoILw3gPQloGVE6O0oOzqafxeNi2KbnUJw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-z6aDLGiHzsMhbS2MjetlIWopWz//K+mCoPXjW6aLr0mypF+Y7qdEh5TyJ20Onf9FbWHiWl4eC+rITdizpnXqOw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-hJRZuFS9UsElX4DJSJfoX4M1qXRH+VFiLMUnhsWvtOOUWRNvvOfDaUSdlNbjwv1IkpVjj/Rd/O59Jl3nhAcxow=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.6", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/protocol-http": "^5.3.4", "@smithy/service-error-classification": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "@smithy/util-middleware": "^4.2.4", "@smithy/util-retry": "^4.2.4", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-OhLx131znrEDxZPAvH/OYufR9d1nB2CQADyYFN4C3V/NQS7Mg4V6uvxHC/Dr96ZQW8IlHJTJ+vAhKt6oxWRndA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.4", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-3X3w7qzmo4XNNdPKNS4nbJcGSwiEMsNsRSunMA92S4DJLLIrH5g1AyuOA2XKM9PAPi8mIWfqC+fnfKNsI4KvHw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client": ["@smithy/smithy-client@4.9.2", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-endpoint": "^4.3.6", "@smithy/middleware-stack": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-stream": "^4.5.5", "tslib": "^2.6.2" } }, "sha512-gZU4uAFcdrSi3io8U99Qs/FvVdRxPvIMToi+MFfsy/DN9UqtknJ1ais+2M9yR8e0ASQpNmFYEKeIKVcMjQg3rg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-retry": ["@smithy/util-retry@4.2.4", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-yQncJmj4dtv/isTXxRb4AamZHy4QFr4ew8GxS6XLWt7sCIxkPxPzINWd7WLISEFPsIan14zrKgvyAF+/yzfwoA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.6", "", { "dependencies": { "@smithy/core": "^3.17.2", "@smithy/middleware-serde": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/shared-ini-file-loader": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/url-parser": "^4.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-PXehXofGMFpDqr933rxD8RGOcZ0QBAWtuzTgYRAHAL2BnKawHDEdf/TnGpcmfPJGwonhginaaeJIKluEojiF/w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Gy3TKCOnm9JwpFooldwAboazw+EFYlC+Bb+1QBsSi5xI0W5lX81j/P5+CXvD/9ZjtYKRgxq+kkqd/KOHflzvgA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser/@smithy/types": ["@smithy/types@3.3.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA=="],
-
- "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw=="],
-
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
-
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
-
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
-
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
-
- "@aws-sdk/s3-request-presigner/@smithy/middleware-endpoint/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
-
- "@aws-sdk/s3-request-presigner/@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.0.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw=="],
+ "@langchain/aws/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
@@ -10840,6 +9233,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.1.1", "", {}, "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
@@ -10882,6 +9277,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.1.1", "", {}, "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
@@ -11002,6 +9399,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.1.1", "", {}, "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
@@ -11030,539 +9429,133 @@
"@langchain/google-gauth/google-auth-library/gaxios/rimraf/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@librechat/client/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "@librechat/frontend/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "@librechat/frontend/jest-environment-jsdom/jsdom/whatwg-url/tr46/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-dotall-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-duplicate-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-named-capturing-groups-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-regexp-modifiers/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-property-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/fetch-http-handler/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1" } }, "sha512-fdWuhEx4+jHLGeew9/IvqVU/fxT/ot70tpRGuOLxE3HzZOyKeTQfYeV1oaBXpzi93WOk668hjMuuagJ2/Qs7ng=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.4", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-jUr3x2CDhV15TOX2/Uoz4gfgeqLrRoTQbYAuhLS7lcVKNev7FeYSJ1ebEfjk+l9kbb7k7LfzIR/irgxys5ZTOg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser": ["@smithy/url-parser@4.2.4", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-w/N/Iw0/PTwJ36PDqU9PzAwVElo4qXxCC0eCTlUtIz/Z5V/2j/cViMHi0hPukSBHp4DVwvUlUhLgCzqSJ6plrg=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-mg83SM3FLI8Sa2ooTJbsh5MFfyMTyNRwxqpKHmE0ICRIa66Aodv80DMsTQI02xBLVJ0hckwqTRr5IGAbbWuFLQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.4", "", { "dependencies": { "@smithy/abort-controller": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/querystring-builder": "^4.2.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-VXHGfzCXLZeKnFp6QXjAdy+U8JF9etfpUXD1FAbzY1GzsFJiDQRQIt2CnMUvUdz3/YaHNqT3RphVWMUpXTIODA=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "librechat-data-provider/@babel/preset-env/@babel/plugin-transform-unicode-sets-regex/@babel/helper-create-regexp-features-plugin/regexpu-core/unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
@@ -11686,6 +9679,8 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
+ "@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.1.1", "", {}, "sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA=="],
+
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/config-resolver/@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream": ["@smithy/util-stream@4.5.5", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.5", "@smithy/node-http-handler": "^4.4.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7M5aVFjT+HPilPOKbOmQfCIPchZe4DSBc1wf1+NvHvSoFTiFtauZzT+onZvCj70xhXd0AEmYnZYmdJIuwxOo4w=="],
@@ -11746,354 +9741,6 @@
"@langchain/google-gauth/google-auth-library/gaxios/rimraf/glob/path-scurry/lru-cache": ["lru-cache@10.2.0", "", {}, "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http/@smithy/smithy-client/@smithy/core/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/hash-node/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/middleware-endpoint/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-aHb5cqXZocdzEkZ/CvhVjdw5l4r1aU/9iMEyoKzH4eXMowT6M0YjBpp7W/+XjkBnY8Xh0kVd55GKjnPKlCwinQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/core/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KQ1gFXXC+WsbPFnk7pzskzOpn4s+KheWgO3dzkIEmnb6NskAIGp/dGdbKisTPJdtov28qNDohQrgDUKzXZBLig=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env/@aws-sdk/core/@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="],
@@ -12210,18 +9857,6 @@
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-agent-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
- "@aws-sdk/client-kendra/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
-
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/core/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
"@langchain/aws/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/smithy-client/@smithy/util-stream/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
diff --git a/client/jest.config.cjs b/client/jest.config.cjs
index c62430d22f..f3b0b91e9b 100644
--- a/client/jest.config.cjs
+++ b/client/jest.config.cjs
@@ -1,4 +1,4 @@
-/** v0.8.1 */
+/** v0.8.3-rc1 */
module.exports = {
roots: ['/src'],
testEnvironment: 'jsdom',
diff --git a/client/package.json b/client/package.json
index aef5f4697a..613a41ac3f 100644
--- a/client/package.json
+++ b/client/package.json
@@ -1,6 +1,6 @@
{
"name": "@librechat/frontend",
- "version": "v0.8.1",
+ "version": "v0.8.3-rc1",
"description": "",
"type": "module",
"scripts": {
@@ -12,7 +12,7 @@
"dev": "cross-env NODE_ENV=development vite",
"preview-prod": "cross-env NODE_ENV=development vite preview",
"test": "cross-env NODE_ENV=development jest --watch",
- "test:ci": "cross-env NODE_ENV=development jest --ci",
+ "test:ci": "cross-env NODE_ENV=development jest --ci --logHeapUsage",
"b:test": "NODE_ENV=test bunx jest --watch",
"b:build": "NODE_ENV=production bun --bun vite build",
"b:dev": "NODE_ENV=development bunx vite"
@@ -39,10 +39,10 @@
"@marsidev/react-turnstile": "^1.1.0",
"@mcp-ui/client": "^5.7.0",
"@radix-ui/react-accordion": "^1.1.2",
- "@radix-ui/react-alert-dialog": "^1.0.2",
+ "@radix-ui/react-alert-dialog": "1.0.2",
"@radix-ui/react-checkbox": "^1.0.3",
"@radix-ui/react-collapsible": "^1.0.3",
- "@radix-ui/react-dialog": "^1.0.2",
+ "@radix-ui/react-dialog": "1.0.2",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-hover-card": "^1.0.5",
"@radix-ui/react-icons": "^1.3.0",
@@ -77,9 +77,10 @@
"jotai": "^2.12.5",
"js-cookie": "^3.0.5",
"librechat-data-provider": "*",
- "lodash": "^4.17.21",
+ "lodash": "^4.17.23",
"lucide-react": "^0.394.0",
"match-sorter": "^8.1.0",
+ "mermaid": "^11.12.3",
"micromark-extension-llm-math": "^3.1.0",
"qrcode.react": "^4.2.0",
"rc-input-number": "^7.4.2",
@@ -95,7 +96,7 @@
"react-lazy-load-image-component": "^1.6.0",
"react-markdown": "^9.0.1",
"react-resizable-panels": "^3.0.6",
- "react-router-dom": "^6.11.2",
+ "react-router-dom": "^6.30.3",
"react-speech-recognition": "^3.10.0",
"react-textarea-autosize": "^8.4.0",
"react-transition-group": "^4.4.5",
@@ -109,9 +110,11 @@
"remark-math": "^6.0.0",
"remark-supersub": "^1.0.0",
"sse.js": "^2.5.0",
+ "swr": "^2.3.8",
"tailwind-merge": "^1.9.1",
"tailwindcss-animate": "^1.0.5",
"tailwindcss-radix": "^2.8.0",
+ "ts-md5": "^1.3.1",
"zod": "^3.22.4"
},
"devDependencies": {
@@ -145,8 +148,7 @@
"jest-file-loader": "^1.0.3",
"jest-junit": "^16.0.0",
"postcss": "^8.4.31",
- "postcss-loader": "^7.1.0",
- "postcss-preset-env": "^8.2.0",
+ "postcss-preset-env": "^11.2.0",
"tailwindcss": "^3.4.1",
"typescript": "^5.3.3",
"vite": "^6.4.1",
diff --git a/client/public/assets/gemini_image_gen.svg b/client/public/assets/gemini_image_gen.svg
new file mode 100644
index 0000000000..25f7457266
--- /dev/null
+++ b/client/public/assets/gemini_image_gen.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/public/assets/maskable-icon.png b/client/public/assets/maskable-icon.png
index 90e48f870b..b48524b867 100644
Binary files a/client/public/assets/maskable-icon.png and b/client/public/assets/maskable-icon.png differ
diff --git a/client/public/assets/web-browser.svg b/client/public/assets/web-browser.svg
deleted file mode 100644
index 3f9c85d14b..0000000000
--- a/client/public/assets/web-browser.svg
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
diff --git a/client/src/@types/i18next.d.ts b/client/src/@types/i18next.d.ts
index 2d50f5a3cd..82f1ce1a3d 100644
--- a/client/src/@types/i18next.d.ts
+++ b/client/src/@types/i18next.d.ts
@@ -1,9 +1,9 @@
import { defaultNS, resources } from '~/locales/i18n';
declare module 'i18next' {
- interface CustomTypeOptions {
- defaultNS: typeof defaultNS;
- resources: typeof resources.en;
- strictKeyChecks: true
- }
-}
\ No newline at end of file
+ interface CustomTypeOptions {
+ defaultNS: typeof defaultNS;
+ resources: typeof resources.en;
+ strictKeyChecks: true;
+ }
+}
diff --git a/client/src/App.jsx b/client/src/App.jsx
index 23651d750c..fe280f7129 100644
--- a/client/src/App.jsx
+++ b/client/src/App.jsx
@@ -18,6 +18,16 @@ const App = () => {
const { setError } = useApiErrorBoundary();
const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ // Always attempt network requests, even when navigator.onLine is false
+ // This is needed because localhost is reachable without WiFi
+ networkMode: 'always',
+ },
+ mutations: {
+ networkMode: 'always',
+ },
+ },
queryCache: new QueryCache({
onError: (error) => {
if (error?.response?.status === 401) {
diff --git a/client/src/Providers/AddedChatContext.tsx b/client/src/Providers/AddedChatContext.tsx
index 9f656debe1..a19aee8746 100644
--- a/client/src/Providers/AddedChatContext.tsx
+++ b/client/src/Providers/AddedChatContext.tsx
@@ -1,6 +1,13 @@
import { createContext, useContext } from 'react';
-import useAddedResponse from '~/hooks/Chat/useAddedResponse';
-type TAddedChatContext = ReturnType;
+import type { TConversation } from 'librechat-data-provider';
+import type { SetterOrUpdater } from 'recoil';
+import type { ConvoGenerator } from '~/common';
+
+type TAddedChatContext = {
+ conversation: TConversation | null;
+ setConversation: SetterOrUpdater;
+ generateConversation: ConvoGenerator;
+};
export const AddedChatContext = createContext({} as TAddedChatContext);
export const useAddedChatContext = () => useContext(AddedChatContext);
diff --git a/client/src/Providers/AgentPanelContext.tsx b/client/src/Providers/AgentPanelContext.tsx
index 4effd7d679..b0d74374b4 100644
--- a/client/src/Providers/AgentPanelContext.tsx
+++ b/client/src/Providers/AgentPanelContext.tsx
@@ -8,7 +8,12 @@ import {
useGetStartupConfig,
useMCPToolsQuery,
} from '~/data-provider';
-import { useLocalize, useGetAgentsConfig, useMCPConnectionStatus } from '~/hooks';
+import {
+ useLocalize,
+ useGetAgentsConfig,
+ useMCPConnectionStatus,
+ useMCPServerManager,
+} from '~/hooks';
import { Panel, isEphemeralAgent } from '~/common';
const AgentPanelContext = createContext(undefined);
@@ -29,7 +34,7 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
const [action, setAction] = useState(undefined);
const [activePanel, setActivePanel] = useState(Panel.builder);
const [agent_id, setCurrentAgentId] = useState(undefined);
-
+ const { availableMCPServers, isLoading, availableMCPServersMap } = useMCPServerManager();
const { data: startupConfig } = useGetStartupConfig();
const { data: actions } = useGetActionsQuery(EModelEndpoint.agents, {
enabled: !isEphemeralAgent(agent_id),
@@ -38,29 +43,39 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
const { data: regularTools } = useAvailableToolsQuery(EModelEndpoint.agents);
const { data: mcpData } = useMCPToolsQuery({
- enabled: !isEphemeralAgent(agent_id) && startupConfig?.mcpServers != null,
+ enabled:
+ !isEphemeralAgent(agent_id) &&
+ !isLoading &&
+ availableMCPServers != null &&
+ availableMCPServers.length > 0,
});
const { agentsConfig, endpointsConfig } = useGetAgentsConfig();
const mcpServerNames = useMemo(
- () => Object.keys(startupConfig?.mcpServers ?? {}),
- [startupConfig],
+ () => availableMCPServers.map((s) => s.serverName),
+ [availableMCPServers],
);
const { connectionStatus } = useMCPConnectionStatus({
enabled: !isEphemeralAgent(agent_id) && mcpServerNames.length > 0,
});
-
+ //TODO to refactor when tools come from tool box
const mcpServersMap = useMemo(() => {
const configuredServers = new Set(mcpServerNames);
const serversMap = new Map();
if (mcpData?.servers) {
for (const [serverName, serverData] of Object.entries(mcpData.servers)) {
+ // Get title and description from config with fallbacks
+ const serverConfig = availableMCPServersMap?.[serverName];
+ const displayName = serverConfig?.title || serverName;
+ const displayDescription =
+ serverConfig?.description || `${localize('com_ui_tool_collection_prefix')} ${serverName}`;
+
const metadata = {
- name: serverName,
+ name: displayName,
pluginKey: serverName,
- description: `${localize('com_ui_tool_collection_prefix')} ${serverName}`,
+ description: displayDescription,
icon: serverData.icon || '',
authConfig: serverData.authConfig,
authenticated: serverData.authenticated,
@@ -82,6 +97,7 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
isConfigured: configuredServers.has(serverName),
isConnected: connectionStatus?.[serverName]?.connectionState === 'connected',
metadata,
+ consumeOnly: serverConfig?.consumeOnly,
});
}
}
@@ -91,11 +107,18 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
if (serversMap.has(mcpServerName)) {
continue;
}
+ // Get title and description from config with fallbacks
+ const serverConfig = availableMCPServersMap?.[mcpServerName];
+ const displayName = serverConfig?.title || mcpServerName;
+ const displayDescription =
+ serverConfig?.description ||
+ `${localize('com_ui_tool_collection_prefix')} ${mcpServerName}`;
+
const metadata = {
- icon: '',
- name: mcpServerName,
+ icon: serverConfig?.iconPath || '',
+ name: displayName,
pluginKey: mcpServerName,
- description: `${localize('com_ui_tool_collection_prefix')} ${mcpServerName}`,
+ description: displayDescription,
} as TPlugin;
serversMap.set(mcpServerName, {
@@ -104,11 +127,12 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
isConfigured: true,
serverName: mcpServerName,
isConnected: connectionStatus?.[mcpServerName]?.connectionState === 'connected',
+ consumeOnly: serverConfig?.consumeOnly,
});
}
return serversMap;
- }, [mcpData, localize, mcpServerNames, connectionStatus]);
+ }, [mcpData, localize, mcpServerNames, connectionStatus, availableMCPServersMap]);
const value: AgentPanelContextType = {
mcp,
@@ -127,6 +151,8 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
setActivePanel,
endpointsConfig,
setCurrentAgentId,
+ availableMCPServers,
+ availableMCPServersMap,
};
return {children} ;
diff --git a/client/src/Providers/BadgeRowContext.tsx b/client/src/Providers/BadgeRowContext.tsx
index 40df795aba..dce1c38a78 100644
--- a/client/src/Providers/BadgeRowContext.tsx
+++ b/client/src/Providers/BadgeRowContext.tsx
@@ -1,4 +1,4 @@
-import React, { createContext, useContext, useEffect, useRef } from 'react';
+import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';
import { useSetRecoilState } from 'recoil';
import { Tools, Constants, LocalStorageKeys, AgentCapabilities } from 'librechat-data-provider';
import type { TAgentsEndpoint } from 'librechat-data-provider';
@@ -9,11 +9,13 @@ import {
useCodeApiKeyForm,
useToolToggle,
} from '~/hooks';
-import { getTimestampedValue, setTimestamp } from '~/utils/timestamps';
+import { getTimestampedValue } from '~/utils/timestamps';
+import { useGetStartupConfig } from '~/data-provider';
import { ephemeralAgentByConvoId } from '~/store';
interface BadgeRowContextType {
conversationId?: string | null;
+ storageContextKey?: string;
agentsConfig?: TAgentsEndpoint | null;
webSearch: ReturnType;
artifacts: ReturnType;
@@ -38,34 +40,70 @@ interface BadgeRowProviderProps {
children: React.ReactNode;
isSubmitting?: boolean;
conversationId?: string | null;
+ specName?: string | null;
}
export default function BadgeRowProvider({
children,
isSubmitting,
conversationId,
+ specName,
}: BadgeRowProviderProps) {
- const lastKeyRef = useRef('');
+ const lastContextKeyRef = useRef('');
const hasInitializedRef = useRef(false);
const { agentsConfig } = useGetAgentsConfig();
+ const { data: startupConfig } = useGetStartupConfig();
const key = conversationId ?? Constants.NEW_CONVO;
+ const hasModelSpecs = (startupConfig?.modelSpecs?.list?.length ?? 0) > 0;
+
+ /**
+ * Compute the storage context key for non-spec persistence:
+ * - `__defaults__`: specs configured but none active → shared defaults key
+ * - undefined: spec active (no persistence) or no specs configured (original behavior)
+ *
+ * When a spec is active, tool/MCP state is NOT persisted — the admin's spec
+ * configuration is always applied fresh. Only non-spec user preferences persist.
+ */
+ const storageContextKey = useMemo(() => {
+ if (!specName && hasModelSpecs) {
+ return Constants.spec_defaults_key as string;
+ }
+ return undefined;
+ }, [specName, hasModelSpecs]);
+
+ /**
+ * Compute the storage suffix for reading localStorage defaults:
+ * - New conversations read from environment key (spec or non-spec defaults)
+ * - Existing conversations read from conversation key (per-conversation state)
+ */
+ const isNewConvo = key === Constants.NEW_CONVO;
+ const storageSuffix = isNewConvo && storageContextKey ? storageContextKey : key;
const setEphemeralAgent = useSetRecoilState(ephemeralAgentByConvoId(key));
- /** Initialize ephemeralAgent from localStorage on mount and when conversation changes */
+ /** Initialize ephemeralAgent from localStorage on mount and when conversation/spec changes.
+ * Skipped when a spec is active — applyModelSpecEphemeralAgent handles both new conversations
+ * (pure spec values) and existing conversations (spec values + localStorage overrides). */
useEffect(() => {
if (isSubmitting) {
return;
}
- // Check if this is a new conversation or the first load
- if (!hasInitializedRef.current || lastKeyRef.current !== key) {
+ if (specName) {
+ // Spec active: applyModelSpecEphemeralAgent handles all state (spec base + localStorage
+ // overrides for existing conversations). Reset init flag so switching back to non-spec
+ // triggers a fresh re-init.
+ hasInitializedRef.current = false;
+ return;
+ }
+ // Check if this is a new conversation/spec or the first load
+ if (!hasInitializedRef.current || lastContextKeyRef.current !== storageSuffix) {
hasInitializedRef.current = true;
- lastKeyRef.current = key;
+ lastContextKeyRef.current = storageSuffix;
- const codeToggleKey = `${LocalStorageKeys.LAST_CODE_TOGGLE_}${key}`;
- const webSearchToggleKey = `${LocalStorageKeys.LAST_WEB_SEARCH_TOGGLE_}${key}`;
- const fileSearchToggleKey = `${LocalStorageKeys.LAST_FILE_SEARCH_TOGGLE_}${key}`;
- const artifactsToggleKey = `${LocalStorageKeys.LAST_ARTIFACTS_TOGGLE_}${key}`;
+ const codeToggleKey = `${LocalStorageKeys.LAST_CODE_TOGGLE_}${storageSuffix}`;
+ const webSearchToggleKey = `${LocalStorageKeys.LAST_WEB_SEARCH_TOGGLE_}${storageSuffix}`;
+ const fileSearchToggleKey = `${LocalStorageKeys.LAST_FILE_SEARCH_TOGGLE_}${storageSuffix}`;
+ const artifactsToggleKey = `${LocalStorageKeys.LAST_ARTIFACTS_TOGGLE_}${storageSuffix}`;
const codeToggleValue = getTimestampedValue(codeToggleKey);
const webSearchToggleValue = getTimestampedValue(webSearchToggleKey);
@@ -106,39 +144,53 @@ export default function BadgeRowProvider({
}
}
- /**
- * Always set values for all tools (use defaults if not in `localStorage`)
- * If `ephemeralAgent` is `null`, create a new object with just our tool values
- */
- const finalValues = {
- [Tools.execute_code]: initialValues[Tools.execute_code] ?? false,
- [Tools.web_search]: initialValues[Tools.web_search] ?? false,
- [Tools.file_search]: initialValues[Tools.file_search] ?? false,
- [AgentCapabilities.artifacts]: initialValues[AgentCapabilities.artifacts] ?? false,
- };
+ const hasOverrides = Object.keys(initialValues).length > 0;
- setEphemeralAgent((prev) => ({
- ...(prev || {}),
- ...finalValues,
- }));
-
- Object.entries(finalValues).forEach(([toolKey, value]) => {
- if (value !== false) {
- let storageKey = artifactsToggleKey;
- if (toolKey === Tools.execute_code) {
- storageKey = codeToggleKey;
- } else if (toolKey === Tools.web_search) {
- storageKey = webSearchToggleKey;
- } else if (toolKey === Tools.file_search) {
- storageKey = fileSearchToggleKey;
+ /** Read persisted MCP values from localStorage */
+ let mcpOverrides: string[] | null = null;
+ const mcpStorageKey = `${LocalStorageKeys.LAST_MCP_}${storageSuffix}`;
+ const mcpRaw = localStorage.getItem(mcpStorageKey);
+ if (mcpRaw !== null) {
+ try {
+ const parsed = JSON.parse(mcpRaw);
+ if (Array.isArray(parsed) && parsed.length > 0) {
+ mcpOverrides = parsed;
}
- // Store the value and set timestamp for existing values
- localStorage.setItem(storageKey, JSON.stringify(value));
- setTimestamp(storageKey);
+ } catch (e) {
+ console.error('Failed to parse MCP values:', e);
}
+ }
+
+ setEphemeralAgent((prev) => {
+ if (prev == null) {
+ /** ephemeralAgent is null — use localStorage defaults */
+ if (hasOverrides || mcpOverrides) {
+ const result = { ...initialValues };
+ if (mcpOverrides) {
+ result.mcp = mcpOverrides;
+ }
+ return result;
+ }
+ return prev;
+ }
+ /** ephemeralAgent already has values (from prior state).
+ * Only fill in undefined keys from localStorage. */
+ let changed = false;
+ const result = { ...prev };
+ for (const [toolKey, value] of Object.entries(initialValues)) {
+ if (result[toolKey] === undefined) {
+ result[toolKey] = value;
+ changed = true;
+ }
+ }
+ if (mcpOverrides && result.mcp === undefined) {
+ result.mcp = mcpOverrides;
+ changed = true;
+ }
+ return changed ? result : prev;
});
}
- }, [key, isSubmitting, setEphemeralAgent]);
+ }, [storageSuffix, specName, isSubmitting, setEphemeralAgent]);
/** CodeInterpreter hooks */
const codeApiKeyForm = useCodeApiKeyForm({});
@@ -146,6 +198,7 @@ export default function BadgeRowProvider({
const codeInterpreter = useToolToggle({
conversationId,
+ storageContextKey,
setIsDialogOpen: setCodeDialogOpen,
toolKey: Tools.execute_code,
localStorageKey: LocalStorageKeys.LAST_CODE_TOGGLE_,
@@ -161,6 +214,7 @@ export default function BadgeRowProvider({
const webSearch = useToolToggle({
conversationId,
+ storageContextKey,
toolKey: Tools.web_search,
localStorageKey: LocalStorageKeys.LAST_WEB_SEARCH_TOGGLE_,
setIsDialogOpen: setWebSearchDialogOpen,
@@ -173,6 +227,7 @@ export default function BadgeRowProvider({
/** FileSearch hook */
const fileSearch = useToolToggle({
conversationId,
+ storageContextKey,
toolKey: Tools.file_search,
localStorageKey: LocalStorageKeys.LAST_FILE_SEARCH_TOGGLE_,
isAuthenticated: true,
@@ -181,12 +236,13 @@ export default function BadgeRowProvider({
/** Artifacts hook - using a custom key since it's not a Tool but a capability */
const artifacts = useToolToggle({
conversationId,
+ storageContextKey,
toolKey: AgentCapabilities.artifacts,
localStorageKey: LocalStorageKeys.LAST_ARTIFACTS_TOGGLE_,
isAuthenticated: true,
});
- const mcpServerManager = useMCPServerManager({ conversationId });
+ const mcpServerManager = useMCPServerManager({ conversationId, storageContextKey });
const value: BadgeRowContextType = {
webSearch,
@@ -194,6 +250,7 @@ export default function BadgeRowProvider({
fileSearch,
agentsConfig,
conversationId,
+ storageContextKey,
codeApiKeyForm,
codeInterpreter,
searchApiKeyForm,
diff --git a/client/src/Providers/DragDropContext.tsx b/client/src/Providers/DragDropContext.tsx
index 35827c7e96..e5a2177f2d 100644
--- a/client/src/Providers/DragDropContext.tsx
+++ b/client/src/Providers/DragDropContext.tsx
@@ -1,7 +1,8 @@
import React, { createContext, useContext, useMemo } from 'react';
-import { getEndpointField } from 'librechat-data-provider';
+import { getEndpointField, isAgentsEndpoint } from 'librechat-data-provider';
import type { EModelEndpoint } from 'librechat-data-provider';
-import { useGetEndpointsQuery } from '~/data-provider';
+import { useGetEndpointsQuery, useGetAgentByIdQuery } from '~/data-provider';
+import { useAgentsMapContext } from './AgentsMapContext';
import { useChatContext } from './ChatContext';
interface DragDropContextValue {
@@ -9,6 +10,7 @@ interface DragDropContextValue {
agentId: string | null | undefined;
endpoint: string | null | undefined;
endpointType?: EModelEndpoint | undefined;
+ useResponsesApi?: boolean;
}
const DragDropContext = createContext(undefined);
@@ -16,6 +18,7 @@ const DragDropContext = createContext(undefine
export function DragDropProvider({ children }: { children: React.ReactNode }) {
const { conversation } = useChatContext();
const { data: endpointsConfig } = useGetEndpointsQuery();
+ const agentsMap = useAgentsMapContext();
const endpointType = useMemo(() => {
return (
@@ -24,6 +27,34 @@ export function DragDropProvider({ children }: { children: React.ReactNode }) {
);
}, [conversation?.endpoint, endpointsConfig]);
+ const needsAgentFetch = useMemo(() => {
+ const isAgents = isAgentsEndpoint(conversation?.endpoint);
+ if (!isAgents || !conversation?.agent_id) {
+ return false;
+ }
+ const agent = agentsMap?.[conversation.agent_id];
+ return !agent?.model_parameters;
+ }, [conversation?.endpoint, conversation?.agent_id, agentsMap]);
+
+ const { data: agentData } = useGetAgentByIdQuery(conversation?.agent_id, {
+ enabled: needsAgentFetch,
+ });
+
+ const useResponsesApi = useMemo(() => {
+ const isAgents = isAgentsEndpoint(conversation?.endpoint);
+ if (!isAgents || !conversation?.agent_id || conversation?.useResponsesApi) {
+ return conversation?.useResponsesApi;
+ }
+ const agent = agentData || agentsMap?.[conversation.agent_id];
+ return agent?.model_parameters?.useResponsesApi;
+ }, [
+ conversation?.endpoint,
+ conversation?.agent_id,
+ conversation?.useResponsesApi,
+ agentData,
+ agentsMap,
+ ]);
+
/** Context value only created when conversation fields change */
const contextValue = useMemo(
() => ({
@@ -31,8 +62,15 @@ export function DragDropProvider({ children }: { children: React.ReactNode }) {
agentId: conversation?.agent_id,
endpoint: conversation?.endpoint,
endpointType: endpointType,
+ useResponsesApi: useResponsesApi,
}),
- [conversation?.conversationId, conversation?.agent_id, conversation?.endpoint, endpointType],
+ [
+ conversation?.conversationId,
+ conversation?.agent_id,
+ conversation?.endpoint,
+ useResponsesApi,
+ endpointType,
+ ],
);
return {children} ;
diff --git a/client/src/Providers/MCPPanelContext.tsx b/client/src/Providers/MCPPanelContext.tsx
deleted file mode 100644
index 948be0ad65..0000000000
--- a/client/src/Providers/MCPPanelContext.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React, { createContext, useContext, useMemo } from 'react';
-import { Constants } from 'librechat-data-provider';
-import { useChatContext } from './ChatContext';
-
-interface MCPPanelContextValue {
- conversationId: string;
-}
-
-const MCPPanelContext = createContext(undefined);
-
-export function MCPPanelProvider({ children }: { children: React.ReactNode }) {
- const { conversation } = useChatContext();
-
- /** Context value only created when conversationId changes */
- const contextValue = useMemo(
- () => ({
- conversationId: conversation?.conversationId ?? Constants.NEW_CONVO,
- }),
- [conversation?.conversationId],
- );
-
- return {children} ;
-}
-
-export function useMCPPanelContext() {
- const context = useContext(MCPPanelContext);
- if (!context) {
- throw new Error('useMCPPanelContext must be used within MCPPanelProvider');
- }
- return context;
-}
diff --git a/client/src/Providers/MessagesViewContext.tsx b/client/src/Providers/MessagesViewContext.tsx
index 630ad277f1..f8f5eef12a 100644
--- a/client/src/Providers/MessagesViewContext.tsx
+++ b/client/src/Providers/MessagesViewContext.tsx
@@ -1,5 +1,4 @@
import React, { createContext, useContext, useMemo } from 'react';
-import { useAddedChatContext } from './AddedChatContext';
import { useChatContext } from './ChatContext';
interface MessagesViewContextValue {
@@ -9,7 +8,6 @@ interface MessagesViewContextValue {
/** Submission and control states */
isSubmitting: ReturnType['isSubmitting'];
- isSubmittingFamily: boolean;
abortScroll: ReturnType['abortScroll'];
setAbortScroll: ReturnType['setAbortScroll'];
@@ -28,15 +26,18 @@ interface MessagesViewContextValue {
const MessagesViewContext = createContext(undefined);
+// Export the context so it can be provided by other providers (e.g., ShareMessagesProvider)
+export { MessagesViewContext };
+export type { MessagesViewContextValue };
+
export function MessagesViewProvider({ children }: { children: React.ReactNode }) {
const chatContext = useChatContext();
- const addedChatContext = useAddedChatContext();
const {
ask,
index,
regenerate,
- isSubmitting: isSubmittingRoot,
+ isSubmitting,
conversation,
latestMessage,
setAbortScroll,
@@ -47,8 +48,6 @@ export function MessagesViewProvider({ children }: { children: React.ReactNode }
setMessages,
} = chatContext;
- const { isSubmitting: isSubmittingAdditional } = addedChatContext;
-
/** Memoize conversation-related values */
const conversationValues = useMemo(
() => ({
@@ -61,12 +60,11 @@ export function MessagesViewProvider({ children }: { children: React.ReactNode }
/** Memoize submission states */
const submissionStates = useMemo(
() => ({
- isSubmitting: isSubmittingRoot,
- isSubmittingFamily: isSubmittingRoot || isSubmittingAdditional,
abortScroll,
+ isSubmitting,
setAbortScroll,
}),
- [isSubmittingRoot, isSubmittingAdditional, abortScroll, setAbortScroll],
+ [isSubmitting, abortScroll, setAbortScroll],
);
/** Memoize message operations (these are typically stable references) */
@@ -123,11 +121,10 @@ export function useMessagesConversation() {
/** Hook for components that only need submission states */
export function useMessagesSubmission() {
- const { isSubmitting, isSubmittingFamily, abortScroll, setAbortScroll } =
- useMessagesViewContext();
+ const { isSubmitting, abortScroll, setAbortScroll } = useMessagesViewContext();
return useMemo(
- () => ({ isSubmitting, isSubmittingFamily, abortScroll, setAbortScroll }),
- [isSubmitting, isSubmittingFamily, abortScroll, setAbortScroll],
+ () => ({ isSubmitting, abortScroll, setAbortScroll }),
+ [isSubmitting, abortScroll, setAbortScroll],
);
}
diff --git a/client/src/Providers/index.ts b/client/src/Providers/index.ts
index d3607d291d..43a16fa976 100644
--- a/client/src/Providers/index.ts
+++ b/client/src/Providers/index.ts
@@ -24,7 +24,6 @@ export * from './SearchContext';
export * from './BadgeRowContext';
export * from './SidePanelContext';
export * from './DragDropContext';
-export * from './MCPPanelContext';
export * from './ArtifactsContext';
export * from './PromptGroupsContext';
export * from './MessagesViewContext';
diff --git a/client/src/common/agents-types.ts b/client/src/common/agents-types.ts
index 9ac6b440a3..c3ea06f890 100644
--- a/client/src/common/agents-types.ts
+++ b/client/src/common/agents-types.ts
@@ -1,6 +1,7 @@
import { AgentCapabilities, ArtifactModes } from 'librechat-data-provider';
import type {
AgentModelParameters,
+ AgentToolOptions,
SupportContact,
AgentProvider,
GraphEdge,
@@ -8,6 +9,8 @@ import type {
} from 'librechat-data-provider';
import type { OptionWithIcon, ExtendedFile } from './types';
+export type AgentQueryResult = { found: true; agent: Agent } | { found: false };
+
export type TAgentOption = OptionWithIcon &
Agent & {
knowledge_files?: Array<[string, ExtendedFile]>;
@@ -33,6 +36,8 @@ export type AgentForm = {
model: string | null;
model_parameters: AgentModelParameters;
tools?: string[];
+ /** Per-tool configuration options (deferred loading, allowed callers, etc.) */
+ tool_options?: AgentToolOptions;
provider?: AgentProvider | OptionWithIcon;
/** @deprecated Use edges instead */
agent_ids?: string[];
diff --git a/client/src/common/mcp.ts b/client/src/common/mcp.ts
deleted file mode 100644
index b4f44a1f94..0000000000
--- a/client/src/common/mcp.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import {
- AuthorizationTypeEnum,
- AuthTypeEnum,
- TokenExchangeMethodEnum,
-} from 'librechat-data-provider';
-import { MCPForm } from '~/common/types';
-
-export const defaultMCPFormValues: MCPForm = {
- type: AuthTypeEnum.None,
- saved_auth_fields: false,
- api_key: '',
- authorization_type: AuthorizationTypeEnum.Basic,
- custom_auth_header: '',
- oauth_client_id: '',
- oauth_client_secret: '',
- authorization_url: '',
- client_url: '',
- scope: '',
- token_exchange_method: TokenExchangeMethodEnum.DefaultPost,
- name: '',
- description: '',
- url: '',
- tools: [],
- icon: '',
- trust: false,
-};
diff --git a/client/src/common/menus.ts b/client/src/common/menus.ts
index d0d81460dd..ee7d7292c9 100644
--- a/client/src/common/menus.ts
+++ b/client/src/common/menus.ts
@@ -15,7 +15,10 @@ export interface MenuItemProps {
separate?: boolean;
hideOnClick?: boolean;
dialog?: React.ReactElement;
+ ariaLabel?: string;
+ ariaChecked?: boolean;
ref?: React.Ref;
+ className?: string;
render?:
| RenderProp & { ref?: React.Ref | undefined }>
| React.ReactElement>
diff --git a/client/src/common/types.ts b/client/src/common/types.ts
index 8f865ce7a8..d47ff02bd8 100644
--- a/client/src/common/types.ts
+++ b/client/src/common/types.ts
@@ -1,5 +1,5 @@
import { RefObject } from 'react';
-import { Constants, FileSources, EModelEndpoint } from 'librechat-data-provider';
+import { FileSources, EModelEndpoint, isEphemeralAgentId } from 'librechat-data-provider';
import type { UseMutationResult } from '@tanstack/react-query';
import type * as InputNumberPrimitive from 'rc-input-number';
import type { SetterOrUpdater, RecoilState } from 'recoil';
@@ -7,9 +7,10 @@ import type { ColumnDef } from '@tanstack/react-table';
import type * as t from 'librechat-data-provider';
import type { LucideIcon } from 'lucide-react';
import type { TranslationKeys } from '~/hooks';
+import { MCPServerDefinition } from '~/hooks/MCP/useMCPServerManager';
export function isEphemeralAgent(agentId: string | null | undefined): boolean {
- return agentId == null || agentId === '' || agentId === Constants.EPHEMERAL_AGENT_ID;
+ return isEphemeralAgentId(agentId);
}
export interface ConfigFieldDetail {
@@ -152,7 +153,6 @@ export enum Panel {
actions = 'actions',
model = 'model',
version = 'version',
- mcp = 'mcp',
}
export type FileSetter =
@@ -176,15 +176,6 @@ export type ActionAuthForm = {
token_exchange_method: t.TokenExchangeMethodEnum;
};
-export type MCPForm = ActionAuthForm & {
- name?: string;
- description?: string;
- url?: string;
- tools?: string[];
- icon?: string;
- trust?: boolean;
-};
-
export type ActionWithNullableMetadata = Omit & {
metadata: t.ActionMetadata | null;
};
@@ -225,6 +216,7 @@ export interface MCPServerInfo {
tools: t.AgentToolType[];
isConfigured: boolean;
isConnected: boolean;
+ consumeOnly?: boolean;
metadata: t.TPlugin;
}
@@ -246,6 +238,8 @@ export type AgentPanelContextType = {
endpointsConfig?: t.TEndpointsConfig | null;
/** Pre-computed MCP server information indexed by server key */
mcpServersMap: Map;
+ availableMCPServers: MCPServerDefinition[];
+ availableMCPServersMap: t.MCPServersListResponse | undefined;
};
export type AgentModelPanelProps = {
@@ -323,10 +317,6 @@ export type TSetOptionsPayload = {
setExample: TSetExample;
addExample: () => void;
removeExample: () => void;
- setAgentOption: TSetOption;
- // getConversation: () => t.TConversation | t.TPreset | null;
- checkPluginSelection: (value: string) => boolean;
- setTools: (newValue: string, remove?: boolean) => void;
setOptions?: TSetOptions;
};
@@ -366,6 +356,8 @@ export type TOptions = {
isResubmission?: boolean;
/** Currently only utilized when `isResubmission === true`, uses that message's currently attached files */
overrideFiles?: t.TMessage['files'];
+ /** Added conversation for multi-convo feature - sent to server as part of submission payload */
+ addedConvo?: t.TConversation;
};
export type TAskFunction = (props: TAskProps, options?: TOptions) => void;
@@ -447,7 +439,7 @@ export type TDialogProps = {
onOpenChange: (open: boolean) => void;
};
-export type TPluginStoreDialogProps = {
+export type ToolDialogProps = {
isOpen: boolean;
setIsOpen: (open: boolean) => void;
};
@@ -602,7 +594,6 @@ export type NewConversationParams = {
export type ConvoGenerator = (params: NewConversationParams) => void | t.TConversation;
export type TBaseResData = {
- plugin?: t.TResPlugin;
final?: boolean;
initial?: boolean;
previousMessages?: t.TMessage[];
diff --git a/client/src/components/Agents/AgentCard.tsx b/client/src/components/Agents/AgentCard.tsx
index 29b85c5dea..7e9dd6da10 100644
--- a/client/src/components/Agents/AgentCard.tsx
+++ b/client/src/components/Agents/AgentCard.tsx
@@ -1,21 +1,23 @@
-import React, { useMemo } from 'react';
-import { Label } from '@librechat/client';
+import React, { useMemo, useState } from 'react';
+import { Label, OGDialog, OGDialogTrigger } from '@librechat/client';
import type t from 'librechat-data-provider';
import { useLocalize, TranslationKeys, useAgentCategories } from '~/hooks';
import { cn, renderAgentAvatar, getContactDisplayName } from '~/utils';
+import AgentDetailContent from './AgentDetailContent';
interface AgentCardProps {
- agent: t.Agent; // The agent data to display
- onClick: () => void; // Callback when card is clicked
- className?: string; // Additional CSS classes
+ agent: t.Agent;
+ onSelect?: (agent: t.Agent) => void;
+ className?: string;
}
/**
- * Card component to display agent information
+ * Card component to display agent information with integrated detail dialog
*/
-const AgentCard: React.FC = ({ agent, onClick, className = '' }) => {
+const AgentCard: React.FC = ({ agent, onSelect, className = '' }) => {
const localize = useLocalize();
const { categories } = useAgentCategories();
+ const [isOpen, setIsOpen] = useState(false);
const categoryLabel = useMemo(() => {
if (!agent.category) return '';
@@ -31,79 +33,89 @@ const AgentCard: React.FC = ({ agent, onClick, className = '' })
return agent.category.charAt(0).toUpperCase() + agent.category.slice(1);
}, [agent.category, categories, localize]);
+ const displayName = getContactDisplayName(agent);
+
+ const handleOpenChange = (open: boolean) => {
+ setIsOpen(open);
+ if (open && onSelect) {
+ onSelect(agent);
+ }
+ };
+
return (
- {
- if (e.key === 'Enter' || e.key === ' ') {
- e.preventDefault();
- onClick();
- }
- }}
- >
- {/* Two column layout */}
-
- {/* Left column: Avatar and Category */}
-
-
{renderAgentAvatar(agent, { size: 'sm' })}
-
- {/* Category tag */}
- {agent.category && (
-
- {categoryLabel}
-
+
+
+ {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ setIsOpen(true);
+ }
+ }}
+ >
+ {/* Category badge - top right */}
+ {categoryLabel && (
+
+ {categoryLabel}
+
)}
-
- {/* Right column: Name, description, and other content */}
-
-
+ {/* Avatar */}
+
+
+ {renderAgentAvatar(agent, { size: 'sm', showBorder: false })}
+
+
+
+ {/* Content */}
+
{/* Agent name */}
-
+
{agent.name}
{/* Agent description */}
-
- {agent.description ?? ''}
-
-
+ {agent.description && (
+
+ {agent.description}
+
+ )}
- {/* Owner info - moved to bottom right */}
- {(() => {
- const displayName = getContactDisplayName(agent);
- if (displayName) {
- return (
-
- );
- }
- return null;
- })()}
+ {/* Author */}
+ {displayName && (
+
+
+ {localize('com_ui_by_author', { 0: displayName || '' })}
+
+
+ )}
+
-
-
+
+
+
+
);
};
diff --git a/client/src/components/Agents/AgentDetail.tsx b/client/src/components/Agents/AgentDetail.tsx
index ef77734e30..1820eed8b9 100644
--- a/client/src/components/Agents/AgentDetail.tsx
+++ b/client/src/components/Agents/AgentDetail.tsx
@@ -1,5 +1,5 @@
import React, { useRef } from 'react';
-import { Link } from 'lucide-react';
+import { Link, Pin, PinOff } from 'lucide-react';
import { useQueryClient } from '@tanstack/react-query';
import { OGDialog, OGDialogContent, Button, useToastContext } from '@librechat/client';
import {
@@ -11,8 +11,8 @@ import {
AgentListResponse,
} from 'librechat-data-provider';
import type t from 'librechat-data-provider';
+import { useLocalize, useDefaultConvo, useFavorites } from '~/hooks';
import { renderAgentAvatar, clearMessagesCache } from '~/utils';
-import { useLocalize, useDefaultConvo } from '~/hooks';
import { useChatContext } from '~/Providers';
interface SupportContact {
@@ -39,6 +39,14 @@ const AgentDetail: React.FC
= ({ agent, isOpen, onClose }) =>
const dialogRef = useRef(null);
const getDefaultConversation = useDefaultConvo();
const { conversation, newConversation } = useChatContext();
+ const { isFavoriteAgent, toggleFavoriteAgent } = useFavorites();
+ const isFavorite = isFavoriteAgent(agent?.id);
+
+ const handleFavoriteClick = () => {
+ if (agent) {
+ toggleFavoriteAgent(agent.id);
+ }
+ };
/**
* Navigate to chat with the selected agent
@@ -133,42 +141,48 @@ const AgentDetail: React.FC = ({ agent, isOpen, onClose }) =>
return (
!open && onClose()}>
- {/* Copy link button - positioned next to close button */}
-
-
-
-
- {/* Agent avatar - top center */}
+ {/* Agent avatar */}
{renderAgentAvatar(agent, { size: 'xl' })}
- {/* Agent name - center aligned below image */}
+ {/* Agent name */}
{agent?.name || localize('com_agents_loading')}
- {/* Contact info - center aligned below name */}
+ {/* Contact info */}
{agent?.support_contact && formatContact() && (
{localize('com_agents_contact')}: {formatContact()}
)}
- {/* Agent description - below contact */}
+ {/* Agent description */}
{agent?.description}
{/* Action button */}
-
+
+
+ {isFavorite ? : }
+
+
+
+
{localize('com_agents_start_chat')}
diff --git a/client/src/components/Agents/AgentDetailContent.tsx b/client/src/components/Agents/AgentDetailContent.tsx
new file mode 100644
index 0000000000..1e06d8230f
--- /dev/null
+++ b/client/src/components/Agents/AgentDetailContent.tsx
@@ -0,0 +1,192 @@
+import React from 'react';
+import { Link, Pin, PinOff } from 'lucide-react';
+import { useQueryClient } from '@tanstack/react-query';
+import { OGDialogContent, Button, useToastContext } from '@librechat/client';
+import {
+ QueryKeys,
+ Constants,
+ EModelEndpoint,
+ PermissionBits,
+ LocalStorageKeys,
+ AgentListResponse,
+} from 'librechat-data-provider';
+import type t from 'librechat-data-provider';
+import { useLocalize, useDefaultConvo, useFavorites } from '~/hooks';
+import { renderAgentAvatar, clearMessagesCache } from '~/utils';
+import { useChatContext } from '~/Providers';
+
+interface SupportContact {
+ name?: string;
+ email?: string;
+}
+
+interface AgentWithSupport extends t.Agent {
+ support_contact?: SupportContact;
+}
+
+interface AgentDetailContentProps {
+ agent: AgentWithSupport;
+}
+
+/**
+ * Dialog content for displaying agent details
+ * Used inside OGDialog with OGDialogTrigger for proper focus management
+ */
+const AgentDetailContent: React.FC
= ({ agent }) => {
+ const localize = useLocalize();
+ const queryClient = useQueryClient();
+ const { showToast } = useToastContext();
+ const getDefaultConversation = useDefaultConvo();
+ const { conversation, newConversation } = useChatContext();
+ const { isFavoriteAgent, toggleFavoriteAgent } = useFavorites();
+ const isFavorite = isFavoriteAgent(agent?.id);
+
+ const handleFavoriteClick = () => {
+ if (agent) {
+ toggleFavoriteAgent(agent.id);
+ }
+ };
+
+ /**
+ * Navigate to chat with the selected agent
+ */
+ const handleStartChat = () => {
+ if (agent) {
+ const keys = [QueryKeys.agents, { requiredPermission: PermissionBits.EDIT }];
+ const listResp = queryClient.getQueryData(keys);
+ if (listResp != null) {
+ if (!listResp.data.some((a) => a.id === agent.id)) {
+ const currentAgents = [agent, ...JSON.parse(JSON.stringify(listResp.data))];
+ queryClient.setQueryData(keys, { ...listResp, data: currentAgents });
+ }
+ }
+
+ localStorage.setItem(`${LocalStorageKeys.AGENT_ID_PREFIX}0`, agent.id);
+
+ clearMessagesCache(queryClient, conversation?.conversationId);
+ queryClient.invalidateQueries([QueryKeys.messages]);
+
+ /** Template with agent configuration */
+ const template = {
+ conversationId: Constants.NEW_CONVO as string,
+ endpoint: EModelEndpoint.agents,
+ agent_id: agent.id,
+ title: localize('com_agents_chat_with', { name: agent.name || localize('com_ui_agent') }),
+ };
+
+ const currentConvo = getDefaultConversation({
+ conversation: { ...(conversation ?? {}), ...template },
+ preset: template,
+ });
+
+ newConversation({
+ template: currentConvo,
+ preset: template,
+ });
+ }
+ };
+
+ /**
+ * Copy the agent's shareable link to clipboard
+ */
+ const handleCopyLink = () => {
+ const baseUrl = new URL(window.location.origin);
+ const chatUrl = `${baseUrl.origin}/c/new?agent_id=${agent.id}`;
+ navigator.clipboard
+ .writeText(chatUrl)
+ .then(() => {
+ showToast({
+ message: localize('com_agents_link_copied'),
+ });
+ })
+ .catch(() => {
+ showToast({
+ message: localize('com_agents_link_copy_failed'),
+ });
+ });
+ };
+
+ /**
+ * Format contact information with mailto links when appropriate
+ */
+ const formatContact = () => {
+ if (!agent?.support_contact) return null;
+
+ const { name, email } = agent.support_contact;
+
+ if (name && email) {
+ return (
+
+ {name}
+
+ );
+ }
+
+ if (email) {
+ return (
+
+ {email}
+
+ );
+ }
+
+ if (name) {
+ return {name} ;
+ }
+
+ return null;
+ };
+
+ return (
+
+ {/* Agent avatar */}
+ {renderAgentAvatar(agent, { size: 'xl' })}
+
+ {/* Agent name */}
+
+
+ {agent?.name || localize('com_agents_loading')}
+
+
+
+ {/* Contact info */}
+ {agent?.support_contact && formatContact() && (
+
+ {localize('com_agents_contact')}: {formatContact()}
+
+ )}
+
+ {/* Agent description */}
+
+ {agent?.description}
+
+
+ {/* Action button */}
+
+
+ {isFavorite ? : }
+
+
+
+
+
+ {localize('com_agents_start_chat')}
+
+
+
+ );
+};
+
+export default AgentDetailContent;
diff --git a/client/src/components/Agents/AgentGrid.tsx b/client/src/components/Agents/AgentGrid.tsx
index ab821eb87a..285df3dc74 100644
--- a/client/src/components/Agents/AgentGrid.tsx
+++ b/client/src/components/Agents/AgentGrid.tsx
@@ -10,10 +10,10 @@ import ErrorDisplay from './ErrorDisplay';
import AgentCard from './AgentCard';
interface AgentGridProps {
- category: string; // Currently selected category
- searchQuery: string; // Current search query
- onSelectAgent: (agent: t.Agent) => void; // Callback when agent is selected
- scrollElementRef?: React.RefObject; // Parent scroll container ref for infinite scroll
+ category: string;
+ searchQuery: string;
+ onSelectAgent: (agent: t.Agent) => void;
+ scrollElementRef?: React.RefObject;
}
/**
@@ -184,7 +184,7 @@ const AgentGrid: React.FC = ({
{/* Agent grid - 2 per row with proper semantic structure */}
{currentAgents && currentAgents.length > 0 && (
= ({
>
{currentAgents.map((agent: t.Agent, index: number) => (
-
onSelectAgent(agent)} />
+
))}
diff --git a/client/src/components/Agents/Marketplace.tsx b/client/src/components/Agents/Marketplace.tsx
index ef882142e2..69db9fc630 100644
--- a/client/src/components/Agents/Marketplace.tsx
+++ b/client/src/components/Agents/Marketplace.tsx
@@ -15,7 +15,6 @@ import { SidePanelGroup } from '~/components/SidePanel';
import { OpenSidebar } from '~/components/Chat/Menus';
import { cn, clearMessagesCache } from '~/utils';
import CategoryTabs from './CategoryTabs';
-import AgentDetail from './AgentDetail';
import SearchBar from './SearchBar';
import AgentGrid from './AgentGrid';
import store from '~/store';
@@ -45,7 +44,6 @@ const AgentMarketplace: React.FC = ({ className = '' }) =
// Get URL parameters
const searchQuery = searchParams.get('q') || '';
- const selectedAgentId = searchParams.get('agent_id') || '';
// Animation state
type Direction = 'left' | 'right';
@@ -58,10 +56,6 @@ const AgentMarketplace: React.FC = ({ className = '' }) =
// Ref for the scrollable container to enable infinite scroll
const scrollContainerRef = useRef(null);
- // Local state
- const [isDetailOpen, setIsDetailOpen] = useState(false);
- const [selectedAgent, setSelectedAgent] = useState(null);
-
// Set page title
useDocumentTitle(`${localize('com_agents_marketplace')} | LibreChat`);
@@ -102,28 +96,12 @@ const AgentMarketplace: React.FC = ({ className = '' }) =
}, [category, categoriesQuery.data, displayCategory]);
/**
- * Handle agent card selection
- *
- * @param agent - The selected agent object
+ * Handle agent card selection - updates URL for deep linking
*/
const handleAgentSelect = (agent: t.Agent) => {
- // Update URL with selected agent
const newParams = new URLSearchParams(searchParams);
newParams.set('agent_id', agent.id);
setSearchParams(newParams);
- setSelectedAgent(agent);
- setIsDetailOpen(true);
- };
-
- /**
- * Handle closing the agent detail dialog
- */
- const handleDetailClose = () => {
- const newParams = new URLSearchParams(searchParams);
- newParams.delete('agent_id');
- setSearchParams(newParams);
- setSelectedAgent(null);
- setIsDetailOpen(false);
};
/**
@@ -229,11 +207,6 @@ const AgentMarketplace: React.FC = ({ className = '' }) =
newConversation();
};
- // Check if a detail view should be open based on URL
- useEffect(() => {
- setIsDetailOpen(!!selectedAgentId);
- }, [selectedAgentId]);
-
// Layout configuration for SidePanelGroup
const defaultLayout = useMemo(() => {
const resizableLayout = localStorage.getItem('react-resizable-panels:layout');
@@ -295,7 +268,7 @@ const AgentMarketplace: React.FC = ({ className = '' }) =
variant="outline"
data-testid="agents-new-chat-button"
aria-label={localize('com_ui_new_chat')}
- className="rounded-xl border border-border-light bg-surface-secondary p-2 hover:bg-surface-hover max-md:hidden"
+ className="rounded-xl border border-border-light bg-surface-secondary p-2 hover:bg-surface-active-alt max-md:hidden"
onClick={handleNewChat}
>
@@ -512,14 +485,6 @@ const AgentMarketplace: React.FC = ({ className = '' }) =
{/* Note: Using Tailwind keyframes for slide in/out animations */}
- {/* Agent detail dialog */}
- {isDetailOpen && selectedAgent && (
-
- )}
diff --git a/client/src/components/Agents/MarketplaceAdminSettings.tsx b/client/src/components/Agents/MarketplaceAdminSettings.tsx
index e09f168afe..c3d7dedda3 100644
--- a/client/src/components/Agents/MarketplaceAdminSettings.tsx
+++ b/client/src/components/Agents/MarketplaceAdminSettings.tsx
@@ -1,75 +1,20 @@
-import { useMemo, useEffect, useState } from 'react';
-import * as Ariakit from '@ariakit/react';
import { ShieldEllipsis } from 'lucide-react';
-import { useForm, Controller } from 'react-hook-form';
-import { Permissions, SystemRoles, roleDefaults, PermissionTypes } from 'librechat-data-provider';
-import {
- Button,
- Switch,
- OGDialog,
- DropdownPopup,
- OGDialogTitle,
- OGDialogContent,
- OGDialogTrigger,
- useToastContext,
-} from '@librechat/client';
-import type { Control, UseFormSetValue, UseFormGetValues } from 'react-hook-form';
+import { Permissions, PermissionTypes } from 'librechat-data-provider';
+import { Button, useToastContext } from '@librechat/client';
+import { AdminSettingsDialog } from '~/components/ui';
import { useUpdateMarketplacePermissionsMutation } from '~/data-provider';
-import { useLocalize, useAuthContext } from '~/hooks';
+import { useLocalize } from '~/hooks';
+import type { PermissionConfig } from '~/components/ui';
-type FormValues = {
- [Permissions.USE]: boolean;
-};
-
-type LabelControllerProps = {
- label: string;
- marketplacePerm: Permissions.USE;
- control: Control;
- setValue: UseFormSetValue;
- getValues: UseFormGetValues;
-};
-
-const LabelController: React.FC = ({
- control,
- marketplacePerm,
- label,
- getValues,
- setValue,
-}) => (
-
-
- setValue(marketplacePerm, !getValues(marketplacePerm), {
- shouldDirty: true,
- })
- }
- tabIndex={0}
- >
- {label}
-
- (
-
- )}
- />
-
-);
+const permissions: PermissionConfig[] = [
+ { permission: Permissions.USE, labelKey: 'com_ui_marketplace_allow_use' },
+];
const MarketplaceAdminSettings = () => {
const localize = useLocalize();
const { showToast } = useToastContext();
- const { user, roles } = useAuthContext();
- const { mutate, isLoading } = useUpdateMarketplacePermissionsMutation({
+
+ const mutation = useUpdateMarketplacePermissionsMutation({
onSuccess: () => {
showToast({ status: 'success', message: localize('com_ui_saved') });
},
@@ -78,133 +23,27 @@ const MarketplaceAdminSettings = () => {
},
});
- const [isRoleMenuOpen, setIsRoleMenuOpen] = useState(false);
- const [selectedRole, setSelectedRole] = useState(SystemRoles.USER);
-
- const defaultValues = useMemo(() => {
- const rolePerms = roles?.[selectedRole]?.permissions;
- if (rolePerms) {
- return rolePerms[PermissionTypes.MARKETPLACE];
- }
- return roleDefaults[selectedRole].permissions[PermissionTypes.MARKETPLACE];
- }, [roles, selectedRole]);
-
- const {
- reset,
- control,
- setValue,
- getValues,
- handleSubmit,
- formState: { isSubmitting },
- } = useForm({
- mode: 'onChange',
- defaultValues,
- });
-
- useEffect(() => {
- const value = roles?.[selectedRole]?.permissions?.[PermissionTypes.MARKETPLACE];
- if (value) {
- reset(value);
- } else {
- reset(roleDefaults[selectedRole].permissions[PermissionTypes.MARKETPLACE]);
- }
- }, [roles, selectedRole, reset]);
-
- if (user?.role !== SystemRoles.ADMIN) {
- return null;
- }
-
- const labelControllerData: {
- marketplacePerm: Permissions.USE;
- label: string;
- }[] = [
- {
- marketplacePerm: Permissions.USE,
- label: localize('com_ui_marketplace_allow_use'),
- },
- ];
-
- const onSubmit = (data: FormValues) => {
- mutate({ roleName: selectedRole, updates: data });
- };
-
- const roleDropdownItems = [
- {
- label: SystemRoles.USER,
- onClick: () => {
- setSelectedRole(SystemRoles.USER);
- },
- },
- {
- label: SystemRoles.ADMIN,
- onClick: () => {
- setSelectedRole(SystemRoles.ADMIN);
- },
- },
- ];
+ const trigger = (
+
+
+
+ );
return (
-
-
-
-
-
-
-
- {`${localize('com_ui_admin_settings')} - ${localize(
- 'com_ui_marketplace',
- )}`}
-
- {/* Role selection dropdown */}
-
- {localize('com_ui_role_select')}:
-
- {selectedRole}
-
- }
- items={roleDropdownItems}
- itemClassName="items-center justify-center"
- sameWidth={true}
- />
-
- {/* Permissions form */}
-
-
-
-
+
);
};
diff --git a/client/src/components/Agents/SearchBar.tsx b/client/src/components/Agents/SearchBar.tsx
index af463682b2..7fab811b4c 100644
--- a/client/src/components/Agents/SearchBar.tsx
+++ b/client/src/components/Agents/SearchBar.tsx
@@ -99,6 +99,7 @@ const SearchBar: React.FC = ({ value, onSearch, className = '' }
)}
diff --git a/client/src/components/Agents/tests/Accessibility.spec.tsx b/client/src/components/Agents/tests/Accessibility.spec.tsx
index 9718497769..8d9a02a982 100644
--- a/client/src/components/Agents/tests/Accessibility.spec.tsx
+++ b/client/src/components/Agents/tests/Accessibility.spec.tsx
@@ -97,6 +97,27 @@ jest.mock('~/hooks', () => ({
useLocalize: () => mockLocalize,
useDebounce: jest.fn(),
useAgentCategories: jest.fn(),
+ useDefaultConvo: jest.fn(() => jest.fn(() => ({}))),
+ useFavorites: jest.fn(() => ({
+ isFavoriteAgent: jest.fn(() => false),
+ toggleFavoriteAgent: jest.fn(),
+ })),
+}));
+
+// Mock Providers
+jest.mock('~/Providers', () => ({
+ useChatContext: jest.fn(() => ({
+ conversation: null,
+ newConversation: jest.fn(),
+ })),
+}));
+
+// Mock @librechat/client toast context
+jest.mock('@librechat/client', () => ({
+ ...jest.requireActual('@librechat/client'),
+ useToastContext: jest.fn(() => ({
+ showToast: jest.fn(),
+ })),
}));
jest.mock('~/data-provider/Agents', () => ({
@@ -115,6 +136,13 @@ jest.mock('../SmartLoader', () => ({
useHasData: jest.fn(() => true),
}));
+// Mock AgentDetailContent to avoid testing dialog internals
+jest.mock('../AgentDetailContent', () => ({
+ __esModule: true,
+ // eslint-disable-next-line i18next/no-literal-string
+ default: () => Agent Detail Content
,
+}));
+
// Import the actual modules to get the mocked functions
import { useMarketplaceAgentsInfiniteQuery } from '~/data-provider/Agents';
import { useAgentCategories, useDebounce } from '~/hooks';
@@ -299,7 +327,12 @@ describe('Accessibility Improvements', () => {
};
it('provides comprehensive ARIA labels', () => {
- render( );
+ const Wrapper = createWrapper();
+ render(
+
+
+ ,
+ );
const card = screen.getByRole('button');
expect(card).toHaveAttribute('aria-label', 'Test Agent agent. A test agent for testing');
@@ -308,16 +341,19 @@ describe('Accessibility Improvements', () => {
});
it('supports keyboard interaction', () => {
- const onClick = jest.fn();
- render( );
+ const Wrapper = createWrapper();
+ render(
+
+
+ ,
+ );
const card = screen.getByRole('button');
- fireEvent.keyDown(card, { key: 'Enter' });
- expect(onClick).toHaveBeenCalledTimes(1);
-
- fireEvent.keyDown(card, { key: ' ' });
- expect(onClick).toHaveBeenCalledTimes(2);
+ // Card should be keyboard accessible - actual dialog behavior is handled by Radix
+ expect(card).toHaveAttribute('tabIndex', '0');
+ expect(() => fireEvent.keyDown(card, { key: 'Enter' })).not.toThrow();
+ expect(() => fireEvent.keyDown(card, { key: ' ' })).not.toThrow();
});
});
diff --git a/client/src/components/Agents/tests/AgentCard.spec.tsx b/client/src/components/Agents/tests/AgentCard.spec.tsx
index 8bcf7fb1d8..5e16f3d265 100644
--- a/client/src/components/Agents/tests/AgentCard.spec.tsx
+++ b/client/src/components/Agents/tests/AgentCard.spec.tsx
@@ -3,6 +3,7 @@ import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import AgentCard from '../AgentCard';
import type t from 'librechat-data-provider';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// Mock useLocalize hook
jest.mock('~/hooks/useLocalize', () => () => (key: string) => {
@@ -11,25 +12,32 @@ jest.mock('~/hooks/useLocalize', () => () => (key: string) => {
com_agents_agent_card_label: '{{name}} agent. {{description}}',
com_agents_category_general: 'General',
com_agents_category_hr: 'Human Resources',
+ com_ui_by_author: 'by {{0}}',
+ com_agents_description_card: '{{description}}',
};
return mockTranslations[key] || key;
});
// Mock useAgentCategories hook
jest.mock('~/hooks', () => ({
- useLocalize: () => (key: string, values?: Record) => {
+ useLocalize: () => (key: string, values?: Record) => {
const mockTranslations: Record = {
com_agents_created_by: 'Created by',
com_agents_agent_card_label: '{{name}} agent. {{description}}',
com_agents_category_general: 'General',
com_agents_category_hr: 'Human Resources',
+ com_ui_by_author: 'by {{0}}',
+ com_agents_description_card: '{{description}}',
};
let translation = mockTranslations[key] || key;
// Replace placeholders with actual values
if (values) {
Object.entries(values).forEach(([placeholder, value]) => {
- translation = translation.replace(new RegExp(`{{${placeholder}}}`, 'g'), value);
+ translation = translation.replace(
+ new RegExp(`\\{\\{${placeholder}\\}\\}`, 'g'),
+ String(value),
+ );
});
}
@@ -42,8 +50,81 @@ jest.mock('~/hooks', () => ({
{ value: 'custom', label: 'Custom Category' }, // Non-localized custom category
],
}),
+ useDefaultConvo: jest.fn(() => jest.fn(() => ({}))),
+ useFavorites: jest.fn(() => ({
+ isFavoriteAgent: jest.fn(() => false),
+ toggleFavoriteAgent: jest.fn(),
+ })),
}));
+// Mock AgentDetailContent to avoid testing dialog internals
+jest.mock('../AgentDetailContent', () => ({
+ __esModule: true,
+ // eslint-disable-next-line i18next/no-literal-string
+ default: () => Agent Detail Content
,
+}));
+
+// Mock Providers
+jest.mock('~/Providers', () => ({
+ useChatContext: jest.fn(() => ({
+ conversation: null,
+ newConversation: jest.fn(),
+ })),
+}));
+
+// Mock @librechat/client with proper Dialog behavior
+jest.mock('@librechat/client', () => {
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
+ const React = require('react');
+ return {
+ ...jest.requireActual('@librechat/client'),
+ useToastContext: jest.fn(() => ({
+ showToast: jest.fn(),
+ })),
+ OGDialog: ({ children, open, onOpenChange }: any) => {
+ // Store onOpenChange in context for trigger to call
+ return (
+
+ {React.Children.map(children, (child: any) => {
+ if (child?.type?.displayName === 'OGDialogTrigger' || child?.props?.['data-trigger']) {
+ return React.cloneElement(child, { onOpenChange });
+ }
+ // Only render content when open
+ if (child?.type?.displayName === 'OGDialogContent' && !open) {
+ return null;
+ }
+ return child;
+ })}
+
+ );
+ },
+ OGDialogTrigger: ({ children, asChild, onOpenChange }: any) => {
+ if (asChild && React.isValidElement(children)) {
+ return React.cloneElement(children as React.ReactElement, {
+ onClick: (e: any) => {
+ (children as any).props?.onClick?.(e);
+ onOpenChange?.(true);
+ },
+ });
+ }
+ return onOpenChange?.(true)}>{children}
;
+ },
+ OGDialogContent: ({ children }: any) => {children}
,
+ Label: ({ children, className }: any) => {children} ,
+ };
+});
+
+// Create wrapper with QueryClient
+const createWrapper = () => {
+ const queryClient = new QueryClient({
+ defaultOptions: { queries: { retry: false } },
+ });
+
+ return ({ children }: { children: React.ReactNode }) => (
+ {children}
+ );
+};
+
describe('AgentCard', () => {
const mockAgent: t.Agent = {
id: '1',
@@ -69,22 +150,30 @@ describe('AgentCard', () => {
},
};
- const mockOnClick = jest.fn();
+ const mockOnSelect = jest.fn();
+ const Wrapper = createWrapper();
beforeEach(() => {
- mockOnClick.mockClear();
+ mockOnSelect.mockClear();
});
it('renders agent information correctly', () => {
- render( );
+ render(
+
+
+ ,
+ );
expect(screen.getByText('Test Agent')).toBeInTheDocument();
expect(screen.getByText('A test agent for testing purposes')).toBeInTheDocument();
- expect(screen.getByText('Test Support')).toBeInTheDocument();
});
it('displays avatar when provided as object', () => {
- render( );
+ render(
+
+
+ ,
+ );
const avatarImg = screen.getByAltText('Test Agent avatar');
expect(avatarImg).toBeInTheDocument();
@@ -97,64 +186,90 @@ describe('AgentCard', () => {
avatar: '/string-avatar.png' as any, // Legacy support for string avatars
};
- render( );
+ render(
+
+
+ ,
+ );
const avatarImg = screen.getByAltText('Test Agent avatar');
expect(avatarImg).toBeInTheDocument();
expect(avatarImg).toHaveAttribute('src', '/string-avatar.png');
});
- it('displays Bot icon fallback when no avatar is provided', () => {
+ it('displays Feather icon fallback when no avatar is provided', () => {
const agentWithoutAvatar = {
...mockAgent,
avatar: undefined,
};
- render( );
+ render(
+
+
+ ,
+ );
- // Check for Bot icon presence by looking for the svg with lucide-bot class
- const botIcon = document.querySelector('.lucide-bot');
- expect(botIcon).toBeInTheDocument();
+ // Check for Feather icon presence by looking for the svg with lucide-feather class
+ const featherIcon = document.querySelector('.lucide-feather');
+ expect(featherIcon).toBeInTheDocument();
});
- it('calls onClick when card is clicked', () => {
- render( );
+ it('card is clickable and has dialog trigger', () => {
+ render(
+
+
+ ,
+ );
const card = screen.getByRole('button');
- fireEvent.click(card);
-
- expect(mockOnClick).toHaveBeenCalledTimes(1);
+ // Card should be clickable - the actual dialog behavior is handled by Radix
+ expect(card).toBeInTheDocument();
+ expect(() => fireEvent.click(card)).not.toThrow();
});
- it('calls onClick when Enter key is pressed', () => {
- render( );
+ it('handles Enter key press', () => {
+ render(
+
+
+ ,
+ );
const card = screen.getByRole('button');
- fireEvent.keyDown(card, { key: 'Enter' });
-
- expect(mockOnClick).toHaveBeenCalledTimes(1);
+ // Card should respond to keyboard - the actual dialog behavior is handled by Radix
+ expect(() => fireEvent.keyDown(card, { key: 'Enter' })).not.toThrow();
});
- it('calls onClick when Space key is pressed', () => {
- render( );
+ it('handles Space key press', () => {
+ render(
+
+
+ ,
+ );
const card = screen.getByRole('button');
- fireEvent.keyDown(card, { key: ' ' });
-
- expect(mockOnClick).toHaveBeenCalledTimes(1);
+ // Card should respond to keyboard - the actual dialog behavior is handled by Radix
+ expect(() => fireEvent.keyDown(card, { key: ' ' })).not.toThrow();
});
- it('does not call onClick for other keys', () => {
- render( );
+ it('does not call onSelect for other keys', () => {
+ render(
+
+
+ ,
+ );
const card = screen.getByRole('button');
fireEvent.keyDown(card, { key: 'Escape' });
- expect(mockOnClick).not.toHaveBeenCalled();
+ expect(mockOnSelect).not.toHaveBeenCalled();
});
it('applies additional className when provided', () => {
- render( );
+ render(
+
+
+ ,
+ );
const card = screen.getByRole('button');
expect(card).toHaveClass('custom-class');
@@ -167,11 +282,14 @@ describe('AgentCard', () => {
authorName: undefined,
};
- render( );
+ render(
+
+
+ ,
+ );
expect(screen.getByText('Test Agent')).toBeInTheDocument();
expect(screen.getByText('A test agent for testing purposes')).toBeInTheDocument();
- expect(screen.queryByText(/Created by/)).not.toBeInTheDocument();
});
it('displays authorName when support_contact is missing', () => {
@@ -181,54 +299,21 @@ describe('AgentCard', () => {
authorName: 'John Doe',
};
- render( );
+ render(
+
+
+ ,
+ );
- expect(screen.getByText('John Doe')).toBeInTheDocument();
- });
-
- it('displays support_contact email when name is missing', () => {
- const agentWithEmailOnly = {
- ...mockAgent,
- support_contact: { email: 'contact@example.com' },
- authorName: undefined,
- };
-
- render( );
-
- expect(screen.getByText('contact@example.com')).toBeInTheDocument();
- });
-
- it('prioritizes support_contact name over authorName', () => {
- const agentWithBoth = {
- ...mockAgent,
- support_contact: { name: 'Support Team' },
- authorName: 'John Doe',
- };
-
- render( );
-
- expect(screen.getByText('Support Team')).toBeInTheDocument();
- expect(screen.queryByText('John Doe')).not.toBeInTheDocument();
- });
-
- it('prioritizes name over email in support_contact', () => {
- const agentWithNameAndEmail = {
- ...mockAgent,
- support_contact: {
- name: 'Support Team',
- email: 'support@example.com',
- },
- authorName: undefined,
- };
-
- render( );
-
- expect(screen.getByText('Support Team')).toBeInTheDocument();
- expect(screen.queryByText('support@example.com')).not.toBeInTheDocument();
+ expect(screen.getByText('by John Doe')).toBeInTheDocument();
});
it('has proper accessibility attributes', () => {
- render( );
+ render(
+
+
+ ,
+ );
const card = screen.getByRole('button');
expect(card).toHaveAttribute('tabIndex', '0');
@@ -244,7 +329,11 @@ describe('AgentCard', () => {
category: 'general',
};
- render( );
+ render(
+
+
+ ,
+ );
expect(screen.getByText('General')).toBeInTheDocument();
});
@@ -255,7 +344,11 @@ describe('AgentCard', () => {
category: 'custom',
};
- render( );
+ render(
+
+
+ ,
+ );
expect(screen.getByText('Custom Category')).toBeInTheDocument();
});
@@ -266,15 +359,35 @@ describe('AgentCard', () => {
category: 'unknown',
};
- render( );
+ render(
+
+
+ ,
+ );
expect(screen.getByText('Unknown')).toBeInTheDocument();
});
it('does not display category tag when category is not provided', () => {
- render( );
+ render(
+
+
+ ,
+ );
expect(screen.queryByText('General')).not.toBeInTheDocument();
expect(screen.queryByText('Unknown')).not.toBeInTheDocument();
});
+
+ it('works without onSelect callback', () => {
+ render(
+
+
+ ,
+ );
+
+ const card = screen.getByRole('button');
+ // Should not throw when clicking without onSelect
+ expect(() => fireEvent.click(card)).not.toThrow();
+ });
});
diff --git a/client/src/components/Agents/tests/AgentDetail.spec.tsx b/client/src/components/Agents/tests/AgentDetail.spec.tsx
index 833405c1e7..0a1afffea7 100644
--- a/client/src/components/Agents/tests/AgentDetail.spec.tsx
+++ b/client/src/components/Agents/tests/AgentDetail.spec.tsx
@@ -21,6 +21,23 @@ jest.mock('~/hooks', () => ({
useMediaQuery: jest.fn(() => false), // Mock as desktop by default
useLocalize: jest.fn(),
useDefaultConvo: jest.fn(),
+ useFavorites: jest.fn(() => ({
+ favorites: [],
+ isFavoriteAgent: jest.fn(() => false),
+ toggleFavoriteAgent: jest.fn(),
+ isFavoriteModel: jest.fn(() => false),
+ toggleFavoriteModel: jest.fn(),
+ addFavoriteAgent: jest.fn(),
+ removeFavoriteAgent: jest.fn(),
+ addFavoriteModel: jest.fn(),
+ removeFavoriteModel: jest.fn(),
+ reorderFavorites: jest.fn(),
+ isLoading: false,
+ isError: false,
+ isUpdating: false,
+ fetchError: null,
+ updateError: null,
+ })),
}));
jest.mock('@librechat/client', () => ({
@@ -342,7 +359,7 @@ describe('AgentDetail', () => {
renderWithProviders( );
const copyLinkButton = screen.getByRole('button', { name: 'com_agents_copy_link' });
- expect(copyLinkButton).toHaveClass('focus:outline-none', 'focus:ring-2');
+ expect(copyLinkButton).toHaveClass('focus-visible:outline-none', 'focus-visible:ring-2');
});
});
diff --git a/client/src/components/Agents/tests/AgentGrid.integration.spec.tsx b/client/src/components/Agents/tests/AgentGrid.integration.spec.tsx
index cad18ea809..87a96acb87 100644
--- a/client/src/components/Agents/tests/AgentGrid.integration.spec.tsx
+++ b/client/src/components/Agents/tests/AgentGrid.integration.spec.tsx
@@ -69,8 +69,8 @@ jest.mock('../ErrorDisplay', () => ({
// Mock AgentCard component
jest.mock('../AgentCard', () => ({
__esModule: true,
- default: ({ agent, onClick }: { agent: t.Agent; onClick: () => void }) => (
-
+ default: ({ agent, onSelect }: { agent: t.Agent; onSelect?: (agent: t.Agent) => void }) => (
+
onSelect?.(agent)}>
{agent.name}
{agent.description}
diff --git a/client/src/components/Artifacts/Artifacts.tsx b/client/src/components/Artifacts/Artifacts.tsx
index a3b1a015c3..5b433cf0f6 100644
--- a/client/src/components/Artifacts/Artifacts.tsx
+++ b/client/src/components/Artifacts/Artifacts.tsx
@@ -257,7 +257,11 @@ export default function Artifacts() {
{isRefreshing ? (
) : (
-
+
)}
)}
@@ -284,7 +288,7 @@ export default function Artifacts() {
onClick={closeArtifacts}
aria-label={localize('com_ui_close')}
>
-
+
diff --git a/client/src/components/Artifacts/Code.tsx b/client/src/components/Artifacts/Code.tsx
index c91b0444b1..6894ce775b 100644
--- a/client/src/components/Artifacts/Code.tsx
+++ b/client/src/components/Artifacts/Code.tsx
@@ -114,7 +114,11 @@ export const CopyCodeButton: React.FC<{ content: string }> = ({ content }) => {
onClick={handleCopy}
aria-label={isCopied ? localize('com_ui_copied') : localize('com_ui_copy_code')}
>
- {isCopied ? : }
+ {isCopied ? (
+
+ ) : (
+
+ )}
);
};
diff --git a/client/src/components/Artifacts/DownloadArtifact.tsx b/client/src/components/Artifacts/DownloadArtifact.tsx
index 9c779bb1eb..c8fb6a12fe 100644
--- a/client/src/components/Artifacts/DownloadArtifact.tsx
+++ b/client/src/components/Artifacts/DownloadArtifact.tsx
@@ -41,7 +41,11 @@ const DownloadArtifact = ({ artifact }: { artifact: Artifact }) => {
onClick={handleDownload}
aria-label={localize('com_ui_download_artifact')}
>
- {isDownloaded ? : }
+ {isDownloaded ? (
+
+ ) : (
+
+ )}
);
};
diff --git a/client/src/components/Auth/AuthLayout.tsx b/client/src/components/Auth/AuthLayout.tsx
index f2290350ce..1aad9a94e7 100644
--- a/client/src/components/Auth/AuthLayout.tsx
+++ b/client/src/components/Auth/AuthLayout.tsx
@@ -73,7 +73,7 @@ function AuthLayout({
-
+
{!hasStartupConfigError && !isFetching && header && (
)}
-
+
);
diff --git a/client/src/components/Auth/Footer.tsx b/client/src/components/Auth/Footer.tsx
index 8d79717683..fccd099eef 100644
--- a/client/src/components/Auth/Footer.tsx
+++ b/client/src/components/Auth/Footer.tsx
@@ -11,9 +11,10 @@ function Footer({ startupConfig }: { startupConfig: TStartupConfig | null | unde
const privacyPolicyRender = privacyPolicy?.externalUrl && (
{localize('com_ui_privacy_policy')}
@@ -22,9 +23,10 @@ function Footer({ startupConfig }: { startupConfig: TStartupConfig | null | unde
const termsOfServiceRender = termsOfService?.externalUrl && (
{localize('com_ui_terms_of_service')}
diff --git a/client/src/components/Auth/Login.tsx b/client/src/components/Auth/Login.tsx
index cade120e17..7c3adf51bd 100644
--- a/client/src/components/Auth/Login.tsx
+++ b/client/src/components/Auth/Login.tsx
@@ -1,15 +1,19 @@
import { useEffect, useState } from 'react';
import { ErrorTypes, registerPage } from 'librechat-data-provider';
import { OpenIDIcon, useToastContext } from '@librechat/client';
-import { useOutletContext, useSearchParams } from 'react-router-dom';
+import { useOutletContext, useSearchParams, useLocation } from 'react-router-dom';
import type { TLoginLayoutContext } from '~/common';
+import { getLoginError, persistRedirectToSession } from '~/utils';
import { ErrorMessage } from '~/components/Auth/ErrorMessage';
import SocialButton from '~/components/Auth/SocialButton';
import { useAuthContext } from '~/hooks/AuthContext';
-import { getLoginError } from '~/utils';
import { useLocalize } from '~/hooks';
import LoginForm from './LoginForm';
+interface LoginLocationState {
+ redirect_to?: string;
+}
+
function Login() {
const localize = useLocalize();
const { showToast } = useToastContext();
@@ -17,13 +21,22 @@ function Login() {
const { startupConfig } = useOutletContext();
const [searchParams, setSearchParams] = useSearchParams();
- // Determine if auto-redirect should be disabled based on the URL parameter
+ const location = useLocation();
const disableAutoRedirect = searchParams.get('redirect') === 'false';
- // Persist the disable flag locally so that once detected, auto-redirect stays disabled.
const [isAutoRedirectDisabled, setIsAutoRedirectDisabled] = useState(disableAutoRedirect);
useEffect(() => {
+ const redirectTo = searchParams.get('redirect_to');
+ if (redirectTo) {
+ persistRedirectToSession(redirectTo);
+ } else {
+ const state = location.state as LoginLocationState | null;
+ if (state?.redirect_to) {
+ persistRedirectToSession(state.redirect_to);
+ }
+ }
+
const oauthError = searchParams?.get('error');
if (oauthError && oauthError === ErrorTypes.AUTH_FAILED) {
showToast({
@@ -34,9 +47,8 @@ function Login() {
newParams.delete('error');
setSearchParams(newParams, { replace: true });
}
- }, [searchParams, setSearchParams, showToast, localize]);
+ }, [searchParams, setSearchParams, showToast, localize, location.state]);
- // Once the disable flag is detected, update local state and remove the parameter from the URL.
useEffect(() => {
if (disableAutoRedirect) {
setIsAutoRedirectDisabled(true);
@@ -46,7 +58,6 @@ function Login() {
}
}, [disableAutoRedirect, searchParams, setSearchParams]);
- // Determine whether we should auto-redirect to OpenID.
const shouldAutoRedirect =
startupConfig?.openidLoginEnabled &&
startupConfig?.openidAutoRedirect &&
@@ -60,7 +71,6 @@ function Login() {
}
}, [shouldAutoRedirect, startupConfig]);
- // Render fallback UI if auto-redirect is active.
if (shouldAutoRedirect) {
return (
@@ -105,7 +115,7 @@ function Login() {
{localize('com_auth_no_account')}{' '}
{localize('com_auth_sign_up')}
diff --git a/client/src/components/Auth/LoginForm.tsx b/client/src/components/Auth/LoginForm.tsx
index 1e0e911eb1..c51c2002e3 100644
--- a/client/src/components/Auth/LoginForm.tsx
+++ b/client/src/components/Auth/LoginForm.tsx
@@ -5,6 +5,7 @@ import { ThemeContext, Spinner, Button, isDark } from '@librechat/client';
import type { TLoginUser, TStartupConfig } from 'librechat-data-provider';
import type { TAuthContext } from '~/common';
import { useResendVerificationEmail, useGetStartupConfig } from '~/data-provider';
+import { validateEmail } from '~/utils';
import { useLocalize } from '~/hooks';
type TLoginFormProps = {
@@ -51,7 +52,7 @@ const LoginForm: React.FC
= ({ onSubmit, startupConfig, error,
const renderError = (fieldName: string) => {
const errorMessage = errors[fieldName]?.message;
return errorMessage ? (
-
+
{String(errorMessage)}
) : null;
@@ -96,10 +97,9 @@ const LoginForm: React.FC = ({ onSubmit, startupConfig, error,
{...register('email', {
required: localize('com_auth_email_required'),
maxLength: { value: 120, message: localize('com_auth_email_max_length') },
- pattern: {
- value: useUsernameLogin ? /\S+/ : /\S+@\S+\.\S+/,
- message: localize('com_auth_email_pattern'),
- },
+ validate: useUsernameLogin
+ ? undefined
+ : (value) => validateEmail(value, localize('com_auth_email_pattern')),
})}
aria-invalid={!!errors.email}
className="webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none"
@@ -147,7 +147,7 @@ const LoginForm: React.FC = ({ onSubmit, startupConfig, error,
{startupConfig.passwordResetEnabled && (
{localize('com_auth_password_forgot')}
diff --git a/client/src/components/Auth/__tests__/Registration.spec.tsx b/client/src/components/Auth/__tests__/Registration.spec.tsx
index 72a21b63b6..6993c862d4 100644
--- a/client/src/components/Auth/__tests__/Registration.spec.tsx
+++ b/client/src/components/Auth/__tests__/Registration.spec.tsx
@@ -156,7 +156,6 @@ test('renders registration form', () => {
);
});
-// eslint-disable-next-line jest/no-commented-out-tests
// test('calls registerUser.mutate on registration', async () => {
// const mutate = jest.fn();
// const { getByTestId, getByRole, history } = setup({
@@ -191,12 +190,16 @@ test('shows validation error messages', async () => {
await userEvent.type(getByTestId('password'), 'pass');
await userEvent.type(getByTestId('confirm_password'), 'password1');
const alerts = getAllByRole('alert');
- expect(alerts).toHaveLength(5);
- expect(alerts[0]).toHaveTextContent(/Name must be at least 3 characters/i);
- expect(alerts[1]).toHaveTextContent(/Username must be at least 2 characters/i);
- expect(alerts[2]).toHaveTextContent(/You must enter a valid email address/i);
- expect(alerts[3]).toHaveTextContent(/Password must be at least 8 characters/i);
- expect(alerts[4]).toHaveTextContent(/Passwords do not match/i);
+ expect(alerts).toHaveLength(6);
+
+ // This first alert is for the theme toggle, which is empty within this test but still picked up by getAllByRole as an alert
+ expect(alerts[0]).toHaveTextContent('');
+
+ expect(alerts[1]).toHaveTextContent(/Name must be at least 3 characters/i);
+ expect(alerts[2]).toHaveTextContent(/Username must be at least 2 characters/i);
+ expect(alerts[3]).toHaveTextContent(/You must enter a valid email address/i);
+ expect(alerts[4]).toHaveTextContent(/Password must be at least 8 characters/i);
+ expect(alerts[5]).toHaveTextContent(/Passwords do not match/i);
});
test('shows error message when registration fails', async () => {
diff --git a/client/src/components/Banners/Banner.tsx b/client/src/components/Banners/Banner.tsx
index d4bc2e5853..b10fa70941 100644
--- a/client/src/components/Banners/Banner.tsx
+++ b/client/src/components/Banners/Banner.tsx
@@ -1,6 +1,7 @@
import { useEffect, useRef } from 'react';
import { XIcon } from 'lucide-react';
import { useRecoilState } from 'recoil';
+import { Button, cn } from '@librechat/client';
import { useGetBannerQuery } from '~/data-provider';
import store from '~/store';
@@ -15,34 +16,48 @@ export const Banner = ({ onHeightChange }: { onHeightChange?: (height: number) =
}
}, [banner, hideBannerHint, onHeightChange]);
- if (!banner || (banner.bannerId && hideBannerHint.includes(banner.bannerId))) {
+ if (
+ !banner ||
+ (banner.bannerId && !banner.persistable && hideBannerHint.includes(banner.bannerId))
+ ) {
return null;
}
const onClick = () => {
+ if (banner.persistable) {
+ return;
+ }
+
setHideBannerHint([...hideBannerHint, banner.bannerId]);
+
if (onHeightChange) {
- onHeightChange(0); // Reset height when banner is closed
+ onHeightChange(0);
}
};
return (
-
-
-
+ {!banner.persistable && (
+
+
+
+ )}
);
};
diff --git a/client/src/components/Bookmarks/BookmarkEditDialog.tsx b/client/src/components/Bookmarks/BookmarkEditDialog.tsx
index aaf965c05d..952a8784eb 100644
--- a/client/src/components/Bookmarks/BookmarkEditDialog.tsx
+++ b/client/src/components/Bookmarks/BookmarkEditDialog.tsx
@@ -91,7 +91,7 @@ const BookmarkEditDialog = ({
-