deepline 0.1.33 → 0.1.36
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 +991 -219
- package/dist/cli/index.mjs +924 -152
- package/dist/index.d.mts +124 -62
- package/dist/index.d.ts +124 -62
- package/dist/index.js +522 -45
- package/dist/index.mjs +522 -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 +186 -75
- package/dist/repo/apps/play-runner-workers/src/runtime/receipts.ts +138 -0
- package/dist/repo/apps/play-runner-workers/src/workflow-retry.ts +50 -0
- package/dist/repo/sdk/src/client.ts +43 -32
- 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 +126 -45
- package/dist/repo/sdk/src/plays/harness-stub.ts +2 -2
- package/dist/repo/sdk/src/tool-output.ts +22 -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 +154 -35
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -215,8 +215,8 @@ function resolveConfig(options) {
|
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
// src/version.ts
|
|
218
|
-
var SDK_VERSION = "0.1.
|
|
219
|
-
var SDK_API_CONTRACT = "2026-05-
|
|
218
|
+
var SDK_VERSION = "0.1.36";
|
|
219
|
+
var SDK_API_CONTRACT = "2026-05-v2-tool-response";
|
|
220
220
|
|
|
221
221
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
222
222
|
var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
|
|
@@ -298,7 +298,7 @@ var HttpClient = class {
|
|
|
298
298
|
const response = await fetch(candidateUrl, {
|
|
299
299
|
method,
|
|
300
300
|
headers,
|
|
301
|
-
body: options?.formData !== void 0 ? options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
301
|
+
body: options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
302
302
|
signal: controller.signal
|
|
303
303
|
});
|
|
304
304
|
clearTimeout(timeoutId);
|
|
@@ -381,10 +381,13 @@ var HttpClient = class {
|
|
|
381
381
|
throw new AuthError();
|
|
382
382
|
}
|
|
383
383
|
if (!response.ok) {
|
|
384
|
+
const body = await response.text();
|
|
385
|
+
const parsed = parseResponseBody(body);
|
|
384
386
|
throw new DeeplineError(
|
|
385
|
-
|
|
387
|
+
apiErrorMessage(parsed, response.status),
|
|
386
388
|
response.status,
|
|
387
|
-
"API_ERROR"
|
|
389
|
+
"API_ERROR",
|
|
390
|
+
{ response: parsed }
|
|
388
391
|
);
|
|
389
392
|
}
|
|
390
393
|
if (!response.body) {
|
|
@@ -434,6 +437,26 @@ var HttpClient = class {
|
|
|
434
437
|
return this.request(path, { method: "DELETE" });
|
|
435
438
|
}
|
|
436
439
|
};
|
|
440
|
+
function parseResponseBody(body) {
|
|
441
|
+
try {
|
|
442
|
+
return JSON.parse(body);
|
|
443
|
+
} catch {
|
|
444
|
+
return body;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function apiErrorMessage(parsed, status) {
|
|
448
|
+
const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
|
|
449
|
+
if (typeof errorValue === "string") {
|
|
450
|
+
return errorValue;
|
|
451
|
+
}
|
|
452
|
+
if (errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string") {
|
|
453
|
+
return errorValue.message;
|
|
454
|
+
}
|
|
455
|
+
if (typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string") {
|
|
456
|
+
return parsed.message;
|
|
457
|
+
}
|
|
458
|
+
return `HTTP ${status}`;
|
|
459
|
+
}
|
|
437
460
|
function parseRetryAfter(response) {
|
|
438
461
|
const header = response.headers.get("retry-after");
|
|
439
462
|
if (header) {
|
|
@@ -503,6 +526,8 @@ function sleep(ms) {
|
|
|
503
526
|
// src/client.ts
|
|
504
527
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
505
528
|
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
529
|
+
var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
|
|
530
|
+
var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-response";
|
|
506
531
|
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
507
532
|
function sleep2(ms) {
|
|
508
533
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
@@ -771,13 +796,16 @@ var DeeplineClient = class {
|
|
|
771
796
|
/**
|
|
772
797
|
* Execute a tool and return the standard execution envelope.
|
|
773
798
|
*
|
|
774
|
-
* The `
|
|
775
|
-
* contains provider
|
|
799
|
+
* The `toolResponse.raw` field contains the raw tool response.
|
|
800
|
+
* `toolResponse.meta` contains tool/provider metadata.
|
|
776
801
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
777
|
-
* Deepline execution.
|
|
802
|
+
* Deepline execution envelope.
|
|
778
803
|
*/
|
|
779
804
|
async executeTool(toolId, input, options) {
|
|
780
|
-
const headers =
|
|
805
|
+
const headers = {
|
|
806
|
+
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
807
|
+
...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
|
|
808
|
+
};
|
|
781
809
|
return this.http.post(
|
|
782
810
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
783
811
|
{ payload: input },
|
|
@@ -1075,34 +1103,37 @@ var DeeplineClient = class {
|
|
|
1075
1103
|
* ```
|
|
1076
1104
|
*/
|
|
1077
1105
|
async stagePlayFiles(files) {
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1080
|
-
"metadata",
|
|
1081
|
-
JSON.stringify({
|
|
1082
|
-
files: files.map((file, index) => ({
|
|
1083
|
-
index,
|
|
1084
|
-
logicalPath: file.logicalPath,
|
|
1085
|
-
contentHash: file.contentHash,
|
|
1086
|
-
contentType: file.contentType,
|
|
1087
|
-
bytes: file.bytes
|
|
1088
|
-
}))
|
|
1089
|
-
})
|
|
1090
|
-
);
|
|
1091
|
-
for (const [index, file] of files.entries()) {
|
|
1092
|
-
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1093
|
-
const body = bytes.buffer.slice(
|
|
1094
|
-
bytes.byteOffset,
|
|
1095
|
-
bytes.byteOffset + bytes.byteLength
|
|
1096
|
-
);
|
|
1106
|
+
const buildFormData = () => {
|
|
1107
|
+
const formData = new FormData();
|
|
1097
1108
|
formData.set(
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1109
|
+
"metadata",
|
|
1110
|
+
JSON.stringify({
|
|
1111
|
+
files: files.map((file, index) => ({
|
|
1112
|
+
index,
|
|
1113
|
+
logicalPath: file.logicalPath,
|
|
1114
|
+
contentHash: file.contentHash,
|
|
1115
|
+
contentType: file.contentType,
|
|
1116
|
+
bytes: file.bytes
|
|
1117
|
+
}))
|
|
1118
|
+
})
|
|
1101
1119
|
);
|
|
1102
|
-
|
|
1120
|
+
for (const [index, file] of files.entries()) {
|
|
1121
|
+
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1122
|
+
const body = bytes.buffer.slice(
|
|
1123
|
+
bytes.byteOffset,
|
|
1124
|
+
bytes.byteOffset + bytes.byteLength
|
|
1125
|
+
);
|
|
1126
|
+
formData.set(
|
|
1127
|
+
`file:${index}`,
|
|
1128
|
+
new Blob([body], { type: file.contentType }),
|
|
1129
|
+
file.logicalPath
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
return formData;
|
|
1133
|
+
};
|
|
1103
1134
|
const response = await this.http.postFormData(
|
|
1104
1135
|
"/api/v2/plays/files/stage",
|
|
1105
|
-
|
|
1136
|
+
buildFormData
|
|
1106
1137
|
);
|
|
1107
1138
|
return response.files;
|
|
1108
1139
|
}
|
|
@@ -1576,6 +1607,391 @@ var DeeplineClient = class {
|
|
|
1576
1607
|
}
|
|
1577
1608
|
};
|
|
1578
1609
|
|
|
1610
|
+
// ../shared_libs/play-runtime/tool-result.ts
|
|
1611
|
+
var TARGET_FALLBACK_KEYS = {
|
|
1612
|
+
email: [/^email$/i, /^address$/i, /email/i],
|
|
1613
|
+
phone: [/^phone$/i, /mobile/i, /phone/i, /telephone/i],
|
|
1614
|
+
linkedin: [/^linkedin_url$/i, /^linkedin$/i, /linkedin/i],
|
|
1615
|
+
company_linkedin_url: [/company.*linkedin/i, /linkedin.*company/i],
|
|
1616
|
+
company_domain: [/^company_domain$/i, /company.*domain/i],
|
|
1617
|
+
company_name: [/^company_name$/i, /company.*name/i],
|
|
1618
|
+
domain: [/^domain$/i, /company_domain/i, /domain/i],
|
|
1619
|
+
status: [/^email_status$/i, /^status$/i],
|
|
1620
|
+
email_status: [/^email_status$/i, /^status$/i]
|
|
1621
|
+
};
|
|
1622
|
+
function isRecord2(value) {
|
|
1623
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1624
|
+
}
|
|
1625
|
+
function toV2RawToolOutputPath(path) {
|
|
1626
|
+
const normalized = String(path || "").trim().replace(/^\./, "");
|
|
1627
|
+
if (!normalized) return "toolResponse.raw";
|
|
1628
|
+
if (normalized === "toolResponse.raw" || normalized.startsWith("toolResponse.raw.")) {
|
|
1629
|
+
return normalized;
|
|
1630
|
+
}
|
|
1631
|
+
const rawPath = normalized.replace(/^result\.data\.?/, "").replace(/^result\.?/, "").replace(/^data\.?/, "").replace(/^\./, "");
|
|
1632
|
+
return rawPath ? `toolResponse.raw.${rawPath}` : "toolResponse.raw";
|
|
1633
|
+
}
|
|
1634
|
+
function isMeaningfulValue(value) {
|
|
1635
|
+
if (value == null) return false;
|
|
1636
|
+
if (typeof value === "string") return value.trim().length > 0;
|
|
1637
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
1638
|
+
if (typeof value === "object") return Object.keys(value).length > 0;
|
|
1639
|
+
return true;
|
|
1640
|
+
}
|
|
1641
|
+
function parsePath(path) {
|
|
1642
|
+
const segments = [];
|
|
1643
|
+
for (const rawPart of path.split(".").filter(Boolean)) {
|
|
1644
|
+
const bracketPattern = /([^\[\]]+)|\[(\d+|\*)\]/g;
|
|
1645
|
+
let matched = false;
|
|
1646
|
+
for (const match of rawPart.matchAll(bracketPattern)) {
|
|
1647
|
+
matched = true;
|
|
1648
|
+
if (match[1]) {
|
|
1649
|
+
segments.push(match[1]);
|
|
1650
|
+
} else if (match[2] === "*") {
|
|
1651
|
+
segments.push("*");
|
|
1652
|
+
} else if (match[2]) {
|
|
1653
|
+
segments.push(Number(match[2]));
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
if (!matched) {
|
|
1657
|
+
segments.push(rawPart);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
return segments;
|
|
1661
|
+
}
|
|
1662
|
+
function pathToString(segments) {
|
|
1663
|
+
return segments.map(
|
|
1664
|
+
(segment, index) => typeof segment === "number" ? `[${segment}]` : segment === "*" ? "[*]" : index === 0 ? segment : `.${segment}`
|
|
1665
|
+
).join("");
|
|
1666
|
+
}
|
|
1667
|
+
function valuesAtSegments(current, segments, path = []) {
|
|
1668
|
+
if (segments.length === 0) {
|
|
1669
|
+
return [{ value: current, path: pathToString(path) }];
|
|
1670
|
+
}
|
|
1671
|
+
const [segment, ...rest] = segments;
|
|
1672
|
+
if (segment === "*") {
|
|
1673
|
+
if (!Array.isArray(current)) return [];
|
|
1674
|
+
return current.flatMap(
|
|
1675
|
+
(entry, index) => valuesAtSegments(entry, rest, [...path, index])
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
if (typeof segment === "number") {
|
|
1679
|
+
if (!Array.isArray(current)) return [];
|
|
1680
|
+
return valuesAtSegments(current[segment], rest, [...path, segment]);
|
|
1681
|
+
}
|
|
1682
|
+
if (!isRecord2(current)) return [];
|
|
1683
|
+
return valuesAtSegments(current[segment], rest, [...path, segment]);
|
|
1684
|
+
}
|
|
1685
|
+
function getValuesAtPath(root, path) {
|
|
1686
|
+
return valuesAtSegments(root, parsePath(path)).map((entry) => entry.value);
|
|
1687
|
+
}
|
|
1688
|
+
function toResultEnvelope(value) {
|
|
1689
|
+
if (isRecord2(value) && "data" in value) {
|
|
1690
|
+
const envelope = { data: value.data };
|
|
1691
|
+
if ("meta" in value) envelope.meta = value.meta;
|
|
1692
|
+
return envelope;
|
|
1693
|
+
}
|
|
1694
|
+
return { data: value };
|
|
1695
|
+
}
|
|
1696
|
+
function normalizeResultPath(path) {
|
|
1697
|
+
const trimmed = String(path || "").trim().replace(/^\./, "");
|
|
1698
|
+
if (!trimmed) return "";
|
|
1699
|
+
return toV2RawToolOutputPath(trimmed);
|
|
1700
|
+
}
|
|
1701
|
+
function toV2RawToolOutputPathPreservingProviderData(path) {
|
|
1702
|
+
const normalized = String(path || "").trim().replace(/^\./, "");
|
|
1703
|
+
if (!normalized) return "toolResponse.raw";
|
|
1704
|
+
if (normalized === "toolResponse.raw" || normalized.startsWith("toolResponse.raw.")) {
|
|
1705
|
+
return normalized;
|
|
1706
|
+
}
|
|
1707
|
+
const rawPath = normalized.replace(/^result\.?/, "").replace(/^\./, "");
|
|
1708
|
+
return rawPath ? `toolResponse.raw.${rawPath}` : "toolResponse.raw";
|
|
1709
|
+
}
|
|
1710
|
+
function candidateResultPaths(path) {
|
|
1711
|
+
const candidates = [
|
|
1712
|
+
normalizeResultPath(path),
|
|
1713
|
+
toV2RawToolOutputPathPreservingProviderData(path)
|
|
1714
|
+
];
|
|
1715
|
+
return candidates.filter(
|
|
1716
|
+
(candidate, index, all) => candidate.length > 0 && all.indexOf(candidate) === index
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
function normalizeRelativePath(path) {
|
|
1720
|
+
return String(path || "").trim().replace(/^result\./, "").replace(/^\./, "");
|
|
1721
|
+
}
|
|
1722
|
+
function getFirstMeaningfulValueAtPath(root, path) {
|
|
1723
|
+
for (const entry of valuesAtSegments(root, parsePath(path))) {
|
|
1724
|
+
if (isMeaningfulValue(entry.value)) {
|
|
1725
|
+
return { value: entry.value, path: entry.path };
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
return null;
|
|
1729
|
+
}
|
|
1730
|
+
function getAtPath(root, path) {
|
|
1731
|
+
const segments = parsePath(path);
|
|
1732
|
+
if (segments.includes("*")) {
|
|
1733
|
+
return getValuesAtPath(root, path).filter(isMeaningfulValue);
|
|
1734
|
+
}
|
|
1735
|
+
let current = root;
|
|
1736
|
+
for (const segment of segments) {
|
|
1737
|
+
if (typeof segment === "number") {
|
|
1738
|
+
if (!Array.isArray(current)) return void 0;
|
|
1739
|
+
current = current[segment];
|
|
1740
|
+
continue;
|
|
1741
|
+
}
|
|
1742
|
+
if (!isRecord2(current)) return void 0;
|
|
1743
|
+
current = current[segment];
|
|
1744
|
+
}
|
|
1745
|
+
return current;
|
|
1746
|
+
}
|
|
1747
|
+
function normalizeRows(value) {
|
|
1748
|
+
if (!Array.isArray(value)) return null;
|
|
1749
|
+
return value.map((entry) => isRecord2(entry) ? entry : { value: entry });
|
|
1750
|
+
}
|
|
1751
|
+
function findFirstTargetByPath(result, paths) {
|
|
1752
|
+
for (const path of paths ?? []) {
|
|
1753
|
+
for (const candidate of candidateResultPaths(path)) {
|
|
1754
|
+
const match = getFirstMeaningfulValueAtPath(result, candidate);
|
|
1755
|
+
if (match) return match;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
return null;
|
|
1759
|
+
}
|
|
1760
|
+
function findFirstTargetByKey(result, target, depth = 0, path = []) {
|
|
1761
|
+
if (depth > 6) return null;
|
|
1762
|
+
if (Array.isArray(result)) {
|
|
1763
|
+
for (let index = 0; index < result.length; index += 1) {
|
|
1764
|
+
const found = findFirstTargetByKey(result[index], target, depth + 1, [
|
|
1765
|
+
...path,
|
|
1766
|
+
index
|
|
1767
|
+
]);
|
|
1768
|
+
if (found) return found;
|
|
1769
|
+
}
|
|
1770
|
+
return null;
|
|
1771
|
+
}
|
|
1772
|
+
if (!isRecord2(result)) return null;
|
|
1773
|
+
const patterns = TARGET_FALLBACK_KEYS[target] ?? [
|
|
1774
|
+
new RegExp(`^${target}$`, "i")
|
|
1775
|
+
];
|
|
1776
|
+
for (const [key, value] of Object.entries(result)) {
|
|
1777
|
+
if (patterns.some((pattern) => pattern.test(key)) && isMeaningfulValue(value)) {
|
|
1778
|
+
return { value, path: pathToString([...path, key]) };
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
for (const [key, value] of Object.entries(result)) {
|
|
1782
|
+
const found = findFirstTargetByKey(value, target, depth + 1, [
|
|
1783
|
+
...path,
|
|
1784
|
+
key
|
|
1785
|
+
]);
|
|
1786
|
+
if (found) return found;
|
|
1787
|
+
}
|
|
1788
|
+
return null;
|
|
1789
|
+
}
|
|
1790
|
+
function resolveListRows(result, listExtractorPaths) {
|
|
1791
|
+
const lists = {};
|
|
1792
|
+
for (const rawPath of listExtractorPaths ?? []) {
|
|
1793
|
+
const path = normalizeResultPath(rawPath);
|
|
1794
|
+
if (!path) continue;
|
|
1795
|
+
const candidates = [
|
|
1796
|
+
...candidateResultPaths(rawPath)
|
|
1797
|
+
].filter(
|
|
1798
|
+
(candidate, index, all) => candidate && all.indexOf(candidate) === index
|
|
1799
|
+
);
|
|
1800
|
+
let resolvedPath = null;
|
|
1801
|
+
let rows = null;
|
|
1802
|
+
for (const candidate of candidates) {
|
|
1803
|
+
rows = normalizeRows(getAtPath(result, candidate));
|
|
1804
|
+
if (rows) {
|
|
1805
|
+
resolvedPath = candidate;
|
|
1806
|
+
break;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
if (!rows) continue;
|
|
1810
|
+
const storedPath = resolvedPath ?? path;
|
|
1811
|
+
const name = storedPath.split(".").filter(Boolean).at(-1)?.replace(/\[\d+\]$/, "");
|
|
1812
|
+
lists[name || storedPath] = { path: storedPath, rows };
|
|
1813
|
+
}
|
|
1814
|
+
return lists;
|
|
1815
|
+
}
|
|
1816
|
+
function deriveListKeys(input) {
|
|
1817
|
+
const keys = {};
|
|
1818
|
+
for (const [target, paths] of Object.entries(
|
|
1819
|
+
input.listIdentityGetters ?? {}
|
|
1820
|
+
)) {
|
|
1821
|
+
const firstPath = paths.map(
|
|
1822
|
+
(rawPath) => normalizeRelativePath(rawPath)
|
|
1823
|
+
).find(Boolean);
|
|
1824
|
+
if (firstPath) {
|
|
1825
|
+
keys[target] = firstPath;
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
if (Object.keys(keys).length > 0) {
|
|
1829
|
+
return keys;
|
|
1830
|
+
}
|
|
1831
|
+
const listPrefix = input.listPath.replace(/\[\d+\]$/, "");
|
|
1832
|
+
for (const [target, paths] of Object.entries(
|
|
1833
|
+
input.resultIdentityGetters ?? {}
|
|
1834
|
+
)) {
|
|
1835
|
+
for (const rawPath of paths) {
|
|
1836
|
+
const path = String(rawPath || "").trim().replace(/^\./, "");
|
|
1837
|
+
if (!path) continue;
|
|
1838
|
+
for (const resultPath of candidateResultPaths(path)) {
|
|
1839
|
+
const directPrefix = `${listPrefix}.`;
|
|
1840
|
+
if (resultPath.startsWith(directPrefix)) {
|
|
1841
|
+
keys[target] = resultPath.slice(directPrefix.length).replace(/^\[\d+\]\.?/, "");
|
|
1842
|
+
break;
|
|
1843
|
+
}
|
|
1844
|
+
const indexedPrefix = `${listPrefix}[0].`;
|
|
1845
|
+
if (resultPath.startsWith(indexedPrefix)) {
|
|
1846
|
+
keys[target] = resultPath.slice(indexedPrefix.length);
|
|
1847
|
+
break;
|
|
1848
|
+
}
|
|
1849
|
+
const wildcardPrefix = `${listPrefix}[*].`;
|
|
1850
|
+
if (resultPath.startsWith(wildcardPrefix)) {
|
|
1851
|
+
keys[target] = resultPath.slice(wildcardPrefix.length);
|
|
1852
|
+
break;
|
|
1853
|
+
}
|
|
1854
|
+
const dottedIndexPrefix = `${listPrefix}.0.`;
|
|
1855
|
+
if (resultPath.startsWith(dottedIndexPrefix)) {
|
|
1856
|
+
keys[target] = resultPath.slice(dottedIndexPrefix.length);
|
|
1857
|
+
break;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
if (keys[target]) break;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
if (Object.keys(keys).length === 0 && input.rows[0]) {
|
|
1864
|
+
for (const key of Object.keys(input.rows[0])) {
|
|
1865
|
+
keys[key] = key;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
return keys;
|
|
1869
|
+
}
|
|
1870
|
+
function buildTargets(result, resultIdentityGetters) {
|
|
1871
|
+
const targets = {};
|
|
1872
|
+
const metadataTargets = new Set(Object.keys(resultIdentityGetters ?? {}));
|
|
1873
|
+
for (const target of metadataTargets) {
|
|
1874
|
+
const fromMetadata = findFirstTargetByPath(
|
|
1875
|
+
result,
|
|
1876
|
+
resultIdentityGetters?.[target]
|
|
1877
|
+
);
|
|
1878
|
+
if (fromMetadata) {
|
|
1879
|
+
targets[target] = fromMetadata;
|
|
1880
|
+
continue;
|
|
1881
|
+
}
|
|
1882
|
+
const fallback = findFirstTargetByKey(result, target);
|
|
1883
|
+
if (fallback) {
|
|
1884
|
+
targets[target] = fallback;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
if (metadataTargets.size > 0) return targets;
|
|
1888
|
+
for (const target of ["email", "phone", "linkedin", "domain", "status"]) {
|
|
1889
|
+
const found = findFirstTargetByKey(result, target);
|
|
1890
|
+
if (found) targets[target] = found;
|
|
1891
|
+
}
|
|
1892
|
+
return targets;
|
|
1893
|
+
}
|
|
1894
|
+
function buildLists(result, metadata) {
|
|
1895
|
+
const lists = {};
|
|
1896
|
+
const resolved = resolveListRows(result, metadata.listExtractorPaths);
|
|
1897
|
+
for (const [name, list] of Object.entries(resolved)) {
|
|
1898
|
+
lists[name] = {
|
|
1899
|
+
path: list.path,
|
|
1900
|
+
count: list.rows.length,
|
|
1901
|
+
keys: deriveListKeys({
|
|
1902
|
+
listPath: list.path,
|
|
1903
|
+
rows: list.rows,
|
|
1904
|
+
resultIdentityGetters: metadata.resultIdentityGetters,
|
|
1905
|
+
listIdentityGetters: metadata.listIdentityGetters
|
|
1906
|
+
})
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
return lists;
|
|
1910
|
+
}
|
|
1911
|
+
function buildExtractedAccessors(targets) {
|
|
1912
|
+
return Object.fromEntries(
|
|
1913
|
+
Object.entries(targets).map(([target, metadata]) => {
|
|
1914
|
+
const accessor = { path: metadata.path };
|
|
1915
|
+
Object.defineProperties(accessor, {
|
|
1916
|
+
value: {
|
|
1917
|
+
value: metadata.value,
|
|
1918
|
+
enumerable: false
|
|
1919
|
+
},
|
|
1920
|
+
get: {
|
|
1921
|
+
value() {
|
|
1922
|
+
return metadata.value ?? null;
|
|
1923
|
+
},
|
|
1924
|
+
enumerable: false
|
|
1925
|
+
}
|
|
1926
|
+
});
|
|
1927
|
+
return [target, accessor];
|
|
1928
|
+
})
|
|
1929
|
+
);
|
|
1930
|
+
}
|
|
1931
|
+
function buildListAccessors(result, lists) {
|
|
1932
|
+
return Object.fromEntries(
|
|
1933
|
+
Object.entries(lists).map(([name, metadata]) => {
|
|
1934
|
+
const accessor = {
|
|
1935
|
+
path: metadata.path,
|
|
1936
|
+
count: metadata.count,
|
|
1937
|
+
keys: metadata.keys
|
|
1938
|
+
};
|
|
1939
|
+
Object.defineProperty(accessor, "get", {
|
|
1940
|
+
value() {
|
|
1941
|
+
return normalizeRows(getAtPath(result, metadata.path)) ?? [];
|
|
1942
|
+
},
|
|
1943
|
+
enumerable: false
|
|
1944
|
+
});
|
|
1945
|
+
return [name, accessor];
|
|
1946
|
+
})
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1949
|
+
function createToolExecuteResult(input) {
|
|
1950
|
+
const result = toResultEnvelope(input.result);
|
|
1951
|
+
const resultRoot = {
|
|
1952
|
+
toolResponse: {
|
|
1953
|
+
raw: result.data,
|
|
1954
|
+
...result.meta ? { meta: result.meta } : {}
|
|
1955
|
+
}
|
|
1956
|
+
};
|
|
1957
|
+
const targets = buildTargets(
|
|
1958
|
+
resultRoot,
|
|
1959
|
+
input.metadata.resultIdentityGetters
|
|
1960
|
+
);
|
|
1961
|
+
const lists = buildLists(resultRoot, input.metadata);
|
|
1962
|
+
const metadata = {
|
|
1963
|
+
toolId: input.metadata.toolId,
|
|
1964
|
+
execution: input.execution,
|
|
1965
|
+
targets,
|
|
1966
|
+
lists
|
|
1967
|
+
};
|
|
1968
|
+
const toolResponse = {
|
|
1969
|
+
raw: result.data,
|
|
1970
|
+
...result.meta ? { meta: result.meta } : {}
|
|
1971
|
+
};
|
|
1972
|
+
const extractedValues = buildExtractedAccessors(targets);
|
|
1973
|
+
const extractedLists = buildListAccessors(resultRoot, lists);
|
|
1974
|
+
const wrapper = {
|
|
1975
|
+
status: input.status,
|
|
1976
|
+
...input.jobId ? { job_id: input.jobId } : {},
|
|
1977
|
+
...input.meta ? { meta: input.meta } : {},
|
|
1978
|
+
toolResponse,
|
|
1979
|
+
extractedValues,
|
|
1980
|
+
extractedLists
|
|
1981
|
+
};
|
|
1982
|
+
Object.defineProperties(wrapper, {
|
|
1983
|
+
toolOutput: {
|
|
1984
|
+
value: toolResponse,
|
|
1985
|
+
enumerable: false
|
|
1986
|
+
}
|
|
1987
|
+
});
|
|
1988
|
+
Object.defineProperty(wrapper, "_metadata", {
|
|
1989
|
+
value: metadata,
|
|
1990
|
+
enumerable: false
|
|
1991
|
+
});
|
|
1992
|
+
return wrapper;
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1579
1995
|
// src/play.ts
|
|
1580
1996
|
var DeeplineConditionalStepResolver = class _DeeplineConditionalStepResolver {
|
|
1581
1997
|
constructor(when2, run, elseValue) {
|
|
@@ -1712,10 +2128,10 @@ var DeeplineContext = class {
|
|
|
1712
2128
|
*
|
|
1713
2129
|
* @example
|
|
1714
2130
|
* ```typescript
|
|
1715
|
-
* const tools = await
|
|
1716
|
-
* const meta = await
|
|
1717
|
-
* const companyLookup = await
|
|
1718
|
-
* const company = companyLookup.
|
|
2131
|
+
* const tools = await deepline.tools.list();
|
|
2132
|
+
* const meta = await deepline.tools.get('apollo_people_search');
|
|
2133
|
+
* const companyLookup = await deepline.tools.execute('test_company_search', { domain: 'stripe.com' });
|
|
2134
|
+
* const company = companyLookup.toolResponse.raw;
|
|
1719
2135
|
* ```
|
|
1720
2136
|
*/
|
|
1721
2137
|
get tools() {
|
|
@@ -1725,11 +2141,14 @@ var DeeplineContext = class {
|
|
|
1725
2141
|
/** Get detailed metadata for a tool. */
|
|
1726
2142
|
get: (toolId) => this.client.getTool(toolId),
|
|
1727
2143
|
/** Execute a tool and return the standard execution envelope. */
|
|
1728
|
-
execute: async (toolId, input) =>
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
2144
|
+
execute: async (toolId, input) => {
|
|
2145
|
+
const response = await this.client.executeTool(
|
|
2146
|
+
toolId,
|
|
2147
|
+
input,
|
|
2148
|
+
{ includeToolMetadata: true }
|
|
2149
|
+
);
|
|
2150
|
+
return toolExecutionEnvelopeToResult(toolId, response);
|
|
2151
|
+
}
|
|
1733
2152
|
};
|
|
1734
2153
|
}
|
|
1735
2154
|
get plays() {
|
|
@@ -1824,6 +2243,49 @@ var Deepline = class {
|
|
|
1824
2243
|
return new DeeplineContext(options);
|
|
1825
2244
|
}
|
|
1826
2245
|
};
|
|
2246
|
+
function isRecord3(value) {
|
|
2247
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2248
|
+
}
|
|
2249
|
+
function stringArrayRecord(value) {
|
|
2250
|
+
if (!isRecord3(value)) return {};
|
|
2251
|
+
return Object.fromEntries(
|
|
2252
|
+
Object.entries(value).map(([key, paths]) => [
|
|
2253
|
+
key,
|
|
2254
|
+
Array.isArray(paths) ? paths.map(String) : []
|
|
2255
|
+
])
|
|
2256
|
+
);
|
|
2257
|
+
}
|
|
2258
|
+
function stringArray(value) {
|
|
2259
|
+
return Array.isArray(value) ? value.map(String) : [];
|
|
2260
|
+
}
|
|
2261
|
+
function toolExecutionEnvelopeToResult(fallbackToolId, response) {
|
|
2262
|
+
const raw = response.toolResponse?.raw ?? null;
|
|
2263
|
+
const meta = response.toolResponse?.meta;
|
|
2264
|
+
const metadata = isRecord3(response._metadata) ? response._metadata.tool : null;
|
|
2265
|
+
const toolMetadata = isRecord3(metadata) ? metadata : {};
|
|
2266
|
+
return createToolExecuteResult({
|
|
2267
|
+
status: typeof response.status === "string" ? response.status : "completed",
|
|
2268
|
+
jobId: typeof response.job_id === "string" ? response.job_id : void 0,
|
|
2269
|
+
result: {
|
|
2270
|
+
data: raw,
|
|
2271
|
+
...isRecord3(meta) ? { meta } : {}
|
|
2272
|
+
},
|
|
2273
|
+
metadata: {
|
|
2274
|
+
toolId: typeof toolMetadata.toolId === "string" ? toolMetadata.toolId : fallbackToolId,
|
|
2275
|
+
resultIdentityGetters: stringArrayRecord(
|
|
2276
|
+
toolMetadata.resultIdentityGetters
|
|
2277
|
+
),
|
|
2278
|
+
listExtractorPaths: stringArray(toolMetadata.listExtractorPaths),
|
|
2279
|
+
listIdentityGetters: stringArrayRecord(toolMetadata.listIdentityGetters)
|
|
2280
|
+
},
|
|
2281
|
+
execution: {
|
|
2282
|
+
idempotent: true,
|
|
2283
|
+
cached: false,
|
|
2284
|
+
source: "live"
|
|
2285
|
+
},
|
|
2286
|
+
meta: isRecord3(response.meta) ? response.meta : void 0
|
|
2287
|
+
});
|
|
2288
|
+
}
|
|
1827
2289
|
function defineInput(schema) {
|
|
1828
2290
|
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
1829
2291
|
throw new Error(
|
|
@@ -1950,7 +2412,7 @@ function getByDottedPath(root, dottedPath) {
|
|
|
1950
2412
|
}
|
|
1951
2413
|
return current;
|
|
1952
2414
|
}
|
|
1953
|
-
function
|
|
2415
|
+
function normalizeRows2(value) {
|
|
1954
2416
|
if (!Array.isArray(value)) return null;
|
|
1955
2417
|
return value.map((entry) => {
|
|
1956
2418
|
if (isPlainObject(entry)) return entry;
|
|
@@ -1959,6 +2421,21 @@ function normalizeRows(value) {
|
|
|
1959
2421
|
}
|
|
1960
2422
|
function candidateRoots(payload) {
|
|
1961
2423
|
const roots = [{ path: null, value: payload }];
|
|
2424
|
+
if (isPlainObject(payload) && isPlainObject(payload.toolResponse)) {
|
|
2425
|
+
roots.push({ path: "toolResponse", value: payload.toolResponse });
|
|
2426
|
+
if (Object.prototype.hasOwnProperty.call(payload.toolResponse, "raw")) {
|
|
2427
|
+
roots.push({
|
|
2428
|
+
path: "toolResponse.raw",
|
|
2429
|
+
value: payload.toolResponse.raw
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
if (isPlainObject(payload) && isPlainObject(payload.output)) {
|
|
2434
|
+
roots.push({ path: "output", value: payload.output });
|
|
2435
|
+
if (Object.prototype.hasOwnProperty.call(payload.output, "body")) {
|
|
2436
|
+
roots.push({ path: "output.body", value: payload.output.body });
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
1962
2439
|
if (isPlainObject(payload) && isPlainObject(payload.result)) {
|
|
1963
2440
|
roots.push({ path: "result", value: payload.result });
|
|
1964
2441
|
if (isPlainObject(payload.result.data)) {
|
|
@@ -1969,7 +2446,7 @@ function candidateRoots(payload) {
|
|
|
1969
2446
|
}
|
|
1970
2447
|
function findBestArrayCandidate(value, pathPrefix = "", depth = 0) {
|
|
1971
2448
|
if (depth > 5) return null;
|
|
1972
|
-
const directRows =
|
|
2449
|
+
const directRows = normalizeRows2(value);
|
|
1973
2450
|
const hasObjectRow = directRows?.some((row) => Object.keys(row).some((key) => key !== "value")) ?? false;
|
|
1974
2451
|
let best = directRows && directRows.length > 0 && hasObjectRow ? { path: pathPrefix, rows: directRows } : null;
|
|
1975
2452
|
if (!isPlainObject(value)) {
|
|
@@ -1991,7 +2468,7 @@ function tryConvertToList(payload, options) {
|
|
|
1991
2468
|
for (const root of candidateRoots(payload)) {
|
|
1992
2469
|
for (const extractorPath of listExtractorPaths) {
|
|
1993
2470
|
const resolved = getByDottedPath(root.value, extractorPath);
|
|
1994
|
-
const rows =
|
|
2471
|
+
const rows = normalizeRows2(resolved);
|
|
1995
2472
|
if (rows && rows.length > 0) {
|
|
1996
2473
|
const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
|
|
1997
2474
|
return { rows, strategy: "configured_paths", sourcePath };
|