valyu-js 2.7.18 → 2.9.0

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.mjs CHANGED
@@ -3,7 +3,8 @@ import { createHmac, timingSafeEqual } from "crypto";
3
3
  import http from "http";
4
4
  import https from "https";
5
5
  import axios from "axios";
6
- var SDK_VERSION = "2.7.17";
6
+ var SDK_VERSION = "2.9.0";
7
+ var TRANSIENT_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
7
8
  function normalizeContentsJobResponse(api) {
8
9
  return {
9
10
  success: api.success ?? true,
@@ -94,6 +95,15 @@ var Valyu = class {
94
95
  list: this._datasourcesList.bind(this),
95
96
  categories: this._datasourcesCategories.bind(this)
96
97
  };
98
+ this.workflows = {
99
+ list: this._workflowsList.bind(this),
100
+ get: this._workflowsGet.bind(this),
101
+ versions: this._workflowsVersions.bind(this),
102
+ preview: this._workflowsPreview.bind(this),
103
+ create: this._workflowsCreate.bind(this),
104
+ update: this._workflowsUpdate.bind(this),
105
+ delete: this._workflowsDelete.bind(this)
106
+ };
97
107
  }
98
108
  /**
99
109
  * Validates date format (YYYY-MM-DD)
@@ -621,6 +631,41 @@ var Valyu = class {
621
631
  async _deepresearchCreate(options) {
622
632
  try {
623
633
  const queryValue = options.query ?? options.input;
634
+ if (options.workflowId) {
635
+ if (queryValue || options.strategy || options.researchStrategy || options.reportFormat) {
636
+ return {
637
+ success: false,
638
+ error: "workflowId is mutually exclusive with query/input/researchStrategy/reportFormat - the workflow template supplies those fields"
639
+ };
640
+ }
641
+ const payload2 = {
642
+ workflow_id: options.workflowId
643
+ };
644
+ if (options.workflowParams !== void 0) {
645
+ payload2.workflow_params = options.workflowParams;
646
+ }
647
+ if (options.workflowVersion !== void 0) {
648
+ payload2.workflow_version = options.workflowVersion;
649
+ }
650
+ const explicitMode = options.mode ?? options.model;
651
+ if (explicitMode) payload2.mode = explicitMode;
652
+ if (options.outputFormats) payload2.output_formats = options.outputFormats;
653
+ if (options.tools) payload2.tools = options.tools;
654
+ if (options.webhookUrl) payload2.webhook_url = options.webhookUrl;
655
+ if (options.alertEmail) {
656
+ payload2.alert_email = typeof options.alertEmail === "string" ? options.alertEmail : {
657
+ email: options.alertEmail.email,
658
+ custom_url: options.alertEmail.custom_url
659
+ };
660
+ }
661
+ if (options.metadata) payload2.metadata = options.metadata;
662
+ const response2 = await this.client.post(
663
+ `${this.baseUrl}/deepresearch/tasks`,
664
+ payload2,
665
+ { headers: this.headers }
666
+ );
667
+ return { success: true, ...response2.data };
668
+ }
624
669
  if (!queryValue?.trim()) {
625
670
  return {
626
671
  success: false,
@@ -744,19 +789,49 @@ var Valyu = class {
744
789
  /**
745
790
  * DeepResearch: Get task status
746
791
  */
747
- async _deepresearchStatus(taskId) {
748
- try {
749
- const response = await this.client.get(
750
- `${this.baseUrl}/deepresearch/tasks/${taskId}/status`,
751
- { headers: this.headers }
752
- );
753
- return { success: true, ...response.data };
754
- } catch (e) {
755
- return {
756
- success: false,
757
- error: e.response?.data?.error || e.message
758
- };
792
+ async _deepresearchStatus(taskId, maxAttempts = 5) {
793
+ const url = `${this.baseUrl}/deepresearch/tasks/${taskId}/status`;
794
+ let lastError = "status endpoint unreachable";
795
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
796
+ try {
797
+ const response = await this.client.get(url, {
798
+ headers: this.headers,
799
+ // Classify status codes ourselves rather than letting axios throw.
800
+ validateStatus: () => true
801
+ });
802
+ if (TRANSIENT_STATUS_CODES.has(response.status)) {
803
+ lastError = `HTTP ${response.status}`;
804
+ } else {
805
+ const contentType = String(
806
+ response.headers?.["content-type"] || ""
807
+ );
808
+ const body = response.data;
809
+ const isJsonObject = contentType.toLowerCase().includes("application/json") && typeof body === "object" && body !== null && !Array.isArray(body);
810
+ if (!isJsonObject) {
811
+ lastError = `non-JSON/empty status response (HTTP ${response.status}, content-type: ${contentType || "none"})`;
812
+ } else if (response.status >= 400) {
813
+ return {
814
+ success: false,
815
+ error: body.error || `HTTP Error: ${response.status}`
816
+ };
817
+ } else {
818
+ const { success: _ignored, ...rest } = body;
819
+ return { success: true, ...rest };
820
+ }
821
+ }
822
+ } catch (e) {
823
+ lastError = e?.message || String(e);
824
+ }
825
+ if (attempt < maxAttempts - 1) {
826
+ const delayMs = Math.min(2 ** attempt, 30) * 1e3 + Math.random() * 1e3;
827
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
828
+ }
759
829
  }
830
+ return {
831
+ success: false,
832
+ unreachable: true,
833
+ error: `Status endpoint unreachable after ${maxAttempts} attempts: ${lastError}`
834
+ };
760
835
  }
761
836
  /**
762
837
  * DeepResearch: Wait for task completion with polling
@@ -768,6 +843,15 @@ var Valyu = class {
768
843
  while (true) {
769
844
  const status = await this._deepresearchStatus(taskId);
770
845
  if (!status.success) {
846
+ if (status.unreachable) {
847
+ if (Date.now() - startTime > maxWaitTime) {
848
+ throw new Error(
849
+ `Status endpoint unreachable for ${maxWaitTime}ms: ${status.error}`
850
+ );
851
+ }
852
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
853
+ continue;
854
+ }
771
855
  throw new Error(status.error);
772
856
  }
773
857
  if (options.onProgress) {
@@ -1639,6 +1723,160 @@ var Valyu = class {
1639
1723
  };
1640
1724
  }
1641
1725
  }
1726
+ /** Extract the most descriptive error message from a Workflows API error. */
1727
+ workflowError(e) {
1728
+ return e.response?.data?.message || e.response?.data?.error || e.message;
1729
+ }
1730
+ /**
1731
+ * Workflows: List workflows available to your org
1732
+ * @param options - Filters: vertical, scope ("valyu" | "org" | "all"), q, tags, limit, expand
1733
+ */
1734
+ async _workflowsList(options = {}) {
1735
+ try {
1736
+ const params = new URLSearchParams();
1737
+ if (options.vertical) params.append("vertical", options.vertical);
1738
+ if (options.scope) params.append("scope", options.scope);
1739
+ if (options.q) params.append("q", options.q);
1740
+ if (options.tags?.length) params.append("tags", options.tags.join(","));
1741
+ if (options.limit !== void 0) {
1742
+ params.append("limit", String(options.limit));
1743
+ }
1744
+ if (options.expand) params.append("expand", "true");
1745
+ const url = `${this.baseUrl}/workflows${params.toString() ? `?${params.toString()}` : ""}`;
1746
+ const response = await this.client.get(url, { headers: this.headers });
1747
+ return { success: true, ...response.data };
1748
+ } catch (e) {
1749
+ return { success: false, error: this.workflowError(e) };
1750
+ }
1751
+ }
1752
+ /**
1753
+ * Workflows: Get a workflow's full detail, including its template
1754
+ * @param slug - Workflow slug
1755
+ * @param version - Specific version to fetch (defaults to the current version)
1756
+ */
1757
+ async _workflowsGet(slug, version) {
1758
+ try {
1759
+ const url = `${this.baseUrl}/workflows/${encodeURIComponent(slug)}${version !== void 0 ? `?version=${version}` : ""}`;
1760
+ const response = await this.client.get(url, { headers: this.headers });
1761
+ return { success: true, workflow: response.data };
1762
+ } catch (e) {
1763
+ return { success: false, error: this.workflowError(e) };
1764
+ }
1765
+ }
1766
+ /**
1767
+ * Workflows: List a workflow's version history
1768
+ * @param slug - Workflow slug
1769
+ */
1770
+ async _workflowsVersions(slug) {
1771
+ try {
1772
+ const response = await this.client.get(
1773
+ `${this.baseUrl}/workflows/${encodeURIComponent(slug)}/versions`,
1774
+ { headers: this.headers }
1775
+ );
1776
+ return { success: true, ...response.data };
1777
+ } catch (e) {
1778
+ return { success: false, error: this.workflowError(e) };
1779
+ }
1780
+ }
1781
+ /**
1782
+ * Workflows: Resolve a workflow's template with params without creating a task
1783
+ * @param slug - Workflow slug
1784
+ * @param options - workflowParams (variable values) and optional workflowVersion
1785
+ */
1786
+ async _workflowsPreview(slug, options = {}) {
1787
+ try {
1788
+ const payload = {};
1789
+ if (options.workflowParams !== void 0) {
1790
+ payload.workflow_params = options.workflowParams;
1791
+ }
1792
+ if (options.workflowVersion !== void 0) {
1793
+ payload.workflow_version = options.workflowVersion;
1794
+ }
1795
+ const response = await this.client.post(
1796
+ `${this.baseUrl}/workflows/${encodeURIComponent(slug)}/preview`,
1797
+ payload,
1798
+ { headers: this.headers }
1799
+ );
1800
+ return { success: true, ...response.data };
1801
+ } catch (e) {
1802
+ return { success: false, error: this.workflowError(e) };
1803
+ }
1804
+ }
1805
+ /**
1806
+ * Workflows: Create a new workflow for your org
1807
+ * @param options - slug, title, version (template body), and optional metadata
1808
+ */
1809
+ async _workflowsCreate(options) {
1810
+ try {
1811
+ const payload = {
1812
+ slug: options.slug,
1813
+ title: options.title,
1814
+ version: options.version
1815
+ };
1816
+ if (options.subtitle !== void 0) payload.subtitle = options.subtitle;
1817
+ if (options.description !== void 0) {
1818
+ payload.description = options.description;
1819
+ }
1820
+ if (options.vertical !== void 0) payload.vertical = options.vertical;
1821
+ if (options.tags !== void 0) payload.tags = options.tags;
1822
+ if (options.icon !== void 0) payload.icon = options.icon;
1823
+ const response = await this.client.post(
1824
+ `${this.baseUrl}/workflows`,
1825
+ payload,
1826
+ { headers: this.headers }
1827
+ );
1828
+ return { success: true, workflow: response.data };
1829
+ } catch (e) {
1830
+ return { success: false, error: this.workflowError(e) };
1831
+ }
1832
+ }
1833
+ /**
1834
+ * Workflows: Update a workflow's metadata and/or publish a new template version.
1835
+ * Only workflows owned by your org can be updated; versions are append-only
1836
+ * (a version body requires a changelog).
1837
+ * @param slug - Workflow slug
1838
+ * @param options - Metadata fields and/or a new version body
1839
+ */
1840
+ async _workflowsUpdate(slug, options) {
1841
+ try {
1842
+ const payload = {};
1843
+ if (options.title !== void 0) payload.title = options.title;
1844
+ if (options.subtitle !== void 0) payload.subtitle = options.subtitle;
1845
+ if (options.description !== void 0) {
1846
+ payload.description = options.description;
1847
+ }
1848
+ if (options.vertical !== void 0) payload.vertical = options.vertical;
1849
+ if (options.tags !== void 0) payload.tags = options.tags;
1850
+ if (options.icon !== void 0) payload.icon = options.icon;
1851
+ if (options.version !== void 0) payload.version = options.version;
1852
+ if (options.setCurrent !== void 0) {
1853
+ payload.set_current = options.setCurrent;
1854
+ }
1855
+ const response = await this.client.patch(
1856
+ `${this.baseUrl}/workflows/${encodeURIComponent(slug)}`,
1857
+ payload,
1858
+ { headers: this.headers }
1859
+ );
1860
+ return { success: true, workflow: response.data };
1861
+ } catch (e) {
1862
+ return { success: false, error: this.workflowError(e) };
1863
+ }
1864
+ }
1865
+ /**
1866
+ * Workflows: Delete a workflow owned by your org (soft delete)
1867
+ * @param slug - Workflow slug
1868
+ */
1869
+ async _workflowsDelete(slug) {
1870
+ try {
1871
+ const response = await this.client.delete(
1872
+ `${this.baseUrl}/workflows/${encodeURIComponent(slug)}`,
1873
+ { headers: this.headers }
1874
+ );
1875
+ return { success: true, ...response.data };
1876
+ } catch (e) {
1877
+ return { success: false, error: this.workflowError(e) };
1878
+ }
1879
+ }
1642
1880
  };
1643
1881
  export {
1644
1882
  Valyu,