deepline 0.1.33 → 0.1.35
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/cli/index.js +959 -207
- package/dist/cli/index.mjs +892 -140
- package/dist/index.d.mts +127 -63
- package/dist/index.d.ts +127 -63
- package/dist/index.js +516 -45
- package/dist/index.mjs +516 -45
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +212 -1
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +129 -2
- package/dist/repo/apps/play-runner-workers/src/entry.ts +147 -64
- package/dist/repo/apps/play-runner-workers/src/workflow-retry.ts +50 -0
- package/dist/repo/sdk/src/client.ts +46 -33
- package/dist/repo/sdk/src/http.ts +44 -4
- package/dist/repo/sdk/src/index.ts +8 -5
- package/dist/repo/sdk/src/play.ts +124 -45
- package/dist/repo/sdk/src/plays/harness-stub.ts +2 -2
- package/dist/repo/sdk/src/tool-output.ts +26 -7
- package/dist/repo/sdk/src/types.ts +45 -11
- package/dist/repo/sdk/src/version.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/run-failure.ts +49 -0
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +138 -35
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -169,8 +169,8 @@ function resolveConfig(options) {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
// src/version.ts
|
|
172
|
-
var SDK_VERSION = "0.1.
|
|
173
|
-
var SDK_API_CONTRACT = "2026-05-
|
|
172
|
+
var SDK_VERSION = "0.1.35";
|
|
173
|
+
var SDK_API_CONTRACT = "2026-05-v2-tool-result-contract";
|
|
174
174
|
|
|
175
175
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
176
176
|
var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
|
|
@@ -252,7 +252,7 @@ var HttpClient = class {
|
|
|
252
252
|
const response = await fetch(candidateUrl, {
|
|
253
253
|
method,
|
|
254
254
|
headers,
|
|
255
|
-
body: options?.formData !== void 0 ? options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
255
|
+
body: options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
256
256
|
signal: controller.signal
|
|
257
257
|
});
|
|
258
258
|
clearTimeout(timeoutId);
|
|
@@ -335,10 +335,13 @@ var HttpClient = class {
|
|
|
335
335
|
throw new AuthError();
|
|
336
336
|
}
|
|
337
337
|
if (!response.ok) {
|
|
338
|
+
const body = await response.text();
|
|
339
|
+
const parsed = parseResponseBody(body);
|
|
338
340
|
throw new DeeplineError(
|
|
339
|
-
|
|
341
|
+
apiErrorMessage(parsed, response.status),
|
|
340
342
|
response.status,
|
|
341
|
-
"API_ERROR"
|
|
343
|
+
"API_ERROR",
|
|
344
|
+
{ response: parsed }
|
|
342
345
|
);
|
|
343
346
|
}
|
|
344
347
|
if (!response.body) {
|
|
@@ -388,6 +391,26 @@ var HttpClient = class {
|
|
|
388
391
|
return this.request(path, { method: "DELETE" });
|
|
389
392
|
}
|
|
390
393
|
};
|
|
394
|
+
function parseResponseBody(body) {
|
|
395
|
+
try {
|
|
396
|
+
return JSON.parse(body);
|
|
397
|
+
} catch {
|
|
398
|
+
return body;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function apiErrorMessage(parsed, status) {
|
|
402
|
+
const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
|
|
403
|
+
if (typeof errorValue === "string") {
|
|
404
|
+
return errorValue;
|
|
405
|
+
}
|
|
406
|
+
if (errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string") {
|
|
407
|
+
return errorValue.message;
|
|
408
|
+
}
|
|
409
|
+
if (typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string") {
|
|
410
|
+
return parsed.message;
|
|
411
|
+
}
|
|
412
|
+
return `HTTP ${status}`;
|
|
413
|
+
}
|
|
391
414
|
function parseRetryAfter(response) {
|
|
392
415
|
const header = response.headers.get("retry-after");
|
|
393
416
|
if (header) {
|
|
@@ -457,6 +480,8 @@ function sleep(ms) {
|
|
|
457
480
|
// src/client.ts
|
|
458
481
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
459
482
|
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
483
|
+
var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
|
|
484
|
+
var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-execution-result";
|
|
460
485
|
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
461
486
|
function sleep2(ms) {
|
|
462
487
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
@@ -725,13 +750,16 @@ var DeeplineClient = class {
|
|
|
725
750
|
/**
|
|
726
751
|
* Execute a tool and return the standard execution envelope.
|
|
727
752
|
*
|
|
728
|
-
* The `
|
|
729
|
-
* contains provider
|
|
753
|
+
* The `toolExecutionResult.toolOutput.raw` field contains the raw tool output.
|
|
754
|
+
* `toolExecutionResult.toolOutput.meta` contains tool/provider metadata.
|
|
730
755
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
731
|
-
* Deepline execution.
|
|
756
|
+
* Deepline execution envelope.
|
|
732
757
|
*/
|
|
733
758
|
async executeTool(toolId, input, options) {
|
|
734
|
-
const headers =
|
|
759
|
+
const headers = {
|
|
760
|
+
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
761
|
+
...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
|
|
762
|
+
};
|
|
735
763
|
return this.http.post(
|
|
736
764
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
737
765
|
{ payload: input },
|
|
@@ -1029,34 +1057,37 @@ var DeeplineClient = class {
|
|
|
1029
1057
|
* ```
|
|
1030
1058
|
*/
|
|
1031
1059
|
async stagePlayFiles(files) {
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1034
|
-
"metadata",
|
|
1035
|
-
JSON.stringify({
|
|
1036
|
-
files: files.map((file, index) => ({
|
|
1037
|
-
index,
|
|
1038
|
-
logicalPath: file.logicalPath,
|
|
1039
|
-
contentHash: file.contentHash,
|
|
1040
|
-
contentType: file.contentType,
|
|
1041
|
-
bytes: file.bytes
|
|
1042
|
-
}))
|
|
1043
|
-
})
|
|
1044
|
-
);
|
|
1045
|
-
for (const [index, file] of files.entries()) {
|
|
1046
|
-
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1047
|
-
const body = bytes.buffer.slice(
|
|
1048
|
-
bytes.byteOffset,
|
|
1049
|
-
bytes.byteOffset + bytes.byteLength
|
|
1050
|
-
);
|
|
1060
|
+
const buildFormData = () => {
|
|
1061
|
+
const formData = new FormData();
|
|
1051
1062
|
formData.set(
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1063
|
+
"metadata",
|
|
1064
|
+
JSON.stringify({
|
|
1065
|
+
files: files.map((file, index) => ({
|
|
1066
|
+
index,
|
|
1067
|
+
logicalPath: file.logicalPath,
|
|
1068
|
+
contentHash: file.contentHash,
|
|
1069
|
+
contentType: file.contentType,
|
|
1070
|
+
bytes: file.bytes
|
|
1071
|
+
}))
|
|
1072
|
+
})
|
|
1055
1073
|
);
|
|
1056
|
-
|
|
1074
|
+
for (const [index, file] of files.entries()) {
|
|
1075
|
+
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1076
|
+
const body = bytes.buffer.slice(
|
|
1077
|
+
bytes.byteOffset,
|
|
1078
|
+
bytes.byteOffset + bytes.byteLength
|
|
1079
|
+
);
|
|
1080
|
+
formData.set(
|
|
1081
|
+
`file:${index}`,
|
|
1082
|
+
new Blob([body], { type: file.contentType }),
|
|
1083
|
+
file.logicalPath
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
return formData;
|
|
1087
|
+
};
|
|
1057
1088
|
const response = await this.http.postFormData(
|
|
1058
1089
|
"/api/v2/plays/files/stage",
|
|
1059
|
-
|
|
1090
|
+
buildFormData
|
|
1060
1091
|
);
|
|
1061
1092
|
return response.files;
|
|
1062
1093
|
}
|
|
@@ -1530,6 +1561,383 @@ var DeeplineClient = class {
|
|
|
1530
1561
|
}
|
|
1531
1562
|
};
|
|
1532
1563
|
|
|
1564
|
+
// ../shared_libs/play-runtime/tool-result.ts
|
|
1565
|
+
var TARGET_FALLBACK_KEYS = {
|
|
1566
|
+
email: [/^email$/i, /^address$/i, /email/i],
|
|
1567
|
+
phone: [/^phone$/i, /mobile/i, /phone/i, /telephone/i],
|
|
1568
|
+
linkedin: [/^linkedin_url$/i, /^linkedin$/i, /linkedin/i],
|
|
1569
|
+
company_linkedin_url: [/company.*linkedin/i, /linkedin.*company/i],
|
|
1570
|
+
company_domain: [/^company_domain$/i, /company.*domain/i],
|
|
1571
|
+
company_name: [/^company_name$/i, /company.*name/i],
|
|
1572
|
+
domain: [/^domain$/i, /company_domain/i, /domain/i],
|
|
1573
|
+
status: [/^email_status$/i, /^status$/i],
|
|
1574
|
+
email_status: [/^email_status$/i, /^status$/i]
|
|
1575
|
+
};
|
|
1576
|
+
function isRecord2(value) {
|
|
1577
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1578
|
+
}
|
|
1579
|
+
function toV2RawToolOutputPath(path) {
|
|
1580
|
+
const normalized = String(path || "").trim().replace(/^\./, "");
|
|
1581
|
+
if (!normalized) return "toolExecutionResult.toolOutput.raw";
|
|
1582
|
+
if (normalized === "toolExecutionResult.toolOutput.raw" || normalized.startsWith("toolExecutionResult.toolOutput.raw.")) {
|
|
1583
|
+
return normalized;
|
|
1584
|
+
}
|
|
1585
|
+
const rawPath = normalized.replace(/^result\.data\.?/, "").replace(/^result\.?/, "").replace(/^data\.?/, "").replace(/^\./, "");
|
|
1586
|
+
return rawPath ? `toolExecutionResult.toolOutput.raw.${rawPath}` : "toolExecutionResult.toolOutput.raw";
|
|
1587
|
+
}
|
|
1588
|
+
function isMeaningfulValue(value) {
|
|
1589
|
+
if (value == null) return false;
|
|
1590
|
+
if (typeof value === "string") return value.trim().length > 0;
|
|
1591
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
1592
|
+
if (typeof value === "object") return Object.keys(value).length > 0;
|
|
1593
|
+
return true;
|
|
1594
|
+
}
|
|
1595
|
+
function parsePath(path) {
|
|
1596
|
+
const segments = [];
|
|
1597
|
+
for (const rawPart of path.split(".").filter(Boolean)) {
|
|
1598
|
+
const bracketPattern = /([^\[\]]+)|\[(\d+|\*)\]/g;
|
|
1599
|
+
let matched = false;
|
|
1600
|
+
for (const match of rawPart.matchAll(bracketPattern)) {
|
|
1601
|
+
matched = true;
|
|
1602
|
+
if (match[1]) {
|
|
1603
|
+
segments.push(match[1]);
|
|
1604
|
+
} else if (match[2] === "*") {
|
|
1605
|
+
segments.push("*");
|
|
1606
|
+
} else if (match[2]) {
|
|
1607
|
+
segments.push(Number(match[2]));
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
if (!matched) {
|
|
1611
|
+
segments.push(rawPart);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
return segments;
|
|
1615
|
+
}
|
|
1616
|
+
function pathToString(segments) {
|
|
1617
|
+
return segments.map(
|
|
1618
|
+
(segment, index) => typeof segment === "number" ? `[${segment}]` : segment === "*" ? "[*]" : index === 0 ? segment : `.${segment}`
|
|
1619
|
+
).join("");
|
|
1620
|
+
}
|
|
1621
|
+
function valuesAtSegments(current, segments, path = []) {
|
|
1622
|
+
if (segments.length === 0) {
|
|
1623
|
+
return [{ value: current, path: pathToString(path) }];
|
|
1624
|
+
}
|
|
1625
|
+
const [segment, ...rest] = segments;
|
|
1626
|
+
if (segment === "*") {
|
|
1627
|
+
if (!Array.isArray(current)) return [];
|
|
1628
|
+
return current.flatMap(
|
|
1629
|
+
(entry, index) => valuesAtSegments(entry, rest, [...path, index])
|
|
1630
|
+
);
|
|
1631
|
+
}
|
|
1632
|
+
if (typeof segment === "number") {
|
|
1633
|
+
if (!Array.isArray(current)) return [];
|
|
1634
|
+
return valuesAtSegments(current[segment], rest, [...path, segment]);
|
|
1635
|
+
}
|
|
1636
|
+
if (!isRecord2(current)) return [];
|
|
1637
|
+
return valuesAtSegments(current[segment], rest, [...path, segment]);
|
|
1638
|
+
}
|
|
1639
|
+
function getValuesAtPath(root, path) {
|
|
1640
|
+
return valuesAtSegments(root, parsePath(path)).map((entry) => entry.value);
|
|
1641
|
+
}
|
|
1642
|
+
function toResultEnvelope(value) {
|
|
1643
|
+
if (isRecord2(value) && "data" in value) {
|
|
1644
|
+
const envelope = { data: value.data };
|
|
1645
|
+
if ("meta" in value) envelope.meta = value.meta;
|
|
1646
|
+
return envelope;
|
|
1647
|
+
}
|
|
1648
|
+
return { data: value };
|
|
1649
|
+
}
|
|
1650
|
+
function normalizeResultPath(path) {
|
|
1651
|
+
const trimmed = String(path || "").trim().replace(/^\./, "");
|
|
1652
|
+
if (!trimmed) return "";
|
|
1653
|
+
return toV2RawToolOutputPath(trimmed);
|
|
1654
|
+
}
|
|
1655
|
+
function toV2RawToolOutputPathPreservingProviderData(path) {
|
|
1656
|
+
const normalized = String(path || "").trim().replace(/^\./, "");
|
|
1657
|
+
if (!normalized) return "toolExecutionResult.toolOutput.raw";
|
|
1658
|
+
if (normalized === "toolExecutionResult.toolOutput.raw" || normalized.startsWith("toolExecutionResult.toolOutput.raw.")) {
|
|
1659
|
+
return normalized;
|
|
1660
|
+
}
|
|
1661
|
+
const rawPath = normalized.replace(/^result\.?/, "").replace(/^\./, "");
|
|
1662
|
+
return rawPath ? `toolExecutionResult.toolOutput.raw.${rawPath}` : "toolExecutionResult.toolOutput.raw";
|
|
1663
|
+
}
|
|
1664
|
+
function candidateResultPaths(path) {
|
|
1665
|
+
const candidates = [
|
|
1666
|
+
normalizeResultPath(path),
|
|
1667
|
+
toV2RawToolOutputPathPreservingProviderData(path)
|
|
1668
|
+
];
|
|
1669
|
+
return candidates.filter(
|
|
1670
|
+
(candidate, index, all) => candidate.length > 0 && all.indexOf(candidate) === index
|
|
1671
|
+
);
|
|
1672
|
+
}
|
|
1673
|
+
function normalizeRelativePath(path) {
|
|
1674
|
+
return String(path || "").trim().replace(/^result\./, "").replace(/^\./, "");
|
|
1675
|
+
}
|
|
1676
|
+
function getFirstMeaningfulValueAtPath(root, path) {
|
|
1677
|
+
for (const entry of valuesAtSegments(root, parsePath(path))) {
|
|
1678
|
+
if (isMeaningfulValue(entry.value)) {
|
|
1679
|
+
return { value: entry.value, path: entry.path };
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
return null;
|
|
1683
|
+
}
|
|
1684
|
+
function getAtPath(root, path) {
|
|
1685
|
+
const segments = parsePath(path);
|
|
1686
|
+
if (segments.includes("*")) {
|
|
1687
|
+
return getValuesAtPath(root, path).filter(isMeaningfulValue);
|
|
1688
|
+
}
|
|
1689
|
+
let current = root;
|
|
1690
|
+
for (const segment of segments) {
|
|
1691
|
+
if (typeof segment === "number") {
|
|
1692
|
+
if (!Array.isArray(current)) return void 0;
|
|
1693
|
+
current = current[segment];
|
|
1694
|
+
continue;
|
|
1695
|
+
}
|
|
1696
|
+
if (!isRecord2(current)) return void 0;
|
|
1697
|
+
current = current[segment];
|
|
1698
|
+
}
|
|
1699
|
+
return current;
|
|
1700
|
+
}
|
|
1701
|
+
function normalizeRows(value) {
|
|
1702
|
+
if (!Array.isArray(value)) return null;
|
|
1703
|
+
return value.map((entry) => isRecord2(entry) ? entry : { value: entry });
|
|
1704
|
+
}
|
|
1705
|
+
function findFirstTargetByPath(result, paths) {
|
|
1706
|
+
for (const path of paths ?? []) {
|
|
1707
|
+
for (const candidate of candidateResultPaths(path)) {
|
|
1708
|
+
const match = getFirstMeaningfulValueAtPath(result, candidate);
|
|
1709
|
+
if (match) return match;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
return null;
|
|
1713
|
+
}
|
|
1714
|
+
function findFirstTargetByKey(result, target, depth = 0, path = []) {
|
|
1715
|
+
if (depth > 6) return null;
|
|
1716
|
+
if (Array.isArray(result)) {
|
|
1717
|
+
for (let index = 0; index < result.length; index += 1) {
|
|
1718
|
+
const found = findFirstTargetByKey(result[index], target, depth + 1, [
|
|
1719
|
+
...path,
|
|
1720
|
+
index
|
|
1721
|
+
]);
|
|
1722
|
+
if (found) return found;
|
|
1723
|
+
}
|
|
1724
|
+
return null;
|
|
1725
|
+
}
|
|
1726
|
+
if (!isRecord2(result)) return null;
|
|
1727
|
+
const patterns = TARGET_FALLBACK_KEYS[target] ?? [
|
|
1728
|
+
new RegExp(`^${target}$`, "i")
|
|
1729
|
+
];
|
|
1730
|
+
for (const [key, value] of Object.entries(result)) {
|
|
1731
|
+
if (patterns.some((pattern) => pattern.test(key)) && isMeaningfulValue(value)) {
|
|
1732
|
+
return { value, path: pathToString([...path, key]) };
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
for (const [key, value] of Object.entries(result)) {
|
|
1736
|
+
const found = findFirstTargetByKey(value, target, depth + 1, [
|
|
1737
|
+
...path,
|
|
1738
|
+
key
|
|
1739
|
+
]);
|
|
1740
|
+
if (found) return found;
|
|
1741
|
+
}
|
|
1742
|
+
return null;
|
|
1743
|
+
}
|
|
1744
|
+
function resolveListRows(result, listExtractorPaths) {
|
|
1745
|
+
const lists = {};
|
|
1746
|
+
for (const rawPath of listExtractorPaths ?? []) {
|
|
1747
|
+
const path = normalizeResultPath(rawPath);
|
|
1748
|
+
if (!path) continue;
|
|
1749
|
+
const candidates = [
|
|
1750
|
+
...candidateResultPaths(rawPath)
|
|
1751
|
+
].filter(
|
|
1752
|
+
(candidate, index, all) => candidate && all.indexOf(candidate) === index
|
|
1753
|
+
);
|
|
1754
|
+
let resolvedPath = null;
|
|
1755
|
+
let rows = null;
|
|
1756
|
+
for (const candidate of candidates) {
|
|
1757
|
+
rows = normalizeRows(getAtPath(result, candidate));
|
|
1758
|
+
if (rows) {
|
|
1759
|
+
resolvedPath = candidate;
|
|
1760
|
+
break;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
if (!rows) continue;
|
|
1764
|
+
const storedPath = resolvedPath ?? path;
|
|
1765
|
+
const name = storedPath.split(".").filter(Boolean).at(-1)?.replace(/\[\d+\]$/, "");
|
|
1766
|
+
lists[name || storedPath] = { path: storedPath, rows };
|
|
1767
|
+
}
|
|
1768
|
+
return lists;
|
|
1769
|
+
}
|
|
1770
|
+
function deriveListKeys(input) {
|
|
1771
|
+
const keys = {};
|
|
1772
|
+
for (const [target, paths] of Object.entries(
|
|
1773
|
+
input.listIdentityGetters ?? {}
|
|
1774
|
+
)) {
|
|
1775
|
+
const firstPath = paths.map(
|
|
1776
|
+
(rawPath) => normalizeRelativePath(rawPath)
|
|
1777
|
+
).find(Boolean);
|
|
1778
|
+
if (firstPath) {
|
|
1779
|
+
keys[target] = firstPath;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
if (Object.keys(keys).length > 0) {
|
|
1783
|
+
return keys;
|
|
1784
|
+
}
|
|
1785
|
+
const listPrefix = input.listPath.replace(/\[\d+\]$/, "");
|
|
1786
|
+
for (const [target, paths] of Object.entries(
|
|
1787
|
+
input.resultIdentityGetters ?? {}
|
|
1788
|
+
)) {
|
|
1789
|
+
for (const rawPath of paths) {
|
|
1790
|
+
const path = String(rawPath || "").trim().replace(/^\./, "");
|
|
1791
|
+
if (!path) continue;
|
|
1792
|
+
for (const resultPath of candidateResultPaths(path)) {
|
|
1793
|
+
const directPrefix = `${listPrefix}.`;
|
|
1794
|
+
if (resultPath.startsWith(directPrefix)) {
|
|
1795
|
+
keys[target] = resultPath.slice(directPrefix.length).replace(/^\[\d+\]\.?/, "");
|
|
1796
|
+
break;
|
|
1797
|
+
}
|
|
1798
|
+
const indexedPrefix = `${listPrefix}[0].`;
|
|
1799
|
+
if (resultPath.startsWith(indexedPrefix)) {
|
|
1800
|
+
keys[target] = resultPath.slice(indexedPrefix.length);
|
|
1801
|
+
break;
|
|
1802
|
+
}
|
|
1803
|
+
const wildcardPrefix = `${listPrefix}[*].`;
|
|
1804
|
+
if (resultPath.startsWith(wildcardPrefix)) {
|
|
1805
|
+
keys[target] = resultPath.slice(wildcardPrefix.length);
|
|
1806
|
+
break;
|
|
1807
|
+
}
|
|
1808
|
+
const dottedIndexPrefix = `${listPrefix}.0.`;
|
|
1809
|
+
if (resultPath.startsWith(dottedIndexPrefix)) {
|
|
1810
|
+
keys[target] = resultPath.slice(dottedIndexPrefix.length);
|
|
1811
|
+
break;
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
if (keys[target]) break;
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
if (Object.keys(keys).length === 0 && input.rows[0]) {
|
|
1818
|
+
for (const key of Object.keys(input.rows[0])) {
|
|
1819
|
+
keys[key] = key;
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
return keys;
|
|
1823
|
+
}
|
|
1824
|
+
function buildTargets(result, resultIdentityGetters) {
|
|
1825
|
+
const targets = {};
|
|
1826
|
+
const metadataTargets = new Set(Object.keys(resultIdentityGetters ?? {}));
|
|
1827
|
+
for (const target of metadataTargets) {
|
|
1828
|
+
const fromMetadata = findFirstTargetByPath(
|
|
1829
|
+
result,
|
|
1830
|
+
resultIdentityGetters?.[target]
|
|
1831
|
+
);
|
|
1832
|
+
if (fromMetadata) {
|
|
1833
|
+
targets[target] = fromMetadata;
|
|
1834
|
+
continue;
|
|
1835
|
+
}
|
|
1836
|
+
const fallback = findFirstTargetByKey(result, target);
|
|
1837
|
+
if (fallback) {
|
|
1838
|
+
targets[target] = fallback;
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
if (metadataTargets.size > 0) return targets;
|
|
1842
|
+
for (const target of ["email", "phone", "linkedin", "domain", "status"]) {
|
|
1843
|
+
const found = findFirstTargetByKey(result, target);
|
|
1844
|
+
if (found) targets[target] = found;
|
|
1845
|
+
}
|
|
1846
|
+
return targets;
|
|
1847
|
+
}
|
|
1848
|
+
function buildLists(result, metadata) {
|
|
1849
|
+
const lists = {};
|
|
1850
|
+
const resolved = resolveListRows(result, metadata.listExtractorPaths);
|
|
1851
|
+
for (const [name, list] of Object.entries(resolved)) {
|
|
1852
|
+
lists[name] = {
|
|
1853
|
+
path: list.path,
|
|
1854
|
+
count: list.rows.length,
|
|
1855
|
+
keys: deriveListKeys({
|
|
1856
|
+
listPath: list.path,
|
|
1857
|
+
rows: list.rows,
|
|
1858
|
+
resultIdentityGetters: metadata.resultIdentityGetters,
|
|
1859
|
+
listIdentityGetters: metadata.listIdentityGetters
|
|
1860
|
+
})
|
|
1861
|
+
};
|
|
1862
|
+
}
|
|
1863
|
+
return lists;
|
|
1864
|
+
}
|
|
1865
|
+
function buildExtractedAccessors(targets) {
|
|
1866
|
+
return Object.fromEntries(
|
|
1867
|
+
Object.entries(targets).map(([target, metadata]) => {
|
|
1868
|
+
const accessor = { path: metadata.path };
|
|
1869
|
+
Object.defineProperties(accessor, {
|
|
1870
|
+
value: {
|
|
1871
|
+
value: metadata.value,
|
|
1872
|
+
enumerable: false
|
|
1873
|
+
},
|
|
1874
|
+
get: {
|
|
1875
|
+
value() {
|
|
1876
|
+
return metadata.value ?? null;
|
|
1877
|
+
},
|
|
1878
|
+
enumerable: false
|
|
1879
|
+
}
|
|
1880
|
+
});
|
|
1881
|
+
return [target, accessor];
|
|
1882
|
+
})
|
|
1883
|
+
);
|
|
1884
|
+
}
|
|
1885
|
+
function buildListAccessors(result, lists) {
|
|
1886
|
+
return Object.fromEntries(
|
|
1887
|
+
Object.entries(lists).map(([name, metadata]) => {
|
|
1888
|
+
const accessor = {
|
|
1889
|
+
path: metadata.path,
|
|
1890
|
+
count: metadata.count,
|
|
1891
|
+
keys: metadata.keys
|
|
1892
|
+
};
|
|
1893
|
+
Object.defineProperty(accessor, "get", {
|
|
1894
|
+
value() {
|
|
1895
|
+
return normalizeRows(getAtPath(result, metadata.path)) ?? [];
|
|
1896
|
+
},
|
|
1897
|
+
enumerable: false
|
|
1898
|
+
});
|
|
1899
|
+
return [name, accessor];
|
|
1900
|
+
})
|
|
1901
|
+
);
|
|
1902
|
+
}
|
|
1903
|
+
function createToolExecuteResult(input) {
|
|
1904
|
+
const result = toResultEnvelope(input.result);
|
|
1905
|
+
const resultRoot = {
|
|
1906
|
+
toolExecutionResult: {
|
|
1907
|
+
toolOutput: {
|
|
1908
|
+
raw: result.data,
|
|
1909
|
+
...result.meta ? { meta: result.meta } : {}
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
};
|
|
1913
|
+
const targets = buildTargets(
|
|
1914
|
+
resultRoot,
|
|
1915
|
+
input.metadata.resultIdentityGetters
|
|
1916
|
+
);
|
|
1917
|
+
const lists = buildLists(resultRoot, input.metadata);
|
|
1918
|
+
const metadata = {
|
|
1919
|
+
toolId: input.metadata.toolId,
|
|
1920
|
+
execution: input.execution,
|
|
1921
|
+
targets,
|
|
1922
|
+
lists
|
|
1923
|
+
};
|
|
1924
|
+
const wrapper = {
|
|
1925
|
+
status: input.status,
|
|
1926
|
+
toolOutput: {
|
|
1927
|
+
raw: result.data,
|
|
1928
|
+
...result.meta ? { meta: result.meta } : {}
|
|
1929
|
+
},
|
|
1930
|
+
meta: input.execution,
|
|
1931
|
+
extractedValues: buildExtractedAccessors(targets),
|
|
1932
|
+
extractedLists: buildListAccessors(resultRoot, lists)
|
|
1933
|
+
};
|
|
1934
|
+
Object.defineProperty(wrapper, "_metadata", {
|
|
1935
|
+
value: metadata,
|
|
1936
|
+
enumerable: false
|
|
1937
|
+
});
|
|
1938
|
+
return wrapper;
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1533
1941
|
// src/play.ts
|
|
1534
1942
|
var DeeplineConditionalStepResolver = class _DeeplineConditionalStepResolver {
|
|
1535
1943
|
constructor(when2, run, elseValue) {
|
|
@@ -1666,10 +2074,10 @@ var DeeplineContext = class {
|
|
|
1666
2074
|
*
|
|
1667
2075
|
* @example
|
|
1668
2076
|
* ```typescript
|
|
1669
|
-
* const tools = await
|
|
1670
|
-
* const meta = await
|
|
1671
|
-
* const companyLookup = await
|
|
1672
|
-
* const company = companyLookup.
|
|
2077
|
+
* const tools = await deepline.tools.list();
|
|
2078
|
+
* const meta = await deepline.tools.get('apollo_people_search');
|
|
2079
|
+
* const companyLookup = await deepline.tools.execute('test_company_search', { domain: 'stripe.com' });
|
|
2080
|
+
* const company = companyLookup.toolOutput.raw;
|
|
1673
2081
|
* ```
|
|
1674
2082
|
*/
|
|
1675
2083
|
get tools() {
|
|
@@ -1679,11 +2087,14 @@ var DeeplineContext = class {
|
|
|
1679
2087
|
/** Get detailed metadata for a tool. */
|
|
1680
2088
|
get: (toolId) => this.client.getTool(toolId),
|
|
1681
2089
|
/** Execute a tool and return the standard execution envelope. */
|
|
1682
|
-
execute: async (toolId, input) =>
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
2090
|
+
execute: async (toolId, input) => {
|
|
2091
|
+
const response = await this.client.executeTool(
|
|
2092
|
+
toolId,
|
|
2093
|
+
input,
|
|
2094
|
+
{ includeToolMetadata: true }
|
|
2095
|
+
);
|
|
2096
|
+
return toolExecutionEnvelopeToResult(toolId, response);
|
|
2097
|
+
}
|
|
1687
2098
|
};
|
|
1688
2099
|
}
|
|
1689
2100
|
get plays() {
|
|
@@ -1778,6 +2189,47 @@ var Deepline = class {
|
|
|
1778
2189
|
return new DeeplineContext(options);
|
|
1779
2190
|
}
|
|
1780
2191
|
};
|
|
2192
|
+
function isRecord3(value) {
|
|
2193
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2194
|
+
}
|
|
2195
|
+
function stringArrayRecord(value) {
|
|
2196
|
+
if (!isRecord3(value)) return {};
|
|
2197
|
+
return Object.fromEntries(
|
|
2198
|
+
Object.entries(value).map(([key, paths]) => [
|
|
2199
|
+
key,
|
|
2200
|
+
Array.isArray(paths) ? paths.map(String) : []
|
|
2201
|
+
])
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
function stringArray(value) {
|
|
2205
|
+
return Array.isArray(value) ? value.map(String) : [];
|
|
2206
|
+
}
|
|
2207
|
+
function toolExecutionEnvelopeToResult(fallbackToolId, response) {
|
|
2208
|
+
const raw = response.toolExecutionResult?.toolOutput?.raw ?? null;
|
|
2209
|
+
const meta = response.toolExecutionResult?.toolOutput?.meta;
|
|
2210
|
+
const metadata = isRecord3(response._metadata) ? response._metadata.tool : null;
|
|
2211
|
+
const toolMetadata = isRecord3(metadata) ? metadata : {};
|
|
2212
|
+
return createToolExecuteResult({
|
|
2213
|
+
status: typeof response.status === "string" ? response.status : "completed",
|
|
2214
|
+
result: {
|
|
2215
|
+
data: raw,
|
|
2216
|
+
...isRecord3(meta) ? { meta } : {}
|
|
2217
|
+
},
|
|
2218
|
+
metadata: {
|
|
2219
|
+
toolId: typeof toolMetadata.toolId === "string" ? toolMetadata.toolId : fallbackToolId,
|
|
2220
|
+
resultIdentityGetters: stringArrayRecord(
|
|
2221
|
+
toolMetadata.resultIdentityGetters
|
|
2222
|
+
),
|
|
2223
|
+
listExtractorPaths: stringArray(toolMetadata.listExtractorPaths),
|
|
2224
|
+
listIdentityGetters: stringArrayRecord(toolMetadata.listIdentityGetters)
|
|
2225
|
+
},
|
|
2226
|
+
execution: {
|
|
2227
|
+
idempotent: true,
|
|
2228
|
+
cached: false,
|
|
2229
|
+
source: "live"
|
|
2230
|
+
}
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
1781
2233
|
function defineInput(schema) {
|
|
1782
2234
|
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
1783
2235
|
throw new Error(
|
|
@@ -1904,7 +2356,7 @@ function getByDottedPath(root, dottedPath) {
|
|
|
1904
2356
|
}
|
|
1905
2357
|
return current;
|
|
1906
2358
|
}
|
|
1907
|
-
function
|
|
2359
|
+
function normalizeRows2(value) {
|
|
1908
2360
|
if (!Array.isArray(value)) return null;
|
|
1909
2361
|
return value.map((entry) => {
|
|
1910
2362
|
if (isPlainObject(entry)) return entry;
|
|
@@ -1913,6 +2365,25 @@ function normalizeRows(value) {
|
|
|
1913
2365
|
}
|
|
1914
2366
|
function candidateRoots(payload) {
|
|
1915
2367
|
const roots = [{ path: null, value: payload }];
|
|
2368
|
+
if (isPlainObject(payload) && isPlainObject(payload.toolExecutionResult)) {
|
|
2369
|
+
roots.push({ path: "toolExecutionResult", value: payload.toolExecutionResult });
|
|
2370
|
+
const toolOutput = payload.toolExecutionResult.toolOutput;
|
|
2371
|
+
if (isPlainObject(toolOutput)) {
|
|
2372
|
+
roots.push({ path: "toolExecutionResult.toolOutput", value: toolOutput });
|
|
2373
|
+
if (Object.prototype.hasOwnProperty.call(toolOutput, "raw")) {
|
|
2374
|
+
roots.push({
|
|
2375
|
+
path: "toolExecutionResult.toolOutput.raw",
|
|
2376
|
+
value: toolOutput.raw
|
|
2377
|
+
});
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
if (isPlainObject(payload) && isPlainObject(payload.output)) {
|
|
2382
|
+
roots.push({ path: "output", value: payload.output });
|
|
2383
|
+
if (Object.prototype.hasOwnProperty.call(payload.output, "body")) {
|
|
2384
|
+
roots.push({ path: "output.body", value: payload.output.body });
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
1916
2387
|
if (isPlainObject(payload) && isPlainObject(payload.result)) {
|
|
1917
2388
|
roots.push({ path: "result", value: payload.result });
|
|
1918
2389
|
if (isPlainObject(payload.result.data)) {
|
|
@@ -1923,7 +2394,7 @@ function candidateRoots(payload) {
|
|
|
1923
2394
|
}
|
|
1924
2395
|
function findBestArrayCandidate(value, pathPrefix = "", depth = 0) {
|
|
1925
2396
|
if (depth > 5) return null;
|
|
1926
|
-
const directRows =
|
|
2397
|
+
const directRows = normalizeRows2(value);
|
|
1927
2398
|
const hasObjectRow = directRows?.some((row) => Object.keys(row).some((key) => key !== "value")) ?? false;
|
|
1928
2399
|
let best = directRows && directRows.length > 0 && hasObjectRow ? { path: pathPrefix, rows: directRows } : null;
|
|
1929
2400
|
if (!isPlainObject(value)) {
|
|
@@ -1945,7 +2416,7 @@ function tryConvertToList(payload, options) {
|
|
|
1945
2416
|
for (const root of candidateRoots(payload)) {
|
|
1946
2417
|
for (const extractorPath of listExtractorPaths) {
|
|
1947
2418
|
const resolved = getByDottedPath(root.value, extractorPath);
|
|
1948
|
-
const rows =
|
|
2419
|
+
const rows = normalizeRows2(resolved);
|
|
1949
2420
|
if (rows && rows.length > 0) {
|
|
1950
2421
|
const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
|
|
1951
2422
|
return { rows, strategy: "configured_paths", sourcePath };
|