deepline 0.1.181 → 0.1.182

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.
@@ -74,11 +74,20 @@
74
74
  */
75
75
  import { DeeplineClient } from './client.js';
76
76
  import { DeeplineError } from './errors.js';
77
- import { createToolExecuteResult } from '../../shared_libs/play-runtime/tool-result.js';
77
+ import {
78
+ attachToolResultListDataset,
79
+ createToolExecuteResult,
80
+ } from '../../shared_libs/play-runtime/tool-result.js';
78
81
  export {
79
82
  readValue,
80
83
  readList,
81
84
  } from '../../shared_libs/play-runtime/tool-result.js';
85
+ import { createDeferredPlayDataset } from '../../shared_libs/plays/dataset.js';
86
+ import {
87
+ QUERY_RESULT_DATASET_PAGE_SIZE,
88
+ isCustomerDbDatasetTool,
89
+ isQueryResultDatasetTool,
90
+ } from '../../shared_libs/play-runtime/query-result-dataset.js';
82
91
  import type {
83
92
  PlayDataset,
84
93
  PlayDatasetInput,
@@ -1473,8 +1482,12 @@ export class DeeplineContext {
1473
1482
  ): Promise<ToolExecuteResult> => {
1474
1483
  const response = await this.client.executeTool(toolId, input, {
1475
1484
  includeToolMetadata: true,
1485
+ responseIntent: 'dataset',
1486
+ });
1487
+ return toolExecutionEnvelopeToResult(toolId, response, {
1488
+ client: this.client,
1489
+ input,
1476
1490
  });
1477
- return toolExecutionEnvelopeToResult(toolId, response);
1478
1491
  },
1479
1492
  };
1480
1493
  }
@@ -1724,9 +1737,163 @@ function extractorDescriptorRecord(
1724
1737
  );
1725
1738
  }
1726
1739
 
1740
+ function rowsFromUnknown(value: unknown): Record<string, unknown>[] {
1741
+ if (!Array.isArray(value)) return [];
1742
+ return value.map((row) => (isRecord(row) ? row : { value: row }));
1743
+ }
1744
+
1745
+ function finiteNonNegativeInteger(value: unknown): number | null {
1746
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
1747
+ return null;
1748
+ }
1749
+ return Math.floor(value);
1750
+ }
1751
+
1752
+ function finitePositiveInteger(value: unknown): number | null {
1753
+ const integer = finiteNonNegativeInteger(value);
1754
+ return integer !== null && integer > 0 ? integer : null;
1755
+ }
1756
+
1757
+ function stableHash(value: string): string {
1758
+ let hash = 0;
1759
+ for (let index = 0; index < value.length; index += 1) {
1760
+ hash = Math.imul(31, hash) + value.charCodeAt(index);
1761
+ hash |= 0;
1762
+ }
1763
+ return Math.abs(hash).toString(36);
1764
+ }
1765
+
1766
+ function attachSdkQueryResultDatasetResult(
1767
+ toolId: string,
1768
+ result: ToolExecuteResult,
1769
+ options?: {
1770
+ client: DeeplineClient;
1771
+ input: Record<string, unknown>;
1772
+ },
1773
+ ): ToolExecuteResult {
1774
+ if (!options || !isQueryResultDatasetTool(toolId)) return result;
1775
+ const raw = isRecord(result.toolResponse.raw)
1776
+ ? result.toolResponse.raw
1777
+ : null;
1778
+ const dataset = isRecord(raw?.dataset) ? raw.dataset : null;
1779
+ const totalRows = finiteNonNegativeInteger(dataset?.total_rows);
1780
+ const sql =
1781
+ typeof options.input.sql === 'string'
1782
+ ? options.input.sql
1783
+ : typeof options.input.query === 'string'
1784
+ ? options.input.query
1785
+ : typeof raw?.sql === 'string'
1786
+ ? raw.sql
1787
+ : null;
1788
+ if (!dataset || totalRows === null || !sql) {
1789
+ return result;
1790
+ }
1791
+ const datasetLimit =
1792
+ finitePositiveInteger(dataset.returned_limit) ?? totalRows;
1793
+ const previewRows = rowsFromUnknown(raw?.rows).slice(0, 25);
1794
+ const fetchPage = async (
1795
+ offset: number,
1796
+ limit: number,
1797
+ ): Promise<Record<string, unknown>[]> => {
1798
+ if (limit <= 0 || offset >= totalRows) return [];
1799
+ const response = await options.client.executeTool(toolId, options.input, {
1800
+ includeToolMetadata: true,
1801
+ responseIntent: 'dataset',
1802
+ metadata: {
1803
+ query_result_dataset: {
1804
+ limit: datasetLimit,
1805
+ offset,
1806
+ page_size: Math.min(limit, QUERY_RESULT_DATASET_PAGE_SIZE),
1807
+ total_rows: totalRows,
1808
+ },
1809
+ ...(isCustomerDbDatasetTool(toolId)
1810
+ ? {
1811
+ customer_db_dataset: {
1812
+ limit: datasetLimit,
1813
+ offset,
1814
+ page_size: Math.min(limit, QUERY_RESULT_DATASET_PAGE_SIZE),
1815
+ total_rows: totalRows,
1816
+ },
1817
+ }
1818
+ : {}),
1819
+ },
1820
+ });
1821
+ const pageRaw = isRecord(response.toolResponse?.raw)
1822
+ ? response.toolResponse.raw
1823
+ : null;
1824
+ return rowsFromUnknown(pageRaw?.rows);
1825
+ };
1826
+ const collectRows = async (
1827
+ limit: number | undefined,
1828
+ ): Promise<Record<string, unknown>[]> => {
1829
+ const target = Math.min(limit ?? totalRows, totalRows, datasetLimit);
1830
+ const collected: Record<string, unknown>[] = [];
1831
+ for (
1832
+ let offset = 0;
1833
+ offset < target;
1834
+ offset += QUERY_RESULT_DATASET_PAGE_SIZE
1835
+ ) {
1836
+ collected.push(
1837
+ ...(await fetchPage(
1838
+ offset,
1839
+ Math.min(QUERY_RESULT_DATASET_PAGE_SIZE, target - offset),
1840
+ )),
1841
+ );
1842
+ }
1843
+ return collected.slice(0, target);
1844
+ };
1845
+ const executionNonce =
1846
+ typeof result.job_id === 'string' && result.job_id.trim()
1847
+ ? result.job_id.trim()
1848
+ : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
1849
+ const safeNonce = executionNonce
1850
+ .replace(/[^A-Za-z0-9_.:-]/g, '_')
1851
+ .slice(0, 64);
1852
+ const datasetScope = `${options.client.baseUrl}:${toolId}:${sql}:${datasetLimit}`;
1853
+ const playDataset = createDeferredPlayDataset({
1854
+ datasetKind: 'csv',
1855
+ datasetId: `sdk-tool-list:${toolId}:${stableHash(datasetScope)}:${datasetLimit}:${safeNonce}`,
1856
+ count: Math.min(totalRows, datasetLimit),
1857
+ previewRows,
1858
+ sourceLabel: 'query result rows',
1859
+ tableNamespace: null,
1860
+ resolvers: {
1861
+ count: async () => Math.min(totalRows, datasetLimit),
1862
+ peek: async (limit) => collectRows(limit),
1863
+ materialize: async (limit) => collectRows(limit),
1864
+ iterate: () =>
1865
+ ({
1866
+ async *[Symbol.asyncIterator]() {
1867
+ const count = Math.min(totalRows, datasetLimit);
1868
+ for (
1869
+ let offset = 0;
1870
+ offset < count;
1871
+ offset += QUERY_RESULT_DATASET_PAGE_SIZE
1872
+ ) {
1873
+ yield* await fetchPage(
1874
+ offset,
1875
+ Math.min(QUERY_RESULT_DATASET_PAGE_SIZE, count - offset),
1876
+ );
1877
+ }
1878
+ },
1879
+ }) as AsyncIterable<Record<string, unknown>>,
1880
+ },
1881
+ });
1882
+ return attachToolResultListDataset(result, {
1883
+ name: 'rows',
1884
+ path: 'toolResponse.raw.rows',
1885
+ dataset: playDataset,
1886
+ count: Math.min(totalRows, datasetLimit),
1887
+ });
1888
+ }
1889
+
1727
1890
  function toolExecutionEnvelopeToResult(
1728
1891
  fallbackToolId: string,
1729
1892
  response: ToolExecution,
1893
+ options?: {
1894
+ client: DeeplineClient;
1895
+ input: Record<string, unknown>;
1896
+ },
1730
1897
  ): ToolExecuteResult {
1731
1898
  const raw = response.toolResponse?.raw ?? null;
1732
1899
  const meta = response.toolResponse?.meta;
@@ -1735,30 +1902,37 @@ function toolExecutionEnvelopeToResult(
1735
1902
  : null;
1736
1903
  const toolMetadata = isRecord(metadata) ? metadata : {};
1737
1904
 
1738
- return createToolExecuteResult({
1739
- status: typeof response.status === 'string' ? response.status : 'completed',
1740
- jobId: typeof response.job_id === 'string' ? response.job_id : undefined,
1741
- result: {
1742
- data: raw,
1743
- ...(isRecord(meta) ? { meta } : {}),
1744
- },
1745
- metadata: {
1746
- toolId:
1747
- typeof toolMetadata.toolId === 'string'
1748
- ? toolMetadata.toolId
1749
- : fallbackToolId,
1750
- extractors: extractorDescriptorRecord(toolMetadata.extractors),
1751
- targetGetters: stringArrayRecord(toolMetadata.targetGetters),
1752
- listExtractorPaths: stringArray(toolMetadata.listExtractorPaths),
1753
- listIdentityGetters: stringArrayRecord(toolMetadata.listIdentityGetters),
1754
- },
1755
- execution: {
1756
- idempotent: true,
1757
- cached: false,
1758
- source: 'live',
1759
- },
1760
- meta: isRecord(response.meta) ? response.meta : undefined,
1761
- });
1905
+ return attachSdkQueryResultDatasetResult(
1906
+ fallbackToolId,
1907
+ createToolExecuteResult({
1908
+ status:
1909
+ typeof response.status === 'string' ? response.status : 'completed',
1910
+ jobId: typeof response.job_id === 'string' ? response.job_id : undefined,
1911
+ result: {
1912
+ data: raw,
1913
+ ...(isRecord(meta) ? { meta } : {}),
1914
+ },
1915
+ metadata: {
1916
+ toolId:
1917
+ typeof toolMetadata.toolId === 'string'
1918
+ ? toolMetadata.toolId
1919
+ : fallbackToolId,
1920
+ extractors: extractorDescriptorRecord(toolMetadata.extractors),
1921
+ targetGetters: stringArrayRecord(toolMetadata.targetGetters),
1922
+ listExtractorPaths: stringArray(toolMetadata.listExtractorPaths),
1923
+ listIdentityGetters: stringArrayRecord(
1924
+ toolMetadata.listIdentityGetters,
1925
+ ),
1926
+ },
1927
+ execution: {
1928
+ idempotent: true,
1929
+ cached: false,
1930
+ source: 'live',
1931
+ },
1932
+ meta: isRecord(response.meta) ? response.meta : undefined,
1933
+ }),
1934
+ options,
1935
+ );
1762
1936
  }
1763
1937
 
1764
1938
  export function defineInput<TInput>(
@@ -105,10 +105,10 @@ export const SDK_RELEASE = {
105
105
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
106
106
  // fields shipped in 0.1.153.
107
107
  // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
108
- version: '0.1.181',
108
+ version: '0.1.182',
109
109
  apiContract: '2026-06-dataset-handle-results-hard-cutover',
110
110
  supportPolicy: {
111
- latest: '0.1.181',
111
+ latest: '0.1.182',
112
112
  minimumSupported: '0.1.53',
113
113
  deprecatedBelow: '0.1.53',
114
114
  commandMinimumSupported: [