mirror of
https://github.com/jina-ai/node-DeepResearch.git
synced 2025-12-26 06:28:56 +08:00
chore: first commit
This commit is contained in:
parent
af341611ee
commit
74716eea13
65
src/agent.ts
65
src/agent.ts
@ -3,6 +3,7 @@ import dotenv from 'dotenv';
|
|||||||
import {ProxyAgent, setGlobalDispatcher} from "undici";
|
import {ProxyAgent, setGlobalDispatcher} from "undici";
|
||||||
import {readUrl} from "./tools/read";
|
import {readUrl} from "./tools/read";
|
||||||
import {search} from "./tools/search";
|
import {search} from "./tools/search";
|
||||||
|
import fs from 'fs/promises';
|
||||||
|
|
||||||
// Proxy setup remains the same
|
// Proxy setup remains the same
|
||||||
if (process.env.https_proxy) {
|
if (process.env.https_proxy) {
|
||||||
@ -139,16 +140,18 @@ function getSchema(allowReflect: boolean): ResponseSchema {
|
|||||||
type: SchemaType.NUMBER,
|
type: SchemaType.NUMBER,
|
||||||
minimum: 0.0,
|
minimum: 0.0,
|
||||||
maximum: 1.0,
|
maximum: 1.0,
|
||||||
description: "Represents the confidence level of in answering the question BEFORE taking the action. Must be a float between 0.0 and 1.0",
|
description: "Represents the confidence level of in answering the question BEFORE taking the action.",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
required: ["action", "reasoning", "confidence"],
|
required: ["action", "reasoning", "confidence"],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrompt(question: string, context?: string, allowReflect: boolean = false) {
|
function getPrompt(question: string, context?: any[], allQuestions?: string[], allowReflect: boolean = false) {
|
||||||
const contextIntro = context ?
|
const contextIntro = context?.length ?
|
||||||
`\nYour current context contains these previous actions:\n\n ${context}\n`
|
`Your current context contains these previous actions and knowledge:
|
||||||
|
${JSON.stringify(context, null, 2)}
|
||||||
|
`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
let actionsDescription = `
|
let actionsDescription = `
|
||||||
@ -164,9 +167,9 @@ When uncertain or needing additional information, select one of these actions:
|
|||||||
- Use for recent information (post-training data) or missing domain knowledge
|
- Use for recent information (post-training data) or missing domain knowledge
|
||||||
|
|
||||||
**readURL**:
|
**readURL**:
|
||||||
- Access content from specific URLs found in current context
|
- Access the full content behind specific URLs
|
||||||
- Requires existing URLs from previous actions
|
- Requires existing URLs from previous actions
|
||||||
- Use when confident a contextual URL contains needed information
|
- Use when you think URL contains needed information
|
||||||
|
|
||||||
**answer**:
|
**answer**:
|
||||||
- Provide final response only when 100% certain
|
- Provide final response only when 100% certain
|
||||||
@ -181,7 +184,9 @@ ${allowReflect ? `- If doubts remain, use "reflect" instead` : ''}`;
|
|||||||
- Original (not variations of existing questions)
|
- Original (not variations of existing questions)
|
||||||
- Focused on single concepts
|
- Focused on single concepts
|
||||||
- Under 20 words
|
- Under 20 words
|
||||||
- Non-compound/non-complex`;
|
- Non-compound/non-complex
|
||||||
|
${allQuestions?.length ? `Existing questions you have asked, make sure to not repeat them:\n ${allQuestions.join('\n')}` : ''}
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `You are an advanced AI research analyst specializing in multi-step reasoning.${contextIntro}${actionsDescription}
|
return `You are an advanced AI research analyst specializing in multi-step reasoning.${contextIntro}${actionsDescription}
|
||||||
@ -198,16 +203,19 @@ Critical Requirements:
|
|||||||
async function getResponse(question: string) {
|
async function getResponse(question: string) {
|
||||||
let tokenBudget = 30000000;
|
let tokenBudget = 30000000;
|
||||||
let totalTokens = 0;
|
let totalTokens = 0;
|
||||||
let context = '';
|
let context = [];
|
||||||
let step = 0;
|
let step = 0;
|
||||||
let gaps: string[] = [question]; // All questions to be answered including the orginal question
|
let gaps: string[] = [question]; // All questions to be answered including the orginal question
|
||||||
|
let allQuestions = [question];
|
||||||
|
|
||||||
while (totalTokens < tokenBudget) {
|
while (totalTokens < tokenBudget) {
|
||||||
|
step++;
|
||||||
|
console.log('===STEPS===', step)
|
||||||
console.log('Gaps:', gaps)
|
console.log('Gaps:', gaps)
|
||||||
const allowReflect = gaps.length <= 1;
|
const allowReflect = gaps.length <= 1;
|
||||||
const currentQuestion = gaps.length > 0 ? gaps.shift()! : question;
|
const currentQuestion = gaps.length > 0 ? gaps.shift()! : question;
|
||||||
const prompt = getPrompt(currentQuestion, context, allowReflect);
|
const prompt = getPrompt(currentQuestion, context, allQuestions, allowReflect);
|
||||||
console.log('Prompt:', prompt.length)
|
console.log('Prompt len:', prompt.length)
|
||||||
|
|
||||||
const model = genAI.getGenerativeModel({
|
const model = genAI.getGenerativeModel({
|
||||||
model: modelName,
|
model: modelName,
|
||||||
@ -221,7 +229,6 @@ async function getResponse(question: string) {
|
|||||||
const result = await model.generateContent(prompt);
|
const result = await model.generateContent(prompt);
|
||||||
const response = await result.response;
|
const response = await result.response;
|
||||||
const usage = response.usageMetadata;
|
const usage = response.usageMetadata;
|
||||||
step++;
|
|
||||||
|
|
||||||
totalTokens += usage?.totalTokenCount || 0;
|
totalTokens += usage?.totalTokenCount || 0;
|
||||||
console.log(`Tokens: ${totalTokens}/${tokenBudget}`);
|
console.log(`Tokens: ${totalTokens}/${tokenBudget}`);
|
||||||
@ -233,34 +240,30 @@ async function getResponse(question: string) {
|
|||||||
if (currentQuestion === question) {
|
if (currentQuestion === question) {
|
||||||
return action;
|
return action;
|
||||||
} else {
|
} else {
|
||||||
context = `${context}\n${JSON.stringify({
|
context.push({
|
||||||
step,
|
step,
|
||||||
|
question: currentQuestion,
|
||||||
...action,
|
...action,
|
||||||
question: currentQuestion
|
});
|
||||||
})}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.action === 'reflect' && action.questionsToAnswer) {
|
if (action.action === 'reflect' && action.questionsToAnswer) {
|
||||||
gaps.push(...action.questionsToAnswer);
|
gaps.push(...action.questionsToAnswer);
|
||||||
|
allQuestions.push(...action.questionsToAnswer);
|
||||||
gaps.push(question); // always keep the original question in the gaps
|
gaps.push(question); // always keep the original question in the gaps
|
||||||
context = `${context}\n${JSON.stringify({
|
|
||||||
step,
|
|
||||||
...action,
|
|
||||||
question: currentQuestion
|
|
||||||
})}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rest of the action handling remains the same
|
// Rest of the action handling remains the same
|
||||||
try {
|
try {
|
||||||
if (action.action === 'search' && action.searchQuery) {
|
if (action.action === 'search' && action.searchQuery) {
|
||||||
const results = await search(action.searchQuery, jinaToken);
|
const results = await search(action.searchQuery, jinaToken);
|
||||||
context = `${context}\n${JSON.stringify({
|
context.push({
|
||||||
step,
|
step,
|
||||||
...action,
|
|
||||||
question: currentQuestion,
|
question: currentQuestion,
|
||||||
|
...action,
|
||||||
result: results.data
|
result: results.data
|
||||||
})}`;
|
});
|
||||||
totalTokens += results.data.reduce((sum, r) => sum + r.usage.tokens, 0);
|
totalTokens += results.data.reduce((sum, r) => sum + r.usage.tokens, 0);
|
||||||
} else if (action.action === 'readURL' && action.URLTargets?.length) {
|
} else if (action.action === 'readURL' && action.URLTargets?.length) {
|
||||||
const urlResults = await Promise.all(
|
const urlResults = await Promise.all(
|
||||||
@ -269,18 +272,26 @@ async function getResponse(question: string) {
|
|||||||
return {url, result: response};
|
return {url, result: response};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
context.push({
|
||||||
context = `${context}\n${JSON.stringify({
|
|
||||||
step,
|
step,
|
||||||
...action,
|
|
||||||
question: currentQuestion,
|
question: currentQuestion,
|
||||||
|
...action,
|
||||||
result: urlResults
|
result: urlResults
|
||||||
})}`;
|
});
|
||||||
totalTokens += urlResults.reduce((sum, r) => sum + r.result.data.usage.tokens, 0);
|
totalTokens += urlResults.reduce((sum, r) => sum + r.result.data.usage.tokens, 0);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching data:', error);
|
console.error('Error fetching data:', error);
|
||||||
}
|
}
|
||||||
|
await storeContext(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function storeContext(context: any[]) {
|
||||||
|
try {
|
||||||
|
await fs.writeFile('context.json', JSON.stringify(context, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to store context:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +300,7 @@ const jinaToken = process.env.JINA_API_KEY as string;
|
|||||||
if (!apiKey) throw new Error("GEMINI_API_KEY not found");
|
if (!apiKey) throw new Error("GEMINI_API_KEY not found");
|
||||||
if (!jinaToken) throw new Error("JINA_API_KEY not found");
|
if (!jinaToken) throw new Error("JINA_API_KEY not found");
|
||||||
|
|
||||||
const modelName = 'gemini-1.5-flash';
|
const modelName = 'gemini-2.0-flash-exp';
|
||||||
const genAI = new GoogleGenerativeAI(apiKey);
|
const genAI = new GoogleGenerativeAI(apiKey);
|
||||||
|
|
||||||
const question = process.argv[2] || "";
|
const question = process.argv[2] || "";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user