@@ -11,29 +11,9 @@ import { GEMINI_API_KEY, JINA_API_KEY, MODEL_NAME } from "./config";
11
11
import { tokenTracker } from "./utils/token-tracker" ;
12
12
13
13
async function sleep ( ms : number ) {
14
- const frames = [ '⠋' , '⠙' , '⠹' , '⠸' , '⠼' , '⠴' , '⠦' , '⠧' , '⠇' , '⠏' ] ;
15
- const startTime = Date . now ( ) ;
16
- const endTime = startTime + ms ;
17
-
18
- // Clear current line and hide cursor
19
- process . stdout . write ( '\x1B[?25l' ) ;
20
-
21
- while ( Date . now ( ) < endTime ) {
22
- const remaining = Math . ceil ( ( endTime - Date . now ( ) ) / 1000 ) ;
23
- const frameIndex = Math . floor ( Date . now ( ) / 100 ) % frames . length ;
24
-
25
- // Clear line and write new frame
26
- process . stdout . write ( `\r${ frames [ frameIndex ] } Cool down... ${ remaining } s remaining` ) ;
27
-
28
- // Small delay for animation
29
- await new Promise ( resolve => setTimeout ( resolve , 50 ) ) ;
30
- }
31
-
32
- // Clear line, show cursor and move to next line
33
- process . stdout . write ( '\r\x1B[K\x1B[?25h\n' ) ;
34
-
35
- // Original sleep
36
- await new Promise ( resolve => setTimeout ( resolve , 0 ) ) ;
14
+ const seconds = Math . ceil ( ms / 1000 ) ;
15
+ console . log ( `Waiting ${ seconds } s...` ) ;
16
+ return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
37
17
}
38
18
39
19
type ResponseSchema = {
@@ -96,7 +76,7 @@ type ResponseSchema = {
96
76
} ;
97
77
98
78
function getSchema ( allowReflect : boolean , allowRead : boolean ) : ResponseSchema {
99
- let actions = [ "search" , "answer" ] ;
79
+ const actions = [ "search" , "answer" ] ;
100
80
if ( allowReflect ) {
101
81
actions . push ( "reflect" ) ;
102
82
}
@@ -164,8 +144,7 @@ function getSchema(allowReflect: boolean, allowRead: boolean): ResponseSchema {
164
144
}
165
145
166
146
function getPrompt ( question : string , context ?: any [ ] , allQuestions ?: string [ ] , allowReflect : boolean = false , badContext ?: any [ ] , knowledge ?: any [ ] , allURLs ?: Record < string , string > ) {
167
- // console.log('Context:', context);
168
- // console.log('All URLs:', JSON.stringify(allURLs, null, 2));
147
+
169
148
170
149
const knowledgeIntro = knowledge ?. length ?
171
150
`
@@ -212,7 +191,7 @@ ${allURLs ? `
212
191
**visit**:
213
192
- Visit any URLs from below to gather external knowledge, choose the most relevant URLs that might contain the answer
214
193
215
- ${ Object . keys ( allURLs ) . map ( ( url , i ) => `
194
+ ${ Object . keys ( allURLs ) . map ( url => `
216
195
+ "${ url } ": "${ allURLs [ url ] } "` ) . join ( '' ) }
217
196
218
197
- When you have enough search result in the context and want to deep dive into specific URLs
@@ -268,8 +247,8 @@ Critical Requirements:
268
247
- Maintain strict JSON syntax` . trim ( ) ;
269
248
}
270
249
271
- let context : StepData [ ] = [ ] ; // successful steps in the current session
272
- let allContext : StepData [ ] = [ ] ; // all steps in the current session, including those leads to wrong results
250
+ const context : StepData [ ] = [ ] ; // successful steps in the current session
251
+ const allContext : StepData [ ] = [ ] ; // all steps in the current session, including those leads to wrong results
273
252
274
253
function updateContext ( step : any ) {
275
254
context . push ( step ) ;
@@ -280,27 +259,25 @@ function removeAllLineBreaks(text: string) {
280
259
return text . replace ( / ( \r \n | \n | \r ) / gm, " " ) ;
281
260
}
282
261
283
- async function getResponse ( question : string , tokenBudget : number = 1000000 ) {
284
- let totalTokens = 0 ;
262
+ async function getResponse ( question : string ) {
285
263
let step = 0 ;
286
264
let totalStep = 0 ;
287
265
let badAttempts = 0 ;
288
- let gaps : string [ ] = [ question ] ; // All questions to be answered including the orginal question
289
- let allQuestions = [ question ] ;
290
- let allKeywords = [ ] ;
291
- let allKnowledge = [ ] ; // knowledge are intermedidate questions that are answered
292
- let badContext = [ ] ;
266
+ const gaps : string [ ] = [ question ] ; // All questions to be answered including the orginal question
267
+ const allQuestions = [ question ] ;
268
+ const allKeywords = [ ] ;
269
+ const allKnowledge = [ ] ; // knowledge are intermedidate questions that are answered
270
+ const badContext = [ ] ;
293
271
let diaryContext = [ ] ;
294
- let allURLs : Record < string , string > = { } ;
295
- while ( totalTokens < tokenBudget ) {
272
+ const allURLs : Record < string , string > = { } ;
273
+ const currentQuestion = gaps . length > 0 ? gaps . shift ( ) ! : question ;
274
+ while ( gaps . length > 0 || currentQuestion === question ) {
296
275
// add 1s delay to avoid rate limiting
297
276
await sleep ( 1000 ) ;
298
277
step ++ ;
299
278
totalStep ++ ;
300
- console . log ( '===STEPS===' , totalStep )
301
- console . log ( 'Gaps:' , gaps )
279
+ console . log ( `Step ${ totalStep } : Processing ${ gaps . length } remaining questions` ) ;
302
280
const allowReflect = gaps . length <= 1 ;
303
- const currentQuestion = gaps . length > 0 ? gaps . shift ( ) ! : question ;
304
281
// update all urls with buildURLMap
305
282
const allowRead = Object . keys ( allURLs ) . length > 0 ;
306
283
const prompt = getPrompt (
@@ -311,7 +288,7 @@ async function getResponse(question: string, tokenBudget: number = 1000000) {
311
288
badContext ,
312
289
allKnowledge ,
313
290
allURLs ) ;
314
- console . log ( 'Prompt len:' , prompt . length )
291
+
315
292
316
293
const model = genAI . getGenerativeModel ( {
317
294
model : MODEL_NAME ,
@@ -325,12 +302,12 @@ async function getResponse(question: string, tokenBudget: number = 1000000) {
325
302
const result = await model . generateContent ( prompt ) ;
326
303
const response = await result . response ;
327
304
const usage = response . usageMetadata ;
305
+ tokenTracker . trackUsage ( 'agent' , usage ?. totalTokenCount || 0 ) ;
306
+
328
307
329
- totalTokens += usage ?. totalTokenCount || 0 ;
330
- console . log ( `Tokens: ${ totalTokens } /${ tokenBudget } ` ) ;
331
308
332
309
const action = JSON . parse ( response . text ( ) ) ;
333
- console . log ( 'Question-Action:' , currentQuestion , action ) ;
310
+
334
311
335
312
if ( action . action === 'answer' ) {
336
313
updateContext ( {
@@ -339,8 +316,8 @@ async function getResponse(question: string, tokenBudget: number = 1000000) {
339
316
...action ,
340
317
} ) ;
341
318
342
- const { response : evaluation , tokens : evalTokens } = await evaluateAnswer ( currentQuestion , action . answer ) ;
343
- totalTokens += evalTokens ;
319
+ const { response : evaluation } = await evaluateAnswer ( currentQuestion , action . answer ) ;
320
+
344
321
345
322
if ( currentQuestion === question ) {
346
323
if ( badAttempts >= 3 ) {
@@ -359,7 +336,7 @@ ${evaluation.reasoning}
359
336
360
337
Your journey ends here.
361
338
` ) ;
362
- console . info ( '\x1b[32m%s\x1b[0m' , 'Final Answer:' , action . answer ) ;
339
+ console . log ( 'Final Answer:' , action . answer ) ;
363
340
tokenTracker . printSummary ( ) ;
364
341
await storeContext ( prompt , [ allContext , allKeywords , allQuestions , allKnowledge ] , totalStep ) ;
365
342
return action ;
@@ -381,7 +358,7 @@ ${evaluation.reasoning}
381
358
382
359
Your journey ends here. You have successfully answered the original question. Congratulations! 🎉
383
360
` ) ;
384
- console . info ( '\x1b[32m%s\x1b[0m' , 'Final Answer:' , action . answer ) ;
361
+ console . log ( 'Final Answer:' , action . answer ) ;
385
362
tokenTracker . printSummary ( ) ;
386
363
await storeContext ( prompt , [ allContext , allKeywords , allQuestions , allKnowledge ] , totalStep ) ;
387
364
return action ;
@@ -413,8 +390,8 @@ The evaluator thinks your answer is bad because:
413
390
${ evaluation . reasoning }
414
391
` ) ;
415
392
// store the bad context and reset the diary context
416
- const { response : errorAnalysis , tokens : analyzeTokens } = await analyzeSteps ( diaryContext ) ;
417
- totalTokens += analyzeTokens ;
393
+ const { response : errorAnalysis } = await analyzeSteps ( diaryContext ) ;
394
+
418
395
badContext . push ( errorAnalysis ) ;
419
396
badAttempts ++ ;
420
397
diaryContext = [ ] ;
@@ -457,7 +434,6 @@ You will now figure out the answers to these sub-questions and see if they can h
457
434
allQuestions . push ( ...newGapQuestions ) ;
458
435
gaps . push ( question ) ; // always keep the original question in the gaps
459
436
} else {
460
- console . log ( 'No new questions to ask' ) ;
461
437
diaryContext . push ( `
462
438
At step ${ step } , you took **reflect** and think about the knowledge gaps. You tried to break down the question "${ currentQuestion } " into gap-questions like this: ${ oldQuestions . join ( ', ' ) }
463
439
But then you realized you have asked them before. You decided to to think out of the box or cut from a completely different angle.
@@ -471,19 +447,18 @@ But then you realized you have asked them before. You decided to to think out of
471
447
}
472
448
else if ( action . action === 'search' && action . searchQuery ) {
473
449
// rewrite queries
474
- let { keywords : keywordsQueries , tokens : rewriteTokens } = await rewriteQuery ( action . searchQuery ) ;
475
- totalTokens += rewriteTokens ;
450
+ let { keywords : keywordsQueries } = await rewriteQuery ( action . searchQuery ) ;
451
+
476
452
const oldKeywords = keywordsQueries ;
477
453
// avoid exisitng searched queries
478
454
if ( allKeywords . length ) {
479
- const { unique_queries : dedupedQueries , tokens : dedupTokens } = await dedupQueries ( keywordsQueries , allKeywords ) ;
480
- totalTokens += dedupTokens ;
455
+ const { unique_queries : dedupedQueries } = await dedupQueries ( keywordsQueries , allKeywords ) ;
481
456
keywordsQueries = dedupedQueries ;
482
457
}
483
458
if ( keywordsQueries . length > 0 ) {
484
459
const searchResults = [ ] ;
485
460
for ( const query of keywordsQueries ) {
486
- console . log ( 'Searching:' , query ) ;
461
+ console . log ( `Search query: ${ query } ` ) ;
487
462
const results = await search ( query , {
488
463
safeSearch : SafeSearchType . STRICT
489
464
} ) ;
@@ -519,7 +494,7 @@ But then you realized you have already searched for these keywords before.
519
494
You decided to think out of the box or cut from a completely different angle.
520
495
` ) ;
521
496
522
- console . log ( 'No new queries to search' ) ;
497
+
523
498
updateContext ( {
524
499
step,
525
500
...action ,
@@ -551,7 +526,7 @@ You found some useful information on the web and add them to your knowledge for
551
526
result : urlResults
552
527
} ) ;
553
528
554
- totalTokens += urlResults . reduce ( ( sum , r ) => sum + r . tokens , 0 ) ;
529
+
555
530
}
556
531
557
532
await storeContext ( prompt , [ allContext , allKeywords , allQuestions , allKnowledge ] , totalStep ) ;
@@ -567,7 +542,7 @@ async function storeContext(prompt: string, memory: any[][], step: number) {
567
542
await fs . writeFile ( 'questions.json' , JSON . stringify ( questions , null , 2 ) ) ;
568
543
await fs . writeFile ( 'knowledge.json' , JSON . stringify ( knowledge , null , 2 ) ) ;
569
544
} catch ( error ) {
570
- console . error ( 'Failed to store context :' , error ) ;
545
+ console . error ( 'Context storage failed :' , error ) ;
571
546
}
572
547
}
573
548
0 commit comments