mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2026-01-02 17:46:56 +00:00
feat(agents): add api search agent
This commit is contained in:
99
src/lib/agents/search/api.ts
Normal file
99
src/lib/agents/search/api.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { ResearcherOutput, SearchAgentInput } from './types';
|
||||
import SessionManager from '@/lib/session';
|
||||
import { classify } from './classifier';
|
||||
import Researcher from './researcher';
|
||||
import { getWriterPrompt } from '@/lib/prompts/search/writer';
|
||||
import { WidgetExecutor } from './widgets';
|
||||
|
||||
class APISearchAgent {
|
||||
async searchAsync(session: SessionManager, input: SearchAgentInput) {
|
||||
const classification = await classify({
|
||||
chatHistory: input.chatHistory,
|
||||
enabledSources: input.config.sources,
|
||||
query: input.followUp,
|
||||
llm: input.config.llm,
|
||||
});
|
||||
|
||||
const widgetPromise = WidgetExecutor.executeAll({
|
||||
classification,
|
||||
chatHistory: input.chatHistory,
|
||||
followUp: input.followUp,
|
||||
llm: input.config.llm,
|
||||
});
|
||||
|
||||
let searchPromise: Promise<ResearcherOutput> | null = null;
|
||||
|
||||
if (!classification.classification.skipSearch) {
|
||||
const researcher = new Researcher();
|
||||
searchPromise = researcher.research(SessionManager.createSession(), {
|
||||
chatHistory: input.chatHistory,
|
||||
followUp: input.followUp,
|
||||
classification: classification,
|
||||
config: input.config,
|
||||
});
|
||||
}
|
||||
|
||||
const [widgetOutputs, searchResults] = await Promise.all([
|
||||
widgetPromise,
|
||||
searchPromise,
|
||||
]);
|
||||
|
||||
if (searchResults) {
|
||||
session.emit('data', {
|
||||
type: 'searchResults',
|
||||
data: searchResults.searchFindings,
|
||||
});
|
||||
}
|
||||
|
||||
session.emit('data', {
|
||||
type: 'researchComplete',
|
||||
});
|
||||
|
||||
const finalContext =
|
||||
searchResults?.searchFindings
|
||||
.map(
|
||||
(f, index) =>
|
||||
`<result index=${index + 1} title=${f.metadata.title}>${f.content}</result>`,
|
||||
)
|
||||
.join('\n') || '';
|
||||
|
||||
const widgetContext = widgetOutputs
|
||||
.map((o) => {
|
||||
return `<result>${o.llmContext}</result>`;
|
||||
})
|
||||
.join('\n-------------\n');
|
||||
|
||||
const finalContextWithWidgets = `<search_results note="These are the search results and assistant can cite these">\n${finalContext}\n</search_results>\n<widgets_result noteForAssistant="Its output is already showed to the user, assistant can use this information to answer the query but do not CITE this as a souce">\n${widgetContext}\n</widgets_result>`;
|
||||
|
||||
const writerPrompt = getWriterPrompt(
|
||||
finalContextWithWidgets,
|
||||
input.config.systemInstructions,
|
||||
input.config.mode,
|
||||
);
|
||||
|
||||
const answerStream = input.config.llm.streamText({
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: writerPrompt,
|
||||
},
|
||||
...input.chatHistory,
|
||||
{
|
||||
role: 'user',
|
||||
content: input.followUp,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
for await (const chunk of answerStream) {
|
||||
session.emit('data', {
|
||||
type: 'response',
|
||||
data: chunk.contentChunk,
|
||||
});
|
||||
}
|
||||
|
||||
session.emit('end', {});
|
||||
}
|
||||
}
|
||||
|
||||
export default APISearchAgent;
|
||||
Reference in New Issue
Block a user