From 1763ee9d1fe46b9979777e7672f542de1e02c96c Mon Sep 17 00:00:00 2001 From: Joaquin Date: Wed, 4 Mar 2026 10:02:51 -0300 Subject: [PATCH 1/4] Add timeout and validation to SearXNG search --- src/lib/searxng.ts | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/lib/searxng.ts b/src/lib/searxng.ts index a0bcd835..87767e09 100644 --- a/src/lib/searxng.ts +++ b/src/lib/searxng.ts @@ -38,11 +38,30 @@ export const searchSearxng = async ( }); } - const res = await fetch(url); - const data = await res.json(); + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 10000); - const results: SearxngSearchResult[] = data.results; - const suggestions: string[] = data.suggestions; + try { + const res = await fetch(url, { + signal: controller.signal, + }); - return { results, suggestions }; + if (!res.ok) { + throw new Error(`SearXNG error: ${res.statusText}`); + } + + const data = await res.json(); + + const results: SearxngSearchResult[] = data.results; + const suggestions: string[] = data.suggestions; + + return { results, suggestions }; + } catch (err: any) { + if (err.name === 'AbortError') { + throw new Error('SearXNG search timed out'); + } + throw err; + } finally { + clearTimeout(timeoutId); + } }; From a2f2ac532ee728d7856e74ed8fb5631b404394b8 Mon Sep 17 00:00:00 2001 From: Joaquin Date: Wed, 4 Mar 2026 10:02:51 -0300 Subject: [PATCH 2/4] Improve resilience: catch widget execution failures --- src/lib/agents/search/api.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/agents/search/api.ts b/src/lib/agents/search/api.ts index 924bc68f..94b70ae9 100644 --- a/src/lib/agents/search/api.ts +++ b/src/lib/agents/search/api.ts @@ -19,6 +19,9 @@ class APISearchAgent { chatHistory: input.chatHistory, followUp: input.followUp, llm: input.config.llm, + }).catch((err) => { + console.error(`Error executing widgets: ${err}`); + return []; }); let searchPromise: Promise | null = null; From f83f813bd750c2667d6287d459abb485f91d2906 Mon Sep 17 00:00:00 2001 From: Kushagra Srivastava <95534749+ItzCrazyKns@users.noreply.github.com> Date: Mon, 9 Mar 2026 19:32:40 +0530 Subject: [PATCH 3/4] Update README.md From 21bd88787e9ea88a79e9fa424c831e342e401526 Mon Sep 17 00:00:00 2001 From: saschabuehrle Date: Sun, 22 Mar 2026 18:11:17 +0100 Subject: [PATCH 4/4] fix: guard against non-array searching queries in research steps (fixes #1075) --- src/components/AssistantSteps.tsx | 4 +++- src/lib/agents/search/researcher/actions/academicSearch.ts | 2 +- src/lib/agents/search/researcher/actions/socialSearch.ts | 2 +- src/lib/agents/search/researcher/actions/webSearch.ts | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/AssistantSteps.tsx b/src/components/AssistantSteps.tsx index c715a924..748463f6 100644 --- a/src/components/AssistantSteps.tsx +++ b/src/components/AssistantSteps.tsx @@ -37,7 +37,8 @@ const getStepTitle = ( if (step.type === 'reasoning') { return isStreaming && !step.reasoning ? 'Thinking...' : 'Thinking'; } else if (step.type === 'searching') { - return `Searching ${step.searching.length} ${step.searching.length === 1 ? 'query' : 'queries'}`; + const queries = Array.isArray(step.searching) ? step.searching : []; + return `Searching ${queries.length} ${queries.length === 1 ? 'query' : 'queries'}`; } else if (step.type === 'search_results') { return `Found ${step.reading.length} ${step.reading.length === 1 ? 'result' : 'results'}`; } else if (step.type === 'reading') { @@ -160,6 +161,7 @@ const AssistantSteps = ({ )} {step.type === 'searching' && + Array.isArray(step.searching) && step.searching.length > 0 && (
{step.searching.map((query, idx) => ( diff --git a/src/lib/agents/search/researcher/actions/academicSearch.ts b/src/lib/agents/search/researcher/actions/academicSearch.ts index 72e1f4b1..0ae822c7 100644 --- a/src/lib/agents/search/researcher/actions/academicSearch.ts +++ b/src/lib/agents/search/researcher/actions/academicSearch.ts @@ -30,7 +30,7 @@ const academicSearchAction: ResearchAction = { config.classification.classification.skipSearch === false && config.classification.classification.academicSearch === true, execute: async (input, additionalConfig) => { - input.queries = input.queries.slice(0, 3); + input.queries = (Array.isArray(input.queries) ? input.queries : [input.queries]).slice(0, 3); const researchBlock = additionalConfig.session.getBlock( additionalConfig.researchBlockId, diff --git a/src/lib/agents/search/researcher/actions/socialSearch.ts b/src/lib/agents/search/researcher/actions/socialSearch.ts index 16468ab4..e22d5b79 100644 --- a/src/lib/agents/search/researcher/actions/socialSearch.ts +++ b/src/lib/agents/search/researcher/actions/socialSearch.ts @@ -30,7 +30,7 @@ const socialSearchAction: ResearchAction = { config.classification.classification.skipSearch === false && config.classification.classification.discussionSearch === true, execute: async (input, additionalConfig) => { - input.queries = input.queries.slice(0, 3); + input.queries = (Array.isArray(input.queries) ? input.queries : [input.queries]).slice(0, 3); const researchBlock = additionalConfig.session.getBlock( additionalConfig.researchBlockId, diff --git a/src/lib/agents/search/researcher/actions/webSearch.ts b/src/lib/agents/search/researcher/actions/webSearch.ts index 4d60b79f..d1785e2b 100644 --- a/src/lib/agents/search/researcher/actions/webSearch.ts +++ b/src/lib/agents/search/researcher/actions/webSearch.ts @@ -85,7 +85,7 @@ const webSearchAction: ResearchAction = { config.sources.includes('web') && config.classification.classification.skipSearch === false, execute: async (input, additionalConfig) => { - input.queries = input.queries.slice(0, 3); + input.queries = (Array.isArray(input.queries) ? input.queries : [input.queries]).slice(0, 3); const researchBlock = additionalConfig.session.getBlock( additionalConfig.researchBlockId,