deepline 0.1.11 → 0.1.12

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.
Files changed (34) hide show
  1. package/README.md +4 -4
  2. package/dist/cli/index.js +509 -353
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/index.mjs +513 -358
  5. package/dist/cli/index.mjs.map +1 -1
  6. package/dist/index.d.mts +250 -307
  7. package/dist/index.d.ts +250 -307
  8. package/dist/index.js +174 -315
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +174 -314
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +23 -13
  13. package/dist/repo/apps/play-runner-workers/src/entry.ts +581 -1220
  14. package/dist/repo/sdk/src/cli/commands/play.ts +381 -247
  15. package/dist/repo/sdk/src/cli/commands/tools.ts +1 -1
  16. package/dist/repo/sdk/src/cli/dataset-stats.ts +86 -12
  17. package/dist/repo/sdk/src/client.ts +54 -51
  18. package/dist/repo/sdk/src/index.ts +7 -16
  19. package/dist/repo/sdk/src/play.ts +122 -140
  20. package/dist/repo/sdk/src/plays/bundle-play-file.ts +6 -3
  21. package/dist/repo/sdk/src/tool-output.ts +0 -146
  22. package/dist/repo/sdk/src/types.ts +2 -0
  23. package/dist/repo/sdk/src/version.ts +1 -1
  24. package/dist/repo/sdk/src/worker-play-entry.ts +3 -0
  25. package/dist/repo/shared_libs/play-runtime/context.ts +510 -267
  26. package/dist/repo/shared_libs/play-runtime/csv-rename.ts +180 -0
  27. package/dist/repo/shared_libs/play-runtime/ctx-types.ts +13 -1
  28. package/dist/repo/shared_libs/play-runtime/tool-result.ts +139 -114
  29. package/dist/repo/shared_libs/plays/bundling/index.ts +68 -5
  30. package/dist/repo/shared_libs/plays/compiler-manifest.ts +1 -1
  31. package/dist/repo/shared_libs/plays/dataset.ts +1 -1
  32. package/dist/repo/shared_libs/plays/runtime-validation.ts +8 -28
  33. package/package.json +1 -1
  34. package/dist/repo/apps/play-runner-workers/src/runtime/tool-result.ts +0 -184
package/dist/index.mjs CHANGED
@@ -149,7 +149,7 @@ function resolveConfig(options) {
149
149
  }
150
150
 
151
151
  // src/version.ts
152
- var SDK_VERSION = "0.1.11";
152
+ var SDK_VERSION = "0.1.12";
153
153
  var SDK_API_CONTRACT = "2026-04-plays-v1";
154
154
 
155
155
  // ../shared_libs/play-runtime/coordinator-headers.ts
@@ -424,6 +424,9 @@ function sleep(ms) {
424
424
 
425
425
  // src/client.ts
426
426
  var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
427
+ function isRecord(value) {
428
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
429
+ }
427
430
  function normalizePlayStatus(raw) {
428
431
  const status = typeof raw.status === "string" ? raw.status : typeof raw.temporalStatus === "string" ? mapLegacyTemporalStatus(raw.temporalStatus) : "running";
429
432
  const runId = typeof raw.runId === "string" ? raw.runId : typeof raw.workflowId === "string" ? raw.workflowId : "";
@@ -476,12 +479,27 @@ var DeeplineClient = class {
476
479
  ).filter((field) => Boolean(field?.name)) : [];
477
480
  return fields.length > 0 ? { fields } : schema;
478
481
  }
479
- playRunCommand(name) {
480
- return `deepline plays run ${name} --input '{...}' --watch`;
482
+ schemaMetadata(schema, key) {
483
+ if (!isRecord(schema)) return null;
484
+ const value = schema[key];
485
+ return isRecord(value) ? value : null;
486
+ }
487
+ playRunCommand(play, options) {
488
+ const target = play.reference || play.name;
489
+ if (options?.csvInput) {
490
+ const inputField = typeof options.csvInput.inputField === "string" && options.csvInput.inputField.trim() ? options.csvInput.inputField.trim() : "csv";
491
+ return `deepline plays run ${target} --${inputField} leads.csv --watch`;
492
+ }
493
+ return `deepline plays run ${target} --input '{...}' --watch`;
481
494
  }
482
495
  summarizePlayListItem(play, options) {
483
496
  const aliases = play.aliases?.length ? play.aliases : [play.name];
484
- const runCommand = this.playRunCommand(play.name);
497
+ const csvInput = this.schemaMetadata(play.inputSchema, "csvInput");
498
+ const rowOutputSchema = this.schemaMetadata(
499
+ play.outputSchema,
500
+ "rowOutputSchema"
501
+ );
502
+ const runCommand = this.playRunCommand(play, { csvInput });
485
503
  return {
486
504
  name: play.name,
487
505
  ...play.reference ? { reference: play.reference } : {},
@@ -493,6 +511,8 @@ var DeeplineClient = class {
493
511
  aliases,
494
512
  inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
495
513
  outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
514
+ ...csvInput ? { csvInput } : {},
515
+ ...rowOutputSchema ? { rowOutputSchema } : {},
496
516
  runCommand,
497
517
  examples: [runCommand],
498
518
  currentPublishedVersion: play.currentPublishedVersion ?? null,
@@ -559,50 +579,14 @@ var DeeplineClient = class {
559
579
  );
560
580
  }
561
581
  /**
562
- * Execute a tool and return the extracted result.
563
- *
564
- * Sends the input payload to the tool and returns the `.result` field from the
565
- * response. For the full response envelope (including job_id, credits, etc.),
566
- * use {@link executeToolRaw}.
567
- *
568
- * @param toolId - Tool identifier (e.g. `"test_company_search"`)
569
- * @param input - Tool-specific input parameters
570
- * @returns The tool's output (shape varies by tool)
571
- * @throws {@link DeeplineError} if the tool execution fails
582
+ * Execute a tool and return the standard execution envelope.
572
583
  *
573
- * @example
574
- * ```typescript
575
- * const company = await client.executeTool('test_company_search', {
576
- * domain: 'stripe.com',
577
- * });
578
- * console.log(company); // { name: "Stripe", industry: "Financial Services", ... }
579
- * ```
584
+ * The `result.data` field contains the provider payload. `result.meta`
585
+ * contains provider/upstream metadata such as HTTP status or paging details.
586
+ * Top-level fields such as `status`, `job_id`, and `billing` describe the
587
+ * Deepline execution.
580
588
  */
581
589
  async executeTool(toolId, input) {
582
- const res = await this.http.post(
583
- `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
584
- { payload: input }
585
- );
586
- return res.result ?? res;
587
- }
588
- /**
589
- * Execute a tool and return the full response envelope.
590
- *
591
- * Unlike {@link executeTool}, this returns the complete API response including
592
- * `job_id`, `status`, `credits`, and the raw `result` object.
593
- *
594
- * @param toolId - Tool identifier
595
- * @param input - Tool-specific input parameters
596
- * @returns Full response with job metadata and result
597
- *
598
- * @example
599
- * ```typescript
600
- * const raw = await client.executeToolRaw('test_company_search', { domain: 'stripe.com' });
601
- * console.log(`Job: ${raw.job_id}, Credits: ${raw.credits}`);
602
- * console.log(`Result:`, raw.result);
603
- * ```
604
- */
605
- async executeToolRaw(toolId, input) {
606
590
  return this.http.post(
607
591
  `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
608
592
  { payload: input }
@@ -1224,258 +1208,6 @@ var DeeplineClient = class {
1224
1208
  }
1225
1209
  };
1226
1210
 
1227
- // src/tool-output.ts
1228
- import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
1229
- import { homedir as homedir2 } from "os";
1230
- import { join as join2 } from "path";
1231
- function isPlainObject(value) {
1232
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1233
- }
1234
- var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1235
- var PHONE_KEY_PATTERN = /(^|[_-])(phone|mobile|cell|telephone|tel)([_-]|$)|phone|mobile|telephone/i;
1236
- function normalizeScalarString(value) {
1237
- if (typeof value === "string") {
1238
- const trimmed = value.trim();
1239
- return trimmed.length > 0 ? trimmed : null;
1240
- }
1241
- if (typeof value === "number" && Number.isFinite(value)) {
1242
- return String(value);
1243
- }
1244
- return null;
1245
- }
1246
- function looksLikeEmail(value) {
1247
- const candidate = normalizeScalarString(value);
1248
- if (!candidate || !EMAIL_PATTERN.test(candidate)) return null;
1249
- return candidate;
1250
- }
1251
- function looksLikePhone(value) {
1252
- const candidate = normalizeScalarString(value);
1253
- if (!candidate) return null;
1254
- const digits = candidate.replace(/\D/g, "");
1255
- if (digits.length < 7 || digits.length > 16) return null;
1256
- return candidate;
1257
- }
1258
- function findEmail(value, depth = 0) {
1259
- if (depth > 6) return null;
1260
- const direct = looksLikeEmail(value);
1261
- if (direct) return direct;
1262
- if (Array.isArray(value)) {
1263
- for (const entry of value) {
1264
- const nested = findEmail(entry, depth + 1);
1265
- if (nested) return nested;
1266
- }
1267
- return null;
1268
- }
1269
- if (!isPlainObject(value)) return null;
1270
- for (const [key, child] of Object.entries(value)) {
1271
- if (/email/i.test(key)) {
1272
- const keyed = looksLikeEmail(child);
1273
- if (keyed) return keyed;
1274
- }
1275
- }
1276
- for (const child of Object.values(value)) {
1277
- const nested = findEmail(child, depth + 1);
1278
- if (nested) return nested;
1279
- }
1280
- return null;
1281
- }
1282
- function findPhone(value, depth = 0) {
1283
- if (depth > 6) return null;
1284
- if (Array.isArray(value)) {
1285
- for (const entry of value) {
1286
- const nested = findPhone(entry, depth + 1);
1287
- if (nested) return nested;
1288
- }
1289
- return null;
1290
- }
1291
- if (!isPlainObject(value)) return null;
1292
- for (const [key, child] of Object.entries(value)) {
1293
- if (PHONE_KEY_PATTERN.test(key)) {
1294
- const keyed = looksLikePhone(child);
1295
- if (keyed) return keyed;
1296
- }
1297
- }
1298
- for (const child of Object.values(value)) {
1299
- const nested = findPhone(child, depth + 1);
1300
- if (nested) return nested;
1301
- }
1302
- return null;
1303
- }
1304
- function normalizeListExtractorPaths(paths) {
1305
- if (!Array.isArray(paths)) return [];
1306
- const seen = /* @__PURE__ */ new Set();
1307
- const normalized = [];
1308
- for (const rawPath of paths) {
1309
- if (typeof rawPath !== "string") continue;
1310
- const path = rawPath.trim();
1311
- if (!path) continue;
1312
- for (const candidate of [path, path.replace(/^result\./, "")]) {
1313
- if (!candidate || seen.has(candidate)) continue;
1314
- seen.add(candidate);
1315
- normalized.push(candidate);
1316
- }
1317
- }
1318
- return normalized;
1319
- }
1320
- var DeeplineToolCallResult = class {
1321
- constructor(value, options) {
1322
- this.value = value;
1323
- this.listExtractorPaths = normalizeListExtractorPaths(
1324
- options?.listExtractorPaths
1325
- );
1326
- }
1327
- value;
1328
- listExtractorPaths;
1329
- getEmail() {
1330
- return findEmail(this.value);
1331
- }
1332
- getPhone() {
1333
- return findPhone(this.value);
1334
- }
1335
- tryList(options) {
1336
- const explicitPaths = normalizeListExtractorPaths(options?.listExtractorPaths);
1337
- return tryConvertToList(this.value, {
1338
- listExtractorPaths: explicitPaths.length > 0 ? explicitPaths : this.listExtractorPaths
1339
- })?.rows ?? null;
1340
- }
1341
- };
1342
- function createToolCallResult(value, options) {
1343
- return new DeeplineToolCallResult(value, options);
1344
- }
1345
- function getByDottedPath(root, dottedPath) {
1346
- let current = root;
1347
- for (const segment of String(dottedPath || "").split(".").filter(Boolean)) {
1348
- if (!isPlainObject(current) || !(segment in current)) {
1349
- return null;
1350
- }
1351
- current = current[segment];
1352
- }
1353
- return current;
1354
- }
1355
- function normalizeRows(value) {
1356
- if (!Array.isArray(value)) return null;
1357
- return value.map((entry) => {
1358
- if (isPlainObject(entry)) return entry;
1359
- return { value: entry };
1360
- });
1361
- }
1362
- function candidateRoots(payload) {
1363
- const roots = [{ path: null, value: payload }];
1364
- if (isPlainObject(payload) && isPlainObject(payload.result)) {
1365
- roots.push({ path: "result", value: payload.result });
1366
- if (isPlainObject(payload.result.data)) {
1367
- roots.push({ path: "result.data", value: payload.result.data });
1368
- }
1369
- }
1370
- return roots;
1371
- }
1372
- function findBestArrayCandidate(value, pathPrefix = "", depth = 0) {
1373
- if (depth > 5) return null;
1374
- const directRows = normalizeRows(value);
1375
- const hasObjectRow = directRows?.some((row) => Object.keys(row).some((key) => key !== "value")) ?? false;
1376
- let best = directRows && directRows.length > 0 && hasObjectRow ? { path: pathPrefix, rows: directRows } : null;
1377
- if (!isPlainObject(value)) {
1378
- return best;
1379
- }
1380
- for (const [key, child] of Object.entries(value)) {
1381
- const childPath = pathPrefix ? `${pathPrefix}.${key}` : key;
1382
- const candidate = findBestArrayCandidate(child, childPath, depth + 1);
1383
- if (!candidate) continue;
1384
- if (!best || candidate.rows.length > best.rows.length) {
1385
- best = candidate;
1386
- }
1387
- }
1388
- return best;
1389
- }
1390
- function tryConvertToList(payload, options) {
1391
- const listExtractorPaths = Array.isArray(options?.listExtractorPaths) ? options?.listExtractorPaths.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
1392
- if (listExtractorPaths.length > 0) {
1393
- for (const root of candidateRoots(payload)) {
1394
- for (const extractorPath of listExtractorPaths) {
1395
- const resolved = getByDottedPath(root.value, extractorPath);
1396
- const rows = normalizeRows(resolved);
1397
- if (rows && rows.length > 0) {
1398
- const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
1399
- return { rows, strategy: "configured_paths", sourcePath };
1400
- }
1401
- }
1402
- }
1403
- }
1404
- for (const root of candidateRoots(payload)) {
1405
- const candidate = findBestArrayCandidate(root.value, root.path ?? "");
1406
- if (!candidate || candidate.rows.length === 0) continue;
1407
- return {
1408
- rows: candidate.rows,
1409
- strategy: "auto_detected",
1410
- sourcePath: candidate.path || root.path
1411
- };
1412
- }
1413
- return null;
1414
- }
1415
- function ensureOutputDir() {
1416
- const outputDir = join2(homedir2(), ".local", "share", "deepline", "data");
1417
- mkdirSync2(outputDir, { recursive: true });
1418
- return outputDir;
1419
- }
1420
- function writeJsonOutputFile(payload, stem) {
1421
- const outputDir = ensureOutputDir();
1422
- const outputPath = join2(outputDir, `${stem}_${Date.now()}.json`);
1423
- writeFileSync2(outputPath, JSON.stringify(payload, null, 2), "utf-8");
1424
- return outputPath;
1425
- }
1426
- function writeCsvOutputFile(rows, stem) {
1427
- const outputDir = ensureOutputDir();
1428
- const outputPath = join2(outputDir, `${stem}_${Date.now()}.csv`);
1429
- const seen = /* @__PURE__ */ new Set();
1430
- const columns = [];
1431
- for (const row of rows) {
1432
- for (const key of Object.keys(row)) {
1433
- if (!seen.has(key)) {
1434
- seen.add(key);
1435
- columns.push(key);
1436
- }
1437
- }
1438
- }
1439
- const escapeCell = (value) => {
1440
- const normalized = value == null ? "" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
1441
- if (/[",\n]/.test(normalized)) {
1442
- return `"${normalized.replace(/"/g, '""')}"`;
1443
- }
1444
- return normalized;
1445
- };
1446
- const lines = [];
1447
- lines.push(columns.map(escapeCell).join(","));
1448
- for (const row of rows) {
1449
- lines.push(columns.map((column) => escapeCell(row[column])).join(","));
1450
- }
1451
- writeFileSync2(outputPath, `${lines.join("\n")}
1452
- `, "utf-8");
1453
- const previewRows = rows.slice(0, 5);
1454
- const previewColumns = columns.slice(0, 5);
1455
- const preview = [
1456
- previewColumns.join(","),
1457
- ...previewRows.map((row) => previewColumns.map((column) => escapeCell(row[column])).join(","))
1458
- ].join("\n");
1459
- return {
1460
- path: outputPath,
1461
- rowCount: rows.length,
1462
- columns,
1463
- preview
1464
- };
1465
- }
1466
- function extractSummaryFields(payload) {
1467
- const candidates = candidateRoots(payload);
1468
- for (const candidate of candidates) {
1469
- if (!isPlainObject(candidate.value)) continue;
1470
- const summaryEntries = Object.entries(candidate.value).filter(([, value]) => {
1471
- return value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
1472
- });
1473
- if (summaryEntries.length === 0) continue;
1474
- return Object.fromEntries(summaryEntries);
1475
- }
1476
- return {};
1477
- }
1478
-
1479
1211
  // src/play.ts
1480
1212
  var DeeplineConditionalStepResolver = class _DeeplineConditionalStepResolver {
1481
1213
  constructor(when2, run, elseValue) {
@@ -1614,12 +1346,8 @@ var DeeplineContext = class {
1614
1346
  * ```typescript
1615
1347
  * const tools = await ctx.tools.list();
1616
1348
  * const meta = await ctx.tools.get('apollo_people_search');
1617
- * const result = await ctx.tools.execute({
1618
- * tool: 'test_company_search',
1619
- * input: { domain: 'stripe.com' },
1620
- * });
1621
- * const rows = result.tryList({ listExtractorPaths: ['people'] });
1622
- * const email = result.getEmail();
1349
+ * const companyLookup = await ctx.tools.execute('test_company_search', { domain: 'stripe.com' });
1350
+ * const company = companyLookup.result.data;
1623
1351
  * ```
1624
1352
  */
1625
1353
  get tools() {
@@ -1628,16 +1356,8 @@ var DeeplineContext = class {
1628
1356
  list: () => this.client.listTools(),
1629
1357
  /** Get detailed metadata for a tool. */
1630
1358
  get: (toolId) => this.client.getTool(toolId),
1631
- /** Execute a tool and return an ergonomic result wrapper. */
1632
- execute: async (request) => {
1633
- const [metadata, value] = await Promise.all([
1634
- this.client.getTool(request.tool),
1635
- this.client.executeTool(request.tool, request.input)
1636
- ]);
1637
- return createToolCallResult(value, {
1638
- listExtractorPaths: metadata.listExtractorPaths ?? []
1639
- });
1640
- }
1359
+ /** Execute a tool and return the standard execution envelope. */
1360
+ execute: async (toolId, input) => this.client.executeTool(toolId, input)
1641
1361
  };
1642
1362
  }
1643
1363
  get plays() {
@@ -1840,6 +1560,147 @@ function getDefinedPlayMetadata(value) {
1840
1560
  }
1841
1561
  return candidate;
1842
1562
  }
1563
+
1564
+ // src/tool-output.ts
1565
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
1566
+ import { homedir as homedir2 } from "os";
1567
+ import { join as join2 } from "path";
1568
+ function isPlainObject(value) {
1569
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1570
+ }
1571
+ function getByDottedPath(root, dottedPath) {
1572
+ let current = root;
1573
+ for (const segment of String(dottedPath || "").split(".").filter(Boolean)) {
1574
+ if (!isPlainObject(current) || !(segment in current)) {
1575
+ return null;
1576
+ }
1577
+ current = current[segment];
1578
+ }
1579
+ return current;
1580
+ }
1581
+ function normalizeRows(value) {
1582
+ if (!Array.isArray(value)) return null;
1583
+ return value.map((entry) => {
1584
+ if (isPlainObject(entry)) return entry;
1585
+ return { value: entry };
1586
+ });
1587
+ }
1588
+ function candidateRoots(payload) {
1589
+ const roots = [{ path: null, value: payload }];
1590
+ if (isPlainObject(payload) && isPlainObject(payload.result)) {
1591
+ roots.push({ path: "result", value: payload.result });
1592
+ if (isPlainObject(payload.result.data)) {
1593
+ roots.push({ path: "result.data", value: payload.result.data });
1594
+ }
1595
+ }
1596
+ return roots;
1597
+ }
1598
+ function findBestArrayCandidate(value, pathPrefix = "", depth = 0) {
1599
+ if (depth > 5) return null;
1600
+ const directRows = normalizeRows(value);
1601
+ const hasObjectRow = directRows?.some((row) => Object.keys(row).some((key) => key !== "value")) ?? false;
1602
+ let best = directRows && directRows.length > 0 && hasObjectRow ? { path: pathPrefix, rows: directRows } : null;
1603
+ if (!isPlainObject(value)) {
1604
+ return best;
1605
+ }
1606
+ for (const [key, child] of Object.entries(value)) {
1607
+ const childPath = pathPrefix ? `${pathPrefix}.${key}` : key;
1608
+ const candidate = findBestArrayCandidate(child, childPath, depth + 1);
1609
+ if (!candidate) continue;
1610
+ if (!best || candidate.rows.length > best.rows.length) {
1611
+ best = candidate;
1612
+ }
1613
+ }
1614
+ return best;
1615
+ }
1616
+ function tryConvertToList(payload, options) {
1617
+ const listExtractorPaths = Array.isArray(options?.listExtractorPaths) ? options?.listExtractorPaths.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
1618
+ if (listExtractorPaths.length > 0) {
1619
+ for (const root of candidateRoots(payload)) {
1620
+ for (const extractorPath of listExtractorPaths) {
1621
+ const resolved = getByDottedPath(root.value, extractorPath);
1622
+ const rows = normalizeRows(resolved);
1623
+ if (rows && rows.length > 0) {
1624
+ const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
1625
+ return { rows, strategy: "configured_paths", sourcePath };
1626
+ }
1627
+ }
1628
+ }
1629
+ }
1630
+ for (const root of candidateRoots(payload)) {
1631
+ const candidate = findBestArrayCandidate(root.value, root.path ?? "");
1632
+ if (!candidate || candidate.rows.length === 0) continue;
1633
+ return {
1634
+ rows: candidate.rows,
1635
+ strategy: "auto_detected",
1636
+ sourcePath: candidate.path || root.path
1637
+ };
1638
+ }
1639
+ return null;
1640
+ }
1641
+ function ensureOutputDir() {
1642
+ const outputDir = join2(homedir2(), ".local", "share", "deepline", "data");
1643
+ mkdirSync2(outputDir, { recursive: true });
1644
+ return outputDir;
1645
+ }
1646
+ function writeJsonOutputFile(payload, stem) {
1647
+ const outputDir = ensureOutputDir();
1648
+ const outputPath = join2(outputDir, `${stem}_${Date.now()}.json`);
1649
+ writeFileSync2(outputPath, JSON.stringify(payload, null, 2), "utf-8");
1650
+ return outputPath;
1651
+ }
1652
+ function writeCsvOutputFile(rows, stem) {
1653
+ const outputDir = ensureOutputDir();
1654
+ const outputPath = join2(outputDir, `${stem}_${Date.now()}.csv`);
1655
+ const seen = /* @__PURE__ */ new Set();
1656
+ const columns = [];
1657
+ for (const row of rows) {
1658
+ for (const key of Object.keys(row)) {
1659
+ if (!seen.has(key)) {
1660
+ seen.add(key);
1661
+ columns.push(key);
1662
+ }
1663
+ }
1664
+ }
1665
+ const escapeCell = (value) => {
1666
+ const normalized = value == null ? "" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
1667
+ if (/[",\n]/.test(normalized)) {
1668
+ return `"${normalized.replace(/"/g, '""')}"`;
1669
+ }
1670
+ return normalized;
1671
+ };
1672
+ const lines = [];
1673
+ lines.push(columns.map(escapeCell).join(","));
1674
+ for (const row of rows) {
1675
+ lines.push(columns.map((column) => escapeCell(row[column])).join(","));
1676
+ }
1677
+ writeFileSync2(outputPath, `${lines.join("\n")}
1678
+ `, "utf-8");
1679
+ const previewRows = rows.slice(0, 5);
1680
+ const previewColumns = columns.slice(0, 5);
1681
+ const preview = [
1682
+ previewColumns.join(","),
1683
+ ...previewRows.map((row) => previewColumns.map((column) => escapeCell(row[column])).join(","))
1684
+ ].join("\n");
1685
+ return {
1686
+ path: outputPath,
1687
+ rowCount: rows.length,
1688
+ columns,
1689
+ preview
1690
+ };
1691
+ }
1692
+ function extractSummaryFields(payload) {
1693
+ const candidates = candidateRoots(payload);
1694
+ for (const candidate of candidates) {
1695
+ if (!isPlainObject(candidate.value)) continue;
1696
+ const summaryEntries = Object.entries(candidate.value).filter(([, value]) => {
1697
+ return value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
1698
+ });
1699
+ if (summaryEntries.length === 0) continue;
1700
+ return Object.fromEntries(summaryEntries);
1701
+ }
1702
+ return {};
1703
+ }
1843
1704
  export {
1844
1705
  AuthError,
1845
1706
  ConfigError,
@@ -1851,7 +1712,6 @@ export {
1851
1712
  RateLimitError,
1852
1713
  SDK_API_CONTRACT,
1853
1714
  SDK_VERSION,
1854
- createToolCallResult,
1855
1715
  defineInput,
1856
1716
  definePlay,
1857
1717
  defineWorkflow,