deepline 0.1.180 → 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.
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +241 -4
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/output-datasets.ts +124 -12
- package/dist/bundling-sources/sdk/src/client.ts +7 -5
- package/dist/bundling-sources/sdk/src/play.ts +200 -26
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +263 -44
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/query-result-dataset.ts +120 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +139 -17
- package/dist/cli/index.js +12 -9
- package/dist/cli/index.mjs +12 -9
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +213 -28
- package/dist/index.mjs +213 -28
- package/package.json +1 -1
|
@@ -73,6 +73,7 @@ import {
|
|
|
73
73
|
import { submitChildPlayThroughCoordinator } from './child-play-submit';
|
|
74
74
|
import type { AnyBatchOperationStrategy } from '../../../shared_libs/play-runtime/batching-types';
|
|
75
75
|
import {
|
|
76
|
+
attachToolResultListDataset,
|
|
76
77
|
parseToolExecuteResponse,
|
|
77
78
|
createToolExecuteResult,
|
|
78
79
|
deserializeToolExecuteResult,
|
|
@@ -97,12 +98,20 @@ import {
|
|
|
97
98
|
deriveToolRequestIdentity,
|
|
98
99
|
derivePlayRowIdentity,
|
|
99
100
|
derivePlayRowIdentityFromKey,
|
|
101
|
+
sha256Hex,
|
|
100
102
|
} from '../../../shared_libs/plays/row-identity';
|
|
103
|
+
import { createDeferredPlayDataset } from '../../../shared_libs/plays/dataset';
|
|
101
104
|
import {
|
|
102
105
|
buildDurableCtxCallCacheKey,
|
|
103
106
|
buildDurableToolCallAuthScopeDigest,
|
|
104
107
|
buildDurableToolCallCacheKey,
|
|
105
108
|
} from '../../../shared_libs/play-runtime/durable-call-cache';
|
|
109
|
+
import {
|
|
110
|
+
QUERY_RESULT_DATASET_PAGE_SIZE,
|
|
111
|
+
isCustomerDbDatasetTool,
|
|
112
|
+
isQueryResultDatasetReadRequest,
|
|
113
|
+
isQueryResultDatasetTool,
|
|
114
|
+
} from '../../../shared_libs/play-runtime/query-result-dataset';
|
|
106
115
|
import { buildScopedWorkReceiptKey } from '../../../shared_libs/play-runtime/work-receipts';
|
|
107
116
|
import { DEDUPE_DUPLICATE_KEY_SAMPLE_CAP } from '../../../shared_libs/play-runtime/map-row-identity';
|
|
108
117
|
import {
|
|
@@ -341,7 +350,40 @@ type WorkerFileRef = {
|
|
|
341
350
|
|
|
342
351
|
const EXECUTE_TOOL_METADATA_HEADER = 'x-deepline-include-tool-metadata';
|
|
343
352
|
const EXECUTE_RESPONSE_CONTRACT_HEADER = 'x-deepline-execute-response-contract';
|
|
353
|
+
const EXECUTE_RESPONSE_INTENT_HEADER = 'x-deepline-execute-response-intent';
|
|
344
354
|
const V2_EXECUTE_RESPONSE_CONTRACT = 'v2-tool-execution-result';
|
|
355
|
+
type CustomerDbDatasetRequest = {
|
|
356
|
+
limit?: number;
|
|
357
|
+
offset?: number;
|
|
358
|
+
pageSize?: number;
|
|
359
|
+
totalRows?: number;
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
type WorkerToolDirectOptions = {
|
|
363
|
+
customerDbDataset?: CustomerDbDatasetRequest;
|
|
364
|
+
attachCustomerDbDataset?: boolean;
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
function rowsFromUnknown(value: unknown): Record<string, unknown>[] {
|
|
368
|
+
if (!Array.isArray(value)) return [];
|
|
369
|
+
return value.map((row) =>
|
|
370
|
+
row && typeof row === 'object' && !Array.isArray(row)
|
|
371
|
+
? (row as Record<string, unknown>)
|
|
372
|
+
: { value: row },
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function finiteNonNegativeInteger(value: unknown): number | null {
|
|
377
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
return Math.floor(value);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function finitePositiveInteger(value: unknown): number | null {
|
|
384
|
+
const integer = finiteNonNegativeInteger(value);
|
|
385
|
+
return integer !== null && integer > 0 ? integer : null;
|
|
386
|
+
}
|
|
345
387
|
|
|
346
388
|
function getStringField(value: unknown, key: string): string | null {
|
|
347
389
|
if (!isRecord(value)) return null;
|
|
@@ -706,6 +748,8 @@ async function callRuntimeApiRpcBinding(
|
|
|
706
748
|
if (metadata) headers[EXECUTE_TOOL_METADATA_HEADER] = metadata;
|
|
707
749
|
const contract = h.get(EXECUTE_RESPONSE_CONTRACT_HEADER);
|
|
708
750
|
if (contract) headers[EXECUTE_RESPONSE_CONTRACT_HEADER] = contract;
|
|
751
|
+
const responseIntent = h.get(EXECUTE_RESPONSE_INTENT_HEADER);
|
|
752
|
+
if (responseIntent) headers[EXECUTE_RESPONSE_INTENT_HEADER] = responseIntent;
|
|
709
753
|
const rawBody = typeof init.body === 'string' ? init.body : '';
|
|
710
754
|
const result = await binding.runtimeApiCall({
|
|
711
755
|
executorToken: authorization.replace(/^Bearer\s+/i, '').trim(),
|
|
@@ -1291,6 +1335,7 @@ async function executeTool(
|
|
|
1291
1335
|
abortSignal?: AbortSignal,
|
|
1292
1336
|
runtimeDeadlineMs?: number,
|
|
1293
1337
|
runtimeTimeoutMs?: number,
|
|
1338
|
+
directOptions?: WorkerToolDirectOptions,
|
|
1294
1339
|
): Promise<ToolExecuteResult> {
|
|
1295
1340
|
if (args.toolId === 'test_wait_for_event' && workflowStep) {
|
|
1296
1341
|
const result = await waitForSyntheticIntegrationEvent(
|
|
@@ -1314,6 +1359,7 @@ async function executeTool(
|
|
|
1314
1359
|
abortSignal,
|
|
1315
1360
|
runtimeDeadlineMs,
|
|
1316
1361
|
runtimeTimeoutMs,
|
|
1362
|
+
directOptions,
|
|
1317
1363
|
);
|
|
1318
1364
|
}
|
|
1319
1365
|
|
|
@@ -1328,6 +1374,7 @@ async function executeToolWithLifecycle(
|
|
|
1328
1374
|
abortSignal?: AbortSignal,
|
|
1329
1375
|
runtimeDeadlineMs?: number,
|
|
1330
1376
|
runtimeTimeoutMs?: number,
|
|
1377
|
+
directOptions?: WorkerToolDirectOptions,
|
|
1331
1378
|
): Promise<ToolExecuteResult> {
|
|
1332
1379
|
callbacks?.onToolCalled?.(args.toolId, nowMs());
|
|
1333
1380
|
try {
|
|
@@ -1341,6 +1388,7 @@ async function executeToolWithLifecycle(
|
|
|
1341
1388
|
abortSignal,
|
|
1342
1389
|
runtimeDeadlineMs,
|
|
1343
1390
|
runtimeTimeoutMs,
|
|
1391
|
+
directOptions,
|
|
1344
1392
|
);
|
|
1345
1393
|
} catch (error) {
|
|
1346
1394
|
callbacks?.onToolFailed?.(args.toolId, nowMs());
|
|
@@ -1490,6 +1538,7 @@ async function callToolDirect(
|
|
|
1490
1538
|
abortSignal?: AbortSignal,
|
|
1491
1539
|
runtimeDeadlineMs?: number,
|
|
1492
1540
|
runtimeTimeoutMs?: number,
|
|
1541
|
+
directOptions?: WorkerToolDirectOptions,
|
|
1493
1542
|
): Promise<ToolExecuteResult> {
|
|
1494
1543
|
const { id, toolId, input } = args;
|
|
1495
1544
|
const path = `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`;
|
|
@@ -1517,11 +1566,46 @@ async function callToolDirect(
|
|
|
1517
1566
|
authorization: `Bearer ${req.executorToken}`,
|
|
1518
1567
|
'x-deepline-request-id': `${req.runId}:${toolId}:${id}:attempt:${requestAttempt}`,
|
|
1519
1568
|
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
1569
|
+
[EXECUTE_RESPONSE_INTENT_HEADER]: 'dataset',
|
|
1520
1570
|
[EXECUTE_TOOL_METADATA_HEADER]: 'true',
|
|
1521
1571
|
},
|
|
1522
1572
|
body: JSON.stringify({
|
|
1523
1573
|
payload: input,
|
|
1524
|
-
metadata: {
|
|
1574
|
+
metadata: {
|
|
1575
|
+
parent_run_id: req.runId,
|
|
1576
|
+
...(directOptions?.customerDbDataset
|
|
1577
|
+
? {
|
|
1578
|
+
query_result_dataset: {
|
|
1579
|
+
limit: directOptions.customerDbDataset.limit,
|
|
1580
|
+
offset: directOptions.customerDbDataset.offset,
|
|
1581
|
+
page_size: directOptions.customerDbDataset.pageSize,
|
|
1582
|
+
...(directOptions.customerDbDataset.totalRows !==
|
|
1583
|
+
undefined
|
|
1584
|
+
? {
|
|
1585
|
+
total_rows:
|
|
1586
|
+
directOptions.customerDbDataset.totalRows,
|
|
1587
|
+
}
|
|
1588
|
+
: {}),
|
|
1589
|
+
},
|
|
1590
|
+
...(isCustomerDbDatasetTool(toolId)
|
|
1591
|
+
? {
|
|
1592
|
+
customer_db_dataset: {
|
|
1593
|
+
limit: directOptions.customerDbDataset.limit,
|
|
1594
|
+
offset: directOptions.customerDbDataset.offset,
|
|
1595
|
+
page_size: directOptions.customerDbDataset.pageSize,
|
|
1596
|
+
...(directOptions.customerDbDataset.totalRows !==
|
|
1597
|
+
undefined
|
|
1598
|
+
? {
|
|
1599
|
+
total_rows:
|
|
1600
|
+
directOptions.customerDbDataset.totalRows,
|
|
1601
|
+
}
|
|
1602
|
+
: {}),
|
|
1603
|
+
},
|
|
1604
|
+
}
|
|
1605
|
+
: {}),
|
|
1606
|
+
}
|
|
1607
|
+
: {}),
|
|
1608
|
+
},
|
|
1525
1609
|
...(req.integrationMode
|
|
1526
1610
|
? { integration_mode: req.integrationMode }
|
|
1527
1611
|
: {}),
|
|
@@ -1561,6 +1645,9 @@ async function callToolDirect(
|
|
|
1561
1645
|
parsed.result,
|
|
1562
1646
|
parsed.metadata,
|
|
1563
1647
|
parsed.status,
|
|
1648
|
+
directOptions?.attachCustomerDbDataset === false
|
|
1649
|
+
? undefined
|
|
1650
|
+
: { req, input },
|
|
1564
1651
|
);
|
|
1565
1652
|
}
|
|
1566
1653
|
|
|
@@ -1645,13 +1732,141 @@ function wrapWorkerToolResult(
|
|
|
1645
1732
|
result: unknown,
|
|
1646
1733
|
metadata: ToolResultMetadataInput | null,
|
|
1647
1734
|
status = result == null ? 'no_result' : 'completed',
|
|
1735
|
+
customerDbDatasetOptions?: {
|
|
1736
|
+
req: RunRequest;
|
|
1737
|
+
input: Record<string, unknown>;
|
|
1738
|
+
},
|
|
1648
1739
|
): ToolExecuteResult {
|
|
1649
|
-
|
|
1740
|
+
const wrapped = createToolExecuteResult({
|
|
1650
1741
|
status,
|
|
1651
1742
|
result,
|
|
1652
1743
|
metadata: metadata ?? { toolId },
|
|
1653
1744
|
execution: toolExecutionMetadataForOutcome({ kind: 'live' }),
|
|
1654
1745
|
});
|
|
1746
|
+
return attachWorkerCustomerDbDatasetResult(
|
|
1747
|
+
toolId,
|
|
1748
|
+
wrapped,
|
|
1749
|
+
customerDbDatasetOptions,
|
|
1750
|
+
);
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
function attachWorkerCustomerDbDatasetResult(
|
|
1754
|
+
toolId: string,
|
|
1755
|
+
result: ToolExecuteResult,
|
|
1756
|
+
options?: {
|
|
1757
|
+
req: RunRequest;
|
|
1758
|
+
input: Record<string, unknown>;
|
|
1759
|
+
},
|
|
1760
|
+
): ToolExecuteResult {
|
|
1761
|
+
if (!options || !isQueryResultDatasetTool(toolId)) return result;
|
|
1762
|
+
const raw = isRecord(result.toolOutput.raw) ? result.toolOutput.raw : null;
|
|
1763
|
+
const dataset = isRecord(raw?.dataset) ? raw.dataset : null;
|
|
1764
|
+
const rows = rowsFromUnknown(raw?.rows);
|
|
1765
|
+
const totalRows = finiteNonNegativeInteger(dataset?.total_rows);
|
|
1766
|
+
const sql =
|
|
1767
|
+
typeof options.input.sql === 'string'
|
|
1768
|
+
? options.input.sql
|
|
1769
|
+
: typeof options.input.query === 'string'
|
|
1770
|
+
? options.input.query
|
|
1771
|
+
: typeof raw?.sql === 'string'
|
|
1772
|
+
? raw.sql
|
|
1773
|
+
: null;
|
|
1774
|
+
if (!dataset || totalRows === null || !sql) {
|
|
1775
|
+
return result;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
const datasetLimit =
|
|
1779
|
+
finitePositiveInteger(dataset.returned_limit) ?? totalRows;
|
|
1780
|
+
const previewRows = rows.slice(0, Math.min(rows.length, 25));
|
|
1781
|
+
const jobId = typeof result.job_id === 'string' ? result.job_id.trim() : '';
|
|
1782
|
+
const datasetId = `worker-tool-list:${sha256Hex(
|
|
1783
|
+
`${options.req.runId}:${jobId || Math.random()}`,
|
|
1784
|
+
)}`;
|
|
1785
|
+
const fetchPage = async (
|
|
1786
|
+
offset: number,
|
|
1787
|
+
limit: number,
|
|
1788
|
+
): Promise<Record<string, unknown>[]> => {
|
|
1789
|
+
if (limit <= 0 || offset >= totalRows) return [];
|
|
1790
|
+
const page = await callToolDirect(
|
|
1791
|
+
options.req,
|
|
1792
|
+
{
|
|
1793
|
+
id: 'customer-db-dataset-page',
|
|
1794
|
+
toolId,
|
|
1795
|
+
input: options.input,
|
|
1796
|
+
},
|
|
1797
|
+
undefined,
|
|
1798
|
+
undefined,
|
|
1799
|
+
false,
|
|
1800
|
+
undefined,
|
|
1801
|
+
undefined,
|
|
1802
|
+
undefined,
|
|
1803
|
+
{
|
|
1804
|
+
attachCustomerDbDataset: false,
|
|
1805
|
+
customerDbDataset: {
|
|
1806
|
+
limit: datasetLimit,
|
|
1807
|
+
offset,
|
|
1808
|
+
pageSize: Math.min(limit, QUERY_RESULT_DATASET_PAGE_SIZE),
|
|
1809
|
+
totalRows,
|
|
1810
|
+
},
|
|
1811
|
+
},
|
|
1812
|
+
);
|
|
1813
|
+
const pageRaw = isRecord(page.toolOutput.raw) ? page.toolOutput.raw : null;
|
|
1814
|
+
return rowsFromUnknown(pageRaw?.rows);
|
|
1815
|
+
};
|
|
1816
|
+
const collectRows = async (
|
|
1817
|
+
limit: number | undefined,
|
|
1818
|
+
): Promise<Record<string, unknown>[]> => {
|
|
1819
|
+
const target = Math.min(limit ?? totalRows, totalRows, datasetLimit);
|
|
1820
|
+
const collected: Record<string, unknown>[] = [];
|
|
1821
|
+
for (
|
|
1822
|
+
let offset = 0;
|
|
1823
|
+
offset < target;
|
|
1824
|
+
offset += QUERY_RESULT_DATASET_PAGE_SIZE
|
|
1825
|
+
) {
|
|
1826
|
+
collected.push(
|
|
1827
|
+
...(await fetchPage(
|
|
1828
|
+
offset,
|
|
1829
|
+
Math.min(QUERY_RESULT_DATASET_PAGE_SIZE, target - offset),
|
|
1830
|
+
)),
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
return collected.slice(0, target);
|
|
1834
|
+
};
|
|
1835
|
+
const playDataset = createDeferredPlayDataset({
|
|
1836
|
+
datasetKind: 'csv',
|
|
1837
|
+
datasetId,
|
|
1838
|
+
count: Math.min(totalRows, datasetLimit),
|
|
1839
|
+
previewRows,
|
|
1840
|
+
sourceLabel: 'toolResponse.raw.rows',
|
|
1841
|
+
tableNamespace: null,
|
|
1842
|
+
resolvers: {
|
|
1843
|
+
count: async () => Math.min(totalRows, datasetLimit),
|
|
1844
|
+
peek: async (limit) => collectRows(limit),
|
|
1845
|
+
materialize: async (limit) => collectRows(limit),
|
|
1846
|
+
iterate: () =>
|
|
1847
|
+
({
|
|
1848
|
+
async *[Symbol.asyncIterator]() {
|
|
1849
|
+
const count = Math.min(totalRows, datasetLimit);
|
|
1850
|
+
for (
|
|
1851
|
+
let offset = 0;
|
|
1852
|
+
offset < count;
|
|
1853
|
+
offset += QUERY_RESULT_DATASET_PAGE_SIZE
|
|
1854
|
+
) {
|
|
1855
|
+
yield* await fetchPage(
|
|
1856
|
+
offset,
|
|
1857
|
+
Math.min(QUERY_RESULT_DATASET_PAGE_SIZE, count - offset),
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
},
|
|
1861
|
+
}) as AsyncIterable<Record<string, unknown>>,
|
|
1862
|
+
},
|
|
1863
|
+
});
|
|
1864
|
+
return attachToolResultListDataset(result, {
|
|
1865
|
+
name: 'rows',
|
|
1866
|
+
path: 'toolResponse.raw.rows',
|
|
1867
|
+
dataset: playDataset,
|
|
1868
|
+
count: Math.min(totalRows, datasetLimit),
|
|
1869
|
+
});
|
|
1655
1870
|
}
|
|
1656
1871
|
|
|
1657
1872
|
type RecordedStepProgramOutput = {
|
|
@@ -1685,6 +1900,7 @@ type WorkerToolBatchRequest = {
|
|
|
1685
1900
|
toolId: string;
|
|
1686
1901
|
input: Record<string, unknown>;
|
|
1687
1902
|
workflowStep?: WorkflowStep;
|
|
1903
|
+
directOptions?: WorkerToolDirectOptions;
|
|
1688
1904
|
resolve: (value: unknown) => void;
|
|
1689
1905
|
reject: (error: unknown) => void;
|
|
1690
1906
|
};
|
|
@@ -1975,10 +2191,15 @@ class WorkerToolBatchScheduler {
|
|
|
1975
2191
|
providerActionVersion,
|
|
1976
2192
|
staleAfterSeconds: options?.staleAfterSeconds,
|
|
1977
2193
|
});
|
|
2194
|
+
const queryResultDatasetRead = isQueryResultDatasetReadRequest(
|
|
2195
|
+
toolId,
|
|
2196
|
+
input,
|
|
2197
|
+
);
|
|
2198
|
+
const receiptEligible = !queryResultDatasetRead;
|
|
1978
2199
|
this.queue.push({
|
|
1979
2200
|
id,
|
|
1980
|
-
cacheKey: receiptKey,
|
|
1981
|
-
receiptKey,
|
|
2201
|
+
cacheKey: receiptEligible ? receiptKey : '',
|
|
2202
|
+
receiptKey: receiptEligible ? receiptKey : null,
|
|
1982
2203
|
force: options?.force === true || !!this.req.force,
|
|
1983
2204
|
receiptWaitMaxAttempts: resolveRuntimeToolReceiptWaitMaxAttempts(
|
|
1984
2205
|
typeof runtimeOptions?.receiptWaitMs === 'number'
|
|
@@ -1991,6 +2212,16 @@ class WorkerToolBatchScheduler {
|
|
|
1991
2212
|
toolId,
|
|
1992
2213
|
input,
|
|
1993
2214
|
workflowStep,
|
|
2215
|
+
...(queryResultDatasetRead
|
|
2216
|
+
? {
|
|
2217
|
+
directOptions: {
|
|
2218
|
+
customerDbDataset: {
|
|
2219
|
+
offset: 0,
|
|
2220
|
+
pageSize: QUERY_RESULT_DATASET_PAGE_SIZE,
|
|
2221
|
+
},
|
|
2222
|
+
},
|
|
2223
|
+
}
|
|
2224
|
+
: {}),
|
|
1994
2225
|
resolve: (value) => {
|
|
1995
2226
|
recordRunnerPerfTrace({
|
|
1996
2227
|
req: this.req,
|
|
@@ -2794,6 +3025,7 @@ class WorkerToolBatchScheduler {
|
|
|
2794
3025
|
resolveClaimedWorkerToolRuntimeTimeoutMs([claimed], {
|
|
2795
3026
|
runtimeDeadlineMs: this.runtimeDeadlineMs,
|
|
2796
3027
|
}),
|
|
3028
|
+
request.directOptions,
|
|
2797
3029
|
);
|
|
2798
3030
|
} catch (error) {
|
|
2799
3031
|
this.rejectRequests(
|
|
@@ -3056,6 +3288,11 @@ async function executeBatchedWorkerToolGroup(input: {
|
|
|
3056
3288
|
claimed.request.toolId,
|
|
3057
3289
|
splitResults[index] ?? null,
|
|
3058
3290
|
toolMetadataFallback(claimed.request.toolId),
|
|
3291
|
+
splitResults[index] == null ? 'no_result' : 'completed',
|
|
3292
|
+
{
|
|
3293
|
+
req: input.req,
|
|
3294
|
+
input: claimed.request.input,
|
|
3295
|
+
},
|
|
3059
3296
|
),
|
|
3060
3297
|
})),
|
|
3061
3298
|
);
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
sha256Hex,
|
|
6
6
|
} from '../../../../shared_libs/plays/row-identity';
|
|
7
7
|
import {
|
|
8
|
+
createDeferredPlayDataset,
|
|
9
|
+
isPlayDataset,
|
|
8
10
|
isSerializedPlayDataset,
|
|
9
11
|
type SerializedPlayDataset,
|
|
10
12
|
} from '../../../../shared_libs/plays/dataset';
|
|
@@ -60,6 +62,22 @@ function datasetMetadata(value: unknown): Record<string, unknown> | null {
|
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
function datasetCountFromMetadata(
|
|
66
|
+
metadata: Record<string, unknown> | null,
|
|
67
|
+
): number {
|
|
68
|
+
return typeof metadata?.count === 'number' && Number.isFinite(metadata.count)
|
|
69
|
+
? Math.max(0, Math.floor(metadata.count))
|
|
70
|
+
: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function datasetPreviewFromMetadata(
|
|
74
|
+
metadata: Record<string, unknown> | null,
|
|
75
|
+
): OutputDatasetRow[] {
|
|
76
|
+
return Array.isArray(metadata?.preview)
|
|
77
|
+
? metadata.preview.filter(isRecord).map((row) => ({ ...row }))
|
|
78
|
+
: [];
|
|
79
|
+
}
|
|
80
|
+
|
|
63
81
|
function isRowArray(
|
|
64
82
|
value: unknown,
|
|
65
83
|
path: readonly string[],
|
|
@@ -226,6 +244,47 @@ function disambiguateTableNamespace(
|
|
|
226
244
|
return candidate;
|
|
227
245
|
}
|
|
228
246
|
|
|
247
|
+
function collectExistingDatasetTableNamespaces(value: unknown): Set<string> {
|
|
248
|
+
const namespaces = new Set<string>();
|
|
249
|
+
const seen = new WeakSet<object>();
|
|
250
|
+
|
|
251
|
+
const addNamespace = (namespace: unknown) => {
|
|
252
|
+
if (typeof namespace !== 'string' || !namespace) return;
|
|
253
|
+
try {
|
|
254
|
+
namespaces.add(normalizeTableNamespace(namespace));
|
|
255
|
+
} catch {
|
|
256
|
+
// Historical malformed namespaces should not block generated result
|
|
257
|
+
// names. The original handle/envelope remains unchanged.
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const visit = (candidate: unknown, depth: number): void => {
|
|
262
|
+
if (depth > 20 || candidate == null || typeof candidate !== 'object') {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (seen.has(candidate)) return;
|
|
266
|
+
seen.add(candidate);
|
|
267
|
+
if (isSerializedPlayDataset(candidate)) {
|
|
268
|
+
addNamespace(candidate.tableNamespace);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (isDatasetLike(candidate)) {
|
|
272
|
+
addNamespace(datasetMetadata(candidate)?.tableNamespace);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (Array.isArray(candidate)) {
|
|
276
|
+
for (const entry of candidate) visit(entry, depth + 1);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
for (const child of Object.values(candidate as Record<string, unknown>)) {
|
|
280
|
+
visit(child, depth + 1);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
visit(value, 0);
|
|
285
|
+
return namespaces;
|
|
286
|
+
}
|
|
287
|
+
|
|
229
288
|
export function projectTerminalResultDatasets(
|
|
230
289
|
value: unknown,
|
|
231
290
|
createDataset: DatasetFactory,
|
|
@@ -239,30 +298,84 @@ export function projectTerminalResultDatasets(
|
|
|
239
298
|
const handles: ProjectedResultDatasetHandle[] = [];
|
|
240
299
|
const seen = new WeakMap<object, unknown>();
|
|
241
300
|
const seenHandles = new WeakSet<object>();
|
|
301
|
+
const projectedHandles = new WeakMap<object, unknown>();
|
|
242
302
|
const usedNamespaces = seedUsedNamespaces(options.reservedTableNamespaces);
|
|
303
|
+
for (const namespace of collectExistingDatasetTableNamespaces(value)) {
|
|
304
|
+
usedNamespaces.add(namespace);
|
|
305
|
+
}
|
|
243
306
|
const maxTableNamespaceLength = maxTableNamespaceLengthForPlay(
|
|
244
307
|
options.playName,
|
|
245
308
|
);
|
|
246
309
|
|
|
247
|
-
const
|
|
248
|
-
if (!isRecord(handle)
|
|
310
|
+
const projectHandle = (handle: unknown, path: readonly string[]): unknown => {
|
|
311
|
+
if (!isRecord(handle)) return handle;
|
|
312
|
+
const existingProjection = projectedHandles.get(handle);
|
|
313
|
+
if (existingProjection) return existingProjection;
|
|
249
314
|
const metadata = datasetMetadata(handle);
|
|
250
|
-
|
|
251
|
-
|
|
315
|
+
let projectedHandle: unknown = handle;
|
|
316
|
+
let tableNamespace =
|
|
317
|
+
typeof metadata?.tableNamespace === 'string' && metadata.tableNamespace
|
|
252
318
|
? metadata.tableNamespace
|
|
253
319
|
: null;
|
|
254
|
-
if (!tableNamespace)
|
|
255
|
-
|
|
320
|
+
if (!tableNamespace && isPlayDataset<OutputDatasetRow>(handle)) {
|
|
321
|
+
const resolvedPath = path.length > 0 ? path : ['rows'];
|
|
322
|
+
tableNamespace = disambiguateTableNamespace(
|
|
323
|
+
resultTableNamespaceForPath(resolvedPath, maxTableNamespaceLength),
|
|
324
|
+
resolvedPath,
|
|
325
|
+
usedNamespaces,
|
|
326
|
+
maxTableNamespaceLength,
|
|
327
|
+
);
|
|
328
|
+
projectedHandle = createDeferredPlayDataset({
|
|
329
|
+
datasetKind: 'csv',
|
|
330
|
+
datasetId:
|
|
331
|
+
typeof metadata?.datasetId === 'string'
|
|
332
|
+
? metadata.datasetId
|
|
333
|
+
: `csv:${tableNamespace}`,
|
|
334
|
+
count: datasetCountFromMetadata(metadata),
|
|
335
|
+
previewRows: datasetPreviewFromMetadata(metadata),
|
|
336
|
+
sourceLabel:
|
|
337
|
+
typeof metadata?.sourceLabel === 'string'
|
|
338
|
+
? metadata.sourceLabel
|
|
339
|
+
: null,
|
|
340
|
+
tableNamespace,
|
|
341
|
+
resolvers: {
|
|
342
|
+
count: () => handle.count(),
|
|
343
|
+
peek: (limit) => handle.peek(limit),
|
|
344
|
+
materialize: (limit) => handle.materialize(limit),
|
|
345
|
+
iterate: () =>
|
|
346
|
+
({
|
|
347
|
+
async *[Symbol.asyncIterator]() {
|
|
348
|
+
yield* handle;
|
|
349
|
+
},
|
|
350
|
+
}) as AsyncIterable<OutputDatasetRow>,
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
projectedHandles.set(handle, projectedHandle);
|
|
355
|
+
if (!tableNamespace || seenHandles.has(projectedHandle as object)) {
|
|
356
|
+
return projectedHandle;
|
|
357
|
+
}
|
|
358
|
+
try {
|
|
359
|
+
usedNamespaces.add(normalizeTableNamespace(tableNamespace));
|
|
360
|
+
} catch {
|
|
361
|
+
// Existing dataset handles can carry historical namespaces. Keep the
|
|
362
|
+
// handle, but do not let a malformed namespace poison new result names.
|
|
363
|
+
}
|
|
364
|
+
seenHandles.add(projectedHandle as object);
|
|
365
|
+
const projectedMetadata =
|
|
366
|
+
projectedHandle === handle ? metadata : datasetMetadata(projectedHandle);
|
|
256
367
|
const datasetKind =
|
|
257
|
-
|
|
258
|
-
|
|
368
|
+
projectedMetadata?.datasetKind === 'csv' ||
|
|
369
|
+
projectedMetadata?.datasetKind === 'map'
|
|
370
|
+
? projectedMetadata.datasetKind
|
|
259
371
|
: null;
|
|
260
372
|
handles.push({
|
|
261
373
|
path: path.length > 0 ? path.join('.') : 'rows',
|
|
262
374
|
tableNamespace,
|
|
263
375
|
datasetKind,
|
|
264
|
-
handle,
|
|
376
|
+
handle: projectedHandle,
|
|
265
377
|
});
|
|
378
|
+
return projectedHandle;
|
|
266
379
|
};
|
|
267
380
|
|
|
268
381
|
const promoteRows = (
|
|
@@ -287,7 +400,7 @@ export function projectTerminalResultDatasets(
|
|
|
287
400
|
rows,
|
|
288
401
|
handle,
|
|
289
402
|
});
|
|
290
|
-
|
|
403
|
+
projectHandle(handle, path);
|
|
291
404
|
return handle;
|
|
292
405
|
};
|
|
293
406
|
|
|
@@ -298,8 +411,7 @@ export function projectTerminalResultDatasets(
|
|
|
298
411
|
): unknown => {
|
|
299
412
|
if (depth > 20 || candidate == null) return candidate;
|
|
300
413
|
if (isDatasetLike(candidate)) {
|
|
301
|
-
|
|
302
|
-
return candidate;
|
|
414
|
+
return projectHandle(candidate, path);
|
|
303
415
|
}
|
|
304
416
|
if (isSerializedPlayDataset(candidate)) {
|
|
305
417
|
return candidate;
|
|
@@ -202,7 +202,8 @@ function chunkRegisterPlayArtifacts<T>(artifacts: T[]): T[][] {
|
|
|
202
202
|
|
|
203
203
|
type ExecuteToolRawOptions = {
|
|
204
204
|
includeToolMetadata?: boolean;
|
|
205
|
-
responseIntent?: 'raw' | 'row_artifact';
|
|
205
|
+
responseIntent?: 'dataset' | 'raw' | 'row_artifact';
|
|
206
|
+
metadata?: Record<string, unknown>;
|
|
206
207
|
timeout?: number;
|
|
207
208
|
maxRetries?: number;
|
|
208
209
|
};
|
|
@@ -1310,13 +1311,14 @@ export class DeeplineClient {
|
|
|
1310
1311
|
...(options?.includeToolMetadata
|
|
1311
1312
|
? { [INCLUDE_TOOL_METADATA_HEADER]: 'true' }
|
|
1312
1313
|
: {}),
|
|
1313
|
-
|
|
1314
|
-
? { [EXECUTE_RESPONSE_INTENT_HEADER]: options.responseIntent }
|
|
1315
|
-
: {}),
|
|
1314
|
+
[EXECUTE_RESPONSE_INTENT_HEADER]: options?.responseIntent ?? 'raw',
|
|
1316
1315
|
};
|
|
1317
1316
|
return this.http.post<ToolExecution<TData, TMeta>>(
|
|
1318
1317
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
1319
|
-
{
|
|
1318
|
+
{
|
|
1319
|
+
payload: input,
|
|
1320
|
+
...(options?.metadata ? { metadata: options.metadata } : {}),
|
|
1321
|
+
},
|
|
1320
1322
|
headers,
|
|
1321
1323
|
{
|
|
1322
1324
|
forbiddenAsApiError: true,
|