mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2026-04-10 13:54:28 +00:00
feat(search-actions): make use of executeSearch
This commit is contained in:
@@ -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<typeof schema> = {
|
|
||||||
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;
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import academicSearchAction from './academicSearch';
|
import academicSearchAction from './search/academicSearch';
|
||||||
import doneAction from './done';
|
import doneAction from './done';
|
||||||
import planAction from './plan';
|
import planAction from './plan';
|
||||||
import ActionRegistry from './registry';
|
import ActionRegistry from './registry';
|
||||||
import scrapeURLAction from './scrapeURL';
|
import scrapeURLAction from './scrapeURL';
|
||||||
import socialSearchAction from './socialSearch';
|
import socialSearchAction from './search/socialSearch';
|
||||||
import uploadsSearchAction from './uploadsSearch';
|
import uploadsSearchAction from './uploadsSearch';
|
||||||
import webSearchAction from './webSearch';
|
import webSearchAction from './search/webSearch';
|
||||||
|
|
||||||
ActionRegistry.register(webSearchAction);
|
ActionRegistry.register(webSearchAction);
|
||||||
ActionRegistry.register(doneAction);
|
ActionRegistry.register(doneAction);
|
||||||
|
|||||||
@@ -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<typeof schema> = {
|
||||||
|
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;
|
||||||
@@ -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<typeof schema> = {
|
||||||
|
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;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import z from 'zod';
|
import z from 'zod';
|
||||||
import { ResearchAction } from '../../types';
|
import { ResearchAction } from '../../../types';
|
||||||
import { searchSearxng } from '@/lib/searxng';
|
import { ResearchBlock } from '@/lib/types';
|
||||||
import { Chunk, SearchResultsResearchBlock } from '@/lib/types';
|
import { executeSearch } from './baseSearch';
|
||||||
|
|
||||||
const actionSchema = z.object({
|
const actionSchema = z.object({
|
||||||
type: z.literal('web_search'),
|
type: z.literal('web_search'),
|
||||||
@@ -91,92 +91,22 @@ const webSearchAction: ResearchAction<typeof actionSchema> = {
|
|||||||
|
|
||||||
const researchBlock = additionalConfig.session.getBlock(
|
const researchBlock = additionalConfig.session.getBlock(
|
||||||
additionalConfig.researchBlockId,
|
additionalConfig.researchBlockId,
|
||||||
);
|
) as ResearchBlock | undefined;
|
||||||
|
|
||||||
if (researchBlock && researchBlock.type === 'research') {
|
if (!researchBlock) throw new Error('Failed to retrieve research block');
|
||||||
researchBlock.data.subSteps.push({
|
|
||||||
id: crypto.randomUUID(),
|
|
||||||
type: 'searching',
|
|
||||||
searching: input.queries,
|
|
||||||
});
|
|
||||||
|
|
||||||
additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [
|
const results = await executeSearch({
|
||||||
{
|
llm: additionalConfig.llm,
|
||||||
op: 'replace',
|
embedding: additionalConfig.embedding,
|
||||||
path: '/data/subSteps',
|
mode: additionalConfig.mode,
|
||||||
value: researchBlock.data.subSteps,
|
queries: input.queries,
|
||||||
},
|
researchBlock: researchBlock,
|
||||||
]);
|
session: additionalConfig.session,
|
||||||
}
|
});
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'search_results',
|
type: 'search_results',
|
||||||
results,
|
results: results,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -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<typeof schema> = {
|
|
||||||
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;
|
|
||||||
Reference in New Issue
Block a user