From a580fdfe661c5c51da8155db200510d7f43c419c Mon Sep 17 00:00:00 2001
From: Josh
Date: Sun, 5 Oct 2025 13:49:09 -0500
Subject: [PATCH] Feature/LLM-Providers-UI-Polished (#736)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Add Anthropic and Grok provider support
* feat: Add crucial GPT-5 and reasoning model support for OpenRouter
- Add requires_max_completion_tokens() function for GPT-5, o1, o3, Grok-3 series
- Add prepare_chat_completion_params() for reasoning model compatibility
- Implement max_tokens → max_completion_tokens conversion for reasoning models
- Add temperature handling for reasoning models (must be 1.0 default)
- Enhanced provider validation and API key security in provider endpoints
- Streamlined retry logic (3→2 attempts) for faster issue detection
- Add failure tracking and circuit breaker analysis for debugging
- Support OpenRouter format detection (openai/gpt-5-nano, openai/o1-mini)
- Improved Grok provider empty response handling with structured fallbacks
- Enhanced contextual embedding with provider-aware model selection
Core provider functionality:
- OpenRouter, Grok, Anthropic provider support with full embedding integration
- Provider-specific model defaults and validation
- Secure API connectivity testing endpoints
- Provider context passing for code generation workflows
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude
* fully working model providers, addressing securtiy and code related concerns, throughly hardening our code
* added multiprovider support, embeddings model support, cleaned the pr, need to fix health check, asnyico tasks errors, and contextual embeddings error
* fixed contextual embeddings issue
* - Added inspect-aware shutdown handling so get_llm_client always closes the underlying AsyncOpenAI / httpx.AsyncClient while the loop is still alive, with defensive logging if shutdown happens late (python/src/server/services/llm_provider_service.py:14, python/src/server/ services/llm_provider_service.py:520).
* - Restructured get_llm_client so client creation and usage live in separate try/finally blocks; fallback clients now close without logging spurious Error creating LLM client when downstream code raises (python/src/server/services/llm_provider_service.py:335-556). - Close logic now sanitizes provider names consistently and awaits whichever aclose/close coroutine the SDK exposes, keeping the loop shut down cleanly (python/src/server/services/llm_provider_service.py:530-559). Robust JSON Parsing - Added _extract_json_payload to strip code fences / extra text returned by Ollama before json.loads runs, averting the markdown-induced decode errors you saw in logs (python/src/server/services/storage/code_storage_service.py:40-63). - Swapped the direct parse call for the sanitized payload and emit a debug preview when cleanup alters the content (python/src/server/ services/storage/code_storage_service.py:858-864).
* added provider connection support
* added provider api key not being configured warning
* Updated get_llm_client so missing OpenAI keys automatically fall back to Ollama (matching existing tests) and so unsupported providers still raise the legacy ValueError the suite expects. The fallback now reuses _get_optimal_ollama_instance and rethrows ValueError(OpenAI API key not found and Ollama fallback failed) when it cant connect. Adjusted test_code_extraction_source_id.py to accept the new optional argument on the mocked extractor (and confirm its None when present).
* Resolved a few needed code rabbit suggestion - Updated the knowledge API key validation to call create_embedding with the provider argument and removed the hard-coded OpenAI fallback (python/src/server/api_routes/knowledge_api.py). - Broadened embedding provider detection so prefixed OpenRouter/OpenAI model names route through the correct client (python/src/server/ services/embeddings/embedding_service.py, python/src/server/services/llm_provider_service.py). - Removed the duplicate helper definitions from llm_provider_service.py, eliminating the stray docstring that was causing the import-time syntax error.
* updated via code rabbit PR review, code rabbit in my IDE found no issues and no nitpicks with the updates! what was done: Credential service now persists the provider under the uppercase key LLM_PROVIDER, matching the read path (no new EMBEDDING_PROVIDER usage introduced). Embedding batch creation stops inserting blank strings, logging failures and skipping invalid items before they ever hit the provider (python/src/server/services/embeddings/embedding_service.py). Contextual embedding prompts use real newline characters everywhereboth when constructing the batch prompt and when parsing the models response (python/src/server/services/embeddings/contextual_embedding_service.py). Embedding provider routing already recognizes OpenRouter-prefixed OpenAI models via is_openai_embedding_model; no further change needed there. Embedding insertion now skips unsupported vector dimensions instead of forcing them into the 1536-column, and the backoff loop uses await asyncio.sleep so we no longer block the event loop (python/src/server/services/storage/code_storage_service.py). RAG settings props were extended to include LLM_INSTANCE_NAME and OLLAMA_EMBEDDING_INSTANCE_NAME, and the debug log no longer prints API-key prefixes (the rest of the TanStack refactor/EMBEDDING_PROVIDER support remains deferred).
* test fix
* enhanced Openrouters parsing logic to automatically detect reasoning models and parse regardless of json output or not. this commit creates a robust way for archons parsing to work throughly with openrouter automatically, regardless of the model youre using, to ensure proper functionality with out breaking any generation capabilities!
* updated ui llm interface, added seprate embeddings provider, made the system fully capabale of mix and matching llm providers (local and non local) for chat & embeddings. updated the ragsettings.tsx ui mainly, along with core functionality
* added warning labels and updated ollama health checks
* ready for review, fixed som error warnings and consildated ollama status health checks
* fixed FAILED test_async_embedding_service.py
* code rabbit fixes
* Separated the code-summary LLM provider from the embedding provider, so code example storage now forwards a dedicated embedding provider override end-to-end without hijacking the embedding pipeline. this fixes code rabbits (Preserve provider override in create_embeddings_batch) suggesting
* - Swapped API credential storage to booleans so decrypted keys never sit in React state (archon-ui-main/src/components/
settings/RAGSettings.tsx).
- Normalized Ollama instance URLs and gated the metrics effect on real state changes to avoid mis-counts and duplicate
fetches (RAGSettings.tsx).
- Tightened crawl progress scaling and indented-block parsing to handle min_length=None safely (python/src/server/
services/crawling/code_extraction_service.py:160, python/src/server/services/crawling/code_extraction_service.py:911).
- Added provider-agnostic embedding rate-limit retries so Google and friends back off gracefully (python/src/server/
services/embeddings/embedding_service.py:427).
- Made the orchestration registry async + thread-safe and updated every caller to await it (python/src/server/services/
crawling/crawling_service.py:34, python/src/server/api_routes/knowledge_api.py:1291).
* Update RAGSettings.tsx - header for 'LLM Settings' is now 'LLM Provider Settings'
* (RAG Settings)
- Ollama Health Checks & Metrics
- Added a 10-second timeout to the health fetch so it doesn't hang.
- Adjusted logic so metric refreshes run for embedding-only Ollama setups too.
- Initial page load now checks Ollama if either chat or embedding provider uses it.
- Metrics and alerts now respect which provider (chat/embedding) is currently selected.
- Provider Sync & Alerts
- Fixed a sync bug so the very first provider change updates settings as expected.
- Alerts now track the active provider (chat vs embedding) rather than only the LLM provider.
- Warnings about missing credentials now skip whichever provider is currently selected.
- Modals & Types
- Normalize URLs before handing them to selection modals to keep consistent data.
- Strengthened helper function types (getDisplayedChatModel, getModelPlaceholder, etc.).
(Crawling Service)
- Made the orchestration registry lock lazy-initialized to avoid issues in Python 3.12 and wrapped registry commands
(register, unregister) in async calls. This keeps things thread-safe even during concurrent crawling and cancellation.
* - migration/complete_setup.sql:101 seeds Google/OpenRouter/Anthropic/Grok API key rows so fresh databases expose every
provider by default.
- migration/0.1.0/009_add_provider_placeholders.sql:1 backfills the same rows for existing Supabase instances and
records the migration.
- archon-ui-main/src/components/settings/RAGSettings.tsx:121 introduces a shared credentialprovider map,
reloadApiCredentials runs through all five providers, and the status poller includes the new keys.
- archon-ui-main/src/components/settings/RAGSettings.tsx:353 subscribes to the archon:credentials-updated browser event
so adding/removing a key immediately refetches credential status and pings the corresponding connectivity test.
- archon-ui-main/src/components/settings/RAGSettings.tsx:926 now treats missing Anthropic/OpenRouter/Grok keys as
missing, preventing stale connected badges when a key is removed.
* - archon-ui-main/src/components/settings/RAGSettings.tsx:90 adds a simple display-name map and reuses one red alert
style.
- archon-ui-main/src/components/settings/RAGSettings.tsx:1016 now shows exactly one red banner when the active provider
- Removed the old duplicate Missing API Key Configuration block, so the panel no longer stacks two warnings.
* Update credentialsService.ts default model
* updated the google embedding adapter for multi dimensional rag querying
* thought this micro fix in the google embedding pushed with the embedding update the other day, it didnt. pushing now
---------
Co-authored-by: Chillbruhhh
Co-authored-by: Claude
---
archon-ui-main/package-lock.json | 1383 +++++++-------
archon-ui-main/package.json | 1 +
.../src/components/settings/RAGSettings.tsx | 1696 +++++++++++------
.../src/services/credentialsService.ts | 41 +-
.../0.1.0/009_add_provider_placeholders.sql | 18 +
migration/complete_setup.sql | 5 +-
python/src/server/api_routes/knowledge_api.py | 4 +-
.../crawling/code_extraction_service.py | 68 +-
.../services/crawling/crawling_service.py | 53 +-
.../crawling/document_storage_operations.py | 10 +-
.../src/server/services/credential_service.py | 68 +-
.../services/embeddings/embedding_service.py | 222 ++-
.../services/storage/code_storage_service.py | 9 +-
.../tests/test_code_extraction_source_id.py | 4 +-
14 files changed, 2194 insertions(+), 1388 deletions(-)
create mode 100644 migration/0.1.0/009_add_provider_placeholders.sql
diff --git a/archon-ui-main/package-lock.json b/archon-ui-main/package-lock.json
index a6653753..b29650ab 100644
--- a/archon-ui-main/package-lock.json
+++ b/archon-ui-main/package-lock.json
@@ -30,6 +30,7 @@
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.3.1",
+ "react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"react-router-dom": "^6.26.2",
"tailwind-merge": "latest",
@@ -62,9 +63,9 @@
}
},
"node_modules/@adobe/css-tools": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz",
- "integrity": "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==",
+ "version": "4.4.4",
+ "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz",
+ "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==",
"dev": true,
"license": "MIT"
},
@@ -132,9 +133,9 @@
}
},
"node_modules/@babel/compat-data": {
- "version": "7.27.3",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.3.tgz",
- "integrity": "sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz",
+ "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -142,22 +143,22 @@
}
},
"node_modules/@babel/core": {
- "version": "7.27.4",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz",
- "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
+ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
- "@babel/generator": "^7.27.3",
+ "@babel/generator": "^7.28.3",
"@babel/helper-compilation-targets": "^7.27.2",
- "@babel/helper-module-transforms": "^7.27.3",
- "@babel/helpers": "^7.27.4",
- "@babel/parser": "^7.27.4",
+ "@babel/helper-module-transforms": "^7.28.3",
+ "@babel/helpers": "^7.28.4",
+ "@babel/parser": "^7.28.4",
"@babel/template": "^7.27.2",
- "@babel/traverse": "^7.27.4",
- "@babel/types": "^7.27.3",
+ "@babel/traverse": "^7.28.4",
+ "@babel/types": "^7.28.4",
+ "@jridgewell/remapping": "^2.3.5",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -183,16 +184,16 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.27.3",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.3.tgz",
- "integrity": "sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz",
+ "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.27.3",
- "@babel/types": "^7.27.3",
- "@jridgewell/gen-mapping": "^0.3.5",
- "@jridgewell/trace-mapping": "^0.3.25",
+ "@babel/parser": "^7.28.3",
+ "@babel/types": "^7.28.2",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
},
"engines": {
@@ -226,6 +227,16 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-module-imports": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
@@ -241,15 +252,15 @@
}
},
"node_modules/@babel/helper-module-transforms": {
- "version": "7.27.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz",
- "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
+ "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1",
- "@babel/traverse": "^7.27.3"
+ "@babel/traverse": "^7.28.3"
},
"engines": {
"node": ">=6.9.0"
@@ -299,27 +310,27 @@
}
},
"node_modules/@babel/helpers": {
- "version": "7.27.4",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.4.tgz",
- "integrity": "sha512-Y+bO6U+I7ZKaM5G5rDUZiYfUvQPUibYmAFe7EnKdnKBbVXDZxvp+MWOH5gYciY0EPk4EScsuFMQBbEfpdRKSCQ==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
+ "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.27.2",
- "@babel/types": "^7.27.3"
+ "@babel/types": "^7.28.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
- "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
+ "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.28.0"
+ "@babel/types": "^7.28.4"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -361,9 +372,9 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.27.4",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.4.tgz",
- "integrity": "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
+ "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -385,28 +396,28 @@
}
},
"node_modules/@babel/traverse": {
- "version": "7.27.4",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz",
- "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz",
+ "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
- "@babel/generator": "^7.27.3",
- "@babel/parser": "^7.27.4",
+ "@babel/generator": "^7.28.3",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.28.4",
"@babel/template": "^7.27.2",
- "@babel/types": "^7.27.3",
- "debug": "^4.3.1",
- "globals": "^11.1.0"
+ "@babel/types": "^7.28.4",
+ "debug": "^4.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/types": {
- "version": "7.28.1",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz",
- "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
+ "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -588,9 +599,9 @@
}
},
"node_modules/@codemirror/autocomplete": {
- "version": "6.18.6",
- "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
- "integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
+ "version": "6.18.7",
+ "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.7.tgz",
+ "integrity": "sha512-8EzdeIoWPJDsMBwz3zdzwXnUpCzMiCyz5/A3FIPpriaclFCGDkAzK13sMcnsu5rowqiyeQN2Vs2TsOcoDPZirQ==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
@@ -662,9 +673,9 @@
}
},
"node_modules/@codemirror/lang-html": {
- "version": "6.4.9",
- "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
- "integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
+ "version": "6.4.10",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.10.tgz",
+ "integrity": "sha512-h/SceTVsN5r+WE+TVP2g3KDvNoSzbSrtZXCKo4vkKdbfT5t4otuVgngGdFukOO/rwRD2++pCxoh6xD4TEVMkQA==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
@@ -727,9 +738,9 @@
}
},
"node_modules/@codemirror/lang-liquid": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/@codemirror/lang-liquid/-/lang-liquid-6.2.3.tgz",
- "integrity": "sha512-yeN+nMSrf/lNii3FJxVVEGQwFG0/2eDyH6gNOj+TGCa0hlNO4bhQnoO5ISnd7JOG+7zTEcI/GOoyraisFVY7jQ==",
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-liquid/-/lang-liquid-6.3.0.tgz",
+ "integrity": "sha512-fY1YsUExcieXRTsCiwX/bQ9+PbCTA/Fumv7C7mTUZHoFkibfESnaXwpr2aKH6zZVwysEunsHHkaIpM/pl3xETQ==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
@@ -743,9 +754,9 @@
}
},
"node_modules/@codemirror/lang-markdown": {
- "version": "6.3.3",
- "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.3.3.tgz",
- "integrity": "sha512-1fn1hQAPWlSSMCvnF810AkhWpNLkJpl66CRfIy3vVl20Sl4NwChkorCHqpMtNbXr1EuMJsrDnhEpjZxKZ2UX3A==",
+ "version": "6.3.4",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.3.4.tgz",
+ "integrity": "sha512-fBm0BO03azXnTAsxhONDYHi/qWSI+uSEIpzKM7h/bkIc9fHnFp9y7KTMXKON0teNT97pFhc1a9DQTtWBYEZ7ug==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.7.1",
@@ -807,9 +818,9 @@
}
},
"node_modules/@codemirror/lang-sql": {
- "version": "6.9.0",
- "resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.9.0.tgz",
- "integrity": "sha512-xmtpWqKSgum1B1J3Ro6rf7nuPqf2+kJQg5SjrofCAcyCThOe0ihSktSoXfXuhQBnwx1QbmreBbLJM5Jru6zitg==",
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.10.0.tgz",
+ "integrity": "sha512-6ayPkEd/yRw0XKBx5uAiToSgGECo/GY2NoJIHXIIQh1EVwLuKoU8BP/qK0qH5NLXAbtJRLuT73hx7P9X34iO4w==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
@@ -876,9 +887,9 @@
}
},
"node_modules/@codemirror/language": {
- "version": "6.11.2",
- "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.2.tgz",
- "integrity": "sha512-p44TsNArL4IVXDTbapUmEkAlvWs2CFQbcfc0ymDsis1kH2wh0gcY96AS29c/vp2d0y2Tquk1EDSaawpzilUiAw==",
+ "version": "6.11.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz",
+ "integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.0.0",
@@ -973,9 +984,9 @@
}
},
"node_modules/@codemirror/view": {
- "version": "6.38.1",
- "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.1.tgz",
- "integrity": "sha512-RmTOkE7hRU3OVREqFVITWHz6ocgBjv08GoePscAakgVQfciA3SGCEk7mb9IzwW61cKKmlTpHXG6DUE5Ubx+MGQ==",
+ "version": "6.38.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.3.tgz",
+ "integrity": "sha512-x2t87+oqwB1mduiQZ6huIghjMt4uZKFEdj66IcXw7+a5iBEvv9lh7EWDRHI7crnD4BMGpnyq/RzmCGbiEZLcvQ==",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.5.0",
@@ -1064,9 +1075,9 @@
}
},
"node_modules/@csstools/color-helpers": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz",
- "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz",
+ "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==",
"dev": true,
"funding": [
{
@@ -1108,9 +1119,9 @@
}
},
"node_modules/@csstools/css-color-parser": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz",
- "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz",
+ "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==",
"dev": true,
"funding": [
{
@@ -1124,7 +1135,7 @@
],
"license": "MIT",
"dependencies": {
- "@csstools/color-helpers": "^5.0.2",
+ "@csstools/color-helpers": "^5.1.0",
"@csstools/css-calc": "^2.1.4"
},
"engines": {
@@ -1570,9 +1581,9 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
- "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
+ "version": "4.9.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
+ "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1622,20 +1633,28 @@
"url": "https://opencollective.com/eslint"
}
},
- "node_modules/@eslint/eslintrc/node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "type-fest": "^0.20.2"
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
},
"engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": "*"
}
},
"node_modules/@eslint/js": {
@@ -1717,6 +1736,30 @@
"node": ">=10.10.0"
}
},
+ "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
@@ -1758,9 +1801,9 @@
}
},
"node_modules/@isaacs/cliui/node_modules/ansi-regex": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
- "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1771,9 +1814,9 @@
}
},
"node_modules/@isaacs/cliui/node_modules/strip-ansi": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
+ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1810,18 +1853,25 @@
}
},
"node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.8",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
- "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jridgewell/set-array": "^1.2.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
- },
- "engines": {
- "node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
@@ -1834,27 +1884,17 @@
"node": ">=6.0.0"
}
},
- "node_modules/@jridgewell/set-array": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
- "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.0.0"
- }
- },
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
- "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.25",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
- "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1863,41 +1903,41 @@
}
},
"node_modules/@lexical/clipboard": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.33.1.tgz",
- "integrity": "sha512-Qd3/Cm3TW2DFQv58kMtLi86u5YOgpBdf+o7ySbXz55C613SLACsYQBB3X5Vu5hTx/t/ugYOpII4HkiatW6d9zA==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.35.0.tgz",
+ "integrity": "sha512-ko7xSIIiayvDiqjNDX6fgH9RlcM6r9vrrvJYTcfGVBor5httx16lhIi0QJZ4+RNPvGtTjyFv4bwRmsixRRwImg==",
"license": "MIT",
"dependencies": {
- "@lexical/html": "0.33.1",
- "@lexical/list": "0.33.1",
- "@lexical/selection": "0.33.1",
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/html": "0.35.0",
+ "@lexical/list": "0.35.0",
+ "@lexical/selection": "0.35.0",
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/code": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.33.1.tgz",
- "integrity": "sha512-E0Y/+1znkqVpP52Y6blXGAduoZek9SSehJN+vbH+4iQKyFwTA7JB+jd5C5/K0ik55du9X7SN/oTynByg7lbcAA==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.35.0.tgz",
+ "integrity": "sha512-ox4DZwETQ9IA7+DS6PN8RJNwSAF7RMjL7YTVODIqFZ5tUFIf+5xoCHbz7Fll0Bvixlp12hVH90xnLwTLRGpkKw==",
"license": "MIT",
"dependencies": {
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1",
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0",
"prismjs": "^1.30.0"
}
},
"node_modules/@lexical/devtools-core": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/devtools-core/-/devtools-core-0.33.1.tgz",
- "integrity": "sha512-3yHu5diNtjwhoe2q/x9as6n6rIfA+QO2CfaVjFRkam8rkAW6zUzQT1D0fQdE8nOfWvXBgY1mH/ZLP4dDXBdG5Q==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/devtools-core/-/devtools-core-0.35.0.tgz",
+ "integrity": "sha512-C2wwtsMCR6ZTfO0TqpSM17RLJWyfHmifAfCTjFtOJu15p3M6NO/nHYK5Mt7YMQteuS89mOjB4ng8iwoLEZ6QpQ==",
"license": "MIT",
"dependencies": {
- "@lexical/html": "0.33.1",
- "@lexical/link": "0.33.1",
- "@lexical/mark": "0.33.1",
- "@lexical/table": "0.33.1",
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/html": "0.35.0",
+ "@lexical/link": "0.35.0",
+ "@lexical/mark": "0.35.0",
+ "@lexical/table": "0.35.0",
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
},
"peerDependencies": {
"react": ">=17.x",
@@ -1905,144 +1945,144 @@
}
},
"node_modules/@lexical/dragon": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.33.1.tgz",
- "integrity": "sha512-UQ6DLkcDAr83wA1vz3sUgtcpYcMifC4sF0MieZAoMzFrna6Ekqj7OJ7g8Lo7m7AeuT4NETRVDsjIEDdrQMKLLA==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.35.0.tgz",
+ "integrity": "sha512-SL6mT5pcqrt6hEbJ16vWxip5+r3uvMd0bQV5UUxuk+cxIeuP86iTgRh0HFR7SM2dRTYovL6/tM/O+8QLAUGTIg==",
"license": "MIT",
"dependencies": {
- "lexical": "0.33.1"
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/hashtag": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.33.1.tgz",
- "integrity": "sha512-M3IsDe4cifggMBZgYAVT7hCLWcwQ3dIcUPdr9Xc6wDQQQdEqOQYB0PO//9bSYUVq+BNiiTgysc+TtlM7PiJfiw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.35.0.tgz",
+ "integrity": "sha512-LYJWzXuO2ZjKsvQwrLkNZiS2TsjwYkKjlDgtugzejquTBQ/o/nfSn/MmVx6EkYLOYizaJemmZbz3IBh+u732FA==",
"license": "MIT",
"dependencies": {
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/history": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.33.1.tgz",
- "integrity": "sha512-Bk0h3D6cFkJ7w3HKvqQua7n6Xfz7nR7L3gLDBH9L0nsS4MM9+LteSEZPUe0kj4VuEjnxufYstTc9HA2aNLKxnQ==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.35.0.tgz",
+ "integrity": "sha512-onjDRLLxGbCfHexSxxrQaDaieIHyV28zCDrbxR5dxTfW8F8PxjuNyuaG0z6o468AXYECmclxkP+P4aT6poHEpQ==",
"license": "MIT",
"dependencies": {
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/html": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.33.1.tgz",
- "integrity": "sha512-t14vu4eKa6BWz1N7/rwXgXif1k4dj73dRvllWJgfXum+a36vn1aySNYOlOfqWXF7k1b3uJmoqsWK7n/1ASnimw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.35.0.tgz",
+ "integrity": "sha512-rXGFE5S5rKsg3tVnr1s4iEgOfCApNXGpIFI3T2jGEShaCZ5HLaBY9NVBXnE9Nb49e9bkDkpZ8FZd1qokCbQXbw==",
"license": "MIT",
"dependencies": {
- "@lexical/selection": "0.33.1",
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/selection": "0.35.0",
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/link": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.33.1.tgz",
- "integrity": "sha512-JCTu7Fft2J2kgfqJiWnGei+UMIXVKiZKaXzuHCuGQTFu92DeCyd02azBaFazZHEkSqCIFZ0DqVV2SpIJmd0Ygw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.35.0.tgz",
+ "integrity": "sha512-+0Wx6cBwO8TfdMzpkYFacsmgFh8X1rkiYbq3xoLvk3qV8upYxaMzK1s8Q1cpKmWyI0aZrU6z7fiK4vUqB7+69w==",
"license": "MIT",
"dependencies": {
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/list": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.33.1.tgz",
- "integrity": "sha512-PXp56dWADSThc9WhwWV4vXhUc3sdtCqsfPD3UQNGUZ9rsAY1479rqYLtfYgEmYPc8JWXikQCAKEejahCJIm8OQ==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.35.0.tgz",
+ "integrity": "sha512-owsmc8iwgExBX8sFe8fKTiwJVhYULt9hD1RZ/HwfaiEtRZZkINijqReOBnW2mJfRxBzhFSWc4NG3ISB+fHYzqw==",
"license": "MIT",
"dependencies": {
- "@lexical/selection": "0.33.1",
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/selection": "0.35.0",
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/mark": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.33.1.tgz",
- "integrity": "sha512-tGdOf1e694lnm/HyWUKEkEWjDyfhCBFG7u8iRKNpsYTpB3M1FsJUXbphE2bb8MyWfhHbaNxnklupSSaSPzO88A==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.35.0.tgz",
+ "integrity": "sha512-W0hwMTAVeexvpk9/+J6n1G/sNkpI/Meq1yeDazahFLLAwXLHtvhIAq2P/klgFknDy1hr8X7rcsQuN/bqKcKHYg==",
"license": "MIT",
"dependencies": {
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/markdown": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.33.1.tgz",
- "integrity": "sha512-p5zwWNF70pELRx60wxE8YOFVNiNDkw7gjKoYqkED23q5hj4mcqco9fQf6qeeZChjxLKjfyT6F1PpWgxmlBlxBw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.35.0.tgz",
+ "integrity": "sha512-BlNyXZAt4gWidMw0SRWrhBETY1BpPglFBZI7yzfqukFqgXRh7HUQA28OYeI/nsx9pgNob8TiUduUwShqqvOdEA==",
"license": "MIT",
"dependencies": {
- "@lexical/code": "0.33.1",
- "@lexical/link": "0.33.1",
- "@lexical/list": "0.33.1",
- "@lexical/rich-text": "0.33.1",
- "@lexical/text": "0.33.1",
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/code": "0.35.0",
+ "@lexical/link": "0.35.0",
+ "@lexical/list": "0.35.0",
+ "@lexical/rich-text": "0.35.0",
+ "@lexical/text": "0.35.0",
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/offset": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.33.1.tgz",
- "integrity": "sha512-3YIlUs43QdKSBLEfOkuciE2tn9loxVmkSs/HgaIiLYl0Edf1W00FP4ItSmYU4De5GopXsHq6+Y3ry4pU/ciUiQ==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.35.0.tgz",
+ "integrity": "sha512-DRE4Df6qYf2XiV6foh6KpGNmGAv2ANqt3oVXpyS6W8hTx3+cUuAA1APhCZmLNuU107um4zmHym7taCu6uXW5Yg==",
"license": "MIT",
"dependencies": {
- "lexical": "0.33.1"
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/overflow": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.33.1.tgz",
- "integrity": "sha512-3BDq1lOw567FeCk4rN2ellKwoXTM9zGkGuKnSGlXS1JmtGGGSvT+uTANX3KOOfqTNSrOkrwoM+3hlFv7p6VpiQ==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.35.0.tgz",
+ "integrity": "sha512-B25YvnJQTGlZcrNv7b0PJBLWq3tl8sql497OHfYYLem7EOMPKKDGJScJAKM/91D4H/mMAsx5gnA/XgKobriuTg==",
"license": "MIT",
"dependencies": {
- "lexical": "0.33.1"
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/plain-text": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.33.1.tgz",
- "integrity": "sha512-2HxdhAx6bwF8y5A9P0q3YHsYbhUo4XXm+GyKJO87an8JClL2W+GYLTSDbfNWTh4TtH95eG+UYLOjNEgyU6tsWA==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.35.0.tgz",
+ "integrity": "sha512-lwBCUNMJf7Gujp2syVWMpKRahfbTv5Wq+H3HK1Q1gKH1P2IytPRxssCHvexw9iGwprSyghkKBlbF3fGpEdIJvQ==",
"license": "MIT",
"dependencies": {
- "@lexical/clipboard": "0.33.1",
- "@lexical/selection": "0.33.1",
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/clipboard": "0.35.0",
+ "@lexical/selection": "0.35.0",
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/react": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.33.1.tgz",
- "integrity": "sha512-ylnUmom5h8PY+Z14uDmKLQEoikTPN77GRM0NRCIdtbWmOQqOq/5BhuCzMZE1WvpL5C6n3GtK6IFnsMcsKmVOcw==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.35.0.tgz",
+ "integrity": "sha512-uYAZSqumH8tRymMef+A0f2hQvMwplKK9DXamcefnk3vSNDHHqRWQXpiUo6kD+rKWuQmMbVa5RW4xRQebXEW+1A==",
"license": "MIT",
"dependencies": {
"@floating-ui/react": "^0.27.8",
- "@lexical/devtools-core": "0.33.1",
- "@lexical/dragon": "0.33.1",
- "@lexical/hashtag": "0.33.1",
- "@lexical/history": "0.33.1",
- "@lexical/link": "0.33.1",
- "@lexical/list": "0.33.1",
- "@lexical/mark": "0.33.1",
- "@lexical/markdown": "0.33.1",
- "@lexical/overflow": "0.33.1",
- "@lexical/plain-text": "0.33.1",
- "@lexical/rich-text": "0.33.1",
- "@lexical/table": "0.33.1",
- "@lexical/text": "0.33.1",
- "@lexical/utils": "0.33.1",
- "@lexical/yjs": "0.33.1",
- "lexical": "0.33.1",
+ "@lexical/devtools-core": "0.35.0",
+ "@lexical/dragon": "0.35.0",
+ "@lexical/hashtag": "0.35.0",
+ "@lexical/history": "0.35.0",
+ "@lexical/link": "0.35.0",
+ "@lexical/list": "0.35.0",
+ "@lexical/mark": "0.35.0",
+ "@lexical/markdown": "0.35.0",
+ "@lexical/overflow": "0.35.0",
+ "@lexical/plain-text": "0.35.0",
+ "@lexical/rich-text": "0.35.0",
+ "@lexical/table": "0.35.0",
+ "@lexical/text": "0.35.0",
+ "@lexical/utils": "0.35.0",
+ "@lexical/yjs": "0.35.0",
+ "lexical": "0.35.0",
"react-error-boundary": "^3.1.4"
},
"peerDependencies": {
@@ -2051,67 +2091,67 @@
}
},
"node_modules/@lexical/rich-text": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.33.1.tgz",
- "integrity": "sha512-ZBIsj4LwmamRBCGjJiPSLj7N/XkUDv/pnYn5Rp0BL42WpOiQLvOoGLrZxgUJZEmRPQnx42ZgLKVgrWHsyjuoAA==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.35.0.tgz",
+ "integrity": "sha512-qEHu8g7vOEzz9GUz1VIUxZBndZRJPh9iJUFI+qTDHj+tQqnd5LCs+G9yz6jgNfiuWWpezTp0i1Vz/udNEuDPKQ==",
"license": "MIT",
"dependencies": {
- "@lexical/clipboard": "0.33.1",
- "@lexical/selection": "0.33.1",
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/clipboard": "0.35.0",
+ "@lexical/selection": "0.35.0",
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/selection": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.33.1.tgz",
- "integrity": "sha512-KXPkdCDdVfIUXmkwePu9DAd3kLjL0aAqL5G9CMCFsj7RG9lLvvKk7kpivrAIbRbcsDzO44QwsFPisZHbX4ioXA==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.35.0.tgz",
+ "integrity": "sha512-mMtDE7Q0nycXdFTTH/+ta6EBrBwxBB4Tg8QwsGntzQ1Cq//d838dpXpFjJOqHEeVHUqXpiuj+cBG8+bvz/rPRw==",
"license": "MIT",
"dependencies": {
- "lexical": "0.33.1"
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/table": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.33.1.tgz",
- "integrity": "sha512-pzB11i1Y6fzmy0IPUKJyCdhVBgXaNOxJUxrQJWdKNYCh1eMwwMEQvj+8inItd/11aUkjcdHjwDTht8gL2UHKiQ==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.35.0.tgz",
+ "integrity": "sha512-9jlTlkVideBKwsEnEkqkdg7A3mije1SvmfiqoYnkl1kKJCLA5iH90ywx327PU0p+bdnURAytWUeZPXaEuEl2OA==",
"license": "MIT",
"dependencies": {
- "@lexical/clipboard": "0.33.1",
- "@lexical/utils": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/clipboard": "0.35.0",
+ "@lexical/utils": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/text": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.33.1.tgz",
- "integrity": "sha512-CnyU3q3RytXXWVSvC5StOKISzFAPGK9MuesNDDGyZk7yDK+J98gV6df4RBKfqwcokFMThpkUlvMeKe1+S2y25A==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.35.0.tgz",
+ "integrity": "sha512-uaMh46BkysV8hK8wQwp5g/ByZW+2hPDt8ahAErxtf8NuzQem1FHG/f5RTchmFqqUDVHO3qLNTv4AehEGmXv8MA==",
"license": "MIT",
"dependencies": {
- "lexical": "0.33.1"
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/utils": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.33.1.tgz",
- "integrity": "sha512-eKysPjzEE9zD+2af3WRX5U3XbeNk0z4uv1nXGH3RG15uJ4Huzjht82hzsQpCFUobKmzYlQaQs5y2IYKE2puipQ==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.35.0.tgz",
+ "integrity": "sha512-2H393EYDnFznYCDFOW3MHiRzwEO5M/UBhtUjvTT+9kc+qhX4U3zc8ixQalo5UmZ5B2nh7L/inXdTFzvSRXtsRA==",
"license": "MIT",
"dependencies": {
- "@lexical/list": "0.33.1",
- "@lexical/selection": "0.33.1",
- "@lexical/table": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/list": "0.35.0",
+ "@lexical/selection": "0.35.0",
+ "@lexical/table": "0.35.0",
+ "lexical": "0.35.0"
}
},
"node_modules/@lexical/yjs": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.33.1.tgz",
- "integrity": "sha512-Zx1rabMm/Zjk7n7YQMIQLUN+tqzcg1xqcgNpEHSfK1GA8QMPXCPvXWFT3ZDC4tfZOSy/YIqpVUyWZAomFqRa+g==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.35.0.tgz",
+ "integrity": "sha512-3DSP7QpmTGYU9bN/yljP0PIao4tNIQtsR4ycauWNSawxs/GQCZtSmAPcLRnCm6qpqsDDjUtKjO/1Ej8FRp0m0w==",
"license": "MIT",
"dependencies": {
- "@lexical/offset": "0.33.1",
- "@lexical/selection": "0.33.1",
- "lexical": "0.33.1"
+ "@lexical/offset": "0.35.0",
+ "@lexical/selection": "0.35.0",
+ "lexical": "0.35.0"
},
"peerDependencies": {
"yjs": ">=13.5.22"
@@ -2166,9 +2206,9 @@
}
},
"node_modules/@lezer/html": {
- "version": "1.3.10",
- "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
- "integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
+ "version": "1.3.11",
+ "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.11.tgz",
+ "integrity": "sha512-SV04kK5EHDPPecMCiFNZAnQhUIxktP04yHxgOKK7TZ3+KUAlK9f4dcYbjAWwDx2C2pJmiOeSV05QEbHeQo5JqA==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
@@ -2188,9 +2228,9 @@
}
},
"node_modules/@lezer/javascript": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz",
- "integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==",
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz",
+ "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
@@ -2229,9 +2269,9 @@
}
},
"node_modules/@lezer/php": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.4.tgz",
- "integrity": "sha512-D2dJ0t8Z28/G1guztRczMFvPDUqzeMLSQbdWQmaiHV7urc8NlEOnjYk9UrZ531OcLiRxD4Ihcbv7AsDpNKDRaQ==",
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.5.tgz",
+ "integrity": "sha512-W7asp9DhM6q0W6DYNwIkLSKOvxlXRrif+UXBMxzsJUuqmhE7oVU+gS3THO4S/Puh7Xzgm858UNaFi6dxTP8dJA==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
@@ -2301,9 +2341,9 @@
"license": "MIT"
},
"node_modules/@mdxeditor/editor": {
- "version": "3.42.0",
- "resolved": "https://registry.npmjs.org/@mdxeditor/editor/-/editor-3.42.0.tgz",
- "integrity": "sha512-nQN07RkTm842T477IjPqp1FhWCQMpmbLToOVrc6EjSI60aHifwzva+eqYmElHFKE2jyGiD5FsaQXri1SSORJNg==",
+ "version": "3.46.1",
+ "resolved": "https://registry.npmjs.org/@mdxeditor/editor/-/editor-3.46.1.tgz",
+ "integrity": "sha512-TL0Ol88NhlXYfThD6kYGhxIQkUMjBkHZ2OsbvHU6mD2RpqcTp1/tinLmADzmoreKSl/52rcj+lTbrJwBmeiHRw==",
"license": "MIT",
"dependencies": {
"@codemirror/commands": "^6.2.4",
@@ -2313,16 +2353,16 @@
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.23.0",
"@codesandbox/sandpack-react": "^2.20.0",
- "@lexical/clipboard": "^0.33.1",
- "@lexical/link": "^0.33.1",
- "@lexical/list": "^0.33.1",
- "@lexical/markdown": "^0.33.1",
- "@lexical/plain-text": "^0.33.1",
- "@lexical/react": "^0.33.1",
- "@lexical/rich-text": "^0.33.1",
- "@lexical/selection": "^0.33.1",
- "@lexical/utils": "^0.33.1",
- "@mdxeditor/gurx": "^1.1.4",
+ "@lexical/clipboard": "^0.35.0",
+ "@lexical/link": "^0.35.0",
+ "@lexical/list": "^0.35.0",
+ "@lexical/markdown": "^0.35.0",
+ "@lexical/plain-text": "^0.35.0",
+ "@lexical/react": "^0.35.0",
+ "@lexical/rich-text": "^0.35.0",
+ "@lexical/selection": "^0.35.0",
+ "@lexical/utils": "^0.35.0",
+ "@mdxeditor/gurx": "^1.2.4",
"@radix-ui/colors": "^3.0.0",
"@radix-ui/react-dialog": "^1.1.11",
"@radix-ui/react-icons": "^1.3.2",
@@ -2337,7 +2377,7 @@
"codemirror": "^6.0.1",
"downshift": "^7.6.0",
"js-yaml": "4.1.0",
- "lexical": "^0.33.1",
+ "lexical": "^0.35.0",
"mdast-util-directive": "^3.0.0",
"mdast-util-from-markdown": "^2.0.0",
"mdast-util-frontmatter": "^2.0.1",
@@ -2372,9 +2412,9 @@
}
},
"node_modules/@mdxeditor/gurx": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@mdxeditor/gurx/-/gurx-1.2.3.tgz",
- "integrity": "sha512-5DQOlEx46oN9spggrC8husAGAhVoEFBGIYKN48es08XhRUbSU6l5bcIQYwRrQaY8clU1tExIcXzw8/fNnoxjpg==",
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@mdxeditor/gurx/-/gurx-1.2.4.tgz",
+ "integrity": "sha512-9ZykIFYhKaXaaSPCs1cuI+FvYDegJjbKwmA4ASE/zY+hJY6EYqvoye4esiO85CjhOw9aoD/izD/CU78/egVqmg==",
"license": "MIT",
"engines": {
"node": ">=16"
@@ -3436,16 +3476,16 @@
}
},
"node_modules/@rolldown/pluginutils": {
- "version": "1.0.0-beta.9",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.9.tgz",
- "integrity": "sha512-e9MeMtVWo186sgvFFJOPGy7/d2j2mZhLJIdVW0C/xDluuOvymEATqz6zKsP0ZmXGzQtqlyjz5sC1sYQUoJG98w==",
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
"dev": true,
"license": "MIT"
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz",
- "integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.2.tgz",
+ "integrity": "sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==",
"cpu": [
"arm"
],
@@ -3457,9 +3497,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz",
- "integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.2.tgz",
+ "integrity": "sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==",
"cpu": [
"arm64"
],
@@ -3471,9 +3511,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz",
- "integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.2.tgz",
+ "integrity": "sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==",
"cpu": [
"arm64"
],
@@ -3485,9 +3525,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz",
- "integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.2.tgz",
+ "integrity": "sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==",
"cpu": [
"x64"
],
@@ -3499,9 +3539,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz",
- "integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.2.tgz",
+ "integrity": "sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==",
"cpu": [
"arm64"
],
@@ -3513,9 +3553,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz",
- "integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.2.tgz",
+ "integrity": "sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==",
"cpu": [
"x64"
],
@@ -3527,9 +3567,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz",
- "integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.2.tgz",
+ "integrity": "sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==",
"cpu": [
"arm"
],
@@ -3541,9 +3581,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz",
- "integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.2.tgz",
+ "integrity": "sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==",
"cpu": [
"arm"
],
@@ -3555,9 +3595,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz",
- "integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.2.tgz",
+ "integrity": "sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==",
"cpu": [
"arm64"
],
@@ -3569,9 +3609,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz",
- "integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.2.tgz",
+ "integrity": "sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==",
"cpu": [
"arm64"
],
@@ -3582,10 +3622,10 @@
"linux"
]
},
- "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz",
- "integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==",
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.2.tgz",
+ "integrity": "sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==",
"cpu": [
"loong64"
],
@@ -3596,10 +3636,10 @@
"linux"
]
},
- "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz",
- "integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==",
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.2.tgz",
+ "integrity": "sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==",
"cpu": [
"ppc64"
],
@@ -3611,9 +3651,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz",
- "integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.2.tgz",
+ "integrity": "sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==",
"cpu": [
"riscv64"
],
@@ -3625,9 +3665,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz",
- "integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.2.tgz",
+ "integrity": "sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==",
"cpu": [
"riscv64"
],
@@ -3639,9 +3679,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz",
- "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.2.tgz",
+ "integrity": "sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==",
"cpu": [
"s390x"
],
@@ -3653,9 +3693,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz",
- "integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.2.tgz",
+ "integrity": "sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==",
"cpu": [
"x64"
],
@@ -3667,9 +3707,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz",
- "integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.2.tgz",
+ "integrity": "sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==",
"cpu": [
"x64"
],
@@ -3680,10 +3720,24 @@
"linux"
]
},
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.2.tgz",
+ "integrity": "sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz",
- "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.2.tgz",
+ "integrity": "sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==",
"cpu": [
"arm64"
],
@@ -3695,9 +3749,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz",
- "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.2.tgz",
+ "integrity": "sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==",
"cpu": [
"ia32"
],
@@ -3708,10 +3762,24 @@
"win32"
]
},
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.2.tgz",
+ "integrity": "sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz",
- "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.2.tgz",
+ "integrity": "sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==",
"cpu": [
"x64"
],
@@ -3736,9 +3804,9 @@
"license": "MIT"
},
"node_modules/@tanstack/query-core": {
- "version": "5.87.0",
- "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.87.0.tgz",
- "integrity": "sha512-gRZig2csRl71i/HEAHlE9TOmMqKKs9WkMAqIUlzagH+sNtgjvqxwaVo2HmfNGe+iDWUak0ratSkiRv0m/Y8ijg==",
+ "version": "5.90.2",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.2.tgz",
+ "integrity": "sha512-k/TcR3YalnzibscALLwxeiLUub6jN5EDLwKDiO7q5f4ICEoptJ+n9+7vcEFy5/x/i6Q+Lb/tXrsKCggf5uQJXQ==",
"license": "MIT",
"funding": {
"type": "github",
@@ -3746,9 +3814,9 @@
}
},
"node_modules/@tanstack/query-devtools": {
- "version": "5.86.0",
- "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.86.0.tgz",
- "integrity": "sha512-/JDw9BP80eambEK/EsDMGAcsL2VFT+8F5KCOwierjPU7QP8Wt1GT32yJpn3qOinBM8/zS3Jy36+F0GiyJp411A==",
+ "version": "5.90.1",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.90.1.tgz",
+ "integrity": "sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ==",
"license": "MIT",
"funding": {
"type": "github",
@@ -3756,12 +3824,12 @@
}
},
"node_modules/@tanstack/react-query": {
- "version": "5.87.0",
- "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.87.0.tgz",
- "integrity": "sha512-3uRCGHo7KWHl6h7ptzLd5CbrjTQP5Q/37aC1cueClkSN4t/OaNFmfGolgs1AoA0kFjP/OZxTY2ytQoifyJzpWQ==",
+ "version": "5.90.2",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.2.tgz",
+ "integrity": "sha512-CLABiR+h5PYfOWr/z+vWFt5VsOA2ekQeRQBFSKlcoW6Ndx/f8rfyVmq4LbgOM4GG2qtxAxjLYLOpCNTYm4uKzw==",
"license": "MIT",
"dependencies": {
- "@tanstack/query-core": "5.87.0"
+ "@tanstack/query-core": "5.90.2"
},
"funding": {
"type": "github",
@@ -3772,26 +3840,26 @@
}
},
"node_modules/@tanstack/react-query-devtools": {
- "version": "5.87.0",
- "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.87.0.tgz",
- "integrity": "sha512-OeOSKsPyLcTVLdn391iNeRqYFEmpYJrY9t+FjKpaC6ql0SyRu2XT3mKYJIfYczhMMlwOIlbJkNaifBveertV8Q==",
+ "version": "5.90.2",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.90.2.tgz",
+ "integrity": "sha512-vAXJzZuBXtCQtrY3F/yUNJCV4obT/A/n81kb3+YqLbro5Z2+phdAbceO+deU3ywPw8B42oyJlp4FhO0SoivDFQ==",
"license": "MIT",
"dependencies": {
- "@tanstack/query-devtools": "5.86.0"
+ "@tanstack/query-devtools": "5.90.1"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
- "@tanstack/react-query": "^5.87.0",
+ "@tanstack/react-query": "^5.90.2",
"react": "^18 || ^19"
}
},
"node_modules/@testing-library/dom": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
- "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
+ "version": "10.4.1",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
+ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -3800,9 +3868,9 @@
"@babel/runtime": "^7.12.5",
"@types/aria-query": "^5.0.1",
"aria-query": "5.3.0",
- "chalk": "^4.1.0",
"dom-accessibility-api": "^0.5.9",
"lz-string": "^1.5.0",
+ "picocolors": "1.1.1",
"pretty-format": "^27.0.2"
},
"engines": {
@@ -3810,18 +3878,17 @@
}
},
"node_modules/@testing-library/jest-dom": {
- "version": "6.6.3",
- "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz",
- "integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==",
+ "version": "6.8.0",
+ "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.8.0.tgz",
+ "integrity": "sha512-WgXcWzVM6idy5JaftTVC8Vs83NKRmGJz4Hqs4oyOuO2J4r/y79vvKZsb+CaGyCSEbUPI6OsewfPd0G1A0/TUZQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@adobe/css-tools": "^4.4.0",
"aria-query": "^5.0.0",
- "chalk": "^3.0.0",
"css.escape": "^1.5.1",
"dom-accessibility-api": "^0.6.3",
- "lodash": "^4.17.21",
+ "picocolors": "^1.1.1",
"redent": "^3.0.0"
},
"engines": {
@@ -3830,20 +3897,6 @@
"yarn": ">=1"
}
},
- "node_modules/@testing-library/jest-dom/node_modules/chalk": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
- "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz",
@@ -3985,13 +4038,13 @@
}
},
"node_modules/@types/babel__traverse": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz",
- "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==",
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.20.7"
+ "@babel/types": "^7.28.2"
}
},
"node_modules/@types/debug": {
@@ -4004,9 +4057,9 @@
}
},
"node_modules/@types/estree": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
- "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
"license": "MIT"
},
"node_modules/@types/estree-jsx": {
@@ -4050,9 +4103,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "20.19.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.0.tgz",
- "integrity": "sha512-hfrc+1tud1xcdVTABC2JiomZJEklMcXYNTVtZLAeqTVWD+qL5jkHKT+1lOtqDdGxt+mB53DTtiz673vfjU8D1Q==",
+ "version": "20.19.17",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.17.tgz",
+ "integrity": "sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -4060,15 +4113,15 @@
}
},
"node_modules/@types/prop-types": {
- "version": "15.7.14",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz",
- "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==",
+ "version": "15.7.15",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
+ "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
"license": "MIT"
},
"node_modules/@types/react": {
- "version": "18.3.23",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz",
- "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==",
+ "version": "18.3.24",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.24.tgz",
+ "integrity": "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==",
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
@@ -4252,32 +4305,6 @@
}
}
},
- "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "9.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
- "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/@typescript-eslint/utils": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz",
@@ -4329,16 +4356,16 @@
"license": "ISC"
},
"node_modules/@vitejs/plugin-react": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.5.0.tgz",
- "integrity": "sha512-JuLWaEqypaJmOJPLWwO335Ig6jSgC1FTONCWAxnqcQthLTK/Yc9aH6hr9z/87xciejbQcnP3GnA1FWUSWeXaeg==",
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/core": "^7.26.10",
- "@babel/plugin-transform-react-jsx-self": "^7.25.9",
- "@babel/plugin-transform-react-jsx-source": "^7.25.9",
- "@rolldown/pluginutils": "1.0.0-beta.9",
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
"@types/babel__core": "^7.20.5",
"react-refresh": "^0.17.0"
},
@@ -4346,7 +4373,7 @@
"node": "^14.18.0 || >=16.0.0"
},
"peerDependencies": {
- "vite": "^4.2.0 || ^5.0.0 || ^6.0.0"
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
}
},
"node_modules/@vitest/coverage-v8": {
@@ -4573,9 +4600,9 @@
"license": "MIT"
},
"node_modules/acorn": {
- "version": "8.14.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
- "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
@@ -4607,9 +4634,9 @@
}
},
"node_modules/agent-base": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
- "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4856,6 +4883,16 @@
],
"license": "MIT"
},
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.8.6",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.6.tgz",
+ "integrity": "sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.js"
+ }
+ },
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -4870,14 +4907,13 @@
}
},
"node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
+ "balanced-match": "^1.0.0"
}
},
"node_modules/braces": {
@@ -4894,9 +4930,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.25.0",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz",
- "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==",
+ "version": "4.26.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz",
+ "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==",
"dev": true,
"funding": [
{
@@ -4914,9 +4950,10 @@
],
"license": "MIT",
"dependencies": {
- "caniuse-lite": "^1.0.30001718",
- "electron-to-chromium": "^1.5.160",
- "node-releases": "^2.0.19",
+ "baseline-browser-mapping": "^2.8.3",
+ "caniuse-lite": "^1.0.30001741",
+ "electron-to-chromium": "^1.5.218",
+ "node-releases": "^2.0.21",
"update-browserslist-db": "^1.1.3"
},
"bin": {
@@ -5031,9 +5068,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001720",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz",
- "integrity": "sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==",
+ "version": "1.0.30001745",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001745.tgz",
+ "integrity": "sha512-ywt6i8FzvdgrrrGbr1jZVObnVv6adj+0if2/omv9cmR2oiZs30zL4DIyaptKcbOrBdOIc74QTMoJvSE2QHh5UQ==",
"dev": true,
"funding": [
{
@@ -5365,13 +5402,13 @@
}
},
"node_modules/cssstyle": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.3.1.tgz",
- "integrity": "sha512-ZgW+Jgdd7i52AaLYCriF8Mxqft0gD/R9i9wi6RWBhs1pqdPEzPjym7rvRKi397WmQFf3SlyUsszhw+VVCbx79Q==",
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz",
+ "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@asamuzakjp/css-color": "^3.1.2",
+ "@asamuzakjp/css-color": "^3.2.0",
"rrweb-cssom": "^0.8.0"
},
"engines": {
@@ -5429,9 +5466,9 @@
}
},
"node_modules/debug": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -5446,16 +5483,16 @@
}
},
"node_modules/decimal.js": {
- "version": "10.5.0",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz",
- "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==",
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
+ "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
"dev": true,
"license": "MIT"
},
"node_modules/decode-named-character-reference": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz",
- "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz",
+ "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==",
"license": "MIT",
"dependencies": {
"character-entities": "^2.0.0"
@@ -5721,9 +5758,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
- "version": "1.5.161",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.161.tgz",
- "integrity": "sha512-hwtetwfKNZo/UlwHIVBlKZVdy7o8bIZxxKs0Mv/ROPiQQQmDgdm5a+KvKtBsxM8ZjFzTaCeLoodZ8jiBE3o9rA==",
+ "version": "1.5.223",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.223.tgz",
+ "integrity": "sha512-qKm55ic6nbEmagFlTFczML33rF90aU+WtrJ9MdTCThrcvDNdUHN4p6QfVN78U06ZmguqXIyMPyYhw2TrbDUwPQ==",
"dev": true,
"license": "ISC"
},
@@ -5735,9 +5772,9 @@
"license": "MIT"
},
"node_modules/entities": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz",
- "integrity": "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
@@ -5996,29 +6033,16 @@
}
},
"node_modules/eslint-plugin-react-refresh": {
- "version": "0.4.20",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz",
- "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==",
+ "version": "0.4.21",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.21.tgz",
+ "integrity": "sha512-MWDWTtNC4voTcWDxXbdmBNe8b/TxfxRFUL6hXgKWJjN9c1AagYEmpiFWBWzDw+5H3SulWUe1pJKTnoSdmk88UA==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"eslint": ">=8.40"
}
},
- "node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint/node_modules/eslint-scope": {
+ "node_modules/eslint-scope": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
@@ -6035,30 +6059,41 @@
"url": "https://opencollective.com/eslint"
}
},
- "node_modules/eslint/node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
- "license": "BSD-2-Clause",
+ "license": "Apache-2.0",
"engines": {
- "node": ">=4.0"
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
}
},
- "node_modules/eslint/node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "node_modules/eslint/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "type-fest": "^0.20.2"
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/eslint/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
},
"engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": "*"
}
},
"node_modules/esniff": {
@@ -6107,16 +6142,6 @@
"node": ">=0.10"
}
},
- "node_modules/esquery/node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=4.0"
- }
- },
"node_modules/esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
@@ -6130,7 +6155,7 @@
"node": ">=4.0"
}
},
- "node_modules/esrecurse/node_modules/estraverse": {
+ "node_modules/estraverse": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
@@ -6412,15 +6437,16 @@
}
},
"node_modules/form-data": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
- "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
+ "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"dev": true,
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
@@ -6643,14 +6669,44 @@
"node": ">=10.13.0"
}
},
- "node_modules/globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
"engines": {
- "node": ">=4"
+ "node": "*"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/globby": {
@@ -7486,9 +7542,9 @@
}
},
"node_modules/istanbul-reports": {
- "version": "3.1.7",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
- "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
+ "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -7665,9 +7721,9 @@
}
},
"node_modules/lexical": {
- "version": "0.33.1",
- "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.33.1.tgz",
- "integrity": "sha512-+kiCS/GshQmCs/meMb8MQT4AMvw3S3Ef0lSCv2Xi6Itvs59OD+NjQWNfYkDteIbKtVE/w0Yiqh56VyGwIb8UcA==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.35.0.tgz",
+ "integrity": "sha512-3VuV8xXhh5xJA6tzvfDvE0YBCMkIZUmxtRilJQDDdCgJCc+eut6qAv2qbN+pbqvarqcQqPN1UF+8YvsjmyOZpw==",
"license": "MIT"
},
"node_modules/lib0": {
@@ -7745,13 +7801,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -7820,13 +7869,13 @@
}
},
"node_modules/magic-string": {
- "version": "0.30.17",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
- "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+ "version": "0.30.19",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
+ "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jridgewell/sourcemap-codec": "^1.5.0"
+ "@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/magicast": {
@@ -8891,9 +8940,9 @@
}
},
"node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -8912,6 +8961,16 @@
"node": ">= 0.6"
}
},
+ "node_modules/mime-types/node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/mimic-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
@@ -8936,16 +8995,19 @@
}
},
"node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+ "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"license": "ISC",
"dependencies": {
- "brace-expansion": "^1.1.7"
+ "brace-expansion": "^2.0.1"
},
"engines": {
- "node": "*"
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/minipass": {
@@ -8959,16 +9021,16 @@
}
},
"node_modules/mlly": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz",
- "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==",
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz",
+ "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "acorn": "^8.14.0",
- "pathe": "^2.0.1",
- "pkg-types": "^1.3.0",
- "ufo": "^1.5.4"
+ "acorn": "^8.15.0",
+ "pathe": "^2.0.3",
+ "pkg-types": "^1.3.1",
+ "ufo": "^1.6.1"
}
},
"node_modules/mlly/node_modules/pathe": {
@@ -9031,9 +9093,9 @@
}
},
"node_modules/nanoid": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz",
- "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==",
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz",
+ "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==",
"funding": [
{
"type": "github",
@@ -9062,9 +9124,9 @@
"license": "ISC"
},
"node_modules/node-releases": {
- "version": "2.0.19",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
- "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+ "version": "2.0.21",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz",
+ "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==",
"dev": true,
"license": "MIT"
},
@@ -9118,9 +9180,9 @@
}
},
"node_modules/nwsapi": {
- "version": "2.2.20",
- "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz",
- "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==",
+ "version": "2.2.22",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.22.tgz",
+ "integrity": "sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==",
"dev": true,
"license": "MIT"
},
@@ -9549,10 +9611,20 @@
}
},
"node_modules/postcss-js": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
- "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz",
+ "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==",
"dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
"license": "MIT",
"dependencies": {
"camelcase-css": "^2.0.1"
@@ -9560,10 +9632,6 @@
"engines": {
"node": "^12 || ^14 || >= 16"
},
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
"peerDependencies": {
"postcss": "^8.4.21"
}
@@ -9885,9 +9953,9 @@
}
},
"node_modules/react-hook-form": {
- "version": "7.62.0",
- "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.62.0.tgz",
- "integrity": "sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==",
+ "version": "7.63.0",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.63.0.tgz",
+ "integrity": "sha512-ZwueDMvUeucovM2VjkCf7zIHcs1aAlDimZu2Hvel5C5907gUzMpm4xCrQXtRzCvsBqFjonB4m3x4LzCFI1ZKWA==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
@@ -9900,6 +9968,15 @@
"react": "^16.8.0 || ^17 || ^18 || ^19"
}
},
+ "node_modules/react-icons": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
+ "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -10211,13 +10288,13 @@
}
},
"node_modules/rollup": {
- "version": "4.41.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz",
- "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==",
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.2.tgz",
+ "integrity": "sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/estree": "1.0.7"
+ "@types/estree": "1.0.8"
},
"bin": {
"rollup": "dist/bin/rollup"
@@ -10227,26 +10304,28 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.41.1",
- "@rollup/rollup-android-arm64": "4.41.1",
- "@rollup/rollup-darwin-arm64": "4.41.1",
- "@rollup/rollup-darwin-x64": "4.41.1",
- "@rollup/rollup-freebsd-arm64": "4.41.1",
- "@rollup/rollup-freebsd-x64": "4.41.1",
- "@rollup/rollup-linux-arm-gnueabihf": "4.41.1",
- "@rollup/rollup-linux-arm-musleabihf": "4.41.1",
- "@rollup/rollup-linux-arm64-gnu": "4.41.1",
- "@rollup/rollup-linux-arm64-musl": "4.41.1",
- "@rollup/rollup-linux-loongarch64-gnu": "4.41.1",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1",
- "@rollup/rollup-linux-riscv64-gnu": "4.41.1",
- "@rollup/rollup-linux-riscv64-musl": "4.41.1",
- "@rollup/rollup-linux-s390x-gnu": "4.41.1",
- "@rollup/rollup-linux-x64-gnu": "4.41.1",
- "@rollup/rollup-linux-x64-musl": "4.41.1",
- "@rollup/rollup-win32-arm64-msvc": "4.41.1",
- "@rollup/rollup-win32-ia32-msvc": "4.41.1",
- "@rollup/rollup-win32-x64-msvc": "4.41.1",
+ "@rollup/rollup-android-arm-eabi": "4.52.2",
+ "@rollup/rollup-android-arm64": "4.52.2",
+ "@rollup/rollup-darwin-arm64": "4.52.2",
+ "@rollup/rollup-darwin-x64": "4.52.2",
+ "@rollup/rollup-freebsd-arm64": "4.52.2",
+ "@rollup/rollup-freebsd-x64": "4.52.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.52.2",
+ "@rollup/rollup-linux-arm-musleabihf": "4.52.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.52.2",
+ "@rollup/rollup-linux-arm64-musl": "4.52.2",
+ "@rollup/rollup-linux-loong64-gnu": "4.52.2",
+ "@rollup/rollup-linux-ppc64-gnu": "4.52.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.52.2",
+ "@rollup/rollup-linux-riscv64-musl": "4.52.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.52.2",
+ "@rollup/rollup-linux-x64-gnu": "4.52.2",
+ "@rollup/rollup-linux-x64-musl": "4.52.2",
+ "@rollup/rollup-openharmony-arm64": "4.52.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.52.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.52.2",
+ "@rollup/rollup-win32-x64-gnu": "4.52.2",
+ "@rollup/rollup-win32-x64-msvc": "4.52.2",
"fsevents": "~2.3.2"
}
},
@@ -10639,9 +10718,9 @@
"license": "MIT"
},
"node_modules/string-width/node_modules/ansi-regex": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
- "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -10652,9 +10731,9 @@
}
},
"node_modules/string-width/node_modules/strip-ansi": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
+ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -10814,16 +10893,6 @@
"node": ">=16 || 14 >=14.17"
}
},
- "node_modules/sucrase/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
"node_modules/sucrase/node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@@ -10901,9 +10970,9 @@
"license": "MIT"
},
"node_modules/tailwind-merge": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.0.tgz",
- "integrity": "sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
+ "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==",
"license": "MIT",
"funding": {
"type": "github",
@@ -10963,6 +11032,30 @@
"node": ">=8"
}
},
+ "node_modules/test-exclude/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/test-exclude/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -11212,9 +11305,9 @@
}
},
"node_modules/typescript": {
- "version": "5.8.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
- "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "version": "5.9.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
+ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -11518,9 +11611,9 @@
}
},
"node_modules/vfile-message": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz",
- "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz",
+ "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==",
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0",
@@ -11532,9 +11625,9 @@
}
},
"node_modules/vite": {
- "version": "5.4.19",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz",
- "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
+ "version": "5.4.20",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz",
+ "integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11910,9 +12003,9 @@
}
},
"node_modules/wrap-ansi/node_modules/ansi-regex": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
- "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -11923,9 +12016,9 @@
}
},
"node_modules/wrap-ansi/node_modules/ansi-styles": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
- "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -11936,9 +12029,9 @@
}
},
"node_modules/wrap-ansi/node_modules/strip-ansi": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
+ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11959,9 +12052,9 @@
"license": "ISC"
},
"node_modules/ws": {
- "version": "8.18.2",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
- "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
+ "version": "8.18.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -12005,9 +12098,9 @@
"license": "ISC"
},
"node_modules/yaml": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
- "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
+ "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
"dev": true,
"license": "ISC",
"bin": {
@@ -12059,9 +12152,9 @@
}
},
"node_modules/zod": {
- "version": "3.25.46",
- "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.46.tgz",
- "integrity": "sha512-IqRxcHEIjqLd4LNS/zKffB3Jzg3NwqJxQQ0Ns7pdrvgGkwQsEBdEQcOHaBVqvvZArShRzI39+aMST3FBGmTrLQ==",
+ "version": "3.25.76",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
diff --git a/archon-ui-main/package.json b/archon-ui-main/package.json
index 31c07574..a0f86e81 100644
--- a/archon-ui-main/package.json
+++ b/archon-ui-main/package.json
@@ -50,6 +50,7 @@
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.3.1",
+ "react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"react-router-dom": "^6.26.2",
"tailwind-merge": "latest",
diff --git a/archon-ui-main/src/components/settings/RAGSettings.tsx b/archon-ui-main/src/components/settings/RAGSettings.tsx
index ccba61ce..62739fc7 100644
--- a/archon-ui-main/src/components/settings/RAGSettings.tsx
+++ b/archon-ui-main/src/components/settings/RAGSettings.tsx
@@ -1,9 +1,12 @@
-import React, { useState, useEffect, useRef } from 'react';
-import { Settings, Check, Save, Loader, ChevronDown, ChevronUp, Zap, Database, Trash2 } from 'lucide-react';
+import React, { useState, useEffect, useRef, useCallback } from 'react';
+import { Settings, Check, Save, Loader, ChevronDown, ChevronUp, Zap, Database, Trash2, Cog } from 'lucide-react';
import { Card } from '../ui/Card';
import { Input } from '../ui/Input';
import { Select } from '../ui/Select';
import { Button } from '../ui/Button';
+import { Button as GlowButton } from '../../features/ui/primitives/button';
+import { LuBrainCircuit } from 'react-icons/lu';
+import { PiDatabaseThin } from 'react-icons/pi';
import { useToast } from '../../features/shared/hooks/useToast';
import { credentialsService } from '../../services/credentialsService';
import OllamaModelDiscoveryModal from './OllamaModelDiscoveryModal';
@@ -11,6 +14,9 @@ import OllamaModelSelectionModal from './OllamaModelSelectionModal';
type ProviderKey = 'openai' | 'google' | 'ollama' | 'anthropic' | 'grok' | 'openrouter';
+// Providers that support embedding models
+const EMBEDDING_CAPABLE_PROVIDERS: ProviderKey[] = ['openai', 'google', 'ollama'];
+
interface ProviderModels {
chatModel: string;
embeddingModel: string;
@@ -85,27 +91,53 @@ const colorStyles: Record = {
grok: 'border-yellow-500 bg-yellow-500/10',
};
-const providerAlertStyles: Record = {
- openai: 'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800 text-green-800 dark:text-green-300',
- google: 'bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800 text-blue-800 dark:text-blue-300',
- openrouter: 'bg-cyan-50 dark:bg-cyan-900/20 border-cyan-200 dark:border-cyan-800 text-cyan-800 dark:text-cyan-300',
- ollama: 'bg-purple-50 dark:bg-purple-900/20 border-purple-200 dark:border-purple-800 text-purple-800 dark:text-purple-300',
- anthropic: 'bg-orange-50 dark:bg-orange-900/20 border-orange-200 dark:border-orange-800 text-orange-800 dark:text-orange-300',
- grok: 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800 text-yellow-800 dark:text-yellow-300',
-};
+const providerWarningAlertStyle = 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800 text-yellow-800 dark:text-yellow-300';
+const providerErrorAlertStyle = 'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800 text-red-800 dark:text-red-300';
+const providerMissingAlertStyle = providerErrorAlertStyle;
-const providerAlertMessages: Record = {
- openai: 'Configure your OpenAI API key in the credentials section to use GPT models.',
- google: 'Configure your Google API key in the credentials section to use Gemini models.',
- openrouter: 'Configure your OpenRouter API key in the credentials section to use models.',
- ollama: 'Configure your Ollama instances in this panel to connect local models.',
- anthropic: 'Configure your Anthropic API key in the credentials section to use Claude models.',
- grok: 'Configure your Grok API key in the credentials section to use Grok models.',
+const providerDisplayNames: Record = {
+ openai: 'OpenAI',
+ google: 'Google',
+ openrouter: 'OpenRouter',
+ ollama: 'Ollama',
+ anthropic: 'Anthropic',
+ grok: 'Grok',
};
const isProviderKey = (value: unknown): value is ProviderKey =>
typeof value === 'string' && ['openai', 'google', 'openrouter', 'ollama', 'anthropic', 'grok'].includes(value);
+// Default base URL for Ollama instances when not explicitly configured
+const DEFAULT_OLLAMA_URL = 'http://host.docker.internal:11434/v1';
+
+const PROVIDER_CREDENTIAL_KEYS = [
+ 'OPENAI_API_KEY',
+ 'GOOGLE_API_KEY',
+ 'ANTHROPIC_API_KEY',
+ 'OPENROUTER_API_KEY',
+ 'GROK_API_KEY',
+] as const;
+
+type ProviderCredentialKey = typeof PROVIDER_CREDENTIAL_KEYS[number];
+
+const CREDENTIAL_PROVIDER_MAP: Record = {
+ OPENAI_API_KEY: 'openai',
+ GOOGLE_API_KEY: 'google',
+ ANTHROPIC_API_KEY: 'anthropic',
+ OPENROUTER_API_KEY: 'openrouter',
+ GROK_API_KEY: 'grok',
+};
+
+const normalizeBaseUrl = (url?: string | null): string | null => {
+ if (!url) return null;
+ const trimmed = url.trim();
+ if (!trimmed) return null;
+
+ let normalized = trimmed.replace(/\/+$/, '');
+ normalized = normalized.replace(/\/v1$/i, '');
+ return normalized || null;
+};
+
interface RAGSettingsProps {
ragSettings: {
MODEL_CHOICE: string;
@@ -118,6 +150,7 @@ interface RAGSettingsProps {
LLM_BASE_URL?: string;
LLM_INSTANCE_NAME?: string;
EMBEDDING_MODEL?: string;
+ EMBEDDING_PROVIDER?: string;
OLLAMA_EMBEDDING_URL?: string;
OLLAMA_EMBEDDING_INSTANCE_NAME?: string;
// Crawling Performance Settings
@@ -148,6 +181,7 @@ export const RAGSettings = ({
const [showCrawlingSettings, setShowCrawlingSettings] = useState(false);
const [showStorageSettings, setShowStorageSettings] = useState(false);
const [showModelDiscoveryModal, setShowModelDiscoveryModal] = useState(false);
+ const [showOllamaConfig, setShowOllamaConfig] = useState(false);
// Edit modals state
const [showEditLLMModal, setShowEditLLMModal] = useState(false);
@@ -160,6 +194,16 @@ export const RAGSettings = ({
// Provider-specific model persistence state
const [providerModels, setProviderModels] = useState(() => loadProviderModels());
+ // Independent provider selection state
+ const [chatProvider, setChatProvider] = useState(() =>
+ (ragSettings.LLM_PROVIDER as ProviderKey) || 'openai'
+ );
+ const [embeddingProvider, setEmbeddingProvider] = useState(() =>
+ // Default to openai if no specific embedding provider is set
+ (ragSettings.EMBEDDING_PROVIDER as ProviderKey) || 'openai'
+ );
+ const [activeSelection, setActiveSelection] = useState<'chat' | 'embedding'>('chat');
+
// Instance configurations
const [llmInstanceConfig, setLLMInstanceConfig] = useState({
name: '',
@@ -215,16 +259,32 @@ export const RAGSettings = ({
}
}, [ragSettings.OLLAMA_EMBEDDING_URL, ragSettings.OLLAMA_EMBEDDING_INSTANCE_NAME]);
- // Provider model persistence effects
+ // Provider model persistence effects - separate for chat and embedding
useEffect(() => {
- // Update provider models when current models change
- const currentProvider = ragSettings.LLM_PROVIDER as ProviderKey;
- if (currentProvider && ragSettings.MODEL_CHOICE && ragSettings.EMBEDDING_MODEL) {
+ // Update chat provider models when chat model changes
+ if (chatProvider && ragSettings.MODEL_CHOICE) {
setProviderModels(prev => {
const updated = {
...prev,
- [currentProvider]: {
- chatModel: ragSettings.MODEL_CHOICE,
+ [chatProvider]: {
+ ...prev[chatProvider],
+ chatModel: ragSettings.MODEL_CHOICE
+ }
+ };
+ saveProviderModels(updated);
+ return updated;
+ });
+ }
+ }, [ragSettings.MODEL_CHOICE, chatProvider]);
+
+ useEffect(() => {
+ // Update embedding provider models when embedding model changes
+ if (embeddingProvider && ragSettings.EMBEDDING_MODEL) {
+ setProviderModels(prev => {
+ const updated = {
+ ...prev,
+ [embeddingProvider]: {
+ ...prev[embeddingProvider],
embeddingModel: ragSettings.EMBEDDING_MODEL
}
};
@@ -232,93 +292,181 @@ export const RAGSettings = ({
return updated;
});
}
- }, [ragSettings.MODEL_CHOICE, ragSettings.EMBEDDING_MODEL, ragSettings.LLM_PROVIDER]);
+ }, [ragSettings.EMBEDDING_MODEL, embeddingProvider]);
- // Load API credentials for status checking
- useEffect(() => {
- const loadApiCredentials = async () => {
- try {
- // Get decrypted values for the API keys we need for status checking
- const keyNames = ['OPENAI_API_KEY', 'GOOGLE_API_KEY', 'ANTHROPIC_API_KEY'];
- const statusResults = await credentialsService.checkCredentialStatus(keyNames);
-
- const credentials: {[key: string]: string} = {};
-
- for (const [key, result] of Object.entries(statusResults)) {
- if (result.has_value && result.value && result.value.trim().length > 0) {
- credentials[key] = result.value;
- }
- }
-
- console.log('🔑 Loaded API credentials for status checking:', Object.keys(credentials));
- setApiCredentials(credentials);
- } catch (error) {
- console.error('Failed to load API credentials for status checking:', error);
- }
- };
-
- loadApiCredentials();
- }, []);
-
- // Reload API credentials when ragSettings change (e.g., after saving)
- // Use a ref to track if we've loaded credentials to prevent infinite loops
const hasLoadedCredentialsRef = useRef(false);
-
- // Manual reload function for external calls
- const reloadApiCredentials = async () => {
+
+ const reloadApiCredentials = useCallback(async () => {
try {
- // Get decrypted values for the API keys we need for status checking
- const keyNames = ['OPENAI_API_KEY', 'GOOGLE_API_KEY', 'ANTHROPIC_API_KEY'];
- const statusResults = await credentialsService.checkCredentialStatus(keyNames);
-
- const credentials: {[key: string]: string} = {};
-
- for (const [key, result] of Object.entries(statusResults)) {
- if (result.has_value && result.value && result.value.trim().length > 0) {
- credentials[key] = result.value;
- }
+ const statusResults = await credentialsService.checkCredentialStatus(
+ Array.from(PROVIDER_CREDENTIAL_KEYS),
+ );
+
+ const credentials: { [key: string]: boolean } = {};
+
+ for (const key of PROVIDER_CREDENTIAL_KEYS) {
+ const result = statusResults[key];
+ credentials[key] = !!result?.has_value;
}
-
- console.log('🔄 Reloaded API credentials for status checking:', Object.keys(credentials));
+
+ console.log(
+ '🔑 Updated API credential status snapshot:',
+ Object.keys(credentials),
+ );
setApiCredentials(credentials);
hasLoadedCredentialsRef.current = true;
} catch (error) {
- console.error('Failed to reload API credentials:', error);
+ console.error('Failed to load API credentials for status checking:', error);
}
- };
-
+ }, []);
+
useEffect(() => {
- // Only reload if we have ragSettings and haven't loaded yet, or if LLM_PROVIDER changed
- if (Object.keys(ragSettings).length > 0 && (!hasLoadedCredentialsRef.current || ragSettings.LLM_PROVIDER)) {
- reloadApiCredentials();
+ void reloadApiCredentials();
+ }, [reloadApiCredentials]);
+
+ useEffect(() => {
+ if (!hasLoadedCredentialsRef.current) {
+ return;
}
- }, [ragSettings.LLM_PROVIDER]); // Only depend on LLM_PROVIDER changes
-
- // Reload credentials periodically to catch updates from other components (like onboarding)
+
+ void reloadApiCredentials();
+ }, [ragSettings.LLM_PROVIDER, reloadApiCredentials]);
+
useEffect(() => {
- // Set up periodic reload every 30 seconds when component is active (reduced from 2s)
const interval = setInterval(() => {
if (Object.keys(ragSettings).length > 0) {
- reloadApiCredentials();
+ void reloadApiCredentials();
}
- }, 30000); // Changed from 2000ms to 30000ms (30 seconds)
+ }, 30000);
return () => clearInterval(interval);
- }, [ragSettings.LLM_PROVIDER]); // Only restart interval if provider changes
-
+ }, [ragSettings.LLM_PROVIDER, reloadApiCredentials]);
+
+ useEffect(() => {
+ const needsDetection = chatProvider === 'ollama' || embeddingProvider === 'ollama';
+
+ if (!needsDetection) {
+ setOllamaServerStatus('unknown');
+ return;
+ }
+
+ const baseUrl = (
+ ragSettings.LLM_BASE_URL?.trim() ||
+ llmInstanceConfig.url?.trim() ||
+ ragSettings.OLLAMA_EMBEDDING_URL?.trim() ||
+ embeddingInstanceConfig.url?.trim() ||
+ DEFAULT_OLLAMA_URL
+ );
+
+ const normalizedUrl = baseUrl.replace('/v1', '').replace(/\/$/, '');
+
+ let cancelled = false;
+
+ (async () => {
+ try {
+ const response = await fetch(
+ `/api/ollama/instances/health?instance_urls=${encodeURIComponent(normalizedUrl)}`,
+ { method: 'GET', headers: { Accept: 'application/json' }, signal: AbortSignal.timeout(10000) }
+ );
+
+ if (cancelled) return;
+
+ if (!response.ok) {
+ setOllamaServerStatus('offline');
+ return;
+ }
+
+ const data = await response.json();
+ const instanceStatus = data.instance_status?.[normalizedUrl];
+ setOllamaServerStatus(instanceStatus?.is_healthy ? 'online' : 'offline');
+ } catch (error) {
+ if (!cancelled) {
+ setOllamaServerStatus('offline');
+ }
+ }
+ })();
+
+ return () => {
+ cancelled = true;
+ };
+ }, [chatProvider, embeddingProvider, ragSettings.LLM_BASE_URL, ragSettings.OLLAMA_EMBEDDING_URL, llmInstanceConfig.url, embeddingInstanceConfig.url]);
+
+ // Sync independent provider states with ragSettings (one-way: ragSettings -> local state)
+ useEffect(() => {
+ if (ragSettings.LLM_PROVIDER && ragSettings.LLM_PROVIDER !== chatProvider) {
+ setChatProvider(ragSettings.LLM_PROVIDER as ProviderKey);
+ }
+ }, [ragSettings.LLM_PROVIDER]); // Remove chatProvider dependency to avoid loops
+
+ useEffect(() => {
+ if (ragSettings.EMBEDDING_PROVIDER && ragSettings.EMBEDDING_PROVIDER !== embeddingProvider) {
+ setEmbeddingProvider(ragSettings.EMBEDDING_PROVIDER as ProviderKey);
+ }
+ }, [ragSettings.EMBEDDING_PROVIDER]); // Remove embeddingProvider dependency to avoid loops
+
+ useEffect(() => {
+ setOllamaManualConfirmed(false);
+ setOllamaServerStatus('unknown');
+ }, [ragSettings.LLM_BASE_URL, ragSettings.OLLAMA_EMBEDDING_URL, chatProvider, embeddingProvider]);
+
+ // Update ragSettings when independent providers change (one-way: local state -> ragSettings)
+ // Split the “first‐run” guard into two refs so chat and embedding effects don’t interfere.
+ const updateChatRagSettingsRef = useRef(true);
+ const updateEmbeddingRagSettingsRef = useRef(true);
+
+ useEffect(() => {
+ // Only update if this is a user‐initiated change, not a sync from ragSettings
+ if (updateChatRagSettingsRef.current && chatProvider !== ragSettings.LLM_PROVIDER) {
+ setRagSettings(prev => ({
+ ...prev,
+ LLM_PROVIDER: chatProvider
+ }));
+ }
+ updateChatRagSettingsRef.current = true;
+ }, [chatProvider]);
+
+ useEffect(() => {
+ // Only update if this is a user‐initiated change, not a sync from ragSettings
+ if (updateEmbeddingRagSettingsRef.current && embeddingProvider && embeddingProvider !== ragSettings.EMBEDDING_PROVIDER) {
+ setRagSettings(prev => ({
+ ...prev,
+ EMBEDDING_PROVIDER: embeddingProvider
+ }));
+ }
+ updateEmbeddingRagSettingsRef.current = true;
+ }, [embeddingProvider]);
+
+
// Status tracking
const [llmStatus, setLLMStatus] = useState({ online: false, responseTime: null, checking: false });
const [embeddingStatus, setEmbeddingStatus] = useState({ online: false, responseTime: null, checking: false });
+ const llmRetryTimeoutRef = useRef(null);
+ const embeddingRetryTimeoutRef = useRef(null);
// API key credentials for status checking
- const [apiCredentials, setApiCredentials] = useState<{[key: string]: string}>({});
+ const [apiCredentials, setApiCredentials] = useState<{[key: string]: boolean}>({});
// Provider connection status tracking
const [providerConnectionStatus, setProviderConnectionStatus] = useState<{
[key: string]: { connected: boolean; checking: boolean; lastChecked?: Date }
}>({});
+ const [ollamaServerStatus, setOllamaServerStatus] = useState<'unknown' | 'online' | 'offline'>('unknown');
+ const [ollamaManualConfirmed, setOllamaManualConfirmed] = useState(false);
+
+ useEffect(() => {
+ return () => {
+ if (llmRetryTimeoutRef.current) {
+ clearTimeout(llmRetryTimeoutRef.current);
+ llmRetryTimeoutRef.current = null;
+ }
+ if (embeddingRetryTimeoutRef.current) {
+ clearTimeout(embeddingRetryTimeoutRef.current);
+ embeddingRetryTimeoutRef.current = null;
+ }
+ };
+ }, []);
// Test connection to external providers
- const testProviderConnection = async (provider: string): Promise => {
+ const testProviderConnection = useCallback(async (provider: string): Promise => {
setProviderConnectionStatus(prev => ({
...prev,
[provider]: { ...prev[provider], checking: true }
@@ -345,7 +493,7 @@ export const RAGSettings = ({
}));
return false;
}
- };
+ }, []);
// Test provider connections when API credentials change
useEffect(() => {
@@ -371,7 +519,39 @@ export const RAGSettings = ({
const interval = setInterval(testConnections, 60000);
return () => clearInterval(interval);
- }, [apiCredentials]); // Test when credentials change
+ }, [apiCredentials, testProviderConnection]); // Test when credentials change
+
+ useEffect(() => {
+ const handleCredentialUpdate = (event: Event) => {
+ const detail = (event as CustomEvent<{ keys?: string[] }>).detail;
+ const updatedKeys = (detail?.keys ?? []).map(key => key.toUpperCase());
+
+ if (updatedKeys.length === 0) {
+ void reloadApiCredentials();
+ return;
+ }
+
+ const touchedProviderKeys = updatedKeys.filter(key => key in CREDENTIAL_PROVIDER_MAP);
+ if (touchedProviderKeys.length === 0) {
+ return;
+ }
+
+ void reloadApiCredentials();
+
+ touchedProviderKeys.forEach(key => {
+ const provider = CREDENTIAL_PROVIDER_MAP[key as ProviderCredentialKey];
+ if (provider) {
+ void testProviderConnection(provider);
+ }
+ });
+ };
+
+ window.addEventListener('archon:credentials-updated', handleCredentialUpdate);
+
+ return () => {
+ window.removeEventListener('archon:credentials-updated', handleCredentialUpdate);
+ };
+ }, [reloadApiCredentials, testProviderConnection]);
// Ref to track if initial test has been run (will be used after function definitions)
const hasRunInitialTestRef = useRef(false);
@@ -444,7 +624,14 @@ export const RAGSettings = ({
};
// Manual test function with user feedback using backend proxy
- const manualTestConnection = async (url: string, setStatus: React.Dispatch>, instanceName: string) => {
+const manualTestConnection = async (
+ url: string,
+ setStatus: React.Dispatch>,
+ instanceName: string,
+ context?: 'chat' | 'embedding',
+ options?: { suppressToast?: boolean }
+ ): Promise => {
+ const suppressToast = options?.suppressToast ?? false;
setStatus(prev => ({ ...prev, checking: true }));
const startTime = Date.now();
@@ -471,31 +658,58 @@ export const RAGSettings = ({
if (instanceStatus?.is_healthy) {
const responseTime = Math.round(instanceStatus.response_time_ms || (Date.now() - startTime));
setStatus({ online: true, responseTime, checking: false });
- showToast(`${instanceName} connection successful: ${instanceStatus.models_available || 0} models available (${responseTime}ms)`, 'success');
-
+
+ // Context-aware model count display
+ let modelCount = instanceStatus.models_available || 0;
+ let modelType = 'models';
+
+ if (context === 'chat') {
+ modelCount = ollamaMetrics.llmInstanceModels?.chat || 0;
+ modelType = 'chat models';
+ } else if (context === 'embedding') {
+ modelCount = ollamaMetrics.embeddingInstanceModels?.embedding || 0;
+ modelType = 'embedding models';
+ }
+
+ if (!suppressToast) {
+ showToast(`${instanceName} connection successful: ${modelCount} ${modelType} available (${responseTime}ms)`, 'success');
+ }
+
// Scenario 2: Manual "Test Connection" button - refresh Ollama metrics if Ollama provider is selected
- if (ragSettings.LLM_PROVIDER === 'ollama') {
+ if (ragSettings.LLM_PROVIDER === 'ollama' || embeddingProvider === 'ollama' || context === 'embedding') {
console.log('🔄 Fetching Ollama metrics - Test Connection button clicked');
fetchOllamaMetrics();
}
+
+ return true;
} else {
setStatus({ online: false, responseTime: null, checking: false });
- showToast(`${instanceName} connection failed: ${instanceStatus?.error_message || 'Instance is not healthy'}`, 'error');
+ if (!suppressToast) {
+ showToast(`${instanceName} connection failed: ${instanceStatus?.error_message || 'Instance is not healthy'}`, 'error');
+ }
+ return false;
}
} else {
setStatus({ online: false, responseTime: null, checking: false });
- showToast(`${instanceName} connection failed: Backend proxy error (HTTP ${response.status})`, 'error');
+ if (!suppressToast) {
+ showToast(`${instanceName} connection failed: Backend proxy error (HTTP ${response.status})`, 'error');
+ }
+ return false;
}
} catch (error: any) {
setStatus({ online: false, responseTime: null, checking: false });
-
- if (error.name === 'AbortError') {
- showToast(`${instanceName} connection failed: Request timeout (>15s)`, 'error');
- } else {
- showToast(`${instanceName} connection failed: ${error.message || 'Unknown error'}`, 'error');
+
+ if (!suppressToast) {
+ if (error.name === 'AbortError') {
+ showToast(`${instanceName} connection failed: Request timeout (>15s)`, 'error');
+ } else {
+ showToast(`${instanceName} connection failed: ${error.message || 'Unknown error'}`, 'error');
+ }
}
+
+ return false;
}
- };;
+ };
// Function to handle LLM instance deletion
const handleDeleteLLMInstance = () => {
@@ -546,11 +760,14 @@ export const RAGSettings = ({
try {
setOllamaMetrics(prev => ({ ...prev, loading: true }));
- // Prepare instance URLs for the API call
- const instanceUrls = [];
- if (llmInstanceConfig.url) instanceUrls.push(llmInstanceConfig.url);
- if (embeddingInstanceConfig.url && embeddingInstanceConfig.url !== llmInstanceConfig.url) {
- instanceUrls.push(embeddingInstanceConfig.url);
+ // Prepare normalized instance URLs for the API call
+ const instanceUrls: string[] = [];
+ const llmUrlBase = normalizeBaseUrl(llmInstanceConfig.url);
+ const embUrlBase = normalizeBaseUrl(embeddingInstanceConfig.url);
+
+ if (llmUrlBase) instanceUrls.push(llmUrlBase);
+ if (embUrlBase && embUrlBase !== llmUrlBase) {
+ instanceUrls.push(embUrlBase);
}
if (instanceUrls.length === 0) {
@@ -574,18 +791,18 @@ export const RAGSettings = ({
// Count models for LLM instance
const llmChatModels = allChatModels.filter((model: any) =>
- model.instance_url === llmInstanceConfig.url
+ normalizeBaseUrl(model.instance_url) === llmUrlBase
);
const llmEmbeddingModels = allEmbeddingModels.filter((model: any) =>
- model.instance_url === llmInstanceConfig.url
+ normalizeBaseUrl(model.instance_url) === llmUrlBase
);
-
+
// Count models for Embedding instance
const embChatModels = allChatModels.filter((model: any) =>
- model.instance_url === embeddingInstanceConfig.url
+ normalizeBaseUrl(model.instance_url) === embUrlBase
);
const embEmbeddingModels = allEmbeddingModels.filter((model: any) =>
- model.instance_url === embeddingInstanceConfig.url
+ normalizeBaseUrl(model.instance_url) === embUrlBase
);
// Calculate totals
@@ -624,7 +841,7 @@ export const RAGSettings = ({
// Use refs to prevent infinite connection testing
const lastTestedLLMConfigRef = useRef({ url: '', name: '', provider: '' });
const lastTestedEmbeddingConfigRef = useRef({ url: '', name: '', provider: '' });
- const lastMetricsFetchRef = useRef({ provider: '', llmUrl: '', embUrl: '', llmOnline: false, embOnline: false });
+ const lastMetricsFetchRef = useRef({ provider: '', embProvider: '', llmUrl: '', embUrl: '', llmOnline: false, embOnline: false });
// Auto-testing disabled to prevent API calls on every keystroke per user request
// Connection testing should only happen on manual "Test Connection" or "Save Changes" button clicks
@@ -672,91 +889,106 @@ export const RAGSettings = ({
// }
// }, [embeddingInstanceConfig.url, embeddingInstanceConfig.name, ragSettings.LLM_PROVIDER]);
- // Fetch Ollama metrics only when Ollama provider is initially selected (not on URL changes during typing)
React.useEffect(() => {
- if (ragSettings.LLM_PROVIDER === 'ollama') {
- const currentProvider = ragSettings.LLM_PROVIDER;
- const lastProvider = lastMetricsFetchRef.current.provider;
-
- // Only fetch if provider changed to Ollama (scenario 1: user clicks on Ollama Provider)
- if (currentProvider !== lastProvider) {
- lastMetricsFetchRef.current = {
- provider: currentProvider,
- llmUrl: llmInstanceConfig.url,
- embUrl: embeddingInstanceConfig.url,
- llmOnline: llmStatus.online,
- embOnline: embeddingStatus.online
- };
- console.log('🔄 Fetching Ollama metrics - Provider selected');
- fetchOllamaMetrics();
- }
+ const current = {
+ provider: ragSettings.LLM_PROVIDER,
+ embProvider: embeddingProvider,
+ llmUrl: normalizeBaseUrl(llmInstanceConfig.url) ?? '',
+ embUrl: normalizeBaseUrl(embeddingInstanceConfig.url) ?? '',
+ llmOnline: llmStatus.online,
+ embOnline: embeddingStatus.online,
+ };
+ const last = lastMetricsFetchRef.current;
+
+ const meaningfulChange =
+ current.provider !== last.provider ||
+ current.embProvider !== last.embProvider ||
+ current.llmUrl !== last.llmUrl ||
+ current.embUrl !== last.embUrl ||
+ current.llmOnline !== last.llmOnline ||
+ current.embOnline !== last.embOnline;
+
+ if ((current.provider === 'ollama' || current.embProvider === 'ollama') && meaningfulChange) {
+ lastMetricsFetchRef.current = current;
+ console.log('🔄 Fetching Ollama metrics - state changed');
+ fetchOllamaMetrics();
}
- }, [ragSettings.LLM_PROVIDER]); // Only watch provider changes, not URL changes
+ }, [ragSettings.LLM_PROVIDER, embeddingProvider, llmStatus.online, embeddingStatus.online]);
+
+ const hasApiCredential = (credentialKey: ProviderCredentialKey): boolean => {
+ if (credentialKey in apiCredentials) {
+ return Boolean(apiCredentials[credentialKey]);
+ }
+
+ const fallbackKey = Object.keys(apiCredentials).find(
+ key => key.toUpperCase() === credentialKey,
+ );
+
+ return fallbackKey ? Boolean(apiCredentials[fallbackKey]) : false;
+ };
// Function to check if a provider is properly configured
const getProviderStatus = (providerKey: string): 'configured' | 'missing' | 'partial' => {
switch (providerKey) {
case 'openai':
- // Check if OpenAI API key is configured (case insensitive)
- const openAIKey = Object.keys(apiCredentials).find(key => key.toUpperCase() === 'OPENAI_API_KEY');
- const keyValue = openAIKey ? apiCredentials[openAIKey] : undefined;
- // Don't consider encrypted placeholders as valid API keys for connection testing
- const hasOpenAIKey = openAIKey && keyValue && keyValue.trim().length > 0 && !keyValue.includes('[ENCRYPTED]');
-
+ const hasOpenAIKey = hasApiCredential('OPENAI_API_KEY');
+
// Only show configured if we have both API key AND confirmed connection
const openAIConnected = providerConnectionStatus['openai']?.connected || false;
const isChecking = providerConnectionStatus['openai']?.checking || false;
-
- console.log('🔍 OpenAI status check:', {
- openAIKey,
- keyValue: keyValue ? `${keyValue.substring(0, 10)}...` : keyValue,
- hasValue: !!keyValue,
- hasOpenAIKey,
- openAIConnected,
- isChecking,
- allCredentials: Object.keys(apiCredentials)
- });
-
+
+ // Intentionally avoid logging API key material.
+
if (!hasOpenAIKey) return 'missing';
if (isChecking) return 'partial';
return openAIConnected ? 'configured' : 'missing';
case 'google':
- // Check if Google API key is configured (case insensitive)
- const googleKey = Object.keys(apiCredentials).find(key => key.toUpperCase() === 'GOOGLE_API_KEY');
- const googleKeyValue = googleKey ? apiCredentials[googleKey] : undefined;
- // Don't consider encrypted placeholders as valid API keys for connection testing
- const hasGoogleKey = googleKey && googleKeyValue && googleKeyValue.trim().length > 0 && !googleKeyValue.includes('[ENCRYPTED]');
+ const hasGoogleKey = hasApiCredential('GOOGLE_API_KEY');
// Only show configured if we have both API key AND confirmed connection
const googleConnected = providerConnectionStatus['google']?.connected || false;
const googleChecking = providerConnectionStatus['google']?.checking || false;
-
+
if (!hasGoogleKey) return 'missing';
if (googleChecking) return 'partial';
return googleConnected ? 'configured' : 'missing';
case 'ollama':
- // Check if both LLM and embedding instances are configured and online
- if (llmStatus.online && embeddingStatus.online) return 'configured';
- if (llmStatus.online || embeddingStatus.online) return 'partial';
- return 'missing';
+ {
+ if (ollamaManualConfirmed || llmStatus.online || embeddingStatus.online) {
+ return 'configured';
+ }
+
+ if (ollamaServerStatus === 'online') {
+ return 'partial';
+ }
+
+ if (ollamaServerStatus === 'offline') {
+ return 'missing';
+ }
+
+ return 'missing';
+ }
case 'anthropic':
- // Use server-side connection status
+ const hasAnthropicKey = hasApiCredential('ANTHROPIC_API_KEY');
const anthropicConnected = providerConnectionStatus['anthropic']?.connected || false;
const anthropicChecking = providerConnectionStatus['anthropic']?.checking || false;
+ if (!hasAnthropicKey) return 'missing';
if (anthropicChecking) return 'partial';
return anthropicConnected ? 'configured' : 'missing';
case 'grok':
- // Use server-side connection status
+ const hasGrokKey = hasApiCredential('GROK_API_KEY');
const grokConnected = providerConnectionStatus['grok']?.connected || false;
const grokChecking = providerConnectionStatus['grok']?.checking || false;
+ if (!hasGrokKey) return 'missing';
if (grokChecking) return 'partial';
return grokConnected ? 'configured' : 'missing';
case 'openrouter':
- // Use server-side connection status
+ const hasOpenRouterKey = hasApiCredential('OPENROUTER_API_KEY');
const openRouterConnected = providerConnectionStatus['openrouter']?.connected || false;
const openRouterChecking = providerConnectionStatus['openrouter']?.checking || false;
+ if (!hasOpenRouterKey) return 'missing';
if (openRouterChecking) return 'partial';
return openRouterConnected ? 'configured' : 'missing';
default:
@@ -764,20 +996,147 @@ export const RAGSettings = ({
}
};
- const selectedProviderKey = isProviderKey(ragSettings.LLM_PROVIDER)
- ? (ragSettings.LLM_PROVIDER as ProviderKey)
+ const resolvedProviderForAlert = activeSelection === 'chat' ? chatProvider : embeddingProvider;
+ const activeProviderKey = isProviderKey(resolvedProviderForAlert)
+ ? (resolvedProviderForAlert as ProviderKey)
: undefined;
- const selectedProviderStatus = selectedProviderKey ? getProviderStatus(selectedProviderKey) : undefined;
- const shouldShowProviderAlert = Boolean(
- selectedProviderKey && selectedProviderStatus === 'missing'
- );
- const providerAlertClassName = shouldShowProviderAlert && selectedProviderKey
- ? providerAlertStyles[selectedProviderKey]
- : '';
- const providerAlertMessage = shouldShowProviderAlert && selectedProviderKey
- ? providerAlertMessages[selectedProviderKey]
- : '';
+ const selectedProviderStatus = activeProviderKey ? getProviderStatus(activeProviderKey) : undefined;
+
+ let providerAlertMessage: string | null = null;
+ let providerAlertClassName = '';
+
+ if (activeProviderKey === 'ollama') {
+ if (ollamaServerStatus === 'offline') {
+ providerAlertMessage = 'Local Ollama service is not running. Start the Ollama server and ensure it is reachable at the configured URL.';
+ providerAlertClassName = providerErrorAlertStyle;
+ } else if (selectedProviderStatus === 'partial' && ollamaServerStatus === 'online') {
+ providerAlertMessage = 'Local Ollama service detected. Click "Test Connection" to confirm model availability.';
+ providerAlertClassName = providerWarningAlertStyle;
+ }
+ } else if (activeProviderKey && selectedProviderStatus === 'missing') {
+ const providerName = providerDisplayNames[activeProviderKey] ?? activeProviderKey;
+ providerAlertMessage = `${providerName} API key is not configured. Add it in Settings > API Keys.`;
+ providerAlertClassName = providerMissingAlertStyle;
+ }
+
+ const shouldShowProviderAlert = Boolean(providerAlertMessage);
+ useEffect(() => {
+ if (chatProvider !== 'ollama') {
+ if (llmRetryTimeoutRef.current) {
+ clearTimeout(llmRetryTimeoutRef.current);
+ llmRetryTimeoutRef.current = null;
+ }
+ return;
+ }
+
+ const baseUrl = (
+ ragSettings.LLM_BASE_URL?.trim() ||
+ llmInstanceConfig.url?.trim() ||
+ DEFAULT_OLLAMA_URL
+ );
+
+ if (!baseUrl) {
+ return;
+ }
+
+ const instanceName = llmInstanceConfig.name?.trim().length
+ ? llmInstanceConfig.name
+ : 'LLM Instance';
+
+ let cancelled = false;
+
+ const runTest = async () => {
+ if (cancelled) return;
+
+ const success = await manualTestConnection(
+ baseUrl,
+ setLLMStatus,
+ instanceName,
+ 'chat',
+ { suppressToast: true }
+ );
+
+ if (!success && chatProvider === 'ollama' && !cancelled) {
+ llmRetryTimeoutRef.current = window.setTimeout(runTest, 5000);
+ }
+ };
+
+ if (llmRetryTimeoutRef.current) {
+ clearTimeout(llmRetryTimeoutRef.current);
+ llmRetryTimeoutRef.current = null;
+ }
+
+ setLLMStatus(prev => ({ ...prev, checking: true }));
+ runTest();
+
+ return () => {
+ cancelled = true;
+ if (llmRetryTimeoutRef.current) {
+ clearTimeout(llmRetryTimeoutRef.current);
+ llmRetryTimeoutRef.current = null;
+ }
+ };
+ }, [chatProvider, ragSettings.LLM_BASE_URL, ragSettings.LLM_INSTANCE_NAME, llmInstanceConfig.url, llmInstanceConfig.name]);
+
+ useEffect(() => {
+ if (embeddingProvider !== 'ollama') {
+ if (embeddingRetryTimeoutRef.current) {
+ clearTimeout(embeddingRetryTimeoutRef.current);
+ embeddingRetryTimeoutRef.current = null;
+ }
+ return;
+ }
+
+ const baseUrl = (
+ ragSettings.OLLAMA_EMBEDDING_URL?.trim() ||
+ embeddingInstanceConfig.url?.trim() ||
+ DEFAULT_OLLAMA_URL
+ );
+
+ if (!baseUrl) {
+ return;
+ }
+
+ const instanceName = embeddingInstanceConfig.name?.trim().length
+ ? embeddingInstanceConfig.name
+ : 'Embedding Instance';
+
+ let cancelled = false;
+
+ const runTest = async () => {
+ if (cancelled) return;
+
+ const success = await manualTestConnection(
+ baseUrl,
+ setEmbeddingStatus,
+ instanceName,
+ 'embedding',
+ { suppressToast: true }
+ );
+
+ if (!success && embeddingProvider === 'ollama' && !cancelled) {
+ embeddingRetryTimeoutRef.current = window.setTimeout(runTest, 5000);
+ }
+ };
+
+ if (embeddingRetryTimeoutRef.current) {
+ clearTimeout(embeddingRetryTimeoutRef.current);
+ embeddingRetryTimeoutRef.current = null;
+ }
+
+ setEmbeddingStatus(prev => ({ ...prev, checking: true }));
+ runTest();
+
+ return () => {
+ cancelled = true;
+ if (embeddingRetryTimeoutRef.current) {
+ clearTimeout(embeddingRetryTimeoutRef.current);
+ embeddingRetryTimeoutRef.current = null;
+ }
+ };
+ }, [embeddingProvider, ragSettings.OLLAMA_EMBEDDING_URL, ragSettings.OLLAMA_EMBEDDING_INSTANCE_NAME, embeddingInstanceConfig.url, embeddingInstanceConfig.name]);
+
// Test Ollama connectivity when Settings page loads (scenario 4: page load)
// This useEffect is placed after function definitions to ensure access to manualTestConnection
useEffect(() => {
@@ -792,35 +1151,74 @@ export const RAGSettings = ({
});
// Only run once when data is properly loaded and not run before
- if (!hasRunInitialTestRef.current &&
- ragSettings.LLM_PROVIDER === 'ollama' &&
- Object.keys(ragSettings).length > 0 &&
- (llmInstanceConfig.url || embeddingInstanceConfig.url)) {
+ if (
+ !hasRunInitialTestRef.current &&
+ (ragSettings.LLM_PROVIDER === 'ollama' || embeddingProvider === 'ollama') &&
+ Object.keys(ragSettings).length > 0
+ ) {
hasRunInitialTestRef.current = true;
console.log('🔄 Settings page loaded with Ollama - Testing connectivity');
-
- // Test LLM instance if configured (use URL presence as the key indicator)
- // Only test if URL is explicitly set in ragSettings, not just using the default
- if (llmInstanceConfig.url && ragSettings.LLM_BASE_URL) {
+
+ // Test LLM instance if a URL is available (either saved or default)
+ if (llmInstanceConfig.url) {
setTimeout(() => {
const instanceName = llmInstanceConfig.name || 'LLM Instance';
console.log('🔍 Testing LLM instance on page load:', instanceName, llmInstanceConfig.url);
- manualTestConnection(llmInstanceConfig.url, setLLMStatus, instanceName);
+ manualTestConnection(
+ llmInstanceConfig.url,
+ setLLMStatus,
+ instanceName,
+ 'chat',
+ { suppressToast: true }
+ );
}, 1000); // Increased delay to ensure component is fully ready
}
-
+ // If no saved URL, run tests against default endpoint
+ else {
+ setTimeout(() => {
+ const defaultInstanceName = 'Local Ollama (Default)';
+ console.log('🔍 Testing default Ollama chat instance on page load:', DEFAULT_OLLAMA_URL);
+ manualTestConnection(
+ DEFAULT_OLLAMA_URL,
+ setLLMStatus,
+ defaultInstanceName,
+ 'chat',
+ { suppressToast: true }
+ );
+ }, 1000);
+ }
+
// Test Embedding instance if configured and different from LLM instance
- // Only test if URL is explicitly set in ragSettings, not just using the default
- if (embeddingInstanceConfig.url && ragSettings.OLLAMA_EMBEDDING_URL &&
+ if (embeddingInstanceConfig.url &&
embeddingInstanceConfig.url !== llmInstanceConfig.url) {
setTimeout(() => {
const instanceName = embeddingInstanceConfig.name || 'Embedding Instance';
console.log('🔍 Testing Embedding instance on page load:', instanceName, embeddingInstanceConfig.url);
- manualTestConnection(embeddingInstanceConfig.url, setEmbeddingStatus, instanceName);
+ manualTestConnection(
+ embeddingInstanceConfig.url,
+ setEmbeddingStatus,
+ instanceName,
+ 'embedding',
+ { suppressToast: true }
+ );
}, 1500); // Stagger the tests
}
-
+ // If embedding provider is also Ollama but no specific URL is set, test default as fallback
+ else if (embeddingProvider === 'ollama' && !embeddingInstanceConfig.url) {
+ setTimeout(() => {
+ const defaultEmbeddingName = 'Local Ollama (Default)';
+ console.log('🔍 Testing default Ollama embedding instance on page load:', DEFAULT_OLLAMA_URL);
+ manualTestConnection(
+ DEFAULT_OLLAMA_URL,
+ setEmbeddingStatus,
+ defaultEmbeddingName,
+ 'embedding',
+ { suppressToast: true }
+ );
+ }, 1500);
+ }
+
// Fetch Ollama metrics after testing connections
setTimeout(() => {
console.log('📊 Fetching Ollama metrics on page load');
@@ -838,12 +1236,63 @@ export const RAGSettings = ({
knowledge retrieval.
- {/* Provider Selection - 6 Button Layout */}
+ {/* LLM Provider Settings Header */}
+
+
+ LLM Provider Settings
+
+
+
+ {/* Provider Selection Buttons */}
+
+
setActiveSelection('chat')}
+ variant="ghost"
+ className={`min-w-[180px] px-5 py-3 font-semibold text-white dark:text-white
+ border border-emerald-400/70 dark:border-emerald-400/40
+ bg-black/40 backdrop-blur-md
+ shadow-[inset_0_0_16px_rgba(15,118,110,0.38)]
+ hover:bg-emerald-500/12 dark:hover:bg-emerald-500/20
+ hover:border-emerald-300/80 hover:shadow-[0_0_22px_rgba(16,185,129,0.5)]
+ ${(activeSelection === 'chat')
+ ? 'shadow-[0_0_25px_rgba(16,185,129,0.5)] ring-2 ring-emerald-400/50'
+ : 'shadow-[0_0_15px_rgba(16,185,129,0.25)]'}
+ `}
+ >
+
+
+ Chat: {chatProvider}
+
+
+
setActiveSelection('embedding')}
+ variant="ghost"
+ className={`min-w-[180px] px-5 py-3 font-semibold text-white dark:text-white
+ border border-purple-400/70 dark:border-purple-400/40
+ bg-black/40 backdrop-blur-md
+ shadow-[inset_0_0_16px_rgba(109,40,217,0.38)]
+ hover:bg-purple-500/12 dark:hover:bg-purple-500/20
+ hover:border-purple-300/80 hover:shadow-[0_0_24px_rgba(168,85,247,0.52)]
+ ${(activeSelection === 'embedding')
+ ? 'shadow-[0_0_26px_rgba(168,85,247,0.55)] ring-2 ring-purple-400/60'
+ : 'shadow-[0_0_15px_rgba(168,85,247,0.25)]'}
+ `}
+ >
+
+
+ Embeddings: {embeddingProvider}
+
+
+
+
+ {/* Context-Aware Provider Grid */}
-
+
{[
{ key: 'openai', name: 'OpenAI', logo: '/img/OpenAI.png', color: 'green' },
{ key: 'google', name: 'Google', logo: '/img/google-logo.svg', color: 'blue' },
@@ -851,39 +1300,50 @@ export const RAGSettings = ({
{ key: 'ollama', name: 'Ollama', logo: '/img/Ollama.png', color: 'purple' },
{ key: 'anthropic', name: 'Anthropic', logo: '/img/claude-logo.svg', color: 'orange' },
{ key: 'grok', name: 'Grok', logo: '/img/Grok.png', color: 'yellow' }
- ].map(provider => (
+ ]
+ .filter(provider =>
+ activeSelection === 'chat' || EMBEDDING_CAPABLE_PROVIDERS.includes(provider.key as ProviderKey)
+ )
+ .map(provider => (
-{(() => {
+ {(() => {
const status = getProviderStatus(provider.key);
- const isSelected = ragSettings.LLM_PROVIDER === provider.key;
-
+
if (status === 'configured') {
return (
@@ -919,394 +1378,93 @@ export const RAGSettings = ({
))}
-
- {/* Provider-specific configuration */}
- {ragSettings.LLM_PROVIDER === 'ollama' && (
-
-
-
-
Ollama Configuration
-
Configure separate Ollama instances for LLM and embedding models
-
-
- {(llmStatus.online && embeddingStatus.online) ? "2 / 2 Online" :
- (llmStatus.online || embeddingStatus.online) ? "1 / 2 Online" : "0 / 2 Online"}
-
-
-
- {/* LLM Instance Card */}
-
-
-
-
LLM Instance
-
For chat completions and text generation
-
-
- {llmStatus.checking ? (
- Checking...
- ) : llmStatus.online ? (
- Online ({llmStatus.responseTime}ms)
- ) : (
- Offline
- )}
- {llmInstanceConfig.name && llmInstanceConfig.url && (
-
- )}
-
-
-
-
-
- {llmInstanceConfig.name && llmInstanceConfig.url ? (
- <>
-
-
{llmInstanceConfig.name}
-
{llmInstanceConfig.url}
-
-
-
-
Model:
-
{getDisplayedChatModel(ragSettings)}
-
-
-
- {llmStatus.checking ? (
-
- ) : null}
- {ollamaMetrics.loading ? 'Loading...' : `${ollamaMetrics.llmInstanceModels.total} models available`}
-
- >
- ) : (
-
-
No LLM instance configured
-
Configure an instance to use LLM features
-
- {/* Quick setup for single host users */}
- {!embeddingInstanceConfig.url && (
-
-
-
Sets up both LLM and Embedding for one host
-
- )}
-
-
-
- )}
-
-
- {llmInstanceConfig.name && llmInstanceConfig.url && (
-
-
-
-
-
- )}
-
-
-
- {/* Embedding Instance Card */}
-
-
-
-
Embedding Instance
-
For generating text embeddings and vector search
-
-
- {embeddingStatus.checking ? (
- Checking...
- ) : embeddingStatus.online ? (
- Online ({embeddingStatus.responseTime}ms)
- ) : (
- Offline
- )}
- {embeddingInstanceConfig.name && embeddingInstanceConfig.url && (
-
- )}
-
-
-
-
-
- {embeddingInstanceConfig.name && embeddingInstanceConfig.url ? (
- <>
-
-
{embeddingInstanceConfig.name}
-
{embeddingInstanceConfig.url}
-
-
-
-
Model:
-
{getDisplayedEmbeddingModel(ragSettings)}
-
-
-
- {embeddingStatus.checking ? (
-
- ) : null}
- {ollamaMetrics.loading ? 'Loading...' : `${ollamaMetrics.embeddingInstanceModels.total} models available`}
-
- >
- ) : (
-
-
No Embedding instance configured
-
Configure an instance to use embedding features
-
-
- )}
-
-
- {embeddingInstanceConfig.name && embeddingInstanceConfig.url && (
-
-
-
-
-
- )}
-
-
-
- {/* Single Host Indicator */}
- {llmInstanceConfig.url && embeddingInstanceConfig.url &&
- llmInstanceConfig.url === embeddingInstanceConfig.url && (
-
-
-
-
Single Host Setup
-
-
- Both LLM and Embedding instances are using the same Ollama host ({llmInstanceConfig.name})
-
-
- )}
-
- {/* Configuration Summary */}
-
-
Configuration Summary
-
- {/* Instance Comparison Table */}
-
-
-
-
- | Configuration |
- LLM Instance |
- Embedding Instance |
-
-
-
-
- | Instance Name |
-
- {llmInstanceConfig.name || Not configured}
- |
-
- {embeddingInstanceConfig.name || Not configured}
- |
-
-
- | Status |
-
-
- {llmStatus.checking ? "Checking..." : llmStatus.online ? `Online (${llmStatus.responseTime}ms)` : "Offline"}
-
- |
-
-
- {embeddingStatus.checking ? "Checking..." : embeddingStatus.online ? `Online (${embeddingStatus.responseTime}ms)` : "Offline"}
-
- |
-
-
- | Selected Model |
-
- {getDisplayedChatModel(ragSettings) || No model selected}
- |
-
- {getDisplayedEmbeddingModel(ragSettings) || No model selected}
- |
-
-
- | Available Models |
-
- {ollamaMetrics.loading ? (
-
- ) : (
-
- {ollamaMetrics.llmInstanceModels.total} Total Models
- {ollamaMetrics.llmInstanceModels.total > 0 && (
-
-
- {ollamaMetrics.llmInstanceModels.chat} Chat
-
-
- {ollamaMetrics.llmInstanceModels.embedding} Embedding
-
-
- )}
-
- )}
- |
-
- {ollamaMetrics.loading ? (
-
- ) : (
-
- {ollamaMetrics.embeddingInstanceModels.total} Total Models
- {ollamaMetrics.embeddingInstanceModels.total > 0 && (
-
-
- {ollamaMetrics.embeddingInstanceModels.chat} Chat
-
-
- {ollamaMetrics.embeddingInstanceModels.embedding} Embedding
-
-
- )}
-
- )}
- |
-
-
-
-
- {/* System Readiness Summary */}
-
-
- System Readiness:
-
- {(llmStatus.online && embeddingStatus.online) ? "✓ Ready (Both Instances Online)" :
- (llmStatus.online || embeddingStatus.online) ? "⚠ Partial (1 of 2 Online)" : "✗ Not Ready (No Instances Online)"}
-
-
-
- {/* Overall Model Metrics */}
-
-
-
-
Overall Available:
-
- {ollamaMetrics.loading ? (
-
- ) : (
- `${ollamaMetrics.totalModels} total (${ollamaMetrics.chatModels} chat, ${ollamaMetrics.embeddingModels} embedding)`
- )}
-
-
-
-
-
-
-
- )}
-
{shouldShowProviderAlert && (
)}
-
-
+ )}
+
+ {/* Save Settings Button */}
+
:
}
- className="whitespace-nowrap"
+ className="whitespace-nowrap ml-4"
size="md"
onClick={async () => {
try {
setSaving(true);
-
+
// Ensure instance configurations are synced with ragSettings before saving
const updatedSettings = {
...ragSettings,
@@ -1315,12 +1473,12 @@ export const RAGSettings = ({
OLLAMA_EMBEDDING_URL: embeddingInstanceConfig.url,
OLLAMA_EMBEDDING_INSTANCE_NAME: embeddingInstanceConfig.name
};
-
+
await credentialsService.updateRagSettings(updatedSettings);
-
+
// Update local ragSettings state to match what was saved
setRagSettings(updatedSettings);
-
+
showToast('RAG settings saved successfully!', 'success');
} catch (err) {
console.error('Failed to save RAG settings:', err);
@@ -1334,38 +1492,312 @@ export const RAGSettings = ({
{saving ? 'Saving...' : 'Save Settings'}
+
+ {/* Expandable Ollama Configuration Container */}
+ {showOllamaConfig && ((activeSelection === 'chat' && chatProvider === 'ollama') ||
+ (activeSelection === 'embedding' && embeddingProvider === 'ollama')) && (
+
+
+
+
+ {activeSelection === 'chat' ? 'LLM Chat Configuration' : 'Embedding Configuration'}
+
+
+ {activeSelection === 'chat'
+ ? 'Configure Ollama instance for chat completions'
+ : 'Configure Ollama instance for text embeddings'}
+
+
+
+ {(activeSelection === 'chat' ? llmStatus.online : embeddingStatus.online)
+ ? "Online" : "Offline"}
+
+
+
+ {/* Configuration Content */}
+
+ {activeSelection === 'chat' ? (
+ // Chat Model Configuration
+
+ {llmInstanceConfig.name && llmInstanceConfig.url ? (
+ <>
+
+
{llmInstanceConfig.name}
+
{llmInstanceConfig.url}
+
+
+
+
Model:
+
{getDisplayedChatModel(ragSettings)}
+
+
+
+ {llmStatus.checking ? (
+
+ ) : null}
+ {ollamaMetrics.loading ? 'Loading...' : `${ollamaMetrics.llmInstanceModels?.chat || 0} chat models available`}
+
+
+
+ setShowEditLLMModal(true)}
+ >
+ Edit Settings
+
+ {
+ const success = await manualTestConnection(
+ llmInstanceConfig.url,
+ setLLMStatus,
+ llmInstanceConfig.name,
+ 'chat'
+ );
+
+ setOllamaManualConfirmed(success);
+ setOllamaServerStatus(success ? 'online' : 'offline');
+ }}
+ disabled={llmStatus.checking}
+ >
+ {llmStatus.checking ? 'Testing...' : 'Test Connection'}
+
+ setShowLLMModelSelectionModal(true)}
+ >
+ Select Model
+
+
+ >
+ ) : (
+
+
No LLM instance configured
+
Configure an instance to use LLM chat features
+
setShowEditLLMModal(true)}
+ >
+ Add LLM Instance
+
+
+ )}
+
+ ) : (
+ // Embedding Model Configuration
+
+ {embeddingInstanceConfig.name && embeddingInstanceConfig.url ? (
+ <>
+
+
{embeddingInstanceConfig.name}
+
{embeddingInstanceConfig.url}
+
+
+
+
Model:
+
{getDisplayedEmbeddingModel(ragSettings)}
+
+
+
+ {embeddingStatus.checking ? (
+
+ ) : null}
+ {ollamaMetrics.loading ? 'Loading...' : `${ollamaMetrics.embeddingInstanceModels?.embedding || 0} embedding models available`}
+
+
+
+ setShowEditEmbeddingModal(true)}
+ >
+ Edit Settings
+
+ {
+ const success = await manualTestConnection(
+ embeddingInstanceConfig.url,
+ setEmbeddingStatus,
+ embeddingInstanceConfig.name,
+ 'embedding'
+ );
+
+ setOllamaManualConfirmed(success);
+ setOllamaServerStatus(success ? 'online' : 'offline');
+ }}
+ disabled={embeddingStatus.checking}
+ >
+ {embeddingStatus.checking ? 'Testing...' : 'Test Connection'}
+
+ setShowEmbeddingModelSelectionModal(true)}
+ >
+ Select Model
+
+
+ >
+ ) : (
+
+
No Embedding instance configured
+
Configure an instance to use embedding features
+
setShowEditEmbeddingModal(true)}
+ >
+ Add Embedding Instance
+
+
+ )}
+
+ )}
+
+
+ {/* Context-Aware Configuration Summary */}
+
+
+ {activeSelection === 'chat' ? 'LLM Instance Summary' : 'Embedding Instance Summary'}
+
+
+
+
+
+
+ | Configuration |
+
+ {activeSelection === 'chat' ? 'LLM Instance' : 'Embedding Instance'}
+ |
+
+
+
+
+ | Instance Name |
+
+ {activeSelection === 'chat'
+ ? (llmInstanceConfig.name || Not configured)
+ : (embeddingInstanceConfig.name || Not configured)
+ }
+ |
+
+
+ | Instance URL |
+
+ {activeSelection === 'chat'
+ ? (llmInstanceConfig.url || Not configured)
+ : (embeddingInstanceConfig.url || Not configured)
+ }
+ |
+
+
+ | Status |
+
+ {activeSelection === 'chat' ? (
+
+ {llmStatus.checking ? "Checking..." : llmStatus.online ? `Online (${llmStatus.responseTime}ms)` : "Offline"}
+
+ ) : (
+
+ {embeddingStatus.checking ? "Checking..." : embeddingStatus.online ? `Online (${embeddingStatus.responseTime}ms)` : "Offline"}
+
+ )}
+ |
+
+
+ | Selected Model |
+
+ {activeSelection === 'chat'
+ ? (getDisplayedChatModel(ragSettings) || No model selected)
+ : (getDisplayedEmbeddingModel(ragSettings) || No model selected)
+ }
+ |
+
+
+ | Available Models |
+
+ {ollamaMetrics.loading ? (
+
+ ) : activeSelection === 'chat' ? (
+
+ {ollamaMetrics.llmInstanceModels?.chat || 0}
+ chat models
+
+ ) : (
+
+ {ollamaMetrics.embeddingInstanceModels?.embedding || 0}
+ embedding models
+
+ )}
+ |
+
+
+
+
+ {/* Instance-Specific Readiness */}
+
+
+
+ {activeSelection === 'chat' ? 'LLM Instance Status:' : 'Embedding Instance Status:'}
+
+
+ {activeSelection === 'chat'
+ ? (llmStatus.online ? "✓ Ready" : "✗ Not Ready")
+ : (embeddingStatus.online ? "✓ Ready" : "✗ Not Ready")
+ }
+
+
+
+ {/* Instance-Specific Model Metrics */}
+
+
+
+
Available on this instance:
+
+ {ollamaMetrics.loading ? (
+
+ ) : activeSelection === 'chat' ? (
+ `${ollamaMetrics.llmInstanceModels?.chat || 0} chat models`
+ ) : (
+ `${ollamaMetrics.embeddingInstanceModels?.embedding || 0} embedding models`
+ )}
+
+
+
+
+
+
+
+ )}
- {/* Model Settings Row - Only show for non-Ollama providers */}
- {ragSettings.LLM_PROVIDER !== 'ollama' && (
-
- )}
-
+
{/* Second row: Contextual Embeddings, Max Workers, and description */}
@@ -1778,7 +2210,16 @@ export const RAGSettings = ({
showToast('LLM instance updated successfully', 'success');
// Wait 1 second then automatically test connection and refresh models
setTimeout(() => {
- manualTestConnection(llmInstanceConfig.url, setLLMStatus, llmInstanceConfig.name);
+ manualTestConnection(
+ llmInstanceConfig.url,
+ setLLMStatus,
+ llmInstanceConfig.name,
+ 'chat',
+ { suppressToast: true }
+ ).then((success) => {
+ setOllamaManualConfirmed(success);
+ setOllamaServerStatus(success ? 'online' : 'offline');
+ });
fetchOllamaMetrics(); // Refresh model metrics after saving
}, 1000);
}}
@@ -1829,7 +2270,16 @@ export const RAGSettings = ({
showToast('Embedding instance updated successfully', 'success');
// Wait 1 second then automatically test connection and refresh models
setTimeout(() => {
- manualTestConnection(embeddingInstanceConfig.url, setEmbeddingStatus, embeddingInstanceConfig.name);
+ manualTestConnection(
+ embeddingInstanceConfig.url,
+ setEmbeddingStatus,
+ embeddingInstanceConfig.name,
+ 'embedding',
+ { suppressToast: true }
+ ).then((success) => {
+ setOllamaManualConfirmed(success);
+ setOllamaServerStatus(success ? 'online' : 'offline');
+ });
fetchOllamaMetrics(); // Refresh model metrics after saving
}, 1000);
}}
@@ -1854,7 +2304,7 @@ export const RAGSettings = ({
]}
currentModel={ragSettings.MODEL_CHOICE}
modelType="chat"
- selectedInstanceUrl={llmInstanceConfig.url.replace('/v1', '')}
+ selectedInstanceUrl={normalizeBaseUrl(llmInstanceConfig.url) ?? ''}
onSelectModel={(modelName: string) => {
setRagSettings({ ...ragSettings, MODEL_CHOICE: modelName });
showToast(`Selected LLM model: ${modelName}`, 'success');
@@ -1873,7 +2323,7 @@ export const RAGSettings = ({
]}
currentModel={ragSettings.EMBEDDING_MODEL}
modelType="embedding"
- selectedInstanceUrl={embeddingInstanceConfig.url.replace('/v1', '')}
+ selectedInstanceUrl={normalizeBaseUrl(embeddingInstanceConfig.url) ?? ''}
onSelectModel={(modelName: string) => {
setRagSettings({ ...ragSettings, EMBEDDING_MODEL: modelName });
showToast(`Selected embedding model: ${modelName}`, 'success');
@@ -1907,7 +2357,7 @@ export const RAGSettings = ({
};
// Helper functions to get provider-specific model display
-function getDisplayedChatModel(ragSettings: any): string {
+function getDisplayedChatModel(ragSettings: RAGSettingsProps["ragSettings"]): string {
const provider = ragSettings.LLM_PROVIDER || 'openai';
const modelChoice = ragSettings.MODEL_CHOICE;
@@ -1935,8 +2385,8 @@ function getDisplayedChatModel(ragSettings: any): string {
}
}
-function getDisplayedEmbeddingModel(ragSettings: any): string {
- const provider = ragSettings.LLM_PROVIDER || 'openai';
+function getDisplayedEmbeddingModel(ragSettings: RAGSettingsProps["ragSettings"]): string {
+ const provider = ragSettings.EMBEDDING_PROVIDER || ragSettings.LLM_PROVIDER || 'openai';
const embeddingModel = ragSettings.EMBEDDING_MODEL;
// Always prioritize user input to allow editing
@@ -1964,7 +2414,7 @@ function getDisplayedEmbeddingModel(ragSettings: any): string {
}
// Helper functions for model placeholders
-function getModelPlaceholder(provider: string): string {
+function getModelPlaceholder(provider: ProviderKey): string {
switch (provider) {
case 'openai':
return 'e.g., gpt-4o-mini';
@@ -1983,7 +2433,7 @@ function getModelPlaceholder(provider: string): string {
}
}
-function getEmbeddingPlaceholder(provider: string): string {
+function getEmbeddingPlaceholder(provider: ProviderKey): string {
switch (provider) {
case 'openai':
return 'Default: text-embedding-3-small';
diff --git a/archon-ui-main/src/services/credentialsService.ts b/archon-ui-main/src/services/credentialsService.ts
index f52d9679..b2d2da52 100644
--- a/archon-ui-main/src/services/credentialsService.ts
+++ b/archon-ui-main/src/services/credentialsService.ts
@@ -23,6 +23,7 @@ export interface RagSettings {
OLLAMA_EMBEDDING_URL?: string;
OLLAMA_EMBEDDING_INSTANCE_NAME?: string;
EMBEDDING_MODEL?: string;
+ EMBEDDING_PROVIDER?: string;
// Crawling Performance Settings
CRAWL_BATCH_SIZE?: number;
CRAWL_MAX_CONCURRENT?: number;
@@ -75,6 +76,16 @@ import { getApiUrl } from "../config/api";
class CredentialsService {
private baseUrl = getApiUrl();
+ private notifyCredentialUpdate(keys: string[]): void {
+ if (typeof window === "undefined") {
+ return;
+ }
+
+ window.dispatchEvent(
+ new CustomEvent("archon:credentials-updated", { detail: { keys } })
+ );
+ }
+
private handleCredentialError(error: any, context: string): Error {
const errorMessage = error instanceof Error ? error.message : String(error);
@@ -182,15 +193,16 @@ class CredentialsService {
USE_CONTEXTUAL_EMBEDDINGS: false,
CONTEXTUAL_EMBEDDINGS_MAX_WORKERS: 3,
USE_HYBRID_SEARCH: true,
- USE_AGENTIC_RAG: true,
- USE_RERANKING: true,
- MODEL_CHOICE: "gpt-4.1-nano",
- LLM_PROVIDER: "openai",
- LLM_BASE_URL: "",
- LLM_INSTANCE_NAME: "",
- OLLAMA_EMBEDDING_URL: "",
- OLLAMA_EMBEDDING_INSTANCE_NAME: "",
- EMBEDDING_MODEL: "",
+ USE_AGENTIC_RAG: true,
+ USE_RERANKING: true,
+ MODEL_CHOICE: "gpt-4.1-nano",
+ LLM_PROVIDER: "openai",
+ LLM_BASE_URL: "",
+ LLM_INSTANCE_NAME: "",
+ OLLAMA_EMBEDDING_URL: "",
+ OLLAMA_EMBEDDING_INSTANCE_NAME: "",
+ EMBEDDING_PROVIDER: "openai",
+ EMBEDDING_MODEL: "",
// Crawling Performance Settings defaults
CRAWL_BATCH_SIZE: 50,
CRAWL_MAX_CONCURRENT: 10,
@@ -221,6 +233,7 @@ class CredentialsService {
"LLM_INSTANCE_NAME",
"OLLAMA_EMBEDDING_URL",
"OLLAMA_EMBEDDING_INSTANCE_NAME",
+ "EMBEDDING_PROVIDER",
"EMBEDDING_MODEL",
"CRAWL_WAIT_STRATEGY",
].includes(cred.key)
@@ -278,7 +291,9 @@ class CredentialsService {
throw new Error(`HTTP ${response.status}: ${errorText}`);
}
- return response.json();
+ const updated = await response.json();
+ this.notifyCredentialUpdate([credential.key]);
+ return updated;
} catch (error) {
throw this.handleCredentialError(
error,
@@ -302,7 +317,9 @@ class CredentialsService {
throw new Error(`HTTP ${response.status}: ${errorText}`);
}
- return response.json();
+ const created = await response.json();
+ this.notifyCredentialUpdate([credential.key]);
+ return created;
} catch (error) {
throw this.handleCredentialError(
error,
@@ -321,6 +338,8 @@ class CredentialsService {
const errorText = await response.text();
throw new Error(`HTTP ${response.status}: ${errorText}`);
}
+
+ this.notifyCredentialUpdate([key]);
} catch (error) {
throw this.handleCredentialError(error, `Deleting credential '${key}'`);
}
diff --git a/migration/0.1.0/009_add_provider_placeholders.sql b/migration/0.1.0/009_add_provider_placeholders.sql
new file mode 100644
index 00000000..85d526e6
--- /dev/null
+++ b/migration/0.1.0/009_add_provider_placeholders.sql
@@ -0,0 +1,18 @@
+-- Migration: 009_add_provider_placeholders.sql
+-- Description: Add placeholder API key rows for OpenRouter, Anthropic, and Grok
+-- Version: 0.1.0
+-- Author: Archon Team
+-- Date: 2025
+
+-- Insert provider API key placeholders (idempotent)
+INSERT INTO archon_settings (key, encrypted_value, is_encrypted, category, description)
+VALUES
+ ('OPENROUTER_API_KEY', NULL, true, 'api_keys', 'OpenRouter API key for hosted community models. Get from: https://openrouter.ai/keys'),
+ ('ANTHROPIC_API_KEY', NULL, true, 'api_keys', 'Anthropic API key for Claude models. Get from: https://console.anthropic.com/account/keys'),
+ ('GROK_API_KEY', NULL, true, 'api_keys', 'Grok API key for xAI models. Get from: https://console.x.ai/')
+ON CONFLICT (key) DO NOTHING;
+
+-- Record migration application for tracking
+INSERT INTO archon_migrations (version, migration_name)
+VALUES ('0.1.0', '009_add_provider_placeholders')
+ON CONFLICT (version, migration_name) DO NOTHING;
diff --git a/migration/complete_setup.sql b/migration/complete_setup.sql
index 1609060c..801b07b4 100644
--- a/migration/complete_setup.sql
+++ b/migration/complete_setup.sql
@@ -100,7 +100,10 @@ ON CONFLICT (key) DO NOTHING;
-- Add provider API key placeholders
INSERT INTO archon_settings (key, encrypted_value, is_encrypted, category, description) VALUES
-('GOOGLE_API_KEY', NULL, true, 'api_keys', 'Google API Key for Gemini models. Get from: https://aistudio.google.com/apikey')
+('GOOGLE_API_KEY', NULL, true, 'api_keys', 'Google API key for Gemini models. Get from: https://aistudio.google.com/apikey'),
+('OPENROUTER_API_KEY', NULL, true, 'api_keys', 'OpenRouter API key for hosted community models. Get from: https://openrouter.ai/keys'),
+('ANTHROPIC_API_KEY', NULL, true, 'api_keys', 'Anthropic API key for Claude models. Get from: https://console.anthropic.com/account/keys'),
+('GROK_API_KEY', NULL, true, 'api_keys', 'Grok API key for xAI models. Get from: https://console.x.ai/')
ON CONFLICT (key) DO NOTHING;
-- Code Extraction Settings Migration
diff --git a/python/src/server/api_routes/knowledge_api.py b/python/src/server/api_routes/knowledge_api.py
index 1f26dace..47a3d9db 100644
--- a/python/src/server/api_routes/knowledge_api.py
+++ b/python/src/server/api_routes/knowledge_api.py
@@ -1288,7 +1288,7 @@ async def stop_crawl_task(progress_id: str):
found = False
# Step 1: Cancel the orchestration service
- orchestration = get_active_orchestration(progress_id)
+ orchestration = await get_active_orchestration(progress_id)
if orchestration:
orchestration.cancel()
found = True
@@ -1306,7 +1306,7 @@ async def stop_crawl_task(progress_id: str):
found = True
# Step 3: Remove from active orchestrations registry
- unregister_orchestration(progress_id)
+ await unregister_orchestration(progress_id)
# Step 4: Update progress tracker to reflect cancellation (only if we found and cancelled something)
if found:
diff --git a/python/src/server/services/crawling/code_extraction_service.py b/python/src/server/services/crawling/code_extraction_service.py
index 1a540f57..b1705b02 100644
--- a/python/src/server/services/crawling/code_extraction_service.py
+++ b/python/src/server/services/crawling/code_extraction_service.py
@@ -140,6 +140,7 @@ class CodeExtractionService:
progress_callback: Callable | None = None,
cancellation_check: Callable[[], None] | None = None,
provider: str | None = None,
+ embedding_provider: str | None = None,
) -> int:
"""
Extract code examples from crawled documents and store them.
@@ -150,6 +151,8 @@ class CodeExtractionService:
source_id: The unique source_id for all documents
progress_callback: Optional async callback for progress updates
cancellation_check: Optional function to check for cancellation
+ provider: Optional LLM provider identifier for summary generation
+ embedding_provider: Optional embedding provider override for vector creation
Returns:
Number of code examples stored
@@ -158,9 +161,16 @@ class CodeExtractionService:
extraction_callback = None
if progress_callback:
async def extraction_progress(data: dict):
- # Scale progress to 0-20% range
- raw_progress = data.get("progress", 0)
- scaled_progress = int(raw_progress * 0.2) # 0-20%
+ # Scale progress to 0-20% range with normalization similar to later phases
+ raw = data.get("progress", data.get("percentage", 0))
+ try:
+ raw_num = float(raw)
+ except (TypeError, ValueError):
+ raw_num = 0.0
+ if 0.0 <= raw_num <= 1.0:
+ raw_num *= 100.0
+ # 0-20% with clamping
+ scaled_progress = min(20, max(0, int(raw_num * 0.2)))
data["progress"] = scaled_progress
await progress_callback(data)
extraction_callback = extraction_progress
@@ -197,8 +207,15 @@ class CodeExtractionService:
if progress_callback:
async def summary_progress(data: dict):
# Scale progress to 20-90% range
- raw_progress = data.get("progress", 0)
- scaled_progress = 20 + int(raw_progress * 0.7) # 20-90%
+ raw = data.get("progress", data.get("percentage", 0))
+ try:
+ raw_num = float(raw)
+ except (TypeError, ValueError):
+ raw_num = 0.0
+ if 0.0 <= raw_num <= 1.0:
+ raw_num *= 100.0
+ # 20-90% with clamping
+ scaled_progress = min(90, max(20, 20 + int(raw_num * 0.7)))
data["progress"] = scaled_progress
await progress_callback(data)
summary_callback = summary_progress
@@ -216,15 +233,26 @@ class CodeExtractionService:
if progress_callback:
async def storage_progress(data: dict):
# Scale progress to 90-100% range
- raw_progress = data.get("progress", 0)
- scaled_progress = 90 + int(raw_progress * 0.1) # 90-100%
+ raw = data.get("progress", data.get("percentage", 0))
+ try:
+ raw_num = float(raw)
+ except (TypeError, ValueError):
+ raw_num = 0.0
+ if 0.0 <= raw_num <= 1.0:
+ raw_num *= 100.0
+ # 90-100% with clamping
+ scaled_progress = min(100, max(90, 90 + int(raw_num * 0.1)))
data["progress"] = scaled_progress
await progress_callback(data)
storage_callback = storage_progress
# Store code examples in database
return await self._store_code_examples(
- storage_data, url_to_full_document, storage_callback, provider
+ storage_data,
+ url_to_full_document,
+ storage_callback,
+ provider,
+ embedding_provider,
)
async def _extract_code_blocks_from_documents(
@@ -880,9 +908,20 @@ class CodeExtractionService:
current_indent = indent
block_start_idx = i
current_block.append(line)
- elif current_block and len("\n".join(current_block)) >= min_length:
+ elif current_block:
+ block_text = "\n".join(current_block)
+ threshold = (
+ min_length
+ if min_length is not None
+ else await self._get_min_code_length()
+ )
+ if len(block_text) < threshold:
+ current_block = []
+ current_indent = None
+ continue
+
# End of indented block, check if it's code
- code_content = "\n".join(current_block)
+ code_content = block_text
# Try to detect language from content
language = self._detect_language_from_content(code_content)
@@ -1670,12 +1709,20 @@ class CodeExtractionService:
url_to_full_document: dict[str, str],
progress_callback: Callable | None = None,
provider: str | None = None,
+ embedding_provider: str | None = None,
) -> int:
"""
Store code examples in the database.
Returns:
Number of code examples stored
+
+ Args:
+ storage_data: Prepared code example payloads
+ url_to_full_document: Mapping of URLs to their full document content
+ progress_callback: Optional callback for progress updates
+ provider: Optional LLM provider identifier for summaries
+ embedding_provider: Optional embedding provider override for vector storage
"""
# Create progress callback for storage phase
storage_progress_callback = None
@@ -1713,6 +1760,7 @@ class CodeExtractionService:
url_to_full_document=url_to_full_document,
progress_callback=storage_progress_callback,
provider=provider,
+ embedding_provider=embedding_provider,
)
# Report completion of code extraction/storage phase
diff --git a/python/src/server/services/crawling/crawling_service.py b/python/src/server/services/crawling/crawling_service.py
index 69c65719..82a98c0c 100644
--- a/python/src/server/services/crawling/crawling_service.py
+++ b/python/src/server/services/crawling/crawling_service.py
@@ -14,6 +14,7 @@ from typing import Any, Optional
from ...config.logfire_config import get_logger, safe_logfire_error, safe_logfire_info
from ...utils import get_supabase_client
from ...utils.progress.progress_tracker import ProgressTracker
+from ..credential_service import credential_service
# Import strategies
# Import operations
@@ -32,22 +33,35 @@ logger = get_logger(__name__)
# Global registry to track active orchestration services for cancellation support
_active_orchestrations: dict[str, "CrawlingService"] = {}
+_orchestration_lock: asyncio.Lock | None = None
-def get_active_orchestration(progress_id: str) -> Optional["CrawlingService"]:
+def _ensure_orchestration_lock() -> asyncio.Lock:
+ global _orchestration_lock
+ if _orchestration_lock is None:
+ _orchestration_lock = asyncio.Lock()
+ return _orchestration_lock
+
+
+async def get_active_orchestration(progress_id: str) -> Optional["CrawlingService"]:
"""Get an active orchestration service by progress ID."""
- return _active_orchestrations.get(progress_id)
+ lock = _ensure_orchestration_lock()
+ async with lock:
+ return _active_orchestrations.get(progress_id)
-def register_orchestration(progress_id: str, orchestration: "CrawlingService"):
+async def register_orchestration(progress_id: str, orchestration: "CrawlingService"):
"""Register an active orchestration service."""
- _active_orchestrations[progress_id] = orchestration
+ lock = _ensure_orchestration_lock()
+ async with lock:
+ _active_orchestrations[progress_id] = orchestration
-def unregister_orchestration(progress_id: str):
+async def unregister_orchestration(progress_id: str):
"""Unregister an orchestration service."""
- if progress_id in _active_orchestrations:
- del _active_orchestrations[progress_id]
+ lock = _ensure_orchestration_lock()
+ async with lock:
+ _active_orchestrations.pop(progress_id, None)
class CrawlingService:
@@ -246,7 +260,7 @@ class CrawlingService:
# Register this orchestration service for cancellation support
if self.progress_id:
- register_orchestration(self.progress_id, self)
+ await register_orchestration(self.progress_id, self)
# Start the crawl as an async task in the main event loop
# Store the task reference for proper cancellation
@@ -477,15 +491,27 @@ class CrawlingService:
try:
# Extract provider from request or use credential service default
provider = request.get("provider")
+ embedding_provider = None
+
if not provider:
try:
- from ..credential_service import credential_service
provider_config = await credential_service.get_active_provider("llm")
provider = provider_config.get("provider", "openai")
except Exception as e:
- logger.warning(f"Failed to get provider from credential service: {e}, defaulting to openai")
+ logger.warning(
+ f"Failed to get provider from credential service: {e}, defaulting to openai"
+ )
provider = "openai"
+ try:
+ embedding_config = await credential_service.get_active_provider("embedding")
+ embedding_provider = embedding_config.get("provider")
+ except Exception as e:
+ logger.warning(
+ f"Failed to get embedding provider from credential service: {e}. Using configured default."
+ )
+ embedding_provider = None
+
code_examples_count = await self.doc_storage_ops.extract_and_store_code_examples(
crawl_results,
storage_results["url_to_full_document"],
@@ -493,6 +519,7 @@ class CrawlingService:
code_progress_callback,
self._check_cancellation,
provider,
+ embedding_provider,
)
except RuntimeError as e:
# Code extraction failed, continue crawl with warning
@@ -548,7 +575,7 @@ class CrawlingService:
# Unregister after successful completion
if self.progress_id:
- unregister_orchestration(self.progress_id)
+ await unregister_orchestration(self.progress_id)
safe_logfire_info(
f"Unregistered orchestration service after completion | progress_id={self.progress_id}"
)
@@ -567,7 +594,7 @@ class CrawlingService:
)
# Unregister on cancellation
if self.progress_id:
- unregister_orchestration(self.progress_id)
+ await unregister_orchestration(self.progress_id)
safe_logfire_info(
f"Unregistered orchestration service on cancellation | progress_id={self.progress_id}"
)
@@ -591,7 +618,7 @@ class CrawlingService:
await self.progress_tracker.error(error_message)
# Unregister on error
if self.progress_id:
- unregister_orchestration(self.progress_id)
+ await unregister_orchestration(self.progress_id)
safe_logfire_info(
f"Unregistered orchestration service on error | progress_id={self.progress_id}"
)
diff --git a/python/src/server/services/crawling/document_storage_operations.py b/python/src/server/services/crawling/document_storage_operations.py
index 88ed8e80..8bfa4560 100644
--- a/python/src/server/services/crawling/document_storage_operations.py
+++ b/python/src/server/services/crawling/document_storage_operations.py
@@ -352,6 +352,7 @@ class DocumentStorageOperations:
progress_callback: Callable | None = None,
cancellation_check: Callable[[], None] | None = None,
provider: str | None = None,
+ embedding_provider: str | None = None,
) -> int:
"""
Extract code examples from crawled documents and store them.
@@ -363,12 +364,19 @@ class DocumentStorageOperations:
progress_callback: Optional callback for progress updates
cancellation_check: Optional function to check for cancellation
provider: Optional LLM provider to use for code summaries
+ embedding_provider: Optional embedding provider override for code example embeddings
Returns:
Number of code examples stored
"""
result = await self.code_extraction_service.extract_and_store_code_examples(
- crawl_results, url_to_full_document, source_id, progress_callback, cancellation_check, provider
+ crawl_results,
+ url_to_full_document,
+ source_id,
+ progress_callback,
+ cancellation_check,
+ provider,
+ embedding_provider,
)
return result
diff --git a/python/src/server/services/credential_service.py b/python/src/server/services/credential_service.py
index 62fbb47a..a8aee849 100644
--- a/python/src/server/services/credential_service.py
+++ b/python/src/server/services/credential_service.py
@@ -36,42 +36,6 @@ class CredentialItem:
description: str | None = None
-def _detect_embedding_provider_from_model(embedding_model: str) -> str:
- """
- Detect the appropriate embedding provider based on model name.
-
- Args:
- embedding_model: The embedding model name
-
- Returns:
- Provider name: 'google', 'openai', or 'openai' (default)
- """
- if not embedding_model:
- return "openai" # Default
-
- model_lower = embedding_model.lower()
-
- # Google embedding models
- google_patterns = [
- "text-embedding-004",
- "text-embedding-005",
- "text-multilingual-embedding",
- "gemini-embedding",
- "multimodalembedding"
- ]
-
- if any(pattern in model_lower for pattern in google_patterns):
- return "google"
-
- # OpenAI embedding models (and default for unknown)
- openai_patterns = [
- "text-embedding-ada-002",
- "text-embedding-3-small",
- "text-embedding-3-large"
- ]
-
- # Default to OpenAI for OpenAI models or unknown models
- return "openai"
class CredentialService:
@@ -475,26 +439,24 @@ class CredentialService:
# Get the selected provider based on service type
if service_type == "embedding":
- # Get the LLM provider setting to determine embedding provider
- llm_provider = rag_settings.get("LLM_PROVIDER", "openai")
- embedding_model = rag_settings.get("EMBEDDING_MODEL", "text-embedding-3-small")
+ # First check for explicit EMBEDDING_PROVIDER setting (new split provider approach)
+ explicit_embedding_provider = rag_settings.get("EMBEDDING_PROVIDER")
- # Determine embedding provider based on LLM provider
- if llm_provider == "google":
- provider = "google"
- elif llm_provider == "ollama":
- provider = "ollama"
- elif llm_provider == "openrouter":
- # OpenRouter supports both OpenAI and Google embedding models
- provider = _detect_embedding_provider_from_model(embedding_model)
- elif llm_provider in ["anthropic", "grok"]:
- # Anthropic and Grok support both OpenAI and Google embedding models
- provider = _detect_embedding_provider_from_model(embedding_model)
+ # Validate that embedding provider actually supports embeddings
+ embedding_capable_providers = {"openai", "google", "ollama"}
+
+ if (explicit_embedding_provider and
+ explicit_embedding_provider != "" and
+ explicit_embedding_provider in embedding_capable_providers):
+ # Use the explicitly set embedding provider
+ provider = explicit_embedding_provider
+ logger.debug(f"Using explicit embedding provider: '{provider}'")
else:
- # Default case (openai, or unknown providers)
+ # Fall back to OpenAI as default embedding provider for backward compatibility
+ if explicit_embedding_provider and explicit_embedding_provider not in embedding_capable_providers:
+ logger.warning(f"Invalid embedding provider '{explicit_embedding_provider}' doesn't support embeddings, defaulting to OpenAI")
provider = "openai"
-
- logger.debug(f"Determined embedding provider '{provider}' from LLM provider '{llm_provider}' and embedding model '{embedding_model}'")
+ logger.debug(f"No explicit embedding provider set, defaulting to OpenAI for backward compatibility")
else:
provider = rag_settings.get("LLM_PROVIDER", "openai")
# Ensure provider is a valid string, not a boolean or other type
diff --git a/python/src/server/services/embeddings/embedding_service.py b/python/src/server/services/embeddings/embedding_service.py
index 4f825f1d..87ce390b 100644
--- a/python/src/server/services/embeddings/embedding_service.py
+++ b/python/src/server/services/embeddings/embedding_service.py
@@ -5,15 +5,19 @@ Handles all OpenAI embedding operations with proper rate limiting and error hand
"""
import asyncio
+import inspect
import os
+from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Any
+import httpx
+import numpy as np
import openai
from ...config.logfire_config import safe_span, search_logger
from ..credential_service import credential_service
-from ..llm_provider_service import get_embedding_model, get_llm_client, is_google_embedding_model, is_openai_embedding_model
+from ..llm_provider_service import get_embedding_model, get_llm_client
from ..threading_service import get_threading_service
from .embedding_exceptions import (
EmbeddingAPIError,
@@ -64,6 +68,167 @@ class EmbeddingBatchResult:
return self.success_count + self.failure_count
+class EmbeddingProviderAdapter(ABC):
+ """Adapter interface for embedding providers."""
+
+ @abstractmethod
+ async def create_embeddings(
+ self,
+ texts: list[str],
+ model: str,
+ dimensions: int | None = None,
+ ) -> list[list[float]]:
+ """Create embeddings for the given texts."""
+
+
+class OpenAICompatibleEmbeddingAdapter(EmbeddingProviderAdapter):
+ """Adapter for providers using the OpenAI embeddings API shape."""
+
+ def __init__(self, client: Any):
+ self._client = client
+
+ async def create_embeddings(
+ self,
+ texts: list[str],
+ model: str,
+ dimensions: int | None = None,
+ ) -> list[list[float]]:
+ request_args: dict[str, Any] = {
+ "model": model,
+ "input": texts,
+ }
+ if dimensions is not None:
+ request_args["dimensions"] = dimensions
+
+ response = await self._client.embeddings.create(**request_args)
+ return [item.embedding for item in response.data]
+
+
+class GoogleEmbeddingAdapter(EmbeddingProviderAdapter):
+ """Adapter for Google's native embedding endpoint."""
+
+ async def create_embeddings(
+ self,
+ texts: list[str],
+ model: str,
+ dimensions: int | None = None,
+ ) -> list[list[float]]:
+ try:
+ google_api_key = await credential_service.get_credential("GOOGLE_API_KEY")
+ if not google_api_key:
+ raise EmbeddingAPIError("Google API key not found")
+
+ async with httpx.AsyncClient(timeout=30.0) as http_client:
+ embeddings = await asyncio.gather(
+ *(
+ self._fetch_single_embedding(http_client, google_api_key, model, text, dimensions)
+ for text in texts
+ )
+ )
+
+ return embeddings
+
+ except httpx.HTTPStatusError as error:
+ error_content = error.response.text
+ search_logger.error(
+ f"Google embedding API returned {error.response.status_code} - {error_content}",
+ exc_info=True,
+ )
+ raise EmbeddingAPIError(
+ f"Google embedding API error: {error.response.status_code} - {error_content}",
+ original_error=error,
+ ) from error
+ except Exception as error:
+ search_logger.error(f"Error calling Google embedding API: {error}", exc_info=True)
+ raise EmbeddingAPIError(
+ f"Google embedding error: {str(error)}", original_error=error
+ ) from error
+
+ async def _fetch_single_embedding(
+ self,
+ http_client: httpx.AsyncClient,
+ api_key: str,
+ model: str,
+ text: str,
+ dimensions: int | None = None,
+ ) -> list[float]:
+ if model.startswith("models/"):
+ url_model = model[len("models/") :]
+ payload_model = model
+ else:
+ url_model = model
+ payload_model = f"models/{model}"
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/{url_model}:embedContent"
+ headers = {
+ "x-goog-api-key": api_key,
+ "Content-Type": "application/json",
+ }
+ payload = {
+ "model": payload_model,
+ "content": {"parts": [{"text": text}]},
+ }
+
+ # Add output_dimensionality parameter if dimensions are specified and supported
+ if dimensions is not None and dimensions > 0:
+ model_name = payload_model.removeprefix("models/")
+ if model_name.startswith("textembedding-gecko"):
+ supported_dimensions = {128, 256, 512, 768}
+ else:
+ supported_dimensions = {128, 256, 512, 768, 1024, 1536, 2048, 3072}
+
+ if dimensions in supported_dimensions:
+ payload["outputDimensionality"] = dimensions
+ else:
+ search_logger.warning(
+ f"Requested dimension {dimensions} is not supported by Google model '{model_name}'. "
+ "Falling back to the provider default."
+ )
+
+ response = await http_client.post(url, headers=headers, json=payload)
+ response.raise_for_status()
+
+ result = response.json()
+ embedding = result.get("embedding", {})
+ values = embedding.get("values") if isinstance(embedding, dict) else None
+ if not isinstance(values, list):
+ raise EmbeddingAPIError(f"Invalid embedding payload from Google: {result}")
+
+ # Normalize embeddings for dimensions < 3072 as per Google's documentation
+ actual_dimension = len(values)
+ if actual_dimension > 0 and actual_dimension < 3072:
+ values = self._normalize_embedding(values)
+
+ return values
+
+ def _normalize_embedding(self, embedding: list[float]) -> list[float]:
+ """Normalize embedding vector for dimensions < 3072."""
+ try:
+ embedding_array = np.array(embedding, dtype=np.float32)
+ norm = np.linalg.norm(embedding_array)
+ if norm > 0:
+ normalized = embedding_array / norm
+ return normalized.tolist()
+ else:
+ search_logger.warning("Zero-norm embedding detected, returning unnormalized")
+ return embedding
+ except Exception as e:
+ search_logger.error(f"Failed to normalize embedding: {e}")
+ # Return original embedding if normalization fails
+ return embedding
+
+
+def _get_embedding_adapter(provider: str, client: Any) -> EmbeddingProviderAdapter:
+ provider_name = (provider or "").lower()
+ if provider_name == "google":
+ return GoogleEmbeddingAdapter()
+ return OpenAICompatibleEmbeddingAdapter(client)
+
+
+async def _maybe_await(value: Any) -> Any:
+ """Await the value if it is awaitable, otherwise return as-is."""
+
+ return await value if inspect.isawaitable(value) else value
+
# Provider-aware client factory
get_openai_client = get_llm_client
@@ -185,27 +350,25 @@ async def create_embeddings_batch(
"create_embeddings_batch", text_count=len(texts), total_chars=sum(len(t) for t in texts)
) as span:
try:
- # Intelligent embedding provider routing based on model type
- # Get the embedding model first to determine the correct provider
- embedding_model = await get_embedding_model(provider=provider)
+ embedding_config = await _maybe_await(
+ credential_service.get_active_provider(service_type="embedding")
+ )
- # Route to correct provider based on model type
- if is_google_embedding_model(embedding_model):
- embedding_provider = "google"
- search_logger.info(f"Routing to Google for embedding model: {embedding_model}")
- elif is_openai_embedding_model(embedding_model) or "openai/" in embedding_model.lower():
+ embedding_provider = provider or embedding_config.get("provider")
+
+ if not isinstance(embedding_provider, str) or not embedding_provider.strip():
embedding_provider = "openai"
- search_logger.info(f"Routing to OpenAI for embedding model: {embedding_model}")
- else:
- # Keep original provider for ollama and other providers
- embedding_provider = provider
- search_logger.info(f"Using original provider '{provider}' for embedding model: {embedding_model}")
+ if not embedding_provider:
+ search_logger.error("No embedding provider configured")
+ raise ValueError("No embedding provider configured. Please set EMBEDDING_PROVIDER environment variable.")
+
+ search_logger.info(f"Using embedding provider: '{embedding_provider}' (from EMBEDDING_PROVIDER setting)")
async with get_llm_client(provider=embedding_provider, use_embedding_provider=True) as client:
# Load batch size and dimensions from settings
try:
- rag_settings = await credential_service.get_credentials_by_category(
- "rag_strategy"
+ rag_settings = await _maybe_await(
+ credential_service.get_credentials_by_category("rag_strategy")
)
batch_size = int(rag_settings.get("EMBEDDING_BATCH_SIZE", "100"))
embedding_dimensions = int(rag_settings.get("EMBEDDING_DIMENSIONS", "1536"))
@@ -215,6 +378,8 @@ async def create_embeddings_batch(
embedding_dimensions = 1536
total_tokens_used = 0
+ adapter = _get_embedding_adapter(embedding_provider, client)
+ dimensions_to_use = embedding_dimensions if embedding_dimensions > 0 else None
for i in range(0, len(texts), batch_size):
batch = texts[i : i + batch_size]
@@ -243,16 +408,14 @@ async def create_embeddings_batch(
try:
# Create embeddings for this batch
embedding_model = await get_embedding_model(provider=embedding_provider)
-
- response = await client.embeddings.create(
- model=embedding_model,
- input=batch,
- dimensions=embedding_dimensions,
+ embeddings = await adapter.create_embeddings(
+ batch,
+ embedding_model,
+ dimensions=dimensions_to_use,
)
- # Add successful embeddings
- for text, item in zip(batch, response.data, strict=False):
- result.add_success(item.embedding, text)
+ for text, vector in zip(batch, embeddings, strict=False):
+ result.add_success(vector, text)
break # Success, exit retry loop
@@ -297,6 +460,17 @@ async def create_embeddings_batch(
await asyncio.sleep(wait_time)
else:
raise # Will be caught by outer try
+ except EmbeddingRateLimitError as e:
+ retry_count += 1
+ if retry_count < max_retries:
+ wait_time = 2**retry_count
+ search_logger.warning(
+ f"Embedding rate limit for batch {batch_index}: {e}. "
+ f"Waiting {wait_time}s before retry {retry_count}/{max_retries}"
+ )
+ await asyncio.sleep(wait_time)
+ else:
+ raise
except Exception as e:
# This batch failed - track failures but continue with next batch
diff --git a/python/src/server/services/storage/code_storage_service.py b/python/src/server/services/storage/code_storage_service.py
index a993bc70..8e237f7e 100644
--- a/python/src/server/services/storage/code_storage_service.py
+++ b/python/src/server/services/storage/code_storage_service.py
@@ -1091,6 +1091,7 @@ async def add_code_examples_to_supabase(
url_to_full_document: dict[str, str] | None = None,
progress_callback: Callable | None = None,
provider: str | None = None,
+ embedding_provider: str | None = None,
):
"""
Add code examples to the Supabase code_examples table in batches.
@@ -1105,6 +1106,8 @@ async def add_code_examples_to_supabase(
batch_size: Size of each batch for insertion
url_to_full_document: Optional mapping of URLs to full document content
progress_callback: Optional async callback for progress updates
+ provider: Optional LLM provider used for summary generation tracking
+ embedding_provider: Optional embedding provider override for vector generation
"""
if not urls:
return
@@ -1183,8 +1186,8 @@ async def add_code_examples_to_supabase(
# Use original combined texts
batch_texts = combined_texts
- # Create embeddings for the batch
- result = await create_embeddings_batch(batch_texts, provider=provider)
+ # Create embeddings for the batch (optionally overriding the embedding provider)
+ result = await create_embeddings_batch(batch_texts, provider=embedding_provider)
# Log any failures
if result.has_failures:
@@ -1201,7 +1204,7 @@ async def add_code_examples_to_supabase(
from ..llm_provider_service import get_embedding_model
# Get embedding model name
- embedding_model_name = await get_embedding_model(provider=provider)
+ embedding_model_name = await get_embedding_model(provider=embedding_provider)
# Get LLM chat model (used for code summaries and contextual embeddings if enabled)
llm_chat_model = None
diff --git a/python/tests/test_code_extraction_source_id.py b/python/tests/test_code_extraction_source_id.py
index 05405ee7..7899c7fc 100644
--- a/python/tests/test_code_extraction_source_id.py
+++ b/python/tests/test_code_extraction_source_id.py
@@ -111,8 +111,8 @@ class TestCodeExtractionSourceId:
assert args[2] == source_id
assert args[3] is None
assert args[4] is None
- if len(args) > 5:
- assert args[5] is None
+ assert args[5] is None
+ assert args[6] is None
assert result == 5
@pytest.mark.asyncio