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)]'} + `} + > + + + + 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)]'} + `} + > + + + +
+ + {/* 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 */} -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ConfigurationLLM InstanceEmbedding 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 && (

{providerAlertMessage}

)} -
- + )} + + {/* Save Settings Button */} +
+ + {/* 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`} +
+ +
+ + + +
+ + ) : ( +
+
No LLM instance configured
+
Configure an instance to use LLM chat features
+ +
+ )} +
+ ) : ( + // 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`} +
+ +
+ + + +
+ + ) : ( +
+
No Embedding instance configured
+
Configure an instance to use embedding features
+ +
+ )} +
+ )} +
+ + {/* 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' && ( -
-
- setRagSettings({ - ...ragSettings, - MODEL_CHOICE: e.target.value - })} - placeholder={getModelPlaceholder(ragSettings.LLM_PROVIDER || 'openai')} - accentColor="green" - /> -
-
- setRagSettings({ - ...ragSettings, - EMBEDDING_MODEL: e.target.value - })} - placeholder={getEmbeddingPlaceholder(ragSettings.LLM_PROVIDER || 'openai')} - accentColor="green" - /> -
-
- )} - + {/* 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