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