mirror of
https://github.com/jina-ai/node-DeepResearch.git
synced 2026-03-22 07:29:35 +08:00
chore: first commit
This commit is contained in:
101
src/agent.ts
101
src/agent.ts
@@ -125,8 +125,10 @@ function getPrompt(
|
|||||||
question: string,
|
question: string,
|
||||||
context?: string[],
|
context?: string[],
|
||||||
allQuestions?: string[],
|
allQuestions?: string[],
|
||||||
allowReflect: boolean = false,
|
allowReflect: boolean = true,
|
||||||
allowAnswer: boolean = true,
|
allowAnswer: boolean = true,
|
||||||
|
allowRead: boolean = true,
|
||||||
|
allowSearch: boolean = true,
|
||||||
badContext?: { question: string, answer: string, evaluation: string, recap: string; blame: string; improvement: string; }[],
|
badContext?: { question: string, answer: string, evaluation: string, recap: string; blame: string; improvement: string; }[],
|
||||||
knowledge?: { question: string; answer: string; }[],
|
knowledge?: { question: string; answer: string; }[],
|
||||||
allURLs?: Record<string, string>
|
allURLs?: Record<string, string>
|
||||||
@@ -187,10 +189,10 @@ ${learnedStrategy}
|
|||||||
// Build actions section
|
// Build actions section
|
||||||
const actions: string[] = [];
|
const actions: string[] = [];
|
||||||
|
|
||||||
if (allURLs) {
|
if (allURLs && Object.keys(allURLs).length > 0 && allowRead) {
|
||||||
const urlList = Object.entries(allURLs)
|
const urlList = Object.entries(allURLs)
|
||||||
.map(([url, desc]) => ` + "${url}": "${desc}"`)
|
.map(([url, desc]) => ` + "${url}": "${desc}"`)
|
||||||
.join('');
|
.join('\n');
|
||||||
|
|
||||||
actions.push(`**visit**:
|
actions.push(`**visit**:
|
||||||
- Visit any URLs from below to gather external knowledge, choose the most relevant URLs that might contain the answer
|
- Visit any URLs from below to gather external knowledge, choose the most relevant URLs that might contain the answer
|
||||||
@@ -199,10 +201,12 @@ ${urlList}
|
|||||||
- It allows you to access the full content behind any URLs`);
|
- It allows you to access the full content behind any URLs`);
|
||||||
}
|
}
|
||||||
|
|
||||||
actions.push(`**search**:
|
if (allowSearch) {
|
||||||
|
actions.push(`**search**:
|
||||||
- Query external sources using a public search engine
|
- Query external sources using a public search engine
|
||||||
- Focus on solving one specific aspect of the question
|
- Focus on solving one specific aspect of the question
|
||||||
- Only give keywords search query, not full sentences`);
|
- Only give keywords search query, not full sentences`);
|
||||||
|
}
|
||||||
|
|
||||||
if (allowAnswer) {
|
if (allowAnswer) {
|
||||||
actions.push(`**answer**:
|
actions.push(`**answer**:
|
||||||
@@ -260,6 +264,10 @@ async function getResponse(question: string, tokenBudget: number = 1000000, maxB
|
|||||||
const badContext = [];
|
const badContext = [];
|
||||||
let diaryContext = [];
|
let diaryContext = [];
|
||||||
let allowAnswer = true;
|
let allowAnswer = true;
|
||||||
|
let allowSearch = true;
|
||||||
|
let allowRead = true;
|
||||||
|
let allowReflect = true;
|
||||||
|
|
||||||
const allURLs: Record<string, string> = {};
|
const allURLs: Record<string, string> = {};
|
||||||
while (tokenTracker.getTotalUsage() < tokenBudget && badAttempts <= maxBadAttempts) {
|
while (tokenTracker.getTotalUsage() < tokenBudget && badAttempts <= maxBadAttempts) {
|
||||||
// add 1s delay to avoid rate limiting
|
// add 1s delay to avoid rate limiting
|
||||||
@@ -268,11 +276,11 @@ async function getResponse(question: string, tokenBudget: number = 1000000, maxB
|
|||||||
totalStep++;
|
totalStep++;
|
||||||
console.log(`Step ${totalStep}`);
|
console.log(`Step ${totalStep}`);
|
||||||
console.log('Gaps:', gaps);
|
console.log('Gaps:', gaps);
|
||||||
const allowReflect = gaps.length <= 1;
|
allowReflect = allowReflect && (gaps.length <= 1);
|
||||||
const currentQuestion = gaps.length > 0 ? gaps.shift()! : question;
|
const currentQuestion = gaps.length > 0 ? gaps.shift()! : question;
|
||||||
// update all urls with buildURLMap
|
// update all urls with buildURLMap
|
||||||
const allowRead = Object.keys(allURLs).length > 0;
|
allowRead = allowRead && (Object.keys(allURLs).length > 0);
|
||||||
const allowSearch = Object.keys(allURLs).length < 20; // disable search when too many urls already
|
allowSearch = allowSearch && (Object.keys(allURLs).length < 20); // disable search when too many urls already
|
||||||
|
|
||||||
// generate prompt for this step
|
// generate prompt for this step
|
||||||
const prompt = getPrompt(
|
const prompt = getPrompt(
|
||||||
@@ -281,6 +289,8 @@ async function getResponse(question: string, tokenBudget: number = 1000000, maxB
|
|||||||
allQuestions,
|
allQuestions,
|
||||||
allowReflect,
|
allowReflect,
|
||||||
allowAnswer,
|
allowAnswer,
|
||||||
|
allowRead,
|
||||||
|
allowSearch,
|
||||||
badContext,
|
badContext,
|
||||||
allKnowledge,
|
allKnowledge,
|
||||||
allURLs);
|
allURLs);
|
||||||
@@ -308,6 +318,9 @@ async function getResponse(question: string, tokenBudget: number = 1000000, maxB
|
|||||||
|
|
||||||
// reset allowAnswer to true
|
// reset allowAnswer to true
|
||||||
allowAnswer = true;
|
allowAnswer = true;
|
||||||
|
allowReflect = true;
|
||||||
|
allowRead = true;
|
||||||
|
allowSearch = true;
|
||||||
|
|
||||||
// execute the step and action
|
// execute the step and action
|
||||||
if (thisStep.action === 'answer') {
|
if (thisStep.action === 'answer') {
|
||||||
@@ -393,10 +406,12 @@ ${evaluation.reasoning}
|
|||||||
// store the bad context and reset the diary context
|
// store the bad context and reset the diary context
|
||||||
const {response: errorAnalysis} = await analyzeSteps(diaryContext);
|
const {response: errorAnalysis} = await analyzeSteps(diaryContext);
|
||||||
|
|
||||||
badContext.push({question: currentQuestion,
|
badContext.push({
|
||||||
answer: thisStep.answer,
|
question: currentQuestion,
|
||||||
evaluation: evaluation.reasoning,
|
answer: thisStep.answer,
|
||||||
...errorAnalysis});
|
evaluation: evaluation.reasoning,
|
||||||
|
...errorAnalysis
|
||||||
|
});
|
||||||
badAttempts++;
|
badAttempts++;
|
||||||
allowAnswer = false; // disable answer action in the immediate next step
|
allowAnswer = false; // disable answer action in the immediate next step
|
||||||
diaryContext = [];
|
diaryContext = [];
|
||||||
@@ -447,6 +462,8 @@ But then you realized you have asked them before. You decided to to think out of
|
|||||||
...thisStep,
|
...thisStep,
|
||||||
result: 'I have tried all possible questions and found no useful information. I must think out of the box or different angle!!!'
|
result: 'I have tried all possible questions and found no useful information. I must think out of the box or different angle!!!'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
allowReflect = false;
|
||||||
}
|
}
|
||||||
} else if (thisStep.action === 'search' && thisStep.searchQuery) {
|
} else if (thisStep.action === 'search' && thisStep.searchQuery) {
|
||||||
// rewrite queries
|
// rewrite queries
|
||||||
@@ -515,33 +532,57 @@ You decided to think out of the box or cut from a completely different angle.
|
|||||||
...thisStep,
|
...thisStep,
|
||||||
result: 'I have tried all possible queries and found no new information. I must think out of the box or different angle!!!'
|
result: 'I have tried all possible queries and found no new information. I must think out of the box or different angle!!!'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
allowSearch = false;
|
||||||
}
|
}
|
||||||
} else if (thisStep.action === 'visit' && thisStep.URLTargets?.length) {
|
} else if (thisStep.action === 'visit' && thisStep.URLTargets?.length) {
|
||||||
const urlResults = await Promise.all(
|
|
||||||
thisStep.URLTargets.map(async (url: string) => {
|
let uniqueURLs = thisStep.URLTargets;
|
||||||
const {response, tokens} = await readUrl(url, JINA_API_KEY);
|
if (Object.keys(allURLs).length > 0) {
|
||||||
allKnowledge.push({
|
// check duplicate urls
|
||||||
question: `What is in ${response.data.url}?`,
|
uniqueURLs = thisStep.URLTargets.filter((url: string) => !allURLs[url]);
|
||||||
answer: removeAllLineBreaks(response.data.content)
|
}
|
||||||
});
|
|
||||||
// remove that url from allURLs
|
if (uniqueURLs.length > 0) {
|
||||||
delete allURLs[url];
|
|
||||||
return {url, result: response, tokens};
|
const urlResults = await Promise.all(
|
||||||
})
|
uniqueURLs.map(async (url: string) => {
|
||||||
);
|
const {response, tokens} = await readUrl(url, JINA_API_KEY);
|
||||||
diaryContext.push(`
|
allKnowledge.push({
|
||||||
|
question: `What is in ${response.data.url}?`,
|
||||||
|
answer: removeAllLineBreaks(response.data.content)
|
||||||
|
});
|
||||||
|
return {url, result: response, tokens};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
diaryContext.push(`
|
||||||
At step ${step}, you took the **visit** action and deep dive into the following URLs:
|
At step ${step}, you took the **visit** action and deep dive into the following URLs:
|
||||||
${thisStep.URLTargets.join('\n')}
|
${thisStep.URLTargets.join('\n')}
|
||||||
You found some useful information on the web and add them to your knowledge for future reference.
|
You found some useful information on the web and add them to your knowledge for future reference.
|
||||||
`);
|
`);
|
||||||
updateContext({
|
updateContext({
|
||||||
totalStep,
|
totalStep,
|
||||||
question: currentQuestion,
|
question: currentQuestion,
|
||||||
...thisStep,
|
...thisStep,
|
||||||
result: urlResults
|
result: urlResults
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
|
||||||
|
diaryContext.push(`
|
||||||
|
At step ${step}, you took the **visit** action and try to visit the following URLs:
|
||||||
|
${thisStep.URLTargets.join('\n')}
|
||||||
|
But then you realized you have already visited these URLs and you already know very well about their contents.
|
||||||
|
|
||||||
|
You decided to think out of the box or cut from a completely different angle.`);
|
||||||
|
|
||||||
|
updateContext({
|
||||||
|
totalStep,
|
||||||
|
...thisStep,
|
||||||
|
result: 'I have visited all possible URLs and found no new information. I must think out of the box or different angle!!!'
|
||||||
|
});
|
||||||
|
|
||||||
|
allowRead = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await storeContext(prompt, [allContext, allKeywords, allQuestions, allKnowledge], totalStep);
|
await storeContext(prompt, [allContext, allKeywords, allQuestions, allKnowledge], totalStep);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const responseSchema = {
|
|||||||
},
|
},
|
||||||
improvement: {
|
improvement: {
|
||||||
type: SchemaType.STRING,
|
type: SchemaType.STRING,
|
||||||
description: "Suggested improvement plan for the next iteration"
|
description: "Suggested key improvement for the next iteration, do not use bullet points, be concise and hot-take vibe."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
required: ["recap", "blame", "improvement"]
|
required: ["recap", "blame", "improvement"]
|
||||||
|
|||||||
Reference in New Issue
Block a user