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/README.md +33 -20
- package/dist/cli/index.js +1117 -381
- package/dist/cli/index.mjs +1058 -322
- package/dist/index.d.mts +131 -85
- package/dist/index.d.ts +131 -85
- package/dist/index.js +569 -124
- package/dist/index.mjs +570 -125
- 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/config.ts +109 -233
- 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 +48 -12
- 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/scheduler-backend.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +138 -35
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/config.ts
|
|
2
|
-
import {
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
3
|
import { homedir } from "os";
|
|
4
4
|
import { dirname, join, resolve } from "path";
|
|
5
5
|
|
|
@@ -39,13 +39,12 @@ var ConfigError = class extends DeeplineError {
|
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
// src/config.ts
|
|
42
|
+
var HOST_URL_ENV = "DEEPLINE_HOST_URL";
|
|
43
|
+
var API_KEY_ENV = "DEEPLINE_API_KEY";
|
|
42
44
|
var PROD_URL = "https://code.deepline.com";
|
|
43
45
|
var DEFAULT_TIMEOUT = 6e4;
|
|
44
46
|
var DEFAULT_MAX_RETRIES = 3;
|
|
45
|
-
var
|
|
46
|
-
function projectEnvStartDir() {
|
|
47
|
-
return process.env.DEEPLINE_PROJECT_ENV_DIR?.trim() || process.cwd();
|
|
48
|
-
}
|
|
47
|
+
var PROJECT_DEEPLINE_ENV_FILE = ".env.deepline";
|
|
49
48
|
function baseUrlSlug(baseUrl) {
|
|
50
49
|
let url;
|
|
51
50
|
try {
|
|
@@ -54,7 +53,7 @@ function baseUrlSlug(baseUrl) {
|
|
|
54
53
|
return "unknown";
|
|
55
54
|
}
|
|
56
55
|
const host = url.hostname || "unknown";
|
|
57
|
-
const port = url.port ? parseInt(url.port, 10) : null;
|
|
56
|
+
const port = url.port ? Number.parseInt(url.port, 10) : null;
|
|
58
57
|
let slug = host.replace(/[^a-zA-Z0-9]/g, "-");
|
|
59
58
|
if (port && port !== 80 && port !== 443) {
|
|
60
59
|
slug = `${slug}-${port}`;
|
|
@@ -81,109 +80,84 @@ function parseEnvFile(filePath) {
|
|
|
81
80
|
}
|
|
82
81
|
return env;
|
|
83
82
|
}
|
|
84
|
-
function findNearestEnvFile(
|
|
83
|
+
function findNearestEnvFile(name, startDir = process.cwd()) {
|
|
85
84
|
let current = resolve(startDir);
|
|
86
85
|
while (true) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (existsSync(filePath)) return filePath;
|
|
90
|
-
}
|
|
86
|
+
const filePath = join(current, name);
|
|
87
|
+
if (existsSync(filePath)) return filePath;
|
|
91
88
|
const parent = dirname(current);
|
|
92
89
|
if (parent === current) return null;
|
|
93
90
|
current = parent;
|
|
94
91
|
}
|
|
95
92
|
}
|
|
96
|
-
function
|
|
97
|
-
const filePath = findNearestEnvFile(
|
|
93
|
+
function loadProjectDeeplineEnv(startDir = process.cwd()) {
|
|
94
|
+
const filePath = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
|
|
98
95
|
return filePath ? parseEnvFile(filePath) : {};
|
|
99
96
|
}
|
|
100
|
-
function
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
function resolveProfileEnvFileNames() {
|
|
104
|
-
const explicitProfile = process.env.DEEPLINE_ENV_PROFILE?.trim() || process.env.DEEPLINE_PROFILE?.trim() || "";
|
|
105
|
-
const names = [];
|
|
106
|
-
if (explicitProfile) names.push(`.env.deepline.${explicitProfile}`);
|
|
107
|
-
const nodeEnv = process.env.NODE_ENV?.trim();
|
|
108
|
-
if (nodeEnv === "production") names.push(".env.deepline.prod");
|
|
109
|
-
else if (nodeEnv === "staging") names.push(".env.deepline.staging");
|
|
110
|
-
names.push(ACTIVE_DEEPLINE_ENV_FILE);
|
|
111
|
-
return names;
|
|
112
|
-
}
|
|
113
|
-
function resolveProjectAppEnvFileNames() {
|
|
114
|
-
const nodeEnv = process.env.NODE_ENV?.trim();
|
|
115
|
-
const names = [];
|
|
116
|
-
if (nodeEnv === "production") names.push(".env.prod");
|
|
117
|
-
if (nodeEnv === "staging") names.push(".env.staging");
|
|
118
|
-
names.push(".env.local", ".env");
|
|
119
|
-
return names;
|
|
120
|
-
}
|
|
121
|
-
function resolveBaseUrlFromEnvValues(env) {
|
|
122
|
-
return env.DEEPLINE_ORIGIN_URL?.trim() || env.DEEPLINE_API_BASE_URL?.trim() || "";
|
|
123
|
-
}
|
|
124
|
-
function loadProjectDeeplineEnv() {
|
|
125
|
-
return findNearestEnv(resolveProfileEnvFileNames(), projectEnvStartDir());
|
|
126
|
-
}
|
|
127
|
-
function loadProjectAppEnv() {
|
|
128
|
-
return findNearestEnv(resolveProjectAppEnvFileNames(), projectEnvStartDir());
|
|
129
|
-
}
|
|
130
|
-
function normalizeWorktreeBaseUrl(baseUrl, worktreeEnv = findNearestWorktreeEnv()) {
|
|
131
|
-
const trimmed = baseUrl.trim().replace(/\/$/, "");
|
|
132
|
-
if (!trimmed) return trimmed;
|
|
97
|
+
function normalizeBaseUrl(baseUrl) {
|
|
98
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
99
|
+
if (!trimmed) return "";
|
|
133
100
|
try {
|
|
134
101
|
const parsed = new URL(trimmed);
|
|
135
|
-
if (parsed.
|
|
136
|
-
|
|
137
|
-
if (port) return `${parsed.protocol}//localhost:${port}`;
|
|
102
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
103
|
+
return "";
|
|
138
104
|
}
|
|
105
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
139
106
|
} catch {
|
|
107
|
+
return "";
|
|
140
108
|
}
|
|
141
|
-
return trimmed;
|
|
142
109
|
}
|
|
143
|
-
function
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return
|
|
110
|
+
function firstNonEmpty(...values) {
|
|
111
|
+
for (const value of values) {
|
|
112
|
+
const trimmed = value?.trim();
|
|
113
|
+
if (trimmed) return trimmed;
|
|
114
|
+
}
|
|
115
|
+
return "";
|
|
149
116
|
}
|
|
150
|
-
function
|
|
117
|
+
function sdkCliConfigDir(baseUrl) {
|
|
151
118
|
const home = process.env.HOME?.trim() || homedir();
|
|
152
|
-
return join(home, ".local", "deepline", baseUrlSlug(baseUrl || PROD_URL)
|
|
119
|
+
return join(home, ".local", "deepline", baseUrlSlug(baseUrl || PROD_URL));
|
|
120
|
+
}
|
|
121
|
+
function sdkCliEnvFilePath(baseUrl) {
|
|
122
|
+
return join(sdkCliConfigDir(baseUrl), ".env");
|
|
153
123
|
}
|
|
154
124
|
function loadCliEnv(baseUrl = PROD_URL) {
|
|
155
|
-
|
|
156
|
-
return parseEnvFile(envPath);
|
|
125
|
+
return parseEnvFile(sdkCliEnvFilePath(baseUrl));
|
|
157
126
|
}
|
|
158
127
|
function loadGlobalCliEnv() {
|
|
159
128
|
return loadCliEnv(PROD_URL);
|
|
160
129
|
}
|
|
161
130
|
function autoDetectBaseUrl() {
|
|
162
|
-
const
|
|
163
|
-
if (envOrigin) return normalizeWorktreeBaseUrl(envOrigin);
|
|
164
|
-
const envBase = process.env.DEEPLINE_API_BASE_URL?.trim();
|
|
165
|
-
if (envBase) return normalizeWorktreeBaseUrl(envBase);
|
|
166
|
-
const projectDeeplineBaseUrl = resolveBaseUrlFromEnvValues(loadProjectDeeplineEnv());
|
|
167
|
-
if (projectDeeplineBaseUrl) return normalizeWorktreeBaseUrl(projectDeeplineBaseUrl);
|
|
168
|
-
const projectAppBaseUrl = resolveBaseUrlFromEnvValues(loadProjectAppEnv());
|
|
169
|
-
if (projectAppBaseUrl) return normalizeWorktreeBaseUrl(projectAppBaseUrl);
|
|
170
|
-
const worktreeBaseUrl = resolveWorktreeBaseUrl();
|
|
171
|
-
if (worktreeBaseUrl) return worktreeBaseUrl;
|
|
131
|
+
const projectEnv = loadProjectDeeplineEnv();
|
|
172
132
|
const globalEnv = loadGlobalCliEnv();
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
133
|
+
return normalizeBaseUrl(process.env[HOST_URL_ENV] ?? "") || normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "") || normalizeBaseUrl(globalEnv[HOST_URL_ENV] ?? "") || PROD_URL;
|
|
134
|
+
}
|
|
135
|
+
function resolveApiKeyForBaseUrl(baseUrl, explicitApiKey) {
|
|
136
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
137
|
+
const projectEnv = loadProjectDeeplineEnv();
|
|
138
|
+
const cliEnv = loadCliEnv(normalizedBaseUrl || baseUrl);
|
|
139
|
+
const projectBaseUrl = normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "");
|
|
140
|
+
const projectKeyApplies = projectBaseUrl === normalizedBaseUrl;
|
|
141
|
+
return firstNonEmpty(
|
|
142
|
+
explicitApiKey,
|
|
143
|
+
process.env[API_KEY_ENV],
|
|
144
|
+
projectKeyApplies ? projectEnv[API_KEY_ENV] : "",
|
|
145
|
+
cliEnv[API_KEY_ENV]
|
|
146
|
+
);
|
|
176
147
|
}
|
|
177
148
|
function resolveConfig(options) {
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
149
|
+
const baseUrl = normalizeBaseUrl(
|
|
150
|
+
options?.baseUrl?.trim() || autoDetectBaseUrl()
|
|
151
|
+
);
|
|
152
|
+
if (!baseUrl) {
|
|
153
|
+
throw new ConfigError(
|
|
154
|
+
`Invalid ${HOST_URL_ENV}. Expected an http(s) URL such as https://code.deepline.com.`
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
const apiKey = resolveApiKeyForBaseUrl(baseUrl, options?.apiKey);
|
|
184
158
|
if (!apiKey) {
|
|
185
159
|
throw new ConfigError(
|
|
186
|
-
`No API key found. Set
|
|
160
|
+
`No API key found. Set ${API_KEY_ENV}, add it to .env.deepline, or run: deepline auth register`
|
|
187
161
|
);
|
|
188
162
|
}
|
|
189
163
|
return {
|
|
@@ -195,8 +169,8 @@ function resolveConfig(options) {
|
|
|
195
169
|
}
|
|
196
170
|
|
|
197
171
|
// src/version.ts
|
|
198
|
-
var SDK_VERSION = "0.1.
|
|
199
|
-
var SDK_API_CONTRACT = "2026-05-
|
|
172
|
+
var SDK_VERSION = "0.1.35";
|
|
173
|
+
var SDK_API_CONTRACT = "2026-05-v2-tool-result-contract";
|
|
200
174
|
|
|
201
175
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
202
176
|
var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
|
|
@@ -278,7 +252,7 @@ var HttpClient = class {
|
|
|
278
252
|
const response = await fetch(candidateUrl, {
|
|
279
253
|
method,
|
|
280
254
|
headers,
|
|
281
|
-
body: options?.formData !== void 0 ? options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
255
|
+
body: options?.formData !== void 0 ? typeof options.formData === "function" ? options.formData() : options.formData : options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
282
256
|
signal: controller.signal
|
|
283
257
|
});
|
|
284
258
|
clearTimeout(timeoutId);
|
|
@@ -361,10 +335,13 @@ var HttpClient = class {
|
|
|
361
335
|
throw new AuthError();
|
|
362
336
|
}
|
|
363
337
|
if (!response.ok) {
|
|
338
|
+
const body = await response.text();
|
|
339
|
+
const parsed = parseResponseBody(body);
|
|
364
340
|
throw new DeeplineError(
|
|
365
|
-
|
|
341
|
+
apiErrorMessage(parsed, response.status),
|
|
366
342
|
response.status,
|
|
367
|
-
"API_ERROR"
|
|
343
|
+
"API_ERROR",
|
|
344
|
+
{ response: parsed }
|
|
368
345
|
);
|
|
369
346
|
}
|
|
370
347
|
if (!response.body) {
|
|
@@ -414,6 +391,26 @@ var HttpClient = class {
|
|
|
414
391
|
return this.request(path, { method: "DELETE" });
|
|
415
392
|
}
|
|
416
393
|
};
|
|
394
|
+
function parseResponseBody(body) {
|
|
395
|
+
try {
|
|
396
|
+
return JSON.parse(body);
|
|
397
|
+
} catch {
|
|
398
|
+
return body;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function apiErrorMessage(parsed, status) {
|
|
402
|
+
const errorValue = typeof parsed === "object" && parsed && "error" in parsed ? parsed.error : void 0;
|
|
403
|
+
if (typeof errorValue === "string") {
|
|
404
|
+
return errorValue;
|
|
405
|
+
}
|
|
406
|
+
if (errorValue && typeof errorValue === "object" && "message" in errorValue && typeof errorValue.message === "string") {
|
|
407
|
+
return errorValue.message;
|
|
408
|
+
}
|
|
409
|
+
if (typeof parsed === "object" && parsed && "message" in parsed && typeof parsed.message === "string") {
|
|
410
|
+
return parsed.message;
|
|
411
|
+
}
|
|
412
|
+
return `HTTP ${status}`;
|
|
413
|
+
}
|
|
417
414
|
function parseRetryAfter(response) {
|
|
418
415
|
const header = response.headers.get("retry-after");
|
|
419
416
|
if (header) {
|
|
@@ -483,6 +480,8 @@ function sleep(ms) {
|
|
|
483
480
|
// src/client.ts
|
|
484
481
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
485
482
|
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
483
|
+
var EXECUTE_RESPONSE_CONTRACT_HEADER = "x-deepline-execute-response-contract";
|
|
484
|
+
var V2_EXECUTE_RESPONSE_CONTRACT = "v2-tool-execution-result";
|
|
486
485
|
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
487
486
|
function sleep2(ms) {
|
|
488
487
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
@@ -751,13 +750,16 @@ var DeeplineClient = class {
|
|
|
751
750
|
/**
|
|
752
751
|
* Execute a tool and return the standard execution envelope.
|
|
753
752
|
*
|
|
754
|
-
* The `
|
|
755
|
-
* contains provider
|
|
753
|
+
* The `toolExecutionResult.toolOutput.raw` field contains the raw tool output.
|
|
754
|
+
* `toolExecutionResult.toolOutput.meta` contains tool/provider metadata.
|
|
756
755
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
757
|
-
* Deepline execution.
|
|
756
|
+
* Deepline execution envelope.
|
|
758
757
|
*/
|
|
759
758
|
async executeTool(toolId, input, options) {
|
|
760
|
-
const headers =
|
|
759
|
+
const headers = {
|
|
760
|
+
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
761
|
+
...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
|
|
762
|
+
};
|
|
761
763
|
return this.http.post(
|
|
762
764
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
763
765
|
{ payload: input },
|
|
@@ -1055,34 +1057,37 @@ var DeeplineClient = class {
|
|
|
1055
1057
|
* ```
|
|
1056
1058
|
*/
|
|
1057
1059
|
async stagePlayFiles(files) {
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
"metadata",
|
|
1061
|
-
JSON.stringify({
|
|
1062
|
-
files: files.map((file, index) => ({
|
|
1063
|
-
index,
|
|
1064
|
-
logicalPath: file.logicalPath,
|
|
1065
|
-
contentHash: file.contentHash,
|
|
1066
|
-
contentType: file.contentType,
|
|
1067
|
-
bytes: file.bytes
|
|
1068
|
-
}))
|
|
1069
|
-
})
|
|
1070
|
-
);
|
|
1071
|
-
for (const [index, file] of files.entries()) {
|
|
1072
|
-
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1073
|
-
const body = bytes.buffer.slice(
|
|
1074
|
-
bytes.byteOffset,
|
|
1075
|
-
bytes.byteOffset + bytes.byteLength
|
|
1076
|
-
);
|
|
1060
|
+
const buildFormData = () => {
|
|
1061
|
+
const formData = new FormData();
|
|
1077
1062
|
formData.set(
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1063
|
+
"metadata",
|
|
1064
|
+
JSON.stringify({
|
|
1065
|
+
files: files.map((file, index) => ({
|
|
1066
|
+
index,
|
|
1067
|
+
logicalPath: file.logicalPath,
|
|
1068
|
+
contentHash: file.contentHash,
|
|
1069
|
+
contentType: file.contentType,
|
|
1070
|
+
bytes: file.bytes
|
|
1071
|
+
}))
|
|
1072
|
+
})
|
|
1081
1073
|
);
|
|
1082
|
-
|
|
1074
|
+
for (const [index, file] of files.entries()) {
|
|
1075
|
+
const bytes = decodeBase64Bytes(file.contentBase64);
|
|
1076
|
+
const body = bytes.buffer.slice(
|
|
1077
|
+
bytes.byteOffset,
|
|
1078
|
+
bytes.byteOffset + bytes.byteLength
|
|
1079
|
+
);
|
|
1080
|
+
formData.set(
|
|
1081
|
+
`file:${index}`,
|
|
1082
|
+
new Blob([body], { type: file.contentType }),
|
|
1083
|
+
file.logicalPath
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
return formData;
|
|
1087
|
+
};
|
|
1083
1088
|
const response = await this.http.postFormData(
|
|
1084
1089
|
"/api/v2/plays/files/stage",
|
|
1085
|
-
|
|
1090
|
+
buildFormData
|
|
1086
1091
|
);
|
|
1087
1092
|
return response.files;
|
|
1088
1093
|
}
|
|
@@ -1556,6 +1561,383 @@ var DeeplineClient = class {
|
|
|
1556
1561
|
}
|
|
1557
1562
|
};
|
|
1558
1563
|
|
|
1564
|
+
// ../shared_libs/play-runtime/tool-result.ts
|
|
1565
|
+
var TARGET_FALLBACK_KEYS = {
|
|
1566
|
+
email: [/^email$/i, /^address$/i, /email/i],
|
|
1567
|
+
phone: [/^phone$/i, /mobile/i, /phone/i, /telephone/i],
|
|
1568
|
+
linkedin: [/^linkedin_url$/i, /^linkedin$/i, /linkedin/i],
|
|
1569
|
+
company_linkedin_url: [/company.*linkedin/i, /linkedin.*company/i],
|
|
1570
|
+
company_domain: [/^company_domain$/i, /company.*domain/i],
|
|
1571
|
+
company_name: [/^company_name$/i, /company.*name/i],
|
|
1572
|
+
domain: [/^domain$/i, /company_domain/i, /domain/i],
|
|
1573
|
+
status: [/^email_status$/i, /^status$/i],
|
|
1574
|
+
email_status: [/^email_status$/i, /^status$/i]
|
|
1575
|
+
};
|
|
1576
|
+
function isRecord2(value) {
|
|
1577
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1578
|
+
}
|
|
1579
|
+
function toV2RawToolOutputPath(path) {
|
|
1580
|
+
const normalized = String(path || "").trim().replace(/^\./, "");
|
|
1581
|
+
if (!normalized) return "toolExecutionResult.toolOutput.raw";
|
|
1582
|
+
if (normalized === "toolExecutionResult.toolOutput.raw" || normalized.startsWith("toolExecutionResult.toolOutput.raw.")) {
|
|
1583
|
+
return normalized;
|
|
1584
|
+
}
|
|
1585
|
+
const rawPath = normalized.replace(/^result\.data\.?/, "").replace(/^result\.?/, "").replace(/^data\.?/, "").replace(/^\./, "");
|
|
1586
|
+
return rawPath ? `toolExecutionResult.toolOutput.raw.${rawPath}` : "toolExecutionResult.toolOutput.raw";
|
|
1587
|
+
}
|
|
1588
|
+
function isMeaningfulValue(value) {
|
|
1589
|
+
if (value == null) return false;
|
|
1590
|
+
if (typeof value === "string") return value.trim().length > 0;
|
|
1591
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
1592
|
+
if (typeof value === "object") return Object.keys(value).length > 0;
|
|
1593
|
+
return true;
|
|
1594
|
+
}
|
|
1595
|
+
function parsePath(path) {
|
|
1596
|
+
const segments = [];
|
|
1597
|
+
for (const rawPart of path.split(".").filter(Boolean)) {
|
|
1598
|
+
const bracketPattern = /([^\[\]]+)|\[(\d+|\*)\]/g;
|
|
1599
|
+
let matched = false;
|
|
1600
|
+
for (const match of rawPart.matchAll(bracketPattern)) {
|
|
1601
|
+
matched = true;
|
|
1602
|
+
if (match[1]) {
|
|
1603
|
+
segments.push(match[1]);
|
|
1604
|
+
} else if (match[2] === "*") {
|
|
1605
|
+
segments.push("*");
|
|
1606
|
+
} else if (match[2]) {
|
|
1607
|
+
segments.push(Number(match[2]));
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
if (!matched) {
|
|
1611
|
+
segments.push(rawPart);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
return segments;
|
|
1615
|
+
}
|
|
1616
|
+
function pathToString(segments) {
|
|
1617
|
+
return segments.map(
|
|
1618
|
+
(segment, index) => typeof segment === "number" ? `[${segment}]` : segment === "*" ? "[*]" : index === 0 ? segment : `.${segment}`
|
|
1619
|
+
).join("");
|
|
1620
|
+
}
|
|
1621
|
+
function valuesAtSegments(current, segments, path = []) {
|
|
1622
|
+
if (segments.length === 0) {
|
|
1623
|
+
return [{ value: current, path: pathToString(path) }];
|
|
1624
|
+
}
|
|
1625
|
+
const [segment, ...rest] = segments;
|
|
1626
|
+
if (segment === "*") {
|
|
1627
|
+
if (!Array.isArray(current)) return [];
|
|
1628
|
+
return current.flatMap(
|
|
1629
|
+
(entry, index) => valuesAtSegments(entry, rest, [...path, index])
|
|
1630
|
+
);
|
|
1631
|
+
}
|
|
1632
|
+
if (typeof segment === "number") {
|
|
1633
|
+
if (!Array.isArray(current)) return [];
|
|
1634
|
+
return valuesAtSegments(current[segment], rest, [...path, segment]);
|
|
1635
|
+
}
|
|
1636
|
+
if (!isRecord2(current)) return [];
|
|
1637
|
+
return valuesAtSegments(current[segment], rest, [...path, segment]);
|
|
1638
|
+
}
|
|
1639
|
+
function getValuesAtPath(root, path) {
|
|
1640
|
+
return valuesAtSegments(root, parsePath(path)).map((entry) => entry.value);
|
|
1641
|
+
}
|
|
1642
|
+
function toResultEnvelope(value) {
|
|
1643
|
+
if (isRecord2(value) && "data" in value) {
|
|
1644
|
+
const envelope = { data: value.data };
|
|
1645
|
+
if ("meta" in value) envelope.meta = value.meta;
|
|
1646
|
+
return envelope;
|
|
1647
|
+
}
|
|
1648
|
+
return { data: value };
|
|
1649
|
+
}
|
|
1650
|
+
function normalizeResultPath(path) {
|
|
1651
|
+
const trimmed = String(path || "").trim().replace(/^\./, "");
|
|
1652
|
+
if (!trimmed) return "";
|
|
1653
|
+
return toV2RawToolOutputPath(trimmed);
|
|
1654
|
+
}
|
|
1655
|
+
function toV2RawToolOutputPathPreservingProviderData(path) {
|
|
1656
|
+
const normalized = String(path || "").trim().replace(/^\./, "");
|
|
1657
|
+
if (!normalized) return "toolExecutionResult.toolOutput.raw";
|
|
1658
|
+
if (normalized === "toolExecutionResult.toolOutput.raw" || normalized.startsWith("toolExecutionResult.toolOutput.raw.")) {
|
|
1659
|
+
return normalized;
|
|
1660
|
+
}
|
|
1661
|
+
const rawPath = normalized.replace(/^result\.?/, "").replace(/^\./, "");
|
|
1662
|
+
return rawPath ? `toolExecutionResult.toolOutput.raw.${rawPath}` : "toolExecutionResult.toolOutput.raw";
|
|
1663
|
+
}
|
|
1664
|
+
function candidateResultPaths(path) {
|
|
1665
|
+
const candidates = [
|
|
1666
|
+
normalizeResultPath(path),
|
|
1667
|
+
toV2RawToolOutputPathPreservingProviderData(path)
|
|
1668
|
+
];
|
|
1669
|
+
return candidates.filter(
|
|
1670
|
+
(candidate, index, all) => candidate.length > 0 && all.indexOf(candidate) === index
|
|
1671
|
+
);
|
|
1672
|
+
}
|
|
1673
|
+
function normalizeRelativePath(path) {
|
|
1674
|
+
return String(path || "").trim().replace(/^result\./, "").replace(/^\./, "");
|
|
1675
|
+
}
|
|
1676
|
+
function getFirstMeaningfulValueAtPath(root, path) {
|
|
1677
|
+
for (const entry of valuesAtSegments(root, parsePath(path))) {
|
|
1678
|
+
if (isMeaningfulValue(entry.value)) {
|
|
1679
|
+
return { value: entry.value, path: entry.path };
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
return null;
|
|
1683
|
+
}
|
|
1684
|
+
function getAtPath(root, path) {
|
|
1685
|
+
const segments = parsePath(path);
|
|
1686
|
+
if (segments.includes("*")) {
|
|
1687
|
+
return getValuesAtPath(root, path).filter(isMeaningfulValue);
|
|
1688
|
+
}
|
|
1689
|
+
let current = root;
|
|
1690
|
+
for (const segment of segments) {
|
|
1691
|
+
if (typeof segment === "number") {
|
|
1692
|
+
if (!Array.isArray(current)) return void 0;
|
|
1693
|
+
current = current[segment];
|
|
1694
|
+
continue;
|
|
1695
|
+
}
|
|
1696
|
+
if (!isRecord2(current)) return void 0;
|
|
1697
|
+
current = current[segment];
|
|
1698
|
+
}
|
|
1699
|
+
return current;
|
|
1700
|
+
}
|
|
1701
|
+
function normalizeRows(value) {
|
|
1702
|
+
if (!Array.isArray(value)) return null;
|
|
1703
|
+
return value.map((entry) => isRecord2(entry) ? entry : { value: entry });
|
|
1704
|
+
}
|
|
1705
|
+
function findFirstTargetByPath(result, paths) {
|
|
1706
|
+
for (const path of paths ?? []) {
|
|
1707
|
+
for (const candidate of candidateResultPaths(path)) {
|
|
1708
|
+
const match = getFirstMeaningfulValueAtPath(result, candidate);
|
|
1709
|
+
if (match) return match;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
return null;
|
|
1713
|
+
}
|
|
1714
|
+
function findFirstTargetByKey(result, target, depth = 0, path = []) {
|
|
1715
|
+
if (depth > 6) return null;
|
|
1716
|
+
if (Array.isArray(result)) {
|
|
1717
|
+
for (let index = 0; index < result.length; index += 1) {
|
|
1718
|
+
const found = findFirstTargetByKey(result[index], target, depth + 1, [
|
|
1719
|
+
...path,
|
|
1720
|
+
index
|
|
1721
|
+
]);
|
|
1722
|
+
if (found) return found;
|
|
1723
|
+
}
|
|
1724
|
+
return null;
|
|
1725
|
+
}
|
|
1726
|
+
if (!isRecord2(result)) return null;
|
|
1727
|
+
const patterns = TARGET_FALLBACK_KEYS[target] ?? [
|
|
1728
|
+
new RegExp(`^${target}$`, "i")
|
|
1729
|
+
];
|
|
1730
|
+
for (const [key, value] of Object.entries(result)) {
|
|
1731
|
+
if (patterns.some((pattern) => pattern.test(key)) && isMeaningfulValue(value)) {
|
|
1732
|
+
return { value, path: pathToString([...path, key]) };
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
for (const [key, value] of Object.entries(result)) {
|
|
1736
|
+
const found = findFirstTargetByKey(value, target, depth + 1, [
|
|
1737
|
+
...path,
|
|
1738
|
+
key
|
|
1739
|
+
]);
|
|
1740
|
+
if (found) return found;
|
|
1741
|
+
}
|
|
1742
|
+
return null;
|
|
1743
|
+
}
|
|
1744
|
+
function resolveListRows(result, listExtractorPaths) {
|
|
1745
|
+
const lists = {};
|
|
1746
|
+
for (const rawPath of listExtractorPaths ?? []) {
|
|
1747
|
+
const path = normalizeResultPath(rawPath);
|
|
1748
|
+
if (!path) continue;
|
|
1749
|
+
const candidates = [
|
|
1750
|
+
...candidateResultPaths(rawPath)
|
|
1751
|
+
].filter(
|
|
1752
|
+
(candidate, index, all) => candidate && all.indexOf(candidate) === index
|
|
1753
|
+
);
|
|
1754
|
+
let resolvedPath = null;
|
|
1755
|
+
let rows = null;
|
|
1756
|
+
for (const candidate of candidates) {
|
|
1757
|
+
rows = normalizeRows(getAtPath(result, candidate));
|
|
1758
|
+
if (rows) {
|
|
1759
|
+
resolvedPath = candidate;
|
|
1760
|
+
break;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
if (!rows) continue;
|
|
1764
|
+
const storedPath = resolvedPath ?? path;
|
|
1765
|
+
const name = storedPath.split(".").filter(Boolean).at(-1)?.replace(/\[\d+\]$/, "");
|
|
1766
|
+
lists[name || storedPath] = { path: storedPath, rows };
|
|
1767
|
+
}
|
|
1768
|
+
return lists;
|
|
1769
|
+
}
|
|
1770
|
+
function deriveListKeys(input) {
|
|
1771
|
+
const keys = {};
|
|
1772
|
+
for (const [target, paths] of Object.entries(
|
|
1773
|
+
input.listIdentityGetters ?? {}
|
|
1774
|
+
)) {
|
|
1775
|
+
const firstPath = paths.map(
|
|
1776
|
+
(rawPath) => normalizeRelativePath(rawPath)
|
|
1777
|
+
).find(Boolean);
|
|
1778
|
+
if (firstPath) {
|
|
1779
|
+
keys[target] = firstPath;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
if (Object.keys(keys).length > 0) {
|
|
1783
|
+
return keys;
|
|
1784
|
+
}
|
|
1785
|
+
const listPrefix = input.listPath.replace(/\[\d+\]$/, "");
|
|
1786
|
+
for (const [target, paths] of Object.entries(
|
|
1787
|
+
input.resultIdentityGetters ?? {}
|
|
1788
|
+
)) {
|
|
1789
|
+
for (const rawPath of paths) {
|
|
1790
|
+
const path = String(rawPath || "").trim().replace(/^\./, "");
|
|
1791
|
+
if (!path) continue;
|
|
1792
|
+
for (const resultPath of candidateResultPaths(path)) {
|
|
1793
|
+
const directPrefix = `${listPrefix}.`;
|
|
1794
|
+
if (resultPath.startsWith(directPrefix)) {
|
|
1795
|
+
keys[target] = resultPath.slice(directPrefix.length).replace(/^\[\d+\]\.?/, "");
|
|
1796
|
+
break;
|
|
1797
|
+
}
|
|
1798
|
+
const indexedPrefix = `${listPrefix}[0].`;
|
|
1799
|
+
if (resultPath.startsWith(indexedPrefix)) {
|
|
1800
|
+
keys[target] = resultPath.slice(indexedPrefix.length);
|
|
1801
|
+
break;
|
|
1802
|
+
}
|
|
1803
|
+
const wildcardPrefix = `${listPrefix}[*].`;
|
|
1804
|
+
if (resultPath.startsWith(wildcardPrefix)) {
|
|
1805
|
+
keys[target] = resultPath.slice(wildcardPrefix.length);
|
|
1806
|
+
break;
|
|
1807
|
+
}
|
|
1808
|
+
const dottedIndexPrefix = `${listPrefix}.0.`;
|
|
1809
|
+
if (resultPath.startsWith(dottedIndexPrefix)) {
|
|
1810
|
+
keys[target] = resultPath.slice(dottedIndexPrefix.length);
|
|
1811
|
+
break;
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
if (keys[target]) break;
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
if (Object.keys(keys).length === 0 && input.rows[0]) {
|
|
1818
|
+
for (const key of Object.keys(input.rows[0])) {
|
|
1819
|
+
keys[key] = key;
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
return keys;
|
|
1823
|
+
}
|
|
1824
|
+
function buildTargets(result, resultIdentityGetters) {
|
|
1825
|
+
const targets = {};
|
|
1826
|
+
const metadataTargets = new Set(Object.keys(resultIdentityGetters ?? {}));
|
|
1827
|
+
for (const target of metadataTargets) {
|
|
1828
|
+
const fromMetadata = findFirstTargetByPath(
|
|
1829
|
+
result,
|
|
1830
|
+
resultIdentityGetters?.[target]
|
|
1831
|
+
);
|
|
1832
|
+
if (fromMetadata) {
|
|
1833
|
+
targets[target] = fromMetadata;
|
|
1834
|
+
continue;
|
|
1835
|
+
}
|
|
1836
|
+
const fallback = findFirstTargetByKey(result, target);
|
|
1837
|
+
if (fallback) {
|
|
1838
|
+
targets[target] = fallback;
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
if (metadataTargets.size > 0) return targets;
|
|
1842
|
+
for (const target of ["email", "phone", "linkedin", "domain", "status"]) {
|
|
1843
|
+
const found = findFirstTargetByKey(result, target);
|
|
1844
|
+
if (found) targets[target] = found;
|
|
1845
|
+
}
|
|
1846
|
+
return targets;
|
|
1847
|
+
}
|
|
1848
|
+
function buildLists(result, metadata) {
|
|
1849
|
+
const lists = {};
|
|
1850
|
+
const resolved = resolveListRows(result, metadata.listExtractorPaths);
|
|
1851
|
+
for (const [name, list] of Object.entries(resolved)) {
|
|
1852
|
+
lists[name] = {
|
|
1853
|
+
path: list.path,
|
|
1854
|
+
count: list.rows.length,
|
|
1855
|
+
keys: deriveListKeys({
|
|
1856
|
+
listPath: list.path,
|
|
1857
|
+
rows: list.rows,
|
|
1858
|
+
resultIdentityGetters: metadata.resultIdentityGetters,
|
|
1859
|
+
listIdentityGetters: metadata.listIdentityGetters
|
|
1860
|
+
})
|
|
1861
|
+
};
|
|
1862
|
+
}
|
|
1863
|
+
return lists;
|
|
1864
|
+
}
|
|
1865
|
+
function buildExtractedAccessors(targets) {
|
|
1866
|
+
return Object.fromEntries(
|
|
1867
|
+
Object.entries(targets).map(([target, metadata]) => {
|
|
1868
|
+
const accessor = { path: metadata.path };
|
|
1869
|
+
Object.defineProperties(accessor, {
|
|
1870
|
+
value: {
|
|
1871
|
+
value: metadata.value,
|
|
1872
|
+
enumerable: false
|
|
1873
|
+
},
|
|
1874
|
+
get: {
|
|
1875
|
+
value() {
|
|
1876
|
+
return metadata.value ?? null;
|
|
1877
|
+
},
|
|
1878
|
+
enumerable: false
|
|
1879
|
+
}
|
|
1880
|
+
});
|
|
1881
|
+
return [target, accessor];
|
|
1882
|
+
})
|
|
1883
|
+
);
|
|
1884
|
+
}
|
|
1885
|
+
function buildListAccessors(result, lists) {
|
|
1886
|
+
return Object.fromEntries(
|
|
1887
|
+
Object.entries(lists).map(([name, metadata]) => {
|
|
1888
|
+
const accessor = {
|
|
1889
|
+
path: metadata.path,
|
|
1890
|
+
count: metadata.count,
|
|
1891
|
+
keys: metadata.keys
|
|
1892
|
+
};
|
|
1893
|
+
Object.defineProperty(accessor, "get", {
|
|
1894
|
+
value() {
|
|
1895
|
+
return normalizeRows(getAtPath(result, metadata.path)) ?? [];
|
|
1896
|
+
},
|
|
1897
|
+
enumerable: false
|
|
1898
|
+
});
|
|
1899
|
+
return [name, accessor];
|
|
1900
|
+
})
|
|
1901
|
+
);
|
|
1902
|
+
}
|
|
1903
|
+
function createToolExecuteResult(input) {
|
|
1904
|
+
const result = toResultEnvelope(input.result);
|
|
1905
|
+
const resultRoot = {
|
|
1906
|
+
toolExecutionResult: {
|
|
1907
|
+
toolOutput: {
|
|
1908
|
+
raw: result.data,
|
|
1909
|
+
...result.meta ? { meta: result.meta } : {}
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
};
|
|
1913
|
+
const targets = buildTargets(
|
|
1914
|
+
resultRoot,
|
|
1915
|
+
input.metadata.resultIdentityGetters
|
|
1916
|
+
);
|
|
1917
|
+
const lists = buildLists(resultRoot, input.metadata);
|
|
1918
|
+
const metadata = {
|
|
1919
|
+
toolId: input.metadata.toolId,
|
|
1920
|
+
execution: input.execution,
|
|
1921
|
+
targets,
|
|
1922
|
+
lists
|
|
1923
|
+
};
|
|
1924
|
+
const wrapper = {
|
|
1925
|
+
status: input.status,
|
|
1926
|
+
toolOutput: {
|
|
1927
|
+
raw: result.data,
|
|
1928
|
+
...result.meta ? { meta: result.meta } : {}
|
|
1929
|
+
},
|
|
1930
|
+
meta: input.execution,
|
|
1931
|
+
extractedValues: buildExtractedAccessors(targets),
|
|
1932
|
+
extractedLists: buildListAccessors(resultRoot, lists)
|
|
1933
|
+
};
|
|
1934
|
+
Object.defineProperty(wrapper, "_metadata", {
|
|
1935
|
+
value: metadata,
|
|
1936
|
+
enumerable: false
|
|
1937
|
+
});
|
|
1938
|
+
return wrapper;
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1559
1941
|
// src/play.ts
|
|
1560
1942
|
var DeeplineConditionalStepResolver = class _DeeplineConditionalStepResolver {
|
|
1561
1943
|
constructor(when2, run, elseValue) {
|
|
@@ -1692,10 +2074,10 @@ var DeeplineContext = class {
|
|
|
1692
2074
|
*
|
|
1693
2075
|
* @example
|
|
1694
2076
|
* ```typescript
|
|
1695
|
-
* const tools = await
|
|
1696
|
-
* const meta = await
|
|
1697
|
-
* const companyLookup = await
|
|
1698
|
-
* const company = companyLookup.
|
|
2077
|
+
* const tools = await deepline.tools.list();
|
|
2078
|
+
* const meta = await deepline.tools.get('apollo_people_search');
|
|
2079
|
+
* const companyLookup = await deepline.tools.execute('test_company_search', { domain: 'stripe.com' });
|
|
2080
|
+
* const company = companyLookup.toolOutput.raw;
|
|
1699
2081
|
* ```
|
|
1700
2082
|
*/
|
|
1701
2083
|
get tools() {
|
|
@@ -1705,11 +2087,14 @@ var DeeplineContext = class {
|
|
|
1705
2087
|
/** Get detailed metadata for a tool. */
|
|
1706
2088
|
get: (toolId) => this.client.getTool(toolId),
|
|
1707
2089
|
/** Execute a tool and return the standard execution envelope. */
|
|
1708
|
-
execute: async (toolId, input) =>
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
2090
|
+
execute: async (toolId, input) => {
|
|
2091
|
+
const response = await this.client.executeTool(
|
|
2092
|
+
toolId,
|
|
2093
|
+
input,
|
|
2094
|
+
{ includeToolMetadata: true }
|
|
2095
|
+
);
|
|
2096
|
+
return toolExecutionEnvelopeToResult(toolId, response);
|
|
2097
|
+
}
|
|
1713
2098
|
};
|
|
1714
2099
|
}
|
|
1715
2100
|
get plays() {
|
|
@@ -1804,6 +2189,47 @@ var Deepline = class {
|
|
|
1804
2189
|
return new DeeplineContext(options);
|
|
1805
2190
|
}
|
|
1806
2191
|
};
|
|
2192
|
+
function isRecord3(value) {
|
|
2193
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2194
|
+
}
|
|
2195
|
+
function stringArrayRecord(value) {
|
|
2196
|
+
if (!isRecord3(value)) return {};
|
|
2197
|
+
return Object.fromEntries(
|
|
2198
|
+
Object.entries(value).map(([key, paths]) => [
|
|
2199
|
+
key,
|
|
2200
|
+
Array.isArray(paths) ? paths.map(String) : []
|
|
2201
|
+
])
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
function stringArray(value) {
|
|
2205
|
+
return Array.isArray(value) ? value.map(String) : [];
|
|
2206
|
+
}
|
|
2207
|
+
function toolExecutionEnvelopeToResult(fallbackToolId, response) {
|
|
2208
|
+
const raw = response.toolExecutionResult?.toolOutput?.raw ?? null;
|
|
2209
|
+
const meta = response.toolExecutionResult?.toolOutput?.meta;
|
|
2210
|
+
const metadata = isRecord3(response._metadata) ? response._metadata.tool : null;
|
|
2211
|
+
const toolMetadata = isRecord3(metadata) ? metadata : {};
|
|
2212
|
+
return createToolExecuteResult({
|
|
2213
|
+
status: typeof response.status === "string" ? response.status : "completed",
|
|
2214
|
+
result: {
|
|
2215
|
+
data: raw,
|
|
2216
|
+
...isRecord3(meta) ? { meta } : {}
|
|
2217
|
+
},
|
|
2218
|
+
metadata: {
|
|
2219
|
+
toolId: typeof toolMetadata.toolId === "string" ? toolMetadata.toolId : fallbackToolId,
|
|
2220
|
+
resultIdentityGetters: stringArrayRecord(
|
|
2221
|
+
toolMetadata.resultIdentityGetters
|
|
2222
|
+
),
|
|
2223
|
+
listExtractorPaths: stringArray(toolMetadata.listExtractorPaths),
|
|
2224
|
+
listIdentityGetters: stringArrayRecord(toolMetadata.listIdentityGetters)
|
|
2225
|
+
},
|
|
2226
|
+
execution: {
|
|
2227
|
+
idempotent: true,
|
|
2228
|
+
cached: false,
|
|
2229
|
+
source: "live"
|
|
2230
|
+
}
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
1807
2233
|
function defineInput(schema) {
|
|
1808
2234
|
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
1809
2235
|
throw new Error(
|
|
@@ -1930,7 +2356,7 @@ function getByDottedPath(root, dottedPath) {
|
|
|
1930
2356
|
}
|
|
1931
2357
|
return current;
|
|
1932
2358
|
}
|
|
1933
|
-
function
|
|
2359
|
+
function normalizeRows2(value) {
|
|
1934
2360
|
if (!Array.isArray(value)) return null;
|
|
1935
2361
|
return value.map((entry) => {
|
|
1936
2362
|
if (isPlainObject(entry)) return entry;
|
|
@@ -1939,6 +2365,25 @@ function normalizeRows(value) {
|
|
|
1939
2365
|
}
|
|
1940
2366
|
function candidateRoots(payload) {
|
|
1941
2367
|
const roots = [{ path: null, value: payload }];
|
|
2368
|
+
if (isPlainObject(payload) && isPlainObject(payload.toolExecutionResult)) {
|
|
2369
|
+
roots.push({ path: "toolExecutionResult", value: payload.toolExecutionResult });
|
|
2370
|
+
const toolOutput = payload.toolExecutionResult.toolOutput;
|
|
2371
|
+
if (isPlainObject(toolOutput)) {
|
|
2372
|
+
roots.push({ path: "toolExecutionResult.toolOutput", value: toolOutput });
|
|
2373
|
+
if (Object.prototype.hasOwnProperty.call(toolOutput, "raw")) {
|
|
2374
|
+
roots.push({
|
|
2375
|
+
path: "toolExecutionResult.toolOutput.raw",
|
|
2376
|
+
value: toolOutput.raw
|
|
2377
|
+
});
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
if (isPlainObject(payload) && isPlainObject(payload.output)) {
|
|
2382
|
+
roots.push({ path: "output", value: payload.output });
|
|
2383
|
+
if (Object.prototype.hasOwnProperty.call(payload.output, "body")) {
|
|
2384
|
+
roots.push({ path: "output.body", value: payload.output.body });
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
1942
2387
|
if (isPlainObject(payload) && isPlainObject(payload.result)) {
|
|
1943
2388
|
roots.push({ path: "result", value: payload.result });
|
|
1944
2389
|
if (isPlainObject(payload.result.data)) {
|
|
@@ -1949,7 +2394,7 @@ function candidateRoots(payload) {
|
|
|
1949
2394
|
}
|
|
1950
2395
|
function findBestArrayCandidate(value, pathPrefix = "", depth = 0) {
|
|
1951
2396
|
if (depth > 5) return null;
|
|
1952
|
-
const directRows =
|
|
2397
|
+
const directRows = normalizeRows2(value);
|
|
1953
2398
|
const hasObjectRow = directRows?.some((row) => Object.keys(row).some((key) => key !== "value")) ?? false;
|
|
1954
2399
|
let best = directRows && directRows.length > 0 && hasObjectRow ? { path: pathPrefix, rows: directRows } : null;
|
|
1955
2400
|
if (!isPlainObject(value)) {
|
|
@@ -1971,7 +2416,7 @@ function tryConvertToList(payload, options) {
|
|
|
1971
2416
|
for (const root of candidateRoots(payload)) {
|
|
1972
2417
|
for (const extractorPath of listExtractorPaths) {
|
|
1973
2418
|
const resolved = getByDottedPath(root.value, extractorPath);
|
|
1974
|
-
const rows =
|
|
2419
|
+
const rows = normalizeRows2(resolved);
|
|
1975
2420
|
if (rows && rows.length > 0) {
|
|
1976
2421
|
const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
|
|
1977
2422
|
return { rows, strategy: "configured_paths", sourcePath };
|