valyu-js 2.1.7 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -0
- package/dist/index.d.mts +264 -7
- package/dist/index.d.ts +264 -7
- package/dist/index.js +474 -132
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +474 -132
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -13,6 +13,17 @@ var Valyu = class {
|
|
|
13
13
|
"Content-Type": "application/json",
|
|
14
14
|
"x-api-key": apiKey
|
|
15
15
|
};
|
|
16
|
+
this.deepresearch = {
|
|
17
|
+
create: this._deepresearchCreate.bind(this),
|
|
18
|
+
status: this._deepresearchStatus.bind(this),
|
|
19
|
+
wait: this._deepresearchWait.bind(this),
|
|
20
|
+
stream: this._deepresearchStream.bind(this),
|
|
21
|
+
list: this._deepresearchList.bind(this),
|
|
22
|
+
update: this._deepresearchUpdate.bind(this),
|
|
23
|
+
cancel: this._deepresearchCancel.bind(this),
|
|
24
|
+
delete: this._deepresearchDelete.bind(this),
|
|
25
|
+
togglePublic: this._deepresearchTogglePublic.bind(this)
|
|
26
|
+
};
|
|
16
27
|
}
|
|
17
28
|
/**
|
|
18
29
|
* Validates date format (YYYY-MM-DD)
|
|
@@ -432,177 +443,508 @@ var Valyu = class {
|
|
|
432
443
|
}
|
|
433
444
|
}
|
|
434
445
|
/**
|
|
435
|
-
*
|
|
436
|
-
* @param query - The question or query string
|
|
437
|
-
* @param options - Answer configuration options
|
|
438
|
-
* @param options.structuredOutput - JSON Schema object for structured responses
|
|
439
|
-
* @param options.systemInstructions - Custom system-level instructions (max 2000 chars)
|
|
440
|
-
* @param options.searchType - Type of search: "web", "proprietary", "all", or "news"
|
|
441
|
-
* @param options.dataMaxPrice - Maximum spend (USD) for data retrieval
|
|
442
|
-
* @param options.countryCode - Country code filter for search results
|
|
443
|
-
* @param options.includedSources - List of specific sources to include
|
|
444
|
-
* @param options.excludedSources - List of URLs/domains to exclude from search results
|
|
445
|
-
* @param options.startDate - Start date filter (YYYY-MM-DD format)
|
|
446
|
-
* @param options.endDate - End date filter (YYYY-MM-DD format)
|
|
447
|
-
* @param options.fastMode - Fast mode for quicker but shorter results (default: false)
|
|
448
|
-
* @returns Promise resolving to answer response
|
|
446
|
+
* DeepResearch: Create a new research task
|
|
449
447
|
*/
|
|
450
|
-
async
|
|
448
|
+
async _deepresearchCreate(options) {
|
|
451
449
|
try {
|
|
452
|
-
|
|
453
|
-
if (!query || typeof query !== "string" || query.trim().length === 0) {
|
|
450
|
+
if (!options.input?.trim()) {
|
|
454
451
|
return {
|
|
455
452
|
success: false,
|
|
456
|
-
error: "
|
|
453
|
+
error: "input is required and cannot be empty"
|
|
457
454
|
};
|
|
458
455
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
456
|
+
const payload = {
|
|
457
|
+
input: options.input,
|
|
458
|
+
model: options.model || "lite",
|
|
459
|
+
output_formats: options.outputFormats || ["markdown"],
|
|
460
|
+
code_execution: options.codeExecution !== false
|
|
461
|
+
};
|
|
462
|
+
if (options.strategy) payload.strategy = options.strategy;
|
|
463
|
+
if (options.search) {
|
|
464
|
+
payload.search = {
|
|
465
|
+
search_type: options.search.searchType,
|
|
466
|
+
included_sources: options.search.includedSources
|
|
467
467
|
};
|
|
468
468
|
}
|
|
469
|
-
if (options.
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
469
|
+
if (options.urls) payload.urls = options.urls;
|
|
470
|
+
if (options.files) payload.files = options.files;
|
|
471
|
+
if (options.mcpServers) payload.mcp_servers = options.mcpServers;
|
|
472
|
+
if (options.previousReports) {
|
|
473
|
+
payload.previous_reports = options.previousReports;
|
|
474
|
+
}
|
|
475
|
+
if (options.webhookUrl) payload.webhook_url = options.webhookUrl;
|
|
476
|
+
if (options.metadata) payload.metadata = options.metadata;
|
|
477
|
+
const response = await axios.post(
|
|
478
|
+
`${this.baseUrl}/deepresearch/tasks`,
|
|
479
|
+
payload,
|
|
480
|
+
{ headers: this.headers }
|
|
481
|
+
);
|
|
482
|
+
return { success: true, ...response.data };
|
|
483
|
+
} catch (e) {
|
|
484
|
+
return {
|
|
485
|
+
success: false,
|
|
486
|
+
error: e.response?.data?.error || e.message
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* DeepResearch: Get task status
|
|
492
|
+
*/
|
|
493
|
+
async _deepresearchStatus(taskId) {
|
|
494
|
+
try {
|
|
495
|
+
const response = await axios.get(
|
|
496
|
+
`${this.baseUrl}/deepresearch/tasks/${taskId}/status`,
|
|
497
|
+
{ headers: this.headers }
|
|
498
|
+
);
|
|
499
|
+
return { success: true, ...response.data };
|
|
500
|
+
} catch (e) {
|
|
501
|
+
return {
|
|
502
|
+
success: false,
|
|
503
|
+
error: e.response?.data?.error || e.message
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* DeepResearch: Wait for task completion with polling
|
|
509
|
+
*/
|
|
510
|
+
async _deepresearchWait(taskId, options = {}) {
|
|
511
|
+
const pollInterval = options.pollInterval || 5e3;
|
|
512
|
+
const maxWaitTime = options.maxWaitTime || 36e5;
|
|
513
|
+
const startTime = Date.now();
|
|
514
|
+
while (true) {
|
|
515
|
+
const status = await this._deepresearchStatus(taskId);
|
|
516
|
+
if (!status.success) {
|
|
517
|
+
throw new Error(status.error);
|
|
489
518
|
}
|
|
490
|
-
if (options.
|
|
491
|
-
|
|
492
|
-
return {
|
|
493
|
-
success: false,
|
|
494
|
-
error: "dataMaxPrice must be a positive number"
|
|
495
|
-
};
|
|
496
|
-
}
|
|
519
|
+
if (options.onProgress) {
|
|
520
|
+
options.onProgress(status);
|
|
497
521
|
}
|
|
498
|
-
if (
|
|
499
|
-
return
|
|
500
|
-
success: false,
|
|
501
|
-
error: "Invalid startDate format. Must be YYYY-MM-DD"
|
|
502
|
-
};
|
|
522
|
+
if (status.status === "completed" || status.status === "failed" || status.status === "cancelled") {
|
|
523
|
+
return status;
|
|
503
524
|
}
|
|
504
|
-
if (
|
|
505
|
-
|
|
506
|
-
success: false,
|
|
507
|
-
error: "Invalid endDate format. Must be YYYY-MM-DD"
|
|
508
|
-
};
|
|
525
|
+
if (Date.now() - startTime > maxWaitTime) {
|
|
526
|
+
throw new Error("Maximum wait time exceeded");
|
|
509
527
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
528
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* DeepResearch: Stream real-time updates
|
|
533
|
+
*/
|
|
534
|
+
async _deepresearchStream(taskId, callback) {
|
|
535
|
+
let isComplete = false;
|
|
536
|
+
let lastMessageCount = 0;
|
|
537
|
+
while (!isComplete) {
|
|
538
|
+
try {
|
|
539
|
+
const status = await this._deepresearchStatus(taskId);
|
|
540
|
+
if (!status.success) {
|
|
541
|
+
if (callback.onError) {
|
|
542
|
+
callback.onError(new Error(status.error));
|
|
543
|
+
}
|
|
544
|
+
return;
|
|
518
545
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
error: "includedSources must be an array"
|
|
525
|
-
};
|
|
546
|
+
if (status.progress && callback.onProgress) {
|
|
547
|
+
callback.onProgress(
|
|
548
|
+
status.progress.current_step,
|
|
549
|
+
status.progress.total_steps
|
|
550
|
+
);
|
|
526
551
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
return {
|
|
532
|
-
success: false,
|
|
533
|
-
error: `Invalid includedSources format. Invalid sources: ${includedSourcesValidation.invalidSources.join(
|
|
534
|
-
", "
|
|
535
|
-
)}. Sources must be valid URLs, domains (with optional paths), or dataset identifiers in 'provider/dataset' format.`
|
|
536
|
-
};
|
|
552
|
+
if (status.messages && callback.onMessage) {
|
|
553
|
+
const newMessages = status.messages.slice(lastMessageCount);
|
|
554
|
+
newMessages.forEach((msg) => callback.onMessage(msg));
|
|
555
|
+
lastMessageCount = status.messages.length;
|
|
537
556
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
557
|
+
if (status.status === "completed") {
|
|
558
|
+
if (callback.onComplete) {
|
|
559
|
+
callback.onComplete(status);
|
|
560
|
+
}
|
|
561
|
+
isComplete = true;
|
|
562
|
+
} else if (status.status === "failed" || status.status === "cancelled") {
|
|
563
|
+
if (callback.onError) {
|
|
564
|
+
callback.onError(
|
|
565
|
+
new Error(status.error || `Task ${status.status}`)
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
isComplete = true;
|
|
545
569
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
error: `Invalid excludedSources format. Invalid sources: ${excludedSourcesValidation.invalidSources.join(
|
|
553
|
-
", "
|
|
554
|
-
)}. Sources must be valid URLs, domains (with optional paths), or dataset identifiers in 'provider/dataset' format.`
|
|
555
|
-
};
|
|
570
|
+
if (!isComplete) {
|
|
571
|
+
await new Promise((resolve) => setTimeout(resolve, 5e3));
|
|
572
|
+
}
|
|
573
|
+
} catch (error) {
|
|
574
|
+
if (callback.onError) {
|
|
575
|
+
callback.onError(error);
|
|
556
576
|
}
|
|
577
|
+
throw error;
|
|
557
578
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* DeepResearch: List all tasks
|
|
583
|
+
*/
|
|
584
|
+
async _deepresearchList(options) {
|
|
585
|
+
try {
|
|
586
|
+
const limit = options.limit || 10;
|
|
587
|
+
const response = await axios.get(
|
|
588
|
+
`${this.baseUrl}/deepresearch/listtasks?api_key_id=${options.apiKeyId}&limit=${limit}`,
|
|
589
|
+
{ headers: this.headers }
|
|
590
|
+
);
|
|
591
|
+
return { success: true, data: response.data };
|
|
592
|
+
} catch (e) {
|
|
593
|
+
return {
|
|
594
|
+
success: false,
|
|
595
|
+
error: e.response?.data?.error || e.message
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* DeepResearch: Add follow-up instruction
|
|
601
|
+
*/
|
|
602
|
+
async _deepresearchUpdate(taskId, instruction) {
|
|
603
|
+
try {
|
|
604
|
+
if (!instruction?.trim()) {
|
|
605
|
+
return {
|
|
606
|
+
success: false,
|
|
607
|
+
error: "instruction is required and cannot be empty"
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
const response = await axios.post(
|
|
611
|
+
`${this.baseUrl}/deepresearch/tasks/${taskId}/update`,
|
|
612
|
+
{ instruction },
|
|
613
|
+
{ headers: this.headers }
|
|
614
|
+
);
|
|
615
|
+
return { success: true, ...response.data };
|
|
616
|
+
} catch (e) {
|
|
617
|
+
return {
|
|
618
|
+
success: false,
|
|
619
|
+
error: e.response?.data?.error || e.message
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* DeepResearch: Cancel task
|
|
625
|
+
*/
|
|
626
|
+
async _deepresearchCancel(taskId) {
|
|
627
|
+
try {
|
|
628
|
+
const response = await axios.post(
|
|
629
|
+
`${this.baseUrl}/deepresearch/tasks/${taskId}/cancel`,
|
|
630
|
+
{},
|
|
631
|
+
{ headers: this.headers }
|
|
632
|
+
);
|
|
633
|
+
return { success: true, ...response.data };
|
|
634
|
+
} catch (e) {
|
|
635
|
+
return {
|
|
636
|
+
success: false,
|
|
637
|
+
error: e.response?.data?.error || e.message
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* DeepResearch: Delete task
|
|
643
|
+
*/
|
|
644
|
+
async _deepresearchDelete(taskId) {
|
|
645
|
+
try {
|
|
646
|
+
const response = await axios.delete(
|
|
647
|
+
`${this.baseUrl}/deepresearch/tasks/${taskId}/delete`,
|
|
648
|
+
{ headers: this.headers }
|
|
649
|
+
);
|
|
650
|
+
return { success: true, ...response.data };
|
|
651
|
+
} catch (e) {
|
|
652
|
+
return {
|
|
653
|
+
success: false,
|
|
654
|
+
error: e.response?.data?.error || e.message
|
|
561
655
|
};
|
|
562
|
-
|
|
563
|
-
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* DeepResearch: Toggle public flag
|
|
660
|
+
*/
|
|
661
|
+
async _deepresearchTogglePublic(taskId, isPublic) {
|
|
662
|
+
try {
|
|
663
|
+
const response = await axios.post(
|
|
664
|
+
`${this.baseUrl}/deepresearch/tasks/${taskId}/public`,
|
|
665
|
+
{ public: isPublic },
|
|
666
|
+
{ headers: this.headers }
|
|
667
|
+
);
|
|
668
|
+
return { success: true, ...response.data };
|
|
669
|
+
} catch (e) {
|
|
670
|
+
return {
|
|
671
|
+
success: false,
|
|
672
|
+
error: e.response?.data?.error || e.message
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Get AI-powered answers using the Valyu Answer API
|
|
678
|
+
* @param query - The question or query string
|
|
679
|
+
* @param options - Answer configuration options
|
|
680
|
+
* @param options.structuredOutput - JSON Schema object for structured responses
|
|
681
|
+
* @param options.systemInstructions - Custom system-level instructions (max 2000 chars)
|
|
682
|
+
* @param options.searchType - Type of search: "web", "proprietary", "all", or "news"
|
|
683
|
+
* @param options.dataMaxPrice - Maximum spend (USD) for data retrieval
|
|
684
|
+
* @param options.countryCode - Country code filter for search results
|
|
685
|
+
* @param options.includedSources - List of specific sources to include
|
|
686
|
+
* @param options.excludedSources - List of URLs/domains to exclude from search results
|
|
687
|
+
* @param options.startDate - Start date filter (YYYY-MM-DD format)
|
|
688
|
+
* @param options.endDate - End date filter (YYYY-MM-DD format)
|
|
689
|
+
* @param options.fastMode - Fast mode for quicker but shorter results (default: false)
|
|
690
|
+
* @param options.streaming - Enable streaming mode (default: false)
|
|
691
|
+
* @returns Promise resolving to answer response, or AsyncGenerator for streaming
|
|
692
|
+
*/
|
|
693
|
+
async answer(query, options = {}) {
|
|
694
|
+
const validationError = this.validateAnswerParams(query, options);
|
|
695
|
+
if (validationError) {
|
|
696
|
+
if (options.streaming) {
|
|
697
|
+
return this.createErrorGenerator(validationError);
|
|
564
698
|
}
|
|
565
|
-
|
|
566
|
-
|
|
699
|
+
return { success: false, error: validationError };
|
|
700
|
+
}
|
|
701
|
+
const payload = this.buildAnswerPayload(query, options);
|
|
702
|
+
if (options.streaming) {
|
|
703
|
+
return this.streamAnswer(payload);
|
|
704
|
+
} else {
|
|
705
|
+
return this.fetchAnswer(payload);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Validate answer parameters
|
|
710
|
+
*/
|
|
711
|
+
validateAnswerParams(query, options) {
|
|
712
|
+
if (!query || typeof query !== "string" || query.trim().length === 0) {
|
|
713
|
+
return "Query is required and must be a non-empty string";
|
|
714
|
+
}
|
|
715
|
+
const providedSearchTypeString = options.searchType?.toLowerCase();
|
|
716
|
+
if (providedSearchTypeString !== void 0 && providedSearchTypeString !== "web" && providedSearchTypeString !== "proprietary" && providedSearchTypeString !== "all" && providedSearchTypeString !== "news") {
|
|
717
|
+
return "Invalid searchType provided. Must be one of: all, web, proprietary, news";
|
|
718
|
+
}
|
|
719
|
+
if (options.systemInstructions !== void 0) {
|
|
720
|
+
if (typeof options.systemInstructions !== "string") {
|
|
721
|
+
return "systemInstructions must be a string";
|
|
567
722
|
}
|
|
568
|
-
|
|
569
|
-
|
|
723
|
+
const trimmed = options.systemInstructions.trim();
|
|
724
|
+
if (trimmed.length === 0) {
|
|
725
|
+
return "systemInstructions cannot be empty when provided";
|
|
570
726
|
}
|
|
571
|
-
if (
|
|
572
|
-
|
|
727
|
+
if (trimmed.length > 2e3) {
|
|
728
|
+
return "systemInstructions must be 2000 characters or less";
|
|
573
729
|
}
|
|
574
|
-
|
|
575
|
-
|
|
730
|
+
}
|
|
731
|
+
if (options.dataMaxPrice !== void 0) {
|
|
732
|
+
if (typeof options.dataMaxPrice !== "number" || options.dataMaxPrice <= 0) {
|
|
733
|
+
return "dataMaxPrice must be a positive number";
|
|
576
734
|
}
|
|
577
|
-
|
|
578
|
-
|
|
735
|
+
}
|
|
736
|
+
if (options.startDate && !this.validateDateFormat(options.startDate)) {
|
|
737
|
+
return "Invalid startDate format. Must be YYYY-MM-DD";
|
|
738
|
+
}
|
|
739
|
+
if (options.endDate && !this.validateDateFormat(options.endDate)) {
|
|
740
|
+
return "Invalid endDate format. Must be YYYY-MM-DD";
|
|
741
|
+
}
|
|
742
|
+
if (options.startDate && options.endDate) {
|
|
743
|
+
const startDate = new Date(options.startDate);
|
|
744
|
+
const endDate = new Date(options.endDate);
|
|
745
|
+
if (startDate > endDate) {
|
|
746
|
+
return "startDate must be before endDate";
|
|
579
747
|
}
|
|
580
|
-
|
|
581
|
-
|
|
748
|
+
}
|
|
749
|
+
if (options.includedSources !== void 0) {
|
|
750
|
+
if (!Array.isArray(options.includedSources)) {
|
|
751
|
+
return "includedSources must be an array";
|
|
582
752
|
}
|
|
583
|
-
|
|
584
|
-
|
|
753
|
+
const validation = this.validateSources(options.includedSources);
|
|
754
|
+
if (!validation.valid) {
|
|
755
|
+
return `Invalid includedSources format. Invalid sources: ${validation.invalidSources.join(", ")}.`;
|
|
585
756
|
}
|
|
586
|
-
|
|
587
|
-
|
|
757
|
+
}
|
|
758
|
+
if (options.excludedSources !== void 0) {
|
|
759
|
+
if (!Array.isArray(options.excludedSources)) {
|
|
760
|
+
return "excludedSources must be an array";
|
|
588
761
|
}
|
|
589
|
-
const
|
|
590
|
-
|
|
762
|
+
const validation = this.validateSources(options.excludedSources);
|
|
763
|
+
if (!validation.valid) {
|
|
764
|
+
return `Invalid excludedSources format. Invalid sources: ${validation.invalidSources.join(", ")}.`;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
return null;
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Build payload for answer API
|
|
771
|
+
*/
|
|
772
|
+
buildAnswerPayload(query, options) {
|
|
773
|
+
const defaultSearchType = "all";
|
|
774
|
+
const providedSearchTypeString = options.searchType?.toLowerCase();
|
|
775
|
+
let finalSearchType = defaultSearchType;
|
|
776
|
+
if (providedSearchTypeString === "web" || providedSearchTypeString === "proprietary" || providedSearchTypeString === "all" || providedSearchTypeString === "news") {
|
|
777
|
+
finalSearchType = providedSearchTypeString;
|
|
778
|
+
}
|
|
779
|
+
const payload = {
|
|
780
|
+
query: query.trim(),
|
|
781
|
+
search_type: finalSearchType
|
|
782
|
+
};
|
|
783
|
+
if (options.dataMaxPrice !== void 0) payload.data_max_price = options.dataMaxPrice;
|
|
784
|
+
if (options.structuredOutput !== void 0) payload.structured_output = options.structuredOutput;
|
|
785
|
+
if (options.systemInstructions !== void 0) payload.system_instructions = options.systemInstructions.trim();
|
|
786
|
+
if (options.countryCode !== void 0) payload.country_code = options.countryCode;
|
|
787
|
+
if (options.includedSources !== void 0) payload.included_sources = options.includedSources;
|
|
788
|
+
if (options.excludedSources !== void 0) payload.excluded_sources = options.excludedSources;
|
|
789
|
+
if (options.startDate !== void 0) payload.start_date = options.startDate;
|
|
790
|
+
if (options.endDate !== void 0) payload.end_date = options.endDate;
|
|
791
|
+
if (options.fastMode !== void 0) payload.fast_mode = options.fastMode;
|
|
792
|
+
return payload;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Fetch answer (non-streaming mode)
|
|
796
|
+
*/
|
|
797
|
+
async fetchAnswer(payload) {
|
|
798
|
+
try {
|
|
799
|
+
const response = await fetch(`${this.baseUrl}/answer`, {
|
|
800
|
+
method: "POST",
|
|
801
|
+
headers: {
|
|
802
|
+
...this.headers,
|
|
803
|
+
"Accept": "text/event-stream"
|
|
804
|
+
},
|
|
805
|
+
body: JSON.stringify(payload)
|
|
591
806
|
});
|
|
592
|
-
if (!response.
|
|
807
|
+
if (!response.ok) {
|
|
808
|
+
const errorData = await response.json().catch(() => ({}));
|
|
593
809
|
return {
|
|
594
810
|
success: false,
|
|
595
|
-
error:
|
|
811
|
+
error: errorData.error || `HTTP Error: ${response.status}`
|
|
596
812
|
};
|
|
597
813
|
}
|
|
598
|
-
|
|
814
|
+
let fullContent = "";
|
|
815
|
+
let searchResults = [];
|
|
816
|
+
let finalMetadata = {};
|
|
817
|
+
const reader = response.body?.getReader();
|
|
818
|
+
const decoder = new TextDecoder();
|
|
819
|
+
let buffer = "";
|
|
820
|
+
if (reader) {
|
|
821
|
+
while (true) {
|
|
822
|
+
const { done, value } = await reader.read();
|
|
823
|
+
if (done) break;
|
|
824
|
+
buffer += decoder.decode(value, { stream: true });
|
|
825
|
+
const lines = buffer.split("\n");
|
|
826
|
+
buffer = lines.pop() || "";
|
|
827
|
+
for (const line of lines) {
|
|
828
|
+
if (!line.startsWith("data: ")) continue;
|
|
829
|
+
const dataStr = line.slice(6);
|
|
830
|
+
if (dataStr === "[DONE]") continue;
|
|
831
|
+
try {
|
|
832
|
+
const parsed = JSON.parse(dataStr);
|
|
833
|
+
if (parsed.search_results && !parsed.success) {
|
|
834
|
+
searchResults = [...searchResults, ...parsed.search_results];
|
|
835
|
+
} else if (parsed.choices) {
|
|
836
|
+
const content = parsed.choices[0]?.delta?.content || "";
|
|
837
|
+
if (content) fullContent += content;
|
|
838
|
+
} else if (parsed.success !== void 0) {
|
|
839
|
+
finalMetadata = parsed;
|
|
840
|
+
}
|
|
841
|
+
} catch {
|
|
842
|
+
continue;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
if (finalMetadata.success) {
|
|
848
|
+
const finalSearchResults = finalMetadata.search_results || searchResults;
|
|
849
|
+
return {
|
|
850
|
+
success: true,
|
|
851
|
+
ai_tx_id: finalMetadata.ai_tx_id || "",
|
|
852
|
+
original_query: finalMetadata.original_query || payload.query,
|
|
853
|
+
contents: fullContent || finalMetadata.contents || "",
|
|
854
|
+
data_type: finalMetadata.data_type || "unstructured",
|
|
855
|
+
search_results: finalSearchResults,
|
|
856
|
+
search_metadata: finalMetadata.search_metadata || { tx_ids: [], number_of_results: 0, total_characters: 0 },
|
|
857
|
+
ai_usage: finalMetadata.ai_usage || { input_tokens: 0, output_tokens: 0 },
|
|
858
|
+
cost: finalMetadata.cost || { total_deduction_dollars: 0, search_deduction_dollars: 0, ai_deduction_dollars: 0 }
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
return {
|
|
862
|
+
success: false,
|
|
863
|
+
error: finalMetadata.error || "Unknown error occurred"
|
|
864
|
+
};
|
|
599
865
|
} catch (e) {
|
|
600
866
|
return {
|
|
601
867
|
success: false,
|
|
602
|
-
error: e.
|
|
868
|
+
error: e.message || "Request failed"
|
|
603
869
|
};
|
|
604
870
|
}
|
|
605
871
|
}
|
|
872
|
+
/**
|
|
873
|
+
* Stream answer using SSE
|
|
874
|
+
*/
|
|
875
|
+
async *streamAnswer(payload) {
|
|
876
|
+
try {
|
|
877
|
+
const response = await fetch(`${this.baseUrl}/answer`, {
|
|
878
|
+
method: "POST",
|
|
879
|
+
headers: {
|
|
880
|
+
...this.headers,
|
|
881
|
+
"Accept": "text/event-stream"
|
|
882
|
+
},
|
|
883
|
+
body: JSON.stringify(payload)
|
|
884
|
+
});
|
|
885
|
+
if (!response.ok) {
|
|
886
|
+
const errorData = await response.json().catch(() => ({}));
|
|
887
|
+
yield { type: "error", error: errorData.error || `HTTP Error: ${response.status}` };
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
const reader = response.body?.getReader();
|
|
891
|
+
const decoder = new TextDecoder();
|
|
892
|
+
let buffer = "";
|
|
893
|
+
if (!reader) {
|
|
894
|
+
yield { type: "error", error: "No response body" };
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
while (true) {
|
|
898
|
+
const { done, value } = await reader.read();
|
|
899
|
+
if (done) break;
|
|
900
|
+
buffer += decoder.decode(value, { stream: true });
|
|
901
|
+
const lines = buffer.split("\n");
|
|
902
|
+
buffer = lines.pop() || "";
|
|
903
|
+
for (const line of lines) {
|
|
904
|
+
if (!line.startsWith("data: ")) continue;
|
|
905
|
+
const dataStr = line.slice(6);
|
|
906
|
+
if (dataStr === "[DONE]") {
|
|
907
|
+
yield { type: "done" };
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
910
|
+
try {
|
|
911
|
+
const parsed = JSON.parse(dataStr);
|
|
912
|
+
if (parsed.search_results && parsed.success === void 0) {
|
|
913
|
+
yield { type: "search_results", search_results: parsed.search_results };
|
|
914
|
+
} else if (parsed.choices) {
|
|
915
|
+
const delta = parsed.choices[0]?.delta || {};
|
|
916
|
+
const content = delta.content || "";
|
|
917
|
+
const finishReason = parsed.choices[0]?.finish_reason;
|
|
918
|
+
if (content || finishReason) {
|
|
919
|
+
yield { type: "content", content, finish_reason: finishReason };
|
|
920
|
+
}
|
|
921
|
+
} else if (parsed.success !== void 0) {
|
|
922
|
+
yield {
|
|
923
|
+
type: "metadata",
|
|
924
|
+
ai_tx_id: parsed.ai_tx_id,
|
|
925
|
+
original_query: parsed.original_query,
|
|
926
|
+
data_type: parsed.data_type,
|
|
927
|
+
search_results: parsed.search_results,
|
|
928
|
+
search_metadata: parsed.search_metadata,
|
|
929
|
+
ai_usage: parsed.ai_usage,
|
|
930
|
+
cost: parsed.cost
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
} catch {
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
} catch (e) {
|
|
939
|
+
yield { type: "error", error: e.message || "Stream failed" };
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Create an error generator for streaming errors
|
|
944
|
+
*/
|
|
945
|
+
async *createErrorGenerator(error) {
|
|
946
|
+
yield { type: "error", error };
|
|
947
|
+
}
|
|
606
948
|
};
|
|
607
949
|
export {
|
|
608
950
|
Valyu
|