diff --git a/src/lib/agents/search/researcher/actions/academicSearch.ts b/src/lib/agents/search/researcher/actions/academicSearch.ts deleted file mode 100644 index 9c380f4a..00000000 --- a/src/lib/agents/search/researcher/actions/academicSearch.ts +++ /dev/null @@ -1,131 +0,0 @@ -import z from 'zod'; -import { ResearchAction } from '../../types'; -import { Chunk, SearchResultsResearchBlock } from '@/lib/types'; -import { searchSearxng } from '@/lib/searxng'; - -const schema = z.object({ - queries: z.array(z.string()).describe('List of academic search queries'), -}); - -const academicSearchDescription = ` -Use this tool to perform academic searches for scholarly articles, papers, and research studies relevant to the user's query. Provide a list of concise search queries that will help gather comprehensive academic information on the topic at hand. -You can provide up to 3 queries at a time. Make sure the queries are specific and relevant to the user's needs. - -For example, if the user is interested in recent advancements in renewable energy, your queries could be: -1. "Recent advancements in renewable energy 2024" -2. "Cutting-edge research on solar power technologies" -3. "Innovations in wind energy systems" - -If this tool is present and no other tools are more relevant, you MUST use this tool to get the needed academic information. -`; - -const academicSearchAction: ResearchAction = { - name: 'academic_search', - schema: schema, - getDescription: () => academicSearchDescription, - getToolDescription: () => - "Use this tool to perform academic searches for scholarly articles, papers, and research studies relevant to the user's query. Provide a list of concise search queries that will help gather comprehensive academic information on the topic at hand.", - enabled: (config) => - config.sources.includes('academic') && - config.classification.classification.skipSearch === false && - config.classification.classification.academicSearch === true, - execute: async (input, additionalConfig) => { - input.queries = ( - Array.isArray(input.queries) ? input.queries : [input.queries] - ).slice(0, 3); - - const researchBlock = additionalConfig.session.getBlock( - additionalConfig.researchBlockId, - ); - - if (researchBlock && researchBlock.type === 'research') { - researchBlock.data.subSteps.push({ - type: 'searching', - id: crypto.randomUUID(), - searching: input.queries, - }); - - additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [ - { - op: 'replace', - path: '/data/subSteps', - value: researchBlock.data.subSteps, - }, - ]); - } - - const searchResultsBlockId = crypto.randomUUID(); - let searchResultsEmitted = false; - - let results: Chunk[] = []; - - const search = async (q: string) => { - const res = await searchSearxng(q, { - engines: ['arxiv', 'google scholar', 'pubmed'], - }); - - const resultChunks: Chunk[] = res.results.map((r) => ({ - content: r.content || r.title, - metadata: { - title: r.title, - url: r.url, - }, - })); - - results.push(...resultChunks); - - if ( - !searchResultsEmitted && - researchBlock && - researchBlock.type === 'research' - ) { - searchResultsEmitted = true; - - researchBlock.data.subSteps.push({ - id: searchResultsBlockId, - type: 'search_results', - reading: resultChunks, - }); - - additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [ - { - op: 'replace', - path: '/data/subSteps', - value: researchBlock.data.subSteps, - }, - ]); - } else if ( - searchResultsEmitted && - researchBlock && - researchBlock.type === 'research' - ) { - const subStepIndex = researchBlock.data.subSteps.findIndex( - (step) => step.id === searchResultsBlockId, - ); - - const subStep = researchBlock.data.subSteps[ - subStepIndex - ] as SearchResultsResearchBlock; - - subStep.reading.push(...resultChunks); - - additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [ - { - op: 'replace', - path: '/data/subSteps', - value: researchBlock.data.subSteps, - }, - ]); - } - }; - - await Promise.all(input.queries.map(search)); - - return { - type: 'search_results', - results, - }; - }, -}; - -export default academicSearchAction; diff --git a/src/lib/agents/search/researcher/actions/index.ts b/src/lib/agents/search/researcher/actions/index.ts index 8864c083..9af2e56a 100644 --- a/src/lib/agents/search/researcher/actions/index.ts +++ b/src/lib/agents/search/researcher/actions/index.ts @@ -1,11 +1,11 @@ -import academicSearchAction from './academicSearch'; +import academicSearchAction from './search/academicSearch'; import doneAction from './done'; import planAction from './plan'; import ActionRegistry from './registry'; import scrapeURLAction from './scrapeURL'; -import socialSearchAction from './socialSearch'; +import socialSearchAction from './search/socialSearch'; import uploadsSearchAction from './uploadsSearch'; -import webSearchAction from './webSearch'; +import webSearchAction from './search/webSearch'; ActionRegistry.register(webSearchAction); ActionRegistry.register(doneAction); diff --git a/src/lib/agents/search/researcher/actions/search/academicSearch.ts b/src/lib/agents/search/researcher/actions/search/academicSearch.ts new file mode 100644 index 00000000..d77a5cf2 --- /dev/null +++ b/src/lib/agents/search/researcher/actions/search/academicSearch.ts @@ -0,0 +1,62 @@ +import z from 'zod'; +import { ResearchAction } from '../../../types'; +import { ResearchBlock } from '@/lib/types'; +import { executeSearch } from './baseSearch'; + +const schema = z.object({ + queries: z.array(z.string()).describe('List of academic search queries'), +}); + +const academicSearchDescription = ` +Use this tool to perform academic searches for scholarly articles, papers, and research studies relevant to the user's query. Provide a list of concise search queries that will help gather comprehensive academic information on the topic at hand. +You can provide up to 3 queries at a time. Make sure the queries are specific and relevant to the user's needs. + +For example, if the user is interested in recent advancements in renewable energy, your queries could be: +1. "Recent advancements in renewable energy 2024" +2. "Cutting-edge research on solar power technologies" +3. "Innovations in wind energy systems" + +If this tool is present and no other tools are more relevant, you MUST use this tool to get the needed academic information. +`; + +const academicSearchAction: ResearchAction = { + name: 'academic_search', + schema: schema, + getDescription: () => academicSearchDescription, + getToolDescription: () => + "Use this tool to perform academic searches for scholarly articles, papers, and research studies relevant to the user's query. Provide a list of concise search queries that will help gather comprehensive academic information on the topic at hand.", + enabled: (config) => + config.sources.includes('academic') && + config.classification.classification.skipSearch === false && + config.classification.classification.academicSearch === true, + execute: async (input, additionalConfig) => { + input.queries = ( + Array.isArray(input.queries) ? input.queries : [input.queries] + ).slice(0, 3); + + const researchBlock = additionalConfig.session.getBlock( + additionalConfig.researchBlockId, + ) as ResearchBlock | undefined; + + if (!researchBlock) throw new Error('Failed to retrieve research block'); + + const results = await executeSearch({ + llm: additionalConfig.llm, + embedding: additionalConfig.embedding, + mode: additionalConfig.mode, + queries: input.queries, + researchBlock: researchBlock, + session: additionalConfig.session, + searchConfig: { + engines: ['arxiv', 'google scholar', 'pubmed'], + }, + }); + + return { + type: 'search_results', + results: results, + }; + }, +}; + +export default academicSearchAction; diff --git a/src/lib/agents/search/researcher/actions/search/socialSearch.ts b/src/lib/agents/search/researcher/actions/search/socialSearch.ts new file mode 100644 index 00000000..a21d2bfd --- /dev/null +++ b/src/lib/agents/search/researcher/actions/search/socialSearch.ts @@ -0,0 +1,62 @@ +import z from 'zod'; +import { ResearchAction } from '../../../types'; +import { ResearchBlock } from '@/lib/types'; +import { executeSearch } from './baseSearch'; + +const schema = z.object({ + queries: z.array(z.string()).describe('List of social search queries'), +}); + +const socialSearchDescription = ` +Use this tool to perform social media searches for relevant posts, discussions, and trends related to the user's query. Provide a list of concise search queries that will help gather comprehensive social media information on the topic at hand. +You can provide up to 3 queries at a time. Make sure the queries are specific and relevant to the user's needs. + +For example, if the user is interested in public opinion on electric vehicles, your queries could be: +1. "Electric vehicles public opinion 2024" +2. "Social media discussions on EV adoption" +3. "Trends in electric vehicle usage" + +If this tool is present and no other tools are more relevant, you MUST use this tool to get the needed social media information. +`; + +const socialSearchAction: ResearchAction = { + name: 'social_search', + schema: schema, + getDescription: () => socialSearchDescription, + getToolDescription: () => + "Use this tool to perform social media searches for relevant posts, discussions, and trends related to the user's query. Provide a list of concise search queries that will help gather comprehensive social media information on the topic at hand.", + enabled: (config) => + config.sources.includes('discussions') && + config.classification.classification.skipSearch === false && + config.classification.classification.discussionSearch === true, + execute: async (input, additionalConfig) => { + input.queries = ( + Array.isArray(input.queries) ? input.queries : [input.queries] + ).slice(0, 3); + + const researchBlock = additionalConfig.session.getBlock( + additionalConfig.researchBlockId, + ) as ResearchBlock | undefined; + + if (!researchBlock) throw new Error('Failed to retrieve research block'); + + const results = await executeSearch({ + llm: additionalConfig.llm, + embedding: additionalConfig.embedding, + mode: additionalConfig.mode, + queries: input.queries, + researchBlock: researchBlock, + session: additionalConfig.session, + searchConfig: { + engines: ['reddit'], + }, + }); + + return { + type: 'search_results', + results: results, + }; + }, +}; + +export default socialSearchAction; diff --git a/src/lib/agents/search/researcher/actions/webSearch.ts b/src/lib/agents/search/researcher/actions/search/webSearch.ts similarity index 71% rename from src/lib/agents/search/researcher/actions/webSearch.ts rename to src/lib/agents/search/researcher/actions/search/webSearch.ts index 9cce1830..d9f62344 100644 --- a/src/lib/agents/search/researcher/actions/webSearch.ts +++ b/src/lib/agents/search/researcher/actions/search/webSearch.ts @@ -1,7 +1,7 @@ import z from 'zod'; -import { ResearchAction } from '../../types'; -import { searchSearxng } from '@/lib/searxng'; -import { Chunk, SearchResultsResearchBlock } from '@/lib/types'; +import { ResearchAction } from '../../../types'; +import { ResearchBlock } from '@/lib/types'; +import { executeSearch } from './baseSearch'; const actionSchema = z.object({ type: z.literal('web_search'), @@ -91,92 +91,22 @@ const webSearchAction: ResearchAction = { const researchBlock = additionalConfig.session.getBlock( additionalConfig.researchBlockId, - ); + ) as ResearchBlock | undefined; - if (researchBlock && researchBlock.type === 'research') { - researchBlock.data.subSteps.push({ - id: crypto.randomUUID(), - type: 'searching', - searching: input.queries, - }); + if (!researchBlock) throw new Error('Failed to retrieve research block'); - additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [ - { - op: 'replace', - path: '/data/subSteps', - value: researchBlock.data.subSteps, - }, - ]); - } - - const searchResultsBlockId = crypto.randomUUID(); - let searchResultsEmitted = false; - - let results: Chunk[] = []; - - const search = async (q: string) => { - const res = await searchSearxng(q); - - const resultChunks: Chunk[] = res.results.map((r) => ({ - content: r.content || r.title, - metadata: { - title: r.title, - url: r.url, - }, - })); - - results.push(...resultChunks); - - if ( - !searchResultsEmitted && - researchBlock && - researchBlock.type === 'research' - ) { - searchResultsEmitted = true; - - researchBlock.data.subSteps.push({ - id: searchResultsBlockId, - type: 'search_results', - reading: resultChunks, - }); - - additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [ - { - op: 'replace', - path: '/data/subSteps', - value: researchBlock.data.subSteps, - }, - ]); - } else if ( - searchResultsEmitted && - researchBlock && - researchBlock.type === 'research' - ) { - const subStepIndex = researchBlock.data.subSteps.findIndex( - (step) => step.id === searchResultsBlockId, - ); - - const subStep = researchBlock.data.subSteps[ - subStepIndex - ] as SearchResultsResearchBlock; - - subStep.reading.push(...resultChunks); - - additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [ - { - op: 'replace', - path: '/data/subSteps', - value: researchBlock.data.subSteps, - }, - ]); - } - }; - - await Promise.all(input.queries.map(search)); + const results = await executeSearch({ + llm: additionalConfig.llm, + embedding: additionalConfig.embedding, + mode: additionalConfig.mode, + queries: input.queries, + researchBlock: researchBlock, + session: additionalConfig.session, + }); return { type: 'search_results', - results, + results: results, }; }, }; diff --git a/src/lib/agents/search/researcher/actions/socialSearch.ts b/src/lib/agents/search/researcher/actions/socialSearch.ts deleted file mode 100644 index ee4dced4..00000000 --- a/src/lib/agents/search/researcher/actions/socialSearch.ts +++ /dev/null @@ -1,131 +0,0 @@ -import z from 'zod'; -import { ResearchAction } from '../../types'; -import { Chunk, SearchResultsResearchBlock } from '@/lib/types'; -import { searchSearxng } from '@/lib/searxng'; - -const schema = z.object({ - queries: z.array(z.string()).describe('List of social search queries'), -}); - -const socialSearchDescription = ` -Use this tool to perform social media searches for relevant posts, discussions, and trends related to the user's query. Provide a list of concise search queries that will help gather comprehensive social media information on the topic at hand. -You can provide up to 3 queries at a time. Make sure the queries are specific and relevant to the user's needs. - -For example, if the user is interested in public opinion on electric vehicles, your queries could be: -1. "Electric vehicles public opinion 2024" -2. "Social media discussions on EV adoption" -3. "Trends in electric vehicle usage" - -If this tool is present and no other tools are more relevant, you MUST use this tool to get the needed social media information. -`; - -const socialSearchAction: ResearchAction = { - name: 'social_search', - schema: schema, - getDescription: () => socialSearchDescription, - getToolDescription: () => - "Use this tool to perform social media searches for relevant posts, discussions, and trends related to the user's query. Provide a list of concise search queries that will help gather comprehensive social media information on the topic at hand.", - enabled: (config) => - config.sources.includes('discussions') && - config.classification.classification.skipSearch === false && - config.classification.classification.discussionSearch === true, - execute: async (input, additionalConfig) => { - input.queries = ( - Array.isArray(input.queries) ? input.queries : [input.queries] - ).slice(0, 3); - - const researchBlock = additionalConfig.session.getBlock( - additionalConfig.researchBlockId, - ); - - if (researchBlock && researchBlock.type === 'research') { - researchBlock.data.subSteps.push({ - type: 'searching', - id: crypto.randomUUID(), - searching: input.queries, - }); - - additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [ - { - op: 'replace', - path: '/data/subSteps', - value: researchBlock.data.subSteps, - }, - ]); - } - - const searchResultsBlockId = crypto.randomUUID(); - let searchResultsEmitted = false; - - let results: Chunk[] = []; - - const search = async (q: string) => { - const res = await searchSearxng(q, { - engines: ['reddit'], - }); - - const resultChunks: Chunk[] = res.results.map((r) => ({ - content: r.content || r.title, - metadata: { - title: r.title, - url: r.url, - }, - })); - - results.push(...resultChunks); - - if ( - !searchResultsEmitted && - researchBlock && - researchBlock.type === 'research' - ) { - searchResultsEmitted = true; - - researchBlock.data.subSteps.push({ - id: searchResultsBlockId, - type: 'search_results', - reading: resultChunks, - }); - - additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [ - { - op: 'replace', - path: '/data/subSteps', - value: researchBlock.data.subSteps, - }, - ]); - } else if ( - searchResultsEmitted && - researchBlock && - researchBlock.type === 'research' - ) { - const subStepIndex = researchBlock.data.subSteps.findIndex( - (step) => step.id === searchResultsBlockId, - ); - - const subStep = researchBlock.data.subSteps[ - subStepIndex - ] as SearchResultsResearchBlock; - - subStep.reading.push(...resultChunks); - - additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [ - { - op: 'replace', - path: '/data/subSteps', - value: researchBlock.data.subSteps, - }, - ]); - } - }; - - await Promise.all(input.queries.map(search)); - - return { - type: 'search_results', - results, - }; - }, -}; - -export default socialSearchAction;