valyu-js 2.2.0 → 2.2.2
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/dist/index.d.mts +59 -10
- package/dist/index.d.ts +59 -10
- package/dist/index.js +240 -135
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +240 -135
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -687,164 +687,269 @@ var Valyu = class {
|
|
|
687
687
|
* @param options.startDate - Start date filter (YYYY-MM-DD format)
|
|
688
688
|
* @param options.endDate - End date filter (YYYY-MM-DD format)
|
|
689
689
|
* @param options.fastMode - Fast mode for quicker but shorter results (default: false)
|
|
690
|
-
* @
|
|
690
|
+
* @param options.streaming - Enable streaming mode (default: false)
|
|
691
|
+
* @returns Promise resolving to answer response, or AsyncGenerator for streaming
|
|
691
692
|
*/
|
|
692
693
|
async answer(query, options = {}) {
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
if (
|
|
696
|
-
return
|
|
697
|
-
success: false,
|
|
698
|
-
error: "Query is required and must be a non-empty string"
|
|
699
|
-
};
|
|
700
|
-
}
|
|
701
|
-
let finalSearchType = defaultSearchType;
|
|
702
|
-
const providedSearchTypeString = options.searchType?.toLowerCase();
|
|
703
|
-
if (providedSearchTypeString === "web" || providedSearchTypeString === "proprietary" || providedSearchTypeString === "all" || providedSearchTypeString === "news") {
|
|
704
|
-
finalSearchType = providedSearchTypeString;
|
|
705
|
-
} else if (options.searchType !== void 0) {
|
|
706
|
-
return {
|
|
707
|
-
success: false,
|
|
708
|
-
error: "Invalid searchType provided. Must be one of: all, web, proprietary, news"
|
|
709
|
-
};
|
|
694
|
+
const validationError = this.validateAnswerParams(query, options);
|
|
695
|
+
if (validationError) {
|
|
696
|
+
if (options.streaming) {
|
|
697
|
+
return this.createErrorGenerator(validationError);
|
|
710
698
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
if (options.
|
|
733
|
-
|
|
734
|
-
return {
|
|
735
|
-
success: false,
|
|
736
|
-
error: "dataMaxPrice must be a positive number"
|
|
737
|
-
};
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
if (options.startDate && !this.validateDateFormat(options.startDate)) {
|
|
741
|
-
return {
|
|
742
|
-
success: false,
|
|
743
|
-
error: "Invalid startDate format. Must be YYYY-MM-DD"
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
if (options.endDate && !this.validateDateFormat(options.endDate)) {
|
|
747
|
-
return {
|
|
748
|
-
success: false,
|
|
749
|
-
error: "Invalid endDate format. Must be YYYY-MM-DD"
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
if (options.startDate && options.endDate) {
|
|
753
|
-
const startDate = new Date(options.startDate);
|
|
754
|
-
const endDate = new Date(options.endDate);
|
|
755
|
-
if (startDate > endDate) {
|
|
756
|
-
return {
|
|
757
|
-
success: false,
|
|
758
|
-
error: "startDate must be before endDate"
|
|
759
|
-
};
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
if (options.includedSources !== void 0) {
|
|
763
|
-
if (!Array.isArray(options.includedSources)) {
|
|
764
|
-
return {
|
|
765
|
-
success: false,
|
|
766
|
-
error: "includedSources must be an array"
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
const includedSourcesValidation = this.validateSources(
|
|
770
|
-
options.includedSources
|
|
771
|
-
);
|
|
772
|
-
if (!includedSourcesValidation.valid) {
|
|
773
|
-
return {
|
|
774
|
-
success: false,
|
|
775
|
-
error: `Invalid includedSources format. Invalid sources: ${includedSourcesValidation.invalidSources.join(
|
|
776
|
-
", "
|
|
777
|
-
)}. Sources must be valid URLs, domains (with optional paths), or dataset identifiers in 'provider/dataset' format.`
|
|
778
|
-
};
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
if (options.excludedSources !== void 0) {
|
|
782
|
-
if (!Array.isArray(options.excludedSources)) {
|
|
783
|
-
return {
|
|
784
|
-
success: false,
|
|
785
|
-
error: "excludedSources must be an array"
|
|
786
|
-
};
|
|
787
|
-
}
|
|
788
|
-
const excludedSourcesValidation = this.validateSources(
|
|
789
|
-
options.excludedSources
|
|
790
|
-
);
|
|
791
|
-
if (!excludedSourcesValidation.valid) {
|
|
792
|
-
return {
|
|
793
|
-
success: false,
|
|
794
|
-
error: `Invalid excludedSources format. Invalid sources: ${excludedSourcesValidation.invalidSources.join(
|
|
795
|
-
", "
|
|
796
|
-
)}. Sources must be valid URLs, domains (with optional paths), or dataset identifiers in 'provider/dataset' format.`
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
const payload = {
|
|
801
|
-
query: query.trim(),
|
|
802
|
-
search_type: finalSearchType
|
|
803
|
-
};
|
|
804
|
-
if (options.dataMaxPrice !== void 0) {
|
|
805
|
-
payload.data_max_price = options.dataMaxPrice;
|
|
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";
|
|
806
722
|
}
|
|
807
|
-
|
|
808
|
-
|
|
723
|
+
const trimmed = options.systemInstructions.trim();
|
|
724
|
+
if (trimmed.length === 0) {
|
|
725
|
+
return "systemInstructions cannot be empty when provided";
|
|
809
726
|
}
|
|
810
|
-
if (
|
|
811
|
-
|
|
727
|
+
if (trimmed.length > 2e3) {
|
|
728
|
+
return "systemInstructions must be 2000 characters or less";
|
|
812
729
|
}
|
|
813
|
-
|
|
814
|
-
|
|
730
|
+
}
|
|
731
|
+
if (options.dataMaxPrice !== void 0) {
|
|
732
|
+
if (typeof options.dataMaxPrice !== "number" || options.dataMaxPrice <= 0) {
|
|
733
|
+
return "dataMaxPrice must be a positive number";
|
|
815
734
|
}
|
|
816
|
-
|
|
817
|
-
|
|
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";
|
|
818
747
|
}
|
|
819
|
-
|
|
820
|
-
|
|
748
|
+
}
|
|
749
|
+
if (options.includedSources !== void 0) {
|
|
750
|
+
if (!Array.isArray(options.includedSources)) {
|
|
751
|
+
return "includedSources must be an array";
|
|
821
752
|
}
|
|
822
|
-
|
|
823
|
-
|
|
753
|
+
const validation = this.validateSources(options.includedSources);
|
|
754
|
+
if (!validation.valid) {
|
|
755
|
+
return `Invalid includedSources format. Invalid sources: ${validation.invalidSources.join(", ")}.`;
|
|
824
756
|
}
|
|
825
|
-
|
|
826
|
-
|
|
757
|
+
}
|
|
758
|
+
if (options.excludedSources !== void 0) {
|
|
759
|
+
if (!Array.isArray(options.excludedSources)) {
|
|
760
|
+
return "excludedSources must be an array";
|
|
827
761
|
}
|
|
828
|
-
|
|
829
|
-
|
|
762
|
+
const validation = this.validateSources(options.excludedSources);
|
|
763
|
+
if (!validation.valid) {
|
|
764
|
+
return `Invalid excludedSources format. Invalid sources: ${validation.invalidSources.join(", ")}.`;
|
|
830
765
|
}
|
|
831
|
-
|
|
832
|
-
|
|
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)
|
|
833
806
|
});
|
|
834
|
-
if (!response.
|
|
807
|
+
if (!response.ok) {
|
|
808
|
+
const errorData = await response.json().catch(() => ({}));
|
|
835
809
|
return {
|
|
836
810
|
success: false,
|
|
837
|
-
error:
|
|
811
|
+
error: errorData.error || `HTTP Error: ${response.status}`
|
|
838
812
|
};
|
|
839
813
|
}
|
|
840
|
-
|
|
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
|
+
const response2 = {
|
|
850
|
+
success: true,
|
|
851
|
+
tx_id: finalMetadata.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
|
+
if (finalMetadata.extraction_metadata) {
|
|
861
|
+
response2.extraction_metadata = finalMetadata.extraction_metadata;
|
|
862
|
+
}
|
|
863
|
+
return response2;
|
|
864
|
+
}
|
|
865
|
+
return {
|
|
866
|
+
success: false,
|
|
867
|
+
error: finalMetadata.error || "Unknown error occurred"
|
|
868
|
+
};
|
|
841
869
|
} catch (e) {
|
|
842
870
|
return {
|
|
843
871
|
success: false,
|
|
844
|
-
error: e.
|
|
872
|
+
error: e.message || "Request failed"
|
|
845
873
|
};
|
|
846
874
|
}
|
|
847
875
|
}
|
|
876
|
+
/**
|
|
877
|
+
* Stream answer using SSE
|
|
878
|
+
*/
|
|
879
|
+
async *streamAnswer(payload) {
|
|
880
|
+
try {
|
|
881
|
+
const response = await fetch(`${this.baseUrl}/answer`, {
|
|
882
|
+
method: "POST",
|
|
883
|
+
headers: {
|
|
884
|
+
...this.headers,
|
|
885
|
+
"Accept": "text/event-stream"
|
|
886
|
+
},
|
|
887
|
+
body: JSON.stringify(payload)
|
|
888
|
+
});
|
|
889
|
+
if (!response.ok) {
|
|
890
|
+
const errorData = await response.json().catch(() => ({}));
|
|
891
|
+
yield { type: "error", error: errorData.error || `HTTP Error: ${response.status}` };
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const reader = response.body?.getReader();
|
|
895
|
+
const decoder = new TextDecoder();
|
|
896
|
+
let buffer = "";
|
|
897
|
+
if (!reader) {
|
|
898
|
+
yield { type: "error", error: "No response body" };
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
while (true) {
|
|
902
|
+
const { done, value } = await reader.read();
|
|
903
|
+
if (done) break;
|
|
904
|
+
buffer += decoder.decode(value, { stream: true });
|
|
905
|
+
const lines = buffer.split("\n");
|
|
906
|
+
buffer = lines.pop() || "";
|
|
907
|
+
for (const line of lines) {
|
|
908
|
+
if (!line.startsWith("data: ")) continue;
|
|
909
|
+
const dataStr = line.slice(6);
|
|
910
|
+
if (dataStr === "[DONE]") {
|
|
911
|
+
yield { type: "done" };
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
914
|
+
try {
|
|
915
|
+
const parsed = JSON.parse(dataStr);
|
|
916
|
+
if (parsed.search_results && parsed.success === void 0) {
|
|
917
|
+
yield { type: "search_results", search_results: parsed.search_results };
|
|
918
|
+
} else if (parsed.choices) {
|
|
919
|
+
const delta = parsed.choices[0]?.delta || {};
|
|
920
|
+
const content = delta.content || "";
|
|
921
|
+
const finishReason = parsed.choices[0]?.finish_reason;
|
|
922
|
+
if (content || finishReason) {
|
|
923
|
+
yield { type: "content", content, finish_reason: finishReason };
|
|
924
|
+
}
|
|
925
|
+
} else if (parsed.success !== void 0) {
|
|
926
|
+
yield {
|
|
927
|
+
type: "metadata",
|
|
928
|
+
tx_id: parsed.tx_id,
|
|
929
|
+
original_query: parsed.original_query,
|
|
930
|
+
data_type: parsed.data_type,
|
|
931
|
+
search_results: parsed.search_results,
|
|
932
|
+
search_metadata: parsed.search_metadata,
|
|
933
|
+
ai_usage: parsed.ai_usage,
|
|
934
|
+
cost: parsed.cost,
|
|
935
|
+
extraction_metadata: parsed.extraction_metadata
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
} catch {
|
|
939
|
+
continue;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
} catch (e) {
|
|
944
|
+
yield { type: "error", error: e.message || "Stream failed" };
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* Create an error generator for streaming errors
|
|
949
|
+
*/
|
|
950
|
+
async *createErrorGenerator(error) {
|
|
951
|
+
yield { type: "error", error };
|
|
952
|
+
}
|
|
848
953
|
};
|
|
849
954
|
export {
|
|
850
955
|
Valyu
|