deepline 0.1.32 → 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/index.js CHANGED
@@ -85,13 +85,12 @@ var ConfigError = class extends DeeplineError {
85
85
  };
86
86
 
87
87
  // src/config.ts
88
+ var HOST_URL_ENV = "DEEPLINE_HOST_URL";
89
+ var API_KEY_ENV = "DEEPLINE_API_KEY";
88
90
  var PROD_URL = "https://code.deepline.com";
89
91
  var DEFAULT_TIMEOUT = 6e4;
90
92
  var DEFAULT_MAX_RETRIES = 3;
91
- var ACTIVE_DEEPLINE_ENV_FILE = ".env.deepline";
92
- function projectEnvStartDir() {
93
- return process.env.DEEPLINE_PROJECT_ENV_DIR?.trim() || process.cwd();
94
- }
93
+ var PROJECT_DEEPLINE_ENV_FILE = ".env.deepline";
95
94
  function baseUrlSlug(baseUrl) {
96
95
  let url;
97
96
  try {
@@ -100,7 +99,7 @@ function baseUrlSlug(baseUrl) {
100
99
  return "unknown";
101
100
  }
102
101
  const host = url.hostname || "unknown";
103
- const port = url.port ? parseInt(url.port, 10) : null;
102
+ const port = url.port ? Number.parseInt(url.port, 10) : null;
104
103
  let slug = host.replace(/[^a-zA-Z0-9]/g, "-");
105
104
  if (port && port !== 80 && port !== 443) {
106
105
  slug = `${slug}-${port}`;
@@ -127,109 +126,84 @@ function parseEnvFile(filePath) {
127
126
  }
128
127
  return env;
129
128
  }
130
- function findNearestEnvFile(names, startDir = process.cwd()) {
129
+ function findNearestEnvFile(name, startDir = process.cwd()) {
131
130
  let current = (0, import_node_path.resolve)(startDir);
132
131
  while (true) {
133
- for (const name of names) {
134
- const filePath = (0, import_node_path.join)(current, name);
135
- if ((0, import_node_fs.existsSync)(filePath)) return filePath;
136
- }
132
+ const filePath = (0, import_node_path.join)(current, name);
133
+ if ((0, import_node_fs.existsSync)(filePath)) return filePath;
137
134
  const parent = (0, import_node_path.dirname)(current);
138
135
  if (parent === current) return null;
139
136
  current = parent;
140
137
  }
141
138
  }
142
- function findNearestEnv(names, startDir = process.cwd()) {
143
- const filePath = findNearestEnvFile(names, startDir);
139
+ function loadProjectDeeplineEnv(startDir = process.cwd()) {
140
+ const filePath = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
144
141
  return filePath ? parseEnvFile(filePath) : {};
145
142
  }
146
- function findNearestWorktreeEnv(startDir = process.cwd()) {
147
- return findNearestEnv([".env.worktree"], startDir);
148
- }
149
- function resolveProfileEnvFileNames() {
150
- const explicitProfile = process.env.DEEPLINE_ENV_PROFILE?.trim() || process.env.DEEPLINE_PROFILE?.trim() || "";
151
- const names = [];
152
- if (explicitProfile) names.push(`.env.deepline.${explicitProfile}`);
153
- const nodeEnv = process.env.NODE_ENV?.trim();
154
- if (nodeEnv === "production") names.push(".env.deepline.prod");
155
- else if (nodeEnv === "staging") names.push(".env.deepline.staging");
156
- names.push(ACTIVE_DEEPLINE_ENV_FILE);
157
- return names;
158
- }
159
- function resolveProjectAppEnvFileNames() {
160
- const nodeEnv = process.env.NODE_ENV?.trim();
161
- const names = [];
162
- if (nodeEnv === "production") names.push(".env.prod");
163
- if (nodeEnv === "staging") names.push(".env.staging");
164
- names.push(".env.local", ".env");
165
- return names;
166
- }
167
- function resolveBaseUrlFromEnvValues(env) {
168
- return env.DEEPLINE_ORIGIN_URL?.trim() || env.DEEPLINE_API_BASE_URL?.trim() || "";
169
- }
170
- function loadProjectDeeplineEnv() {
171
- return findNearestEnv(resolveProfileEnvFileNames(), projectEnvStartDir());
172
- }
173
- function loadProjectAppEnv() {
174
- return findNearestEnv(resolveProjectAppEnvFileNames(), projectEnvStartDir());
175
- }
176
- function normalizeWorktreeBaseUrl(baseUrl, worktreeEnv = findNearestWorktreeEnv()) {
177
- const trimmed = baseUrl.trim().replace(/\/$/, "");
178
- if (!trimmed) return trimmed;
143
+ function normalizeBaseUrl(baseUrl) {
144
+ const trimmed = baseUrl.trim().replace(/\/+$/, "");
145
+ if (!trimmed) return "";
179
146
  try {
180
147
  const parsed = new URL(trimmed);
181
- if (parsed.hostname.endsWith(".localhost") && parsed.port === "1355") {
182
- const port = worktreeEnv.WORKTREE_APP_PORT || worktreeEnv.PORT;
183
- if (port) return `${parsed.protocol}//localhost:${port}`;
148
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
149
+ return "";
184
150
  }
151
+ return parsed.toString().replace(/\/+$/, "");
185
152
  } catch {
153
+ return "";
186
154
  }
187
- return trimmed;
188
155
  }
189
- function resolveWorktreeBaseUrl() {
190
- const worktreeEnv = findNearestWorktreeEnv();
191
- const declared = worktreeEnv.DEEPLINE_API_BASE_URL || worktreeEnv.WORKTREE_PUBLIC_APP_URL || worktreeEnv.APP_URL || "";
192
- if (declared) return normalizeWorktreeBaseUrl(declared, worktreeEnv);
193
- const port = worktreeEnv.WORKTREE_APP_PORT || worktreeEnv.PORT || "";
194
- return port ? `http://localhost:${port}` : "";
156
+ function firstNonEmpty(...values) {
157
+ for (const value of values) {
158
+ const trimmed = value?.trim();
159
+ if (trimmed) return trimmed;
160
+ }
161
+ return "";
195
162
  }
196
- function sdkCliEnvFilePath(baseUrl) {
163
+ function sdkCliConfigDir(baseUrl) {
197
164
  const home = process.env.HOME?.trim() || (0, import_node_os.homedir)();
198
- return (0, import_node_path.join)(home, ".local", "deepline", baseUrlSlug(baseUrl || PROD_URL), ".env");
165
+ return (0, import_node_path.join)(home, ".local", "deepline", baseUrlSlug(baseUrl || PROD_URL));
166
+ }
167
+ function sdkCliEnvFilePath(baseUrl) {
168
+ return (0, import_node_path.join)(sdkCliConfigDir(baseUrl), ".env");
199
169
  }
200
170
  function loadCliEnv(baseUrl = PROD_URL) {
201
- const envPath = sdkCliEnvFilePath(baseUrl);
202
- return parseEnvFile(envPath);
171
+ return parseEnvFile(sdkCliEnvFilePath(baseUrl));
203
172
  }
204
173
  function loadGlobalCliEnv() {
205
174
  return loadCliEnv(PROD_URL);
206
175
  }
207
176
  function autoDetectBaseUrl() {
208
- const envOrigin = process.env.DEEPLINE_ORIGIN_URL?.trim();
209
- if (envOrigin) return normalizeWorktreeBaseUrl(envOrigin);
210
- const envBase = process.env.DEEPLINE_API_BASE_URL?.trim();
211
- if (envBase) return normalizeWorktreeBaseUrl(envBase);
212
- const projectDeeplineBaseUrl = resolveBaseUrlFromEnvValues(loadProjectDeeplineEnv());
213
- if (projectDeeplineBaseUrl) return normalizeWorktreeBaseUrl(projectDeeplineBaseUrl);
214
- const projectAppBaseUrl = resolveBaseUrlFromEnvValues(loadProjectAppEnv());
215
- if (projectAppBaseUrl) return normalizeWorktreeBaseUrl(projectAppBaseUrl);
216
- const worktreeBaseUrl = resolveWorktreeBaseUrl();
217
- if (worktreeBaseUrl) return worktreeBaseUrl;
177
+ const projectEnv = loadProjectDeeplineEnv();
218
178
  const globalEnv = loadGlobalCliEnv();
219
- const globalOrigin = globalEnv.DEEPLINE_ORIGIN_URL?.trim();
220
- if (globalOrigin) return normalizeWorktreeBaseUrl(globalOrigin);
221
- return PROD_URL;
179
+ return normalizeBaseUrl(process.env[HOST_URL_ENV] ?? "") || normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "") || normalizeBaseUrl(globalEnv[HOST_URL_ENV] ?? "") || PROD_URL;
180
+ }
181
+ function resolveApiKeyForBaseUrl(baseUrl, explicitApiKey) {
182
+ const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
183
+ const projectEnv = loadProjectDeeplineEnv();
184
+ const cliEnv = loadCliEnv(normalizedBaseUrl || baseUrl);
185
+ const projectBaseUrl = normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "");
186
+ const projectKeyApplies = projectBaseUrl === normalizedBaseUrl;
187
+ return firstNonEmpty(
188
+ explicitApiKey,
189
+ process.env[API_KEY_ENV],
190
+ projectKeyApplies ? projectEnv[API_KEY_ENV] : "",
191
+ cliEnv[API_KEY_ENV]
192
+ );
222
193
  }
223
194
  function resolveConfig(options) {
224
- const requestedBaseUrl = options?.baseUrl?.trim() || autoDetectBaseUrl();
225
- const baseUrl = normalizeWorktreeBaseUrl(requestedBaseUrl);
226
- const cliEnv = loadCliEnv(baseUrl);
227
- const projectDeeplineEnv = loadProjectDeeplineEnv();
228
- const projectAppEnv = loadProjectAppEnv();
229
- const apiKey = options?.apiKey?.trim() || process.env.DEEPLINE_API_KEY?.trim() || projectDeeplineEnv.DEEPLINE_API_KEY || projectAppEnv.DEEPLINE_API_KEY || cliEnv.DEEPLINE_API_KEY || "";
195
+ const baseUrl = normalizeBaseUrl(
196
+ options?.baseUrl?.trim() || autoDetectBaseUrl()
197
+ );
198
+ if (!baseUrl) {
199
+ throw new ConfigError(
200
+ `Invalid ${HOST_URL_ENV}. Expected an http(s) URL such as https://code.deepline.com.`
201
+ );
202
+ }
203
+ const apiKey = resolveApiKeyForBaseUrl(baseUrl, options?.apiKey);
230
204
  if (!apiKey) {
231
205
  throw new ConfigError(
232
- `No API key found. Set DEEPLINE_API_KEY env var, pass apiKey option, or run: deepline auth register`
206
+ `No API key found. Set ${API_KEY_ENV}, add it to .env.deepline, or run: deepline auth register`
233
207
  );
234
208
  }
235
209
  return {
@@ -241,8 +215,8 @@ function resolveConfig(options) {
241
215
  }
242
216
 
243
217
  // src/version.ts
244
- var SDK_VERSION = "0.1.32";
245
- var SDK_API_CONTRACT = "2026-05-generic-play-input-flags";
218
+ var SDK_VERSION = "0.1.35";
219
+ var SDK_API_CONTRACT = "2026-05-v2-tool-result-contract";
246
220
 
247
221
  // ../shared_libs/play-runtime/coordinator-headers.ts
248
222
  var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
@@ -324,7 +298,7 @@ var HttpClient = class {
324
298
  const response = await fetch(candidateUrl, {
325
299
  method,
326
300
  headers,
327
- 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,
328
302
  signal: controller.signal
329
303
  });
330
304
  clearTimeout(timeoutId);
@@ -407,10 +381,13 @@ var HttpClient = class {
407
381
  throw new AuthError();
408
382
  }
409
383
  if (!response.ok) {
384
+ const body = await response.text();
385
+ const parsed = parseResponseBody(body);
410
386
  throw new DeeplineError(
411
- `HTTP ${response.status}`,
387
+ apiErrorMessage(parsed, response.status),
412
388
  response.status,
413
- "API_ERROR"
389
+ "API_ERROR",
390
+ { response: parsed }
414
391
  );
415
392
  }
416
393
  if (!response.body) {
@@ -460,6 +437,26 @@ var HttpClient = class {
460
437
  return this.request(path, { method: "DELETE" });
461
438
  }
462
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
+ }
463
460
  function parseRetryAfter(response) {
464
461
  const header = response.headers.get("retry-after");
465
462
  if (header) {
@@ -529,6 +526,8 @@ function sleep(ms) {
529
526
  // src/client.ts
530
527
  var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
531
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";
532
531
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
533
532
  function sleep2(ms) {
534
533
  return new Promise((resolve2) => setTimeout(resolve2, ms));
@@ -797,13 +796,16 @@ var DeeplineClient = class {
797
796
  /**
798
797
  * Execute a tool and return the standard execution envelope.
799
798
  *
800
- * The `result.data` field contains the provider payload. `result.meta`
801
- * contains provider/upstream metadata such as HTTP status or paging details.
799
+ * The `toolExecutionResult.toolOutput.raw` field contains the raw tool output.
800
+ * `toolExecutionResult.toolOutput.meta` contains tool/provider metadata.
802
801
  * Top-level fields such as `status`, `job_id`, and `billing` describe the
803
- * Deepline execution.
802
+ * Deepline execution envelope.
804
803
  */
805
804
  async executeTool(toolId, input, options) {
806
- const headers = options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : void 0;
805
+ const headers = {
806
+ [EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
807
+ ...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
808
+ };
807
809
  return this.http.post(
808
810
  `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
809
811
  { payload: input },
@@ -1101,34 +1103,37 @@ var DeeplineClient = class {
1101
1103
  * ```
1102
1104
  */
1103
1105
  async stagePlayFiles(files) {
1104
- const formData = new FormData();
1105
- formData.set(
1106
- "metadata",
1107
- JSON.stringify({
1108
- files: files.map((file, index) => ({
1109
- index,
1110
- logicalPath: file.logicalPath,
1111
- contentHash: file.contentHash,
1112
- contentType: file.contentType,
1113
- bytes: file.bytes
1114
- }))
1115
- })
1116
- );
1117
- for (const [index, file] of files.entries()) {
1118
- const bytes = decodeBase64Bytes(file.contentBase64);
1119
- const body = bytes.buffer.slice(
1120
- bytes.byteOffset,
1121
- bytes.byteOffset + bytes.byteLength
1122
- );
1106
+ const buildFormData = () => {
1107
+ const formData = new FormData();
1123
1108
  formData.set(
1124
- `file:${index}`,
1125
- new Blob([body], { type: file.contentType }),
1126
- file.logicalPath
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
+ })
1127
1119
  );
1128
- }
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
+ };
1129
1134
  const response = await this.http.postFormData(
1130
1135
  "/api/v2/plays/files/stage",
1131
- formData
1136
+ buildFormData
1132
1137
  );
1133
1138
  return response.files;
1134
1139
  }
@@ -1602,6 +1607,383 @@ var DeeplineClient = class {
1602
1607
  }
1603
1608
  };
1604
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
+
1605
1987
  // src/play.ts
1606
1988
  var DeeplineConditionalStepResolver = class _DeeplineConditionalStepResolver {
1607
1989
  constructor(when2, run, elseValue) {
@@ -1738,10 +2120,10 @@ var DeeplineContext = class {
1738
2120
  *
1739
2121
  * @example
1740
2122
  * ```typescript
1741
- * const tools = await ctx.tools.list();
1742
- * const meta = await ctx.tools.get('apollo_people_search');
1743
- * const companyLookup = await ctx.tools.execute('test_company_search', { domain: 'stripe.com' });
1744
- * const company = companyLookup.result.data;
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;
1745
2127
  * ```
1746
2128
  */
1747
2129
  get tools() {
@@ -1751,11 +2133,14 @@ var DeeplineContext = class {
1751
2133
  /** Get detailed metadata for a tool. */
1752
2134
  get: (toolId) => this.client.getTool(toolId),
1753
2135
  /** Execute a tool and return the standard execution envelope. */
1754
- execute: async (toolId, input) => this.client.executeTool(
1755
- toolId,
1756
- input,
1757
- { includeToolMetadata: true }
1758
- )
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
+ }
1759
2144
  };
1760
2145
  }
1761
2146
  get plays() {
@@ -1850,6 +2235,47 @@ var Deepline = class {
1850
2235
  return new DeeplineContext(options);
1851
2236
  }
1852
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
+ }
1853
2279
  function defineInput(schema) {
1854
2280
  if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
1855
2281
  throw new Error(
@@ -1976,7 +2402,7 @@ function getByDottedPath(root, dottedPath) {
1976
2402
  }
1977
2403
  return current;
1978
2404
  }
1979
- function normalizeRows(value) {
2405
+ function normalizeRows2(value) {
1980
2406
  if (!Array.isArray(value)) return null;
1981
2407
  return value.map((entry) => {
1982
2408
  if (isPlainObject(entry)) return entry;
@@ -1985,6 +2411,25 @@ function normalizeRows(value) {
1985
2411
  }
1986
2412
  function candidateRoots(payload) {
1987
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
+ }
1988
2433
  if (isPlainObject(payload) && isPlainObject(payload.result)) {
1989
2434
  roots.push({ path: "result", value: payload.result });
1990
2435
  if (isPlainObject(payload.result.data)) {
@@ -1995,7 +2440,7 @@ function candidateRoots(payload) {
1995
2440
  }
1996
2441
  function findBestArrayCandidate(value, pathPrefix = "", depth = 0) {
1997
2442
  if (depth > 5) return null;
1998
- const directRows = normalizeRows(value);
2443
+ const directRows = normalizeRows2(value);
1999
2444
  const hasObjectRow = directRows?.some((row) => Object.keys(row).some((key) => key !== "value")) ?? false;
2000
2445
  let best = directRows && directRows.length > 0 && hasObjectRow ? { path: pathPrefix, rows: directRows } : null;
2001
2446
  if (!isPlainObject(value)) {
@@ -2017,7 +2462,7 @@ function tryConvertToList(payload, options) {
2017
2462
  for (const root of candidateRoots(payload)) {
2018
2463
  for (const extractorPath of listExtractorPaths) {
2019
2464
  const resolved = getByDottedPath(root.value, extractorPath);
2020
- const rows = normalizeRows(resolved);
2465
+ const rows = normalizeRows2(resolved);
2021
2466
  if (rows && rows.length > 0) {
2022
2467
  const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
2023
2468
  return { rows, strategy: "configured_paths", sourcePath };