Compare commits

...

8 Commits

Author SHA1 Message Date
Ruben Talstra
924276d4b9 Merge branch 'dev' into refactor/Azure-AI-Search 2025-05-22 10:46:42 +02:00
Ruben Talstra
438392f705 Merge branch 'dev' into refactor/Azure-AI-Search 2025-05-15 17:15:00 +02:00
Ruben Talstra
c925f9f39c 🚀 feat: Add Cloudflare Turnstile support (#5987)
* 🚀 feat: Add @marsidev/react-turnstile dependency to package.json and package-lock.json

* 🚀 feat: Integrate Cloudflare Turnstile configuration support in AppService and add schema validation

* 🚀 feat: Implemented Cloudflare Turnstile integration in Login and Registration forms

* 🚀 feat: Enhance AppService tests with additional mocks and configuration setups

* 🚀 feat: Comment out outdated config version warning tests in AppService.spec.js

* 🚀 feat: Remove outdated warning tests and add new checks for environment variables and API health

* 🔧 test: Update AppService.spec.js to use expect.anything() for paths validation

* 🔧 test: Refactor AppService.spec.js to streamline mocks and enhance clarity

* 🔧 chore: removed not needed test

* Potential fix for code scanning alert no. 5638: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Potential fix for code scanning alert no. 5629: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Potential fix for code scanning alert no. 5642: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Update turnstile.js

* Potential fix for code scanning alert no. 5634: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Potential fix for code scanning alert no. 5646: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Potential fix for code scanning alert no. 5647: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-05-15 09:38:58 -04:00
matt burnett
71effb1a66 🔃 refactor: AgentFooter to conditionally render buttons based on activePanel (#7306) 2025-05-15 09:37:14 -04:00
andresgit
e3acd18c07 🎨 feat: add copy-tex to improve copying KaTeX (#7308)
When selecting equations and using copy paste, uses the correct latex code.

Co-authored-by: Ruben Talstra <RubenTalstra1211@outlook.com>
2025-05-15 09:35:48 -04:00
Ruben Talstra
d14a063302 Merge branch 'main' into refactor/Azure-AI-Search 2025-05-14 17:29:15 +02:00
Ruben Talstra
a36426ef54 Merge branch 'main' into refactor/Azure-AI-Search 2025-03-03 13:51:53 +01:00
Ruben Talstra
edcac7669b 🚀 feat: Support multiple Azure AI Search indexes and enhance search functionality 2025-03-02 13:11:10 +01:00
5 changed files with 50 additions and 18 deletions

View File

@@ -32,11 +32,15 @@ class AzureAISearch extends Tool {
fields.AZURE_AI_SEARCH_SERVICE_ENDPOINT, fields.AZURE_AI_SEARCH_SERVICE_ENDPOINT,
'AZURE_AI_SEARCH_SERVICE_ENDPOINT', 'AZURE_AI_SEARCH_SERVICE_ENDPOINT',
); );
this.indexName = this._initializeField( // Get the indexes as a comma-separated string
this.indexNames = this._initializeField(
fields.AZURE_AI_SEARCH_INDEX_NAME, fields.AZURE_AI_SEARCH_INDEX_NAME,
'AZURE_AI_SEARCH_INDEX_NAME', 'AZURE_AI_SEARCH_INDEX_NAME',
); );
this.apiKey = this._initializeField(fields.AZURE_AI_SEARCH_API_KEY, 'AZURE_AI_SEARCH_API_KEY'); this.apiKey = this._initializeField(
fields.AZURE_AI_SEARCH_API_KEY,
'AZURE_AI_SEARCH_API_KEY',
);
this.apiVersion = this._initializeField( this.apiVersion = this._initializeField(
fields.AZURE_AI_SEARCH_API_VERSION, fields.AZURE_AI_SEARCH_API_VERSION,
'AZURE_AI_SEARCH_API_VERSION', 'AZURE_AI_SEARCH_API_VERSION',
@@ -58,7 +62,7 @@ class AzureAISearch extends Tool {
); );
// Check for required fields // Check for required fields
if (!this.override && (!this.serviceEndpoint || !this.indexName || !this.apiKey)) { if (!this.override && (!this.serviceEndpoint || !this.indexNames || !this.apiKey)) {
throw new Error( throw new Error(
'Missing AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, or AZURE_AI_SEARCH_API_KEY environment variable.', 'Missing AZURE_AI_SEARCH_SERVICE_ENDPOINT, AZURE_AI_SEARCH_INDEX_NAME, or AZURE_AI_SEARCH_API_KEY environment variable.',
); );
@@ -68,12 +72,25 @@ class AzureAISearch extends Tool {
return; return;
} }
// Create SearchClient // Split the indexNames by comma to support multiple indexes, trim whitespace,
this.client = new SearchClient( // convert to lowercase, and filter out any empty strings.
const indexes = this.indexNames
.split(',')
.map(index => index.trim().toLowerCase())
.filter(index => index.length > 0);
if (indexes.length === 0) {
throw new Error('No valid index names provided in AZURE_AI_SEARCH_INDEX_NAME.');
}
// Create a client for each index.
this.clients = indexes.map(index =>
new SearchClient(
this.serviceEndpoint, this.serviceEndpoint,
this.indexName, index,
new AzureKeyCredential(this.apiKey), new AzureKeyCredential(this.apiKey),
{ apiVersion: this.apiVersion }, { apiVersion: this.apiVersion },
),
); );
} }
@@ -88,12 +105,21 @@ class AzureAISearch extends Tool {
if (this.select) { if (this.select) {
searchOption.select = this.select.split(','); searchOption.select = this.select.split(',');
} }
const searchResults = await this.client.search(query, searchOption);
// Query all indexes concurrently
const searchPromises = this.clients.map(async (client) => {
const resultDocuments = []; const resultDocuments = [];
const searchResults = await client.search(query, searchOption);
for await (const result of searchResults.results) { for await (const result of searchResults.results) {
resultDocuments.push(result.document); resultDocuments.push(result.document);
} }
return JSON.stringify(resultDocuments); return resultDocuments;
});
// Wait for all search promises to complete and flatten the results
const resultsByIndex = await Promise.all(searchPromises);
const combinedResults = resultsByIndex.flat();
return JSON.stringify(combinedResults);
} catch (error) { } catch (error) {
logger.error('Azure AI Search request failed', error); logger.error('Azure AI Search request failed', error);
return 'There was an error with Azure AI Search.'; return 'There was an error with Azure AI Search.';

View File

@@ -26,6 +26,7 @@ function loadTurnstileConfig(config, configDefaults) {
options: customTurnstile.options ?? defaults.options, options: customTurnstile.options ?? defaults.options,
}); });
const enabled = Boolean(loadedTurnstile.siteKey); const enabled = Boolean(loadedTurnstile.siteKey);
if (enabled) { if (enabled) {
@@ -36,6 +37,7 @@ function loadTurnstileConfig(config, configDefaults) {
logger.info('Turnstile is DISABLED (no siteKey provided).'); logger.info('Turnstile is DISABLED (no siteKey provided).');
} }
return loadedTurnstile; return loadedTurnstile;
} }

View File

@@ -16,7 +16,6 @@ type TLoginFormProps = {
const LoginForm: React.FC<TLoginFormProps> = ({ onSubmit, startupConfig, error, setError }) => { const LoginForm: React.FC<TLoginFormProps> = ({ onSubmit, startupConfig, error, setError }) => {
const localize = useLocalize(); const localize = useLocalize();
const { theme } = useContext(ThemeContext); const { theme } = useContext(ThemeContext);
const { const {
register, register,
getValues, getValues,
@@ -29,8 +28,10 @@ const LoginForm: React.FC<TLoginFormProps> = ({ onSubmit, startupConfig, error,
const { data: config } = useGetStartupConfig(); const { data: config } = useGetStartupConfig();
const useUsernameLogin = config?.ldap?.username; const useUsernameLogin = config?.ldap?.username;
const validTheme = theme === 'dark' ? 'dark' : 'light'; const validTheme = theme === 'dark' ? 'dark' : 'light';
const requireCaptcha = Boolean(startupConfig.turnstile?.siteKey); const requireCaptcha = Boolean(startupConfig.turnstile?.siteKey);
useEffect(() => { useEffect(() => {
if (error && error.includes('422') && !showResendLink) { if (error && error.includes('422') && !showResendLink) {
setShowResendLink(true); setShowResendLink(true);
@@ -150,6 +151,7 @@ const LoginForm: React.FC<TLoginFormProps> = ({ onSubmit, startupConfig, error,
</a> </a>
)} )}
{requireCaptcha && ( {requireCaptcha && (
<div className="my-4 flex justify-center"> <div className="my-4 flex justify-center">
<Turnstile <Turnstile

View File

@@ -32,7 +32,6 @@ const Registration: React.FC = () => {
const queryParams = new URLSearchParams(location.search); const queryParams = new URLSearchParams(location.search);
const token = queryParams.get('token'); const token = queryParams.get('token');
const validTheme = theme === 'dark' ? 'dark' : 'light'; const validTheme = theme === 'dark' ? 'dark' : 'light';
// only require captcha if we have a siteKey // only require captcha if we have a siteKey
const requireCaptcha = Boolean(startupConfig?.turnstile?.siteKey); const requireCaptcha = Boolean(startupConfig?.turnstile?.siteKey);
@@ -179,6 +178,7 @@ const Registration: React.FC = () => {
})} })}
{startupConfig?.turnstile?.siteKey && ( {startupConfig?.turnstile?.siteKey && (
<div className="my-4 flex justify-center"> <div className="my-4 flex justify-center">
<Turnstile <Turnstile
siteKey={startupConfig.turnstile.siteKey} siteKey={startupConfig.turnstile.siteKey}
@@ -198,6 +198,7 @@ const Registration: React.FC = () => {
disabled={ disabled={
Object.keys(errors).length > 0 || Object.keys(errors).length > 0 ||
isSubmitting || isSubmitting ||
(requireCaptcha && !turnstileToken) (requireCaptcha && !turnstileToken)
} }
type="submit" type="submit"

View File

@@ -53,6 +53,7 @@ export default function AgentFooter({
const showButtons = activePanel === Panel.builder; const showButtons = activePanel === Panel.builder;
return ( return (
<div className="mb-1 flex w-full flex-col gap-2"> <div className="mb-1 flex w-full flex-col gap-2">
{showButtons && <AdvancedButton setActivePanel={setActivePanel} />} {showButtons && <AdvancedButton setActivePanel={setActivePanel} />}
{showButtons && agent_id && <VersionButton setActivePanel={setActivePanel} />} {showButtons && agent_id && <VersionButton setActivePanel={setActivePanel} />}