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.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.35";
|
|
219
|
+
var SDK_API_CONTRACT = "2026-05-v2-tool-result-contract";
|
|
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-execution-result";
|
|
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 `toolExecutionResult.toolOutput.raw` field contains the raw tool output.
|
|
800
|
+
* `toolExecutionResult.toolOutput.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,383 @@ 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 "toolExecutionResult.toolOutput.raw";
|
|
1628
|
+
if (normalized === "toolExecutionResult.toolOutput.raw" || normalized.startsWith("toolExecutionResult.toolOutput.raw.")) {
|
|
1629
|
+
return normalized;
|
|
1630
|
+
}
|
|
1631
|
+
const rawPath = normalized.replace(/^result\.data\.?/, "").replace(/^result\.?/, "").replace(/^data\.?/, "").replace(/^\./, "");
|
|
1632
|
+
return rawPath ? `toolExecutionResult.toolOutput.raw.${rawPath}` : "toolExecutionResult.toolOutput.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 "toolExecutionResult.toolOutput.raw";
|
|
1704
|
+
if (normalized === "toolExecutionResult.toolOutput.raw" || normalized.startsWith("toolExecutionResult.toolOutput.raw.")) {
|
|
1705
|
+
return normalized;
|
|
1706
|
+
}
|
|
1707
|
+
const rawPath = normalized.replace(/^result\.?/, "").replace(/^\./, "");
|
|
1708
|
+
return rawPath ? `toolExecutionResult.toolOutput.raw.${rawPath}` : "toolExecutionResult.toolOutput.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
|
+
toolExecutionResult: {
|
|
1953
|
+
toolOutput: {
|
|
1954
|
+
raw: result.data,
|
|
1955
|
+
...result.meta ? { meta: result.meta } : {}
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
};
|
|
1959
|
+
const targets = buildTargets(
|
|
1960
|
+
resultRoot,
|
|
1961
|
+
input.metadata.resultIdentityGetters
|
|
1962
|
+
);
|
|
1963
|
+
const lists = buildLists(resultRoot, input.metadata);
|
|
1964
|
+
const metadata = {
|
|
1965
|
+
toolId: input.metadata.toolId,
|
|
1966
|
+
execution: input.execution,
|
|
1967
|
+
targets,
|
|
1968
|
+
lists
|
|
1969
|
+
};
|
|
1970
|
+
const wrapper = {
|
|
1971
|
+
status: input.status,
|
|
1972
|
+
toolOutput: {
|
|
1973
|
+
raw: result.data,
|
|
1974
|
+
...result.meta ? { meta: result.meta } : {}
|
|
1975
|
+
},
|
|
1976
|
+
meta: input.execution,
|
|
1977
|
+
extractedValues: buildExtractedAccessors(targets),
|
|
1978
|
+
extractedLists: buildListAccessors(resultRoot, lists)
|
|
1979
|
+
};
|
|
1980
|
+
Object.defineProperty(wrapper, "_metadata", {
|
|
1981
|
+
value: metadata,
|
|
1982
|
+
enumerable: false
|
|
1983
|
+
});
|
|
1984
|
+
return wrapper;
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1579
1987
|
// src/play.ts
|
|
1580
1988
|
var DeeplineConditionalStepResolver = class _DeeplineConditionalStepResolver {
|
|
1581
1989
|
constructor(when2, run, elseValue) {
|
|
@@ -1712,10 +2120,10 @@ var DeeplineContext = class {
|
|
|
1712
2120
|
*
|
|
1713
2121
|
* @example
|
|
1714
2122
|
* ```typescript
|
|
1715
|
-
* const tools = await
|
|
1716
|
-
* const meta = await
|
|
1717
|
-
* const companyLookup = await
|
|
1718
|
-
* const company = companyLookup.
|
|
2123
|
+
* const tools = await deepline.tools.list();
|
|
2124
|
+
* const meta = await deepline.tools.get('apollo_people_search');
|
|
2125
|
+
* const companyLookup = await deepline.tools.execute('test_company_search', { domain: 'stripe.com' });
|
|
2126
|
+
* const company = companyLookup.toolOutput.raw;
|
|
1719
2127
|
* ```
|
|
1720
2128
|
*/
|
|
1721
2129
|
get tools() {
|
|
@@ -1725,11 +2133,14 @@ var DeeplineContext = class {
|
|
|
1725
2133
|
/** Get detailed metadata for a tool. */
|
|
1726
2134
|
get: (toolId) => this.client.getTool(toolId),
|
|
1727
2135
|
/** Execute a tool and return the standard execution envelope. */
|
|
1728
|
-
execute: async (toolId, input) =>
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
2136
|
+
execute: async (toolId, input) => {
|
|
2137
|
+
const response = await this.client.executeTool(
|
|
2138
|
+
toolId,
|
|
2139
|
+
input,
|
|
2140
|
+
{ includeToolMetadata: true }
|
|
2141
|
+
);
|
|
2142
|
+
return toolExecutionEnvelopeToResult(toolId, response);
|
|
2143
|
+
}
|
|
1733
2144
|
};
|
|
1734
2145
|
}
|
|
1735
2146
|
get plays() {
|
|
@@ -1824,6 +2235,47 @@ var Deepline = class {
|
|
|
1824
2235
|
return new DeeplineContext(options);
|
|
1825
2236
|
}
|
|
1826
2237
|
};
|
|
2238
|
+
function isRecord3(value) {
|
|
2239
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2240
|
+
}
|
|
2241
|
+
function stringArrayRecord(value) {
|
|
2242
|
+
if (!isRecord3(value)) return {};
|
|
2243
|
+
return Object.fromEntries(
|
|
2244
|
+
Object.entries(value).map(([key, paths]) => [
|
|
2245
|
+
key,
|
|
2246
|
+
Array.isArray(paths) ? paths.map(String) : []
|
|
2247
|
+
])
|
|
2248
|
+
);
|
|
2249
|
+
}
|
|
2250
|
+
function stringArray(value) {
|
|
2251
|
+
return Array.isArray(value) ? value.map(String) : [];
|
|
2252
|
+
}
|
|
2253
|
+
function toolExecutionEnvelopeToResult(fallbackToolId, response) {
|
|
2254
|
+
const raw = response.toolExecutionResult?.toolOutput?.raw ?? null;
|
|
2255
|
+
const meta = response.toolExecutionResult?.toolOutput?.meta;
|
|
2256
|
+
const metadata = isRecord3(response._metadata) ? response._metadata.tool : null;
|
|
2257
|
+
const toolMetadata = isRecord3(metadata) ? metadata : {};
|
|
2258
|
+
return createToolExecuteResult({
|
|
2259
|
+
status: typeof response.status === "string" ? response.status : "completed",
|
|
2260
|
+
result: {
|
|
2261
|
+
data: raw,
|
|
2262
|
+
...isRecord3(meta) ? { meta } : {}
|
|
2263
|
+
},
|
|
2264
|
+
metadata: {
|
|
2265
|
+
toolId: typeof toolMetadata.toolId === "string" ? toolMetadata.toolId : fallbackToolId,
|
|
2266
|
+
resultIdentityGetters: stringArrayRecord(
|
|
2267
|
+
toolMetadata.resultIdentityGetters
|
|
2268
|
+
),
|
|
2269
|
+
listExtractorPaths: stringArray(toolMetadata.listExtractorPaths),
|
|
2270
|
+
listIdentityGetters: stringArrayRecord(toolMetadata.listIdentityGetters)
|
|
2271
|
+
},
|
|
2272
|
+
execution: {
|
|
2273
|
+
idempotent: true,
|
|
2274
|
+
cached: false,
|
|
2275
|
+
source: "live"
|
|
2276
|
+
}
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
1827
2279
|
function defineInput(schema) {
|
|
1828
2280
|
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
1829
2281
|
throw new Error(
|
|
@@ -1950,7 +2402,7 @@ function getByDottedPath(root, dottedPath) {
|
|
|
1950
2402
|
}
|
|
1951
2403
|
return current;
|
|
1952
2404
|
}
|
|
1953
|
-
function
|
|
2405
|
+
function normalizeRows2(value) {
|
|
1954
2406
|
if (!Array.isArray(value)) return null;
|
|
1955
2407
|
return value.map((entry) => {
|
|
1956
2408
|
if (isPlainObject(entry)) return entry;
|
|
@@ -1959,6 +2411,25 @@ function normalizeRows(value) {
|
|
|
1959
2411
|
}
|
|
1960
2412
|
function candidateRoots(payload) {
|
|
1961
2413
|
const roots = [{ path: null, value: payload }];
|
|
2414
|
+
if (isPlainObject(payload) && isPlainObject(payload.toolExecutionResult)) {
|
|
2415
|
+
roots.push({ path: "toolExecutionResult", value: payload.toolExecutionResult });
|
|
2416
|
+
const toolOutput = payload.toolExecutionResult.toolOutput;
|
|
2417
|
+
if (isPlainObject(toolOutput)) {
|
|
2418
|
+
roots.push({ path: "toolExecutionResult.toolOutput", value: toolOutput });
|
|
2419
|
+
if (Object.prototype.hasOwnProperty.call(toolOutput, "raw")) {
|
|
2420
|
+
roots.push({
|
|
2421
|
+
path: "toolExecutionResult.toolOutput.raw",
|
|
2422
|
+
value: toolOutput.raw
|
|
2423
|
+
});
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
if (isPlainObject(payload) && isPlainObject(payload.output)) {
|
|
2428
|
+
roots.push({ path: "output", value: payload.output });
|
|
2429
|
+
if (Object.prototype.hasOwnProperty.call(payload.output, "body")) {
|
|
2430
|
+
roots.push({ path: "output.body", value: payload.output.body });
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
1962
2433
|
if (isPlainObject(payload) && isPlainObject(payload.result)) {
|
|
1963
2434
|
roots.push({ path: "result", value: payload.result });
|
|
1964
2435
|
if (isPlainObject(payload.result.data)) {
|
|
@@ -1969,7 +2440,7 @@ function candidateRoots(payload) {
|
|
|
1969
2440
|
}
|
|
1970
2441
|
function findBestArrayCandidate(value, pathPrefix = "", depth = 0) {
|
|
1971
2442
|
if (depth > 5) return null;
|
|
1972
|
-
const directRows =
|
|
2443
|
+
const directRows = normalizeRows2(value);
|
|
1973
2444
|
const hasObjectRow = directRows?.some((row) => Object.keys(row).some((key) => key !== "value")) ?? false;
|
|
1974
2445
|
let best = directRows && directRows.length > 0 && hasObjectRow ? { path: pathPrefix, rows: directRows } : null;
|
|
1975
2446
|
if (!isPlainObject(value)) {
|
|
@@ -1991,7 +2462,7 @@ function tryConvertToList(payload, options) {
|
|
|
1991
2462
|
for (const root of candidateRoots(payload)) {
|
|
1992
2463
|
for (const extractorPath of listExtractorPaths) {
|
|
1993
2464
|
const resolved = getByDottedPath(root.value, extractorPath);
|
|
1994
|
-
const rows =
|
|
2465
|
+
const rows = normalizeRows2(resolved);
|
|
1995
2466
|
if (rows && rows.length > 0) {
|
|
1996
2467
|
const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
|
|
1997
2468
|
return { rows, strategy: "configured_paths", sourcePath };
|