deepline 0.1.10 → 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 -305
  7. package/dist/index.d.ts +250 -305
  8. package/dist/index.js +174 -286
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +174 -285
  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 -135
  20. package/dist/repo/sdk/src/plays/bundle-play-file.ts +6 -3
  21. package/dist/repo/sdk/src/tool-output.ts +0 -111
  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.d.ts CHANGED
@@ -603,6 +603,8 @@ interface PlayDescription {
603
603
  aliases: string[];
604
604
  inputSchema?: Record<string, unknown> | null;
605
605
  outputSchema?: Record<string, unknown> | null;
606
+ csvInput?: Record<string, unknown> | null;
607
+ rowOutputSchema?: Record<string, unknown> | null;
606
608
  runCommand: string;
607
609
  examples: string[];
608
610
  currentPublishedVersion?: number | null;
@@ -793,6 +795,16 @@ interface PlayStagedFileRef {
793
795
  bytes: number;
794
796
  }
795
797
 
798
+ type ToolExecution<TData = unknown, TMeta = Record<string, unknown>> = {
799
+ status: string;
800
+ job_id?: string;
801
+ result: {
802
+ data: TData;
803
+ meta?: TMeta;
804
+ };
805
+ billing?: Record<string, unknown>;
806
+ [key: string]: unknown;
807
+ };
796
808
  /**
797
809
  * Low-level client for the Deepline REST API.
798
810
  *
@@ -824,6 +836,7 @@ declare class DeeplineClient {
824
836
  /** The resolved base URL this client is targeting (e.g. `"http://localhost:3000"`). */
825
837
  get baseUrl(): string;
826
838
  private compactSchema;
839
+ private schemaMetadata;
827
840
  private playRunCommand;
828
841
  private summarizePlayListItem;
829
842
  private summarizePlayDetail;
@@ -861,44 +874,14 @@ declare class DeeplineClient {
861
874
  */
862
875
  getTool(toolId: string): Promise<ToolMetadata>;
863
876
  /**
864
- * Execute a tool and return the extracted result.
877
+ * Execute a tool and return the standard execution envelope.
865
878
  *
866
- * Sends the input payload to the tool and returns the `.result` field from the
867
- * response. For the full response envelope (including job_id, credits, etc.),
868
- * use {@link executeToolRaw}.
869
- *
870
- * @param toolId - Tool identifier (e.g. `"test_company_search"`)
871
- * @param input - Tool-specific input parameters
872
- * @returns The tool's output (shape varies by tool)
873
- * @throws {@link DeeplineError} if the tool execution fails
874
- *
875
- * @example
876
- * ```typescript
877
- * const company = await client.executeTool('test_company_search', {
878
- * domain: 'stripe.com',
879
- * });
880
- * console.log(company); // { name: "Stripe", industry: "Financial Services", ... }
881
- * ```
879
+ * The `result.data` field contains the provider payload. `result.meta`
880
+ * contains provider/upstream metadata such as HTTP status or paging details.
881
+ * Top-level fields such as `status`, `job_id`, and `billing` describe the
882
+ * Deepline execution.
882
883
  */
883
- executeTool(toolId: string, input: Record<string, unknown>): Promise<unknown>;
884
- /**
885
- * Execute a tool and return the full response envelope.
886
- *
887
- * Unlike {@link executeTool}, this returns the complete API response including
888
- * `job_id`, `status`, `credits`, and the raw `result` object.
889
- *
890
- * @param toolId - Tool identifier
891
- * @param input - Tool-specific input parameters
892
- * @returns Full response with job metadata and result
893
- *
894
- * @example
895
- * ```typescript
896
- * const raw = await client.executeToolRaw('test_company_search', { domain: 'stripe.com' });
897
- * console.log(`Job: ${raw.job_id}, Credits: ${raw.credits}`);
898
- * console.log(`Result:`, raw.result);
899
- * ```
900
- */
901
- executeToolRaw(toolId: string, input: Record<string, unknown>): Promise<Record<string, unknown>>;
884
+ executeTool<TData = unknown, TMeta = Record<string, unknown>>(toolId: string, input: Record<string, unknown>): Promise<ToolExecution<TData, TMeta>>;
902
885
  queryCustomerDb(input: {
903
886
  sql: string;
904
887
  maxRows?: number;
@@ -1325,7 +1308,7 @@ declare class DeeplineClient {
1325
1308
  }>;
1326
1309
  }
1327
1310
 
1328
- declare const SDK_VERSION = "0.1.10";
1311
+ declare const SDK_VERSION = "0.1.12";
1329
1312
  declare const SDK_API_CONTRACT = "2026-04-plays-v1";
1330
1313
 
1331
1314
  /**
@@ -1468,162 +1451,6 @@ declare const PROD_URL = "https://code.deepline.com";
1468
1451
  */
1469
1452
  declare function resolveConfig(options?: DeeplineClientOptions): ResolvedConfig;
1470
1453
 
1471
- /**
1472
- * Result of converting a tool response to a list of records.
1473
- *
1474
- * @example
1475
- * ```typescript
1476
- * const conversion = tryConvertToList(toolResponse, {
1477
- * listExtractorPaths: ['people', 'result.data'],
1478
- * });
1479
- * if (conversion) {
1480
- * console.log(`Found ${conversion.rows.length} rows via ${conversion.strategy}`);
1481
- * console.log(`Source path: ${conversion.sourcePath}`);
1482
- * }
1483
- * ```
1484
- */
1485
- type ListConversionResult = {
1486
- /** Normalized array of record objects. Scalars are wrapped as `{ value: <scalar> }`. */
1487
- rows: Array<Record<string, unknown>>;
1488
- /**
1489
- * How the list was found:
1490
- * - `'configured_paths'` — matched one of the `listExtractorPaths`
1491
- * - `'auto_detected'` — found via recursive DFS (longest array wins)
1492
- */
1493
- strategy: 'configured_paths' | 'auto_detected';
1494
- /** Dotted path to where the list was found (e.g. `"result.data"`, `"people"`). */
1495
- sourcePath: string | null;
1496
- };
1497
- type Scalar = string | number | boolean | null;
1498
- /** Ergonomic wrapper returned by high-level SDK tool execution. */
1499
- type ToolCallResult = {
1500
- /** Raw tool response. Use this when a provider-specific shape matters. */
1501
- readonly value: unknown;
1502
- /** Best-effort email extraction from common response shapes. */
1503
- getEmail(): string | null;
1504
- /** Best-effort phone extraction from common response shapes. */
1505
- getPhone(): string | null;
1506
- /** Best-effort list extraction. Returns rows only; use `tryConvertToList` for metadata. */
1507
- tryList(options?: {
1508
- listExtractorPaths?: string[];
1509
- }): Array<Record<string, unknown>> | null;
1510
- };
1511
- /** Wrap a raw tool response with the high-level SDK result API. */
1512
- declare function createToolCallResult(value: unknown): ToolCallResult;
1513
- /**
1514
- * Extract a list of records from a tool response.
1515
- *
1516
- * Handles the common problem of tools returning data in varied shapes.
1517
- * First tries configured `listExtractorPaths` (from tool metadata), then
1518
- * falls back to automatic detection via recursive DFS.
1519
- *
1520
- * ## Extraction strategy
1521
- *
1522
- * 1. **Configured paths** — If `listExtractorPaths` is provided, each path is
1523
- * tried against multiple candidate roots (raw payload, `.result`, `.result.data`).
1524
- * First match wins.
1525
- *
1526
- * 2. **Auto-detection** — If no configured path matches, recursively searches
1527
- * the response for the largest array of objects (up to depth 5).
1528
- *
1529
- * @param payload - Raw tool response
1530
- * @param options - Optional extraction configuration
1531
- * @returns Extracted list with metadata, or `null` if no list found
1532
- *
1533
- * @example Using configured paths (from tool metadata)
1534
- * ```typescript
1535
- * const meta = await client.getTool('apollo_people_search');
1536
- * const result = await client.executeTool('apollo_people_search', { query: 'cto' });
1537
- *
1538
- * const list = tryConvertToList(result, {
1539
- * listExtractorPaths: meta.listExtractorPaths,
1540
- * });
1541
- * if (list) {
1542
- * console.log(`${list.rows.length} people found via ${list.strategy}`);
1543
- * // Write to CSV
1544
- * const csv = writeCsvOutputFile(list.rows, 'apollo-people');
1545
- * console.log(`Saved to ${csv.path}`);
1546
- * }
1547
- * ```
1548
- *
1549
- * @example Auto-detection (no configured paths)
1550
- * ```typescript
1551
- * const result = await client.executeTool('some_tool', { query: 'test' });
1552
- * const list = tryConvertToList(result);
1553
- * // Finds the largest array of objects anywhere in the response
1554
- * ```
1555
- */
1556
- declare function tryConvertToList(payload: unknown, options?: {
1557
- listExtractorPaths?: string[];
1558
- }): ListConversionResult | null;
1559
- /**
1560
- * Write a JSON payload to a timestamped file.
1561
- *
1562
- * Output location: `~/.local/share/deepline/data/{stem}_{timestamp}.json`
1563
- *
1564
- * @param payload - Any JSON-serializable value
1565
- * @param stem - Filename prefix (e.g. tool ID or play name)
1566
- * @returns Absolute path to the written file
1567
- *
1568
- * @example
1569
- * ```typescript
1570
- * const result = await client.executeTool('test_company_search', { domain: 'stripe.com' });
1571
- * const path = writeJsonOutputFile(result, 'test_company_search');
1572
- * console.log(`Saved to ${path}`);
1573
- * // ~/.local/share/deepline/data/test_company_search_1713456789000.json
1574
- * ```
1575
- */
1576
- declare function writeJsonOutputFile(payload: unknown, stem: string): string;
1577
- /**
1578
- * Write an array of records to a CSV file.
1579
- *
1580
- * Columns are ordered by first appearance across all rows. Cells containing
1581
- * commas, quotes, or newlines are properly escaped. Objects and arrays are
1582
- * JSON-serialized.
1583
- *
1584
- * Output location: `~/.local/share/deepline/data/{stem}_{timestamp}.csv`
1585
- *
1586
- * @param rows - Array of record objects
1587
- * @param stem - Filename prefix
1588
- * @returns File metadata including path, row count, columns, and a 5×5 preview
1589
- *
1590
- * @example
1591
- * ```typescript
1592
- * const list = tryConvertToList(toolResponse);
1593
- * if (list) {
1594
- * const csv = writeCsvOutputFile(list.rows, 'search-results');
1595
- * console.log(`Wrote ${csv.rowCount} rows, ${csv.columns.length} columns`);
1596
- * console.log(`File: ${csv.path}`);
1597
- * console.log(`Preview:\n${csv.preview}`);
1598
- * }
1599
- * ```
1600
- */
1601
- declare function writeCsvOutputFile(rows: Array<Record<string, unknown>>, stem: string): {
1602
- path: string;
1603
- rowCount: number;
1604
- columns: string[];
1605
- preview: string;
1606
- };
1607
- /**
1608
- * Extract scalar (non-nested) fields from a tool response for summary display.
1609
- *
1610
- * Searches through candidate roots (raw → `.result` → `.result.data`) and
1611
- * returns the first set of scalar fields found. Useful for displaying a
1612
- * quick summary of single-record responses.
1613
- *
1614
- * @param payload - Raw tool response
1615
- * @returns Object containing only scalar fields (string, number, boolean, null)
1616
- *
1617
- * @example
1618
- * ```typescript
1619
- * const result = await client.executeTool('test_company_search', { domain: 'stripe.com' });
1620
- * const summary = extractSummaryFields(result);
1621
- * // { name: "Stripe", industry: "Financial Services", employeeCount: 8000 }
1622
- * // (nested objects and arrays are excluded)
1623
- * ```
1624
- */
1625
- declare function extractSummaryFields(payload: unknown): Record<string, Scalar>;
1626
-
1627
1454
  interface PlayR2FileRef {
1628
1455
  storageKind: 'r2';
1629
1456
  storageKey: string;
@@ -1731,45 +1558,31 @@ type PlayBindings = {
1731
1558
  type LoosePlayObject = {
1732
1559
  [key: string]: LoosePlayObject;
1733
1560
  };
1561
+ type ToolExtractedValue<T = unknown> = {
1562
+ path: string;
1563
+ get(): T | null;
1564
+ };
1565
+ type ToolResultEnvelope<TData = unknown, TMeta = Record<string, unknown>> = {
1566
+ data: TData;
1567
+ meta?: TMeta;
1568
+ };
1569
+ type ToolExecuteResult<TData = unknown, TMeta = Record<string, unknown>> = {
1570
+ status: string;
1571
+ result: ToolResultEnvelope<TData, TMeta>;
1572
+ extracted: Record<string, ToolExtractedValue>;
1573
+ lists: Record<string, {
1574
+ path: string;
1575
+ count: number | null;
1576
+ keys: Record<string, string>;
1577
+ get(): Record<string, unknown>[];
1578
+ }>;
1579
+ };
1734
1580
  type ToolExecutionRequest = {
1735
1581
  id: string;
1736
1582
  tool: string;
1737
1583
  input: Record<string, unknown>;
1738
1584
  description?: string;
1739
1585
  };
1740
- type SdkToolExecutionRequest = {
1741
- tool: string;
1742
- input: Record<string, unknown>;
1743
- };
1744
- type ToolExecuteResult<TResult = unknown> = {
1745
- status: string;
1746
- result: TResult;
1747
- _metadata: {
1748
- toolId: string;
1749
- execution: {
1750
- idempotent: true;
1751
- cached: boolean;
1752
- source: 'live' | 'checkpoint' | 'cache';
1753
- cacheKey?: string;
1754
- };
1755
- targets: Record<string, {
1756
- value: unknown;
1757
- path: string;
1758
- }>;
1759
- lists: Record<string, {
1760
- path: string;
1761
- count: number | null;
1762
- keys: Record<string, string>;
1763
- }>;
1764
- };
1765
- get<T = unknown>(target: string): T | null;
1766
- getEmail(): string | null;
1767
- getPhone(): string | null;
1768
- getLinkedin(): string | null;
1769
- list<T = Record<string, unknown>>(name?: string): T[] | null;
1770
- listPick<const TKeys extends readonly string[]>(keys: TKeys, name?: string): Array<Record<TKeys[number], unknown>> | null;
1771
- listKeys(name?: string): Record<string, string>;
1772
- };
1773
1586
  type StepResolver<Row, Value> = (row: Row, ctx: DeeplinePlayRuntimeContext, index: number) => Value | Promise<Value>;
1774
1587
  type ConditionalStepResolver<Row, Value, Else = null> = {
1775
1588
  readonly kind: 'conditional';
@@ -1797,17 +1610,40 @@ type PlayStepProgramStep = {
1797
1610
  readonly resolver: StepResolver<Record<string, unknown>, unknown> | ConditionalStepResolver<Record<string, unknown>, unknown> | StepProgramResolver<Record<string, unknown>, unknown>;
1798
1611
  };
1799
1612
  type MapStepResolver<Row, Value> = StepResolver<Row, Value> | ConditionalStepResolver<Row, Value> | StepProgramResolver<Row, Value>;
1800
- type MapRowKey<InputRow extends object> = (keyof InputRow & string) | readonly (keyof InputRow & string)[] | ((row: InputRow, index: number) => string | number | readonly unknown[]);
1801
- type MapDefinitionOptions<InputRow extends object> = {
1802
- staleAfterSeconds?: number;
1803
- key?: MapRowKey<InputRow>;
1804
- };
1805
- type MapRunOptions = {
1806
- description?: string;
1807
- };
1808
1613
  type MapStepBuilder<InputRow extends object, OutputRow extends object> = {
1809
1614
  step<Name extends string, Value>(name: Name, resolver: MapStepResolver<OutputRow, Value>): MapStepBuilder<InputRow, OutputRow & Record<Name, Value>>;
1810
- run(options?: MapRunOptions): Promise<PlayDataset<OutputRow>>;
1615
+ run(options?: {
1616
+ description?: string;
1617
+ staleAfterSeconds?: number;
1618
+ concurrency?: number;
1619
+ key?: (keyof InputRow & string) | readonly (keyof InputRow & string)[] | ((row: InputRow, index: number) => string | number | readonly unknown[]);
1620
+ }): Promise<PlayDataset<OutputRow>>;
1621
+ };
1622
+ type CsvRenameMap = Record<string, string | readonly string[]>;
1623
+ /**
1624
+ * Runtime file-like input. At runtime this is the staged file path/reference
1625
+ * string. The type parameter carries static metadata for describe/CLI tooling.
1626
+ */
1627
+ type FileInput<TMetadata = unknown> = string & {
1628
+ readonly __deeplineFileInputMetadata?: TMetadata;
1629
+ };
1630
+ /**
1631
+ * CSV file input whose rows are described by `TRow`.
1632
+ *
1633
+ * The CLI should expose this as the field name from the play input object,
1634
+ * stage local paths passed to that flag, and use `TRow` for row-contract
1635
+ * discovery.
1636
+ */
1637
+ type CsvInput<TRow extends object = Record<string, unknown>> = FileInput<{
1638
+ readonly kind: 'csv';
1639
+ readonly row: TRow;
1640
+ }>;
1641
+ type ColumnMap<TRow extends object> = Partial<Record<Extract<keyof TRow, string>, string | readonly string[]>>;
1642
+ type CsvOptions = {
1643
+ description?: string;
1644
+ columns?: CsvRenameMap;
1645
+ rename?: CsvRenameMap;
1646
+ required?: readonly string[];
1811
1647
  };
1812
1648
  /**
1813
1649
  * Runtime context available inside a play function.
@@ -1819,21 +1655,15 @@ type MapStepBuilder<InputRow extends object, OutputRow extends object> = {
1819
1655
  * ```typescript
1820
1656
  * definePlay('example', async (ctx, input: { domain: string }) => {
1821
1657
  * // Call a tool
1822
- * const company = await ctx.tools.execute({
1823
- * id: 'company_search',
1824
- * tool: 'test_company_search',
1825
- * input: { domain: input.domain },
1658
+ * const company = await ctx.tools.execute('company_search', 'test_company_search', { domain: input.domain }, {
1826
1659
  * description: 'Look up company details by domain.',
1827
1660
  * });
1828
1661
  *
1829
1662
  * // Fan-out: process items with named steps
1830
1663
  * const enriched = await ctx
1831
- * .map('companies', [{ domain: 'a.com' }, { domain: 'b.com' }], { key: 'domain' })
1664
+ * .map('companies', [{ domain: 'a.com' }, { domain: 'b.com' }])
1832
1665
  * .step('company', (row, rowCtx) =>
1833
- * rowCtx.tool({
1834
- * id: 'company_search',
1835
- * tool: 'test_company_search',
1836
- * input: { domain: row.domain },
1666
+ * rowCtx.tool('company_search', 'test_company_search', { domain: row.domain }, {
1837
1667
  * description: 'Look up company details by domain.',
1838
1668
  * }))
1839
1669
  * .run({ description: 'Look up company details.' });
@@ -1868,9 +1698,7 @@ interface DeeplinePlayRuntimeContext {
1868
1698
  *
1869
1699
  * @returns Parsed dataset rows
1870
1700
  */
1871
- csv<T = Record<string, unknown>>(path: string, options?: {
1872
- description?: string;
1873
- }): Promise<PlayDataset<T>>;
1701
+ csv<T = Record<string, unknown>>(path: string, options?: CsvOptions): Promise<PlayDataset<T>>;
1874
1702
  /**
1875
1703
  * Fan-out: process each item through one or more named columns.
1876
1704
  *
@@ -1879,9 +1707,8 @@ interface DeeplinePlayRuntimeContext {
1879
1707
  * play context — call tools, run waterfalls, do arbitrary logic.
1880
1708
  *
1881
1709
  * Items are processed in parallel (paced by the rate-limit scheduler).
1882
- * The first argument identifies the logical map/table namespace. Use
1883
- * `options.key` to pin durable row identity to stable input fields instead of
1884
- * hashing the full input row.
1710
+ * `key` identifies the logical output dataset/table. Row identity is derived
1711
+ * automatically from item content unless advanced run options override it.
1885
1712
  * `options.staleAfterSeconds` intentionally partitions the durable cache on a
1886
1713
  * relative time window. Use `86400` for daily reruns; retries inside the same
1887
1714
  * window still replay safely.
@@ -1891,19 +1718,16 @@ interface DeeplinePlayRuntimeContext {
1891
1718
  * play dataset handle.
1892
1719
  *
1893
1720
  * @typeParam T - Row type
1894
- * @param key - Logical map key used to isolate row identities (e.g. `'main_table'`, `'email_lookup'`)
1721
+ * @param key - Logical output dataset/table name (e.g. `'companies'`, `'email_lookup'`)
1895
1722
  * @param items - Input rows or dataset handle
1896
1723
  * @returns Dataset of rows merged with the computed column values
1897
1724
  *
1898
1725
  * @example Single tool per row
1899
1726
  * ```typescript
1900
1727
  * const results = await ctx
1901
- * .map('leads', leads, { key: 'domain' })
1728
+ * .map('companies', leads)
1902
1729
  * .step('company', (row, ctx) =>
1903
- * ctx.tools.execute({
1904
- * id: 'company_search',
1905
- * tool: 'test_company_search',
1906
- * input: { domain: row.domain },
1730
+ * ctx.tools.execute('company_search', 'test_company_search', { domain: row.domain }, {
1907
1731
  * description: 'Look up company details by domain.',
1908
1732
  * }))
1909
1733
  * .run({ description: 'Look up companies.' });
@@ -1913,12 +1737,9 @@ interface DeeplinePlayRuntimeContext {
1913
1737
  * @example Multiple columns with pre/post logic
1914
1738
  * ```typescript
1915
1739
  * const results = await ctx
1916
- * .map('leads', leads, { key: 'lead_id' })
1740
+ * .map('leads', leads)
1917
1741
  * .step('company', (row, ctx) =>
1918
- * ctx.tools.execute({
1919
- * id: 'company_search',
1920
- * tool: 'test_company_search',
1921
- * input: { domain: row.domain },
1742
+ * ctx.tools.execute('company_search', 'test_company_search', { domain: row.domain }, {
1922
1743
  * description: 'Look up company details by domain.',
1923
1744
  * }))
1924
1745
  * .step('score', (row) =>
@@ -1926,25 +1747,31 @@ interface DeeplinePlayRuntimeContext {
1926
1747
  * .run({ description: 'Enrich leads.' });
1927
1748
  * ```
1928
1749
  */
1929
- map<TItem extends object>(key: string, items: PlayDatasetInput<TItem>, options?: MapDefinitionOptions<TItem>): MapStepBuilder<TItem, TItem>;
1750
+ map<TItem extends object>(key: string, items: PlayDatasetInput<TItem>): MapStepBuilder<TItem, TItem>;
1930
1751
  /** Tool execution namespace. */
1931
1752
  tools: {
1932
1753
  /**
1933
- * Execute a single tool by stable durable execution id and tool ID.
1754
+ * Execute a single tool by stable step key and tool ID.
1934
1755
  *
1935
- * @param request - Tool execution request. `id` is the durable execution id;
1936
- * omit it in row/map steps when the surrounding step id is the execution id.
1756
+ * @param key - Stable step key for idempotent execution
1757
+ * @param toolId - Tool identifier (e.g. `'test_company_search'`)
1758
+ * @param input - Tool-specific input parameters
1937
1759
  * @returns The tool's output
1938
1760
  */
1939
1761
  execute<TOutput = LoosePlayObject>(request: ToolExecutionRequest): Promise<ToolExecuteResult<TOutput>>;
1762
+ execute<TOutput = LoosePlayObject>(key: string, toolId: string, input: Record<string, unknown>, options?: {
1763
+ description?: string;
1764
+ }): Promise<ToolExecuteResult<TOutput>>;
1940
1765
  };
1941
1766
  /**
1942
- * Execute a single tool by stable durable execution id and tool ID.
1767
+ * Execute a single tool by stable step key and tool ID.
1943
1768
  *
1944
- * Shorthand for `ctx.tools.execute({ id, tool, input })`; this is the
1945
- * preferred spelling in row-level step programs.
1769
+ * Shorthand for `ctx.tools.execute(...)`; this is the preferred spelling in
1770
+ * row-level step programs.
1946
1771
  */
1947
- tool<TOutput = LoosePlayObject>(request: ToolExecutionRequest): Promise<ToolExecuteResult<TOutput>>;
1772
+ tool<TOutput = LoosePlayObject>(key: string, toolId: string, input: Record<string, unknown>, options?: {
1773
+ description?: string;
1774
+ }): Promise<ToolExecuteResult<TOutput>>;
1948
1775
  step<T>(id: string, run: () => T | Promise<T>): Promise<T>;
1949
1776
  fetch(key: string, url: string | URL, init?: RequestInit): Promise<{
1950
1777
  ok: boolean;
@@ -2162,13 +1989,9 @@ declare function when<Row, Value>(predicate: (row: Row, index: number) => boolea
2162
1989
  * import { definePlay } from 'deepline';
2163
1990
  *
2164
1991
  * const myPlay = definePlay('my-play', async (ctx, input: { domain: string }) => {
2165
- * const company = await ctx.tools.execute({
2166
- * id: 'company_search',
2167
- * tool: 'test_company_search',
2168
- * input: { domain: input.domain },
1992
+ * return await ctx.tools.execute('company_search', 'test_company_search', { domain: input.domain }, {
2169
1993
  * description: 'Look up company details by domain.',
2170
1994
  * });
2171
- * return { company: company.result };
2172
1995
  * });
2173
1996
  *
2174
1997
  * // Type is: DefinedPlay<{ domain: string }, unknown>
@@ -2206,10 +2029,7 @@ type PlayMetadata = {
2206
2029
  *
2207
2030
  * // Tools
2208
2031
  * const tools = await ctx.tools.list();
2209
- * const result = await ctx.tools.execute({
2210
- * tool: 'test_company_search',
2211
- * input: { domain: 'stripe.com' },
2212
- * });
2032
+ * const result = await ctx.tools.execute('test_company_search', { domain: 'stripe.com' });
2213
2033
  *
2214
2034
  * // Plays
2215
2035
  * const job = await ctx.play('email-waterfall').run({ domain: 'stripe.com' });
@@ -2226,12 +2046,8 @@ declare class DeeplineContext {
2226
2046
  * ```typescript
2227
2047
  * const tools = await ctx.tools.list();
2228
2048
  * const meta = await ctx.tools.get('apollo_people_search');
2229
- * const result = await ctx.tools.execute({
2230
- * tool: 'test_company_search',
2231
- * input: { domain: 'stripe.com' },
2232
- * });
2233
- * const rows = result.tryList({ listExtractorPaths: ['people'] });
2234
- * const email = result.getEmail();
2049
+ * const companyLookup = await ctx.tools.execute('test_company_search', { domain: 'stripe.com' });
2050
+ * const company = companyLookup.result.data;
2235
2051
  * ```
2236
2052
  */
2237
2053
  get tools(): {
@@ -2239,8 +2055,8 @@ declare class DeeplineContext {
2239
2055
  list: () => Promise<ToolDefinition[]>;
2240
2056
  /** Get detailed metadata for a tool. */
2241
2057
  get: (toolId: string) => Promise<ToolMetadata>;
2242
- /** Execute a tool and return an ergonomic result wrapper. */
2243
- execute: (request: SdkToolExecutionRequest) => Promise<ToolCallResult>;
2058
+ /** Execute a tool and return the standard execution envelope. */
2059
+ execute: (toolId: string, input: Record<string, unknown>) => Promise<ToolExecuteResult>;
2244
2060
  };
2245
2061
  get plays(): {
2246
2062
  list: () => Promise<PlayListItem[]>;
@@ -2274,10 +2090,7 @@ declare class DeeplineContext {
2274
2090
  *
2275
2091
  * const ctx = await Deepline.connect();
2276
2092
  * const tools = await ctx.tools.list();
2277
- * const result = await ctx.tools.execute({
2278
- * tool: 'test_company_search',
2279
- * input: { domain: 'stripe.com' },
2280
- * });
2093
+ * const result = await ctx.tools.execute('test_company_search', { domain: 'stripe.com' });
2281
2094
  * ```
2282
2095
  */
2283
2096
  declare class Deepline {
@@ -2329,13 +2142,10 @@ declare function defineInput<TInput>(schema: Record<string, unknown>): PlayInput
2329
2142
  *
2330
2143
  * export default definePlay('company-lookup', async (ctx, input: { domain: string }) => {
2331
2144
  * ctx.log(`Searching for ${input.domain}`);
2332
- * const company = await ctx.tools.execute({
2333
- * id: 'company_search',
2334
- * tool: 'test_company_search',
2335
- * input: { domain: input.domain },
2145
+ * const company = await ctx.tools.execute('company_search', 'test_company_search', { domain: input.domain }, {
2336
2146
  * description: 'Look up company details by domain.',
2337
2147
  * });
2338
- * return { company: company.result };
2148
+ * return company;
2339
2149
  * });
2340
2150
  * ```
2341
2151
  *
@@ -2345,12 +2155,9 @@ declare function defineInput<TInput>(schema: Record<string, unknown>): PlayInput
2345
2155
  * const leads = await ctx.csv('leads.csv');
2346
2156
  * ctx.log(`Processing ${leads.length} rows`);
2347
2157
  * const results = await ctx
2348
- * .map('domain', leads)
2158
+ * .map('companies', leads)
2349
2159
  * .step('company', (row, ctx) =>
2350
- * ctx.tools.execute({
2351
- * id: 'company_search',
2352
- * tool: 'test_company_search',
2353
- * input: { domain: row.domain },
2160
+ * ctx.tools.execute('company_search', 'test_company_search', { domain: row.domain }, {
2354
2161
  * description: 'Look up company details by domain.',
2355
2162
  * }))
2356
2163
  * .run({ description: 'Enrich lead companies.' });
@@ -2361,10 +2168,7 @@ declare function defineInput<TInput>(schema: Record<string, unknown>): PlayInput
2361
2168
  * @example With cron binding
2362
2169
  * ```typescript
2363
2170
  * export default definePlay('daily-report', async (ctx) => {
2364
- * const data = await ctx.tools.execute({
2365
- * id: 'crm_export',
2366
- * tool: 'crm_export',
2367
- * input: { since: 'yesterday' },
2171
+ * const data = await ctx.tools.execute('crm_export', 'crm_export', { since: 'yesterday' }, {
2368
2172
  * description: 'Export yesterday CRM records.',
2369
2173
  * });
2370
2174
  * return data;
@@ -2419,4 +2223,145 @@ declare const defineWorkflow: typeof definePlay;
2419
2223
  */
2420
2224
  declare function getDefinedPlayMetadata(value: unknown): PlayMetadata | null;
2421
2225
 
2422
- export { AuthError, type ClearPlayHistoryRequest, type ClearPlayHistoryResult, type ConditionalStepResolver, ConfigError, Deepline, DeeplineClient, type DeeplineClientOptions, DeeplineContext, DeeplineError, type DeeplineNamedPlay, type DeeplinePlayRuntimeContext, type DefinePlayConfig, type DefinedPlay, type LiveEventEnvelope, type MapDefinitionOptions, type MapRowKey, type MapRunOptions, type MapStepBuilder, type MapStepResolver, PROD_URL, type PlayBindings, type PlayDataset, type PlayDatasetInput, type PlayInputContract, type PlayJob, type PlayListItem, type PlayLiveEvent, type PlayRevisionSummary, type PlayRunResult, type PlayRunStart, type PlayStatus, type PlayStepProgramStep, type PrebuiltPlayRef, type PublishPlayVersionRequest, type PublishPlayVersionResult, RateLimitError, type ResolvedConfig, SDK_API_CONTRACT, SDK_VERSION, type StartPlayRunRequest, type StepProgram, type StepProgramResolver, type StepResolver, type ToolCallResult, type ToolDefinition, type ToolExecuteResult, type ToolMetadata, createToolCallResult, defineInput, definePlay, defineWorkflow, extractSummaryFields, getDefinedPlayMetadata, resolveConfig, steps, tryConvertToList, when, writeCsvOutputFile, writeJsonOutputFile };
2226
+ /**
2227
+ * Result of converting a tool response to a list of records.
2228
+ *
2229
+ * @example
2230
+ * ```typescript
2231
+ * const conversion = tryConvertToList(toolResponse, {
2232
+ * listExtractorPaths: ['people', 'result.data'],
2233
+ * });
2234
+ * if (conversion) {
2235
+ * console.log(`Found ${conversion.rows.length} rows via ${conversion.strategy}`);
2236
+ * console.log(`Source path: ${conversion.sourcePath}`);
2237
+ * }
2238
+ * ```
2239
+ */
2240
+ type ListConversionResult = {
2241
+ /** Normalized array of record objects. Scalars are wrapped as `{ value: <scalar> }`. */
2242
+ rows: Array<Record<string, unknown>>;
2243
+ /**
2244
+ * How the list was found:
2245
+ * - `'configured_paths'` — matched one of the `listExtractorPaths`
2246
+ * - `'auto_detected'` — found via recursive DFS (longest array wins)
2247
+ */
2248
+ strategy: 'configured_paths' | 'auto_detected';
2249
+ /** Dotted path to where the list was found (e.g. `"result.data"`, `"people"`). */
2250
+ sourcePath: string | null;
2251
+ };
2252
+ type Scalar = string | number | boolean | null;
2253
+ /**
2254
+ * Extract a list of records from a tool response.
2255
+ *
2256
+ * Handles the common problem of tools returning data in varied shapes.
2257
+ * First tries configured `listExtractorPaths` (from tool metadata), then
2258
+ * falls back to automatic detection via recursive DFS.
2259
+ *
2260
+ * ## Extraction strategy
2261
+ *
2262
+ * 1. **Configured paths** — If `listExtractorPaths` is provided, each path is
2263
+ * tried against multiple candidate roots (raw payload, `.result`, `.result.data`).
2264
+ * First match wins.
2265
+ *
2266
+ * 2. **Auto-detection** — If no configured path matches, recursively searches
2267
+ * the response for the largest array of objects (up to depth 5).
2268
+ *
2269
+ * @param payload - Raw tool response
2270
+ * @param options - Optional extraction configuration
2271
+ * @returns Extracted list with metadata, or `null` if no list found
2272
+ *
2273
+ * @example Using configured paths (from tool metadata)
2274
+ * ```typescript
2275
+ * const meta = await client.getTool('apollo_people_search');
2276
+ * const result = await client.executeTool('apollo_people_search', { query: 'cto' });
2277
+ *
2278
+ * const list = tryConvertToList(result, {
2279
+ * listExtractorPaths: meta.listExtractorPaths,
2280
+ * });
2281
+ * if (list) {
2282
+ * console.log(`${list.rows.length} people found via ${list.strategy}`);
2283
+ * // Write to CSV
2284
+ * const csv = writeCsvOutputFile(list.rows, 'apollo-people');
2285
+ * console.log(`Saved to ${csv.path}`);
2286
+ * }
2287
+ * ```
2288
+ *
2289
+ * @example Auto-detection (no configured paths)
2290
+ * ```typescript
2291
+ * const result = await client.executeTool('some_tool', { query: 'test' });
2292
+ * const list = tryConvertToList(result);
2293
+ * // Finds the largest array of objects anywhere in the response
2294
+ * ```
2295
+ */
2296
+ declare function tryConvertToList(payload: unknown, options?: {
2297
+ listExtractorPaths?: string[];
2298
+ }): ListConversionResult | null;
2299
+ /**
2300
+ * Write a JSON payload to a timestamped file.
2301
+ *
2302
+ * Output location: `~/.local/share/deepline/data/{stem}_{timestamp}.json`
2303
+ *
2304
+ * @param payload - Any JSON-serializable value
2305
+ * @param stem - Filename prefix (e.g. tool ID or play name)
2306
+ * @returns Absolute path to the written file
2307
+ *
2308
+ * @example
2309
+ * ```typescript
2310
+ * const result = await client.executeTool('test_company_search', { domain: 'stripe.com' });
2311
+ * const path = writeJsonOutputFile(result, 'test_company_search');
2312
+ * console.log(`Saved to ${path}`);
2313
+ * // ~/.local/share/deepline/data/test_company_search_1713456789000.json
2314
+ * ```
2315
+ */
2316
+ declare function writeJsonOutputFile(payload: unknown, stem: string): string;
2317
+ /**
2318
+ * Write an array of records to a CSV file.
2319
+ *
2320
+ * Columns are ordered by first appearance across all rows. Cells containing
2321
+ * commas, quotes, or newlines are properly escaped. Objects and arrays are
2322
+ * JSON-serialized.
2323
+ *
2324
+ * Output location: `~/.local/share/deepline/data/{stem}_{timestamp}.csv`
2325
+ *
2326
+ * @param rows - Array of record objects
2327
+ * @param stem - Filename prefix
2328
+ * @returns File metadata including path, row count, columns, and a 5×5 preview
2329
+ *
2330
+ * @example
2331
+ * ```typescript
2332
+ * const list = tryConvertToList(toolResponse);
2333
+ * if (list) {
2334
+ * const csv = writeCsvOutputFile(list.rows, 'search-results');
2335
+ * console.log(`Wrote ${csv.rowCount} rows, ${csv.columns.length} columns`);
2336
+ * console.log(`File: ${csv.path}`);
2337
+ * console.log(`Preview:\n${csv.preview}`);
2338
+ * }
2339
+ * ```
2340
+ */
2341
+ declare function writeCsvOutputFile(rows: Array<Record<string, unknown>>, stem: string): {
2342
+ path: string;
2343
+ rowCount: number;
2344
+ columns: string[];
2345
+ preview: string;
2346
+ };
2347
+ /**
2348
+ * Extract scalar (non-nested) fields from a tool response for summary display.
2349
+ *
2350
+ * Searches through candidate roots (raw → `.result` → `.result.data`) and
2351
+ * returns the first set of scalar fields found. Useful for displaying a
2352
+ * quick summary of single-record responses.
2353
+ *
2354
+ * @param payload - Raw tool response
2355
+ * @returns Object containing only scalar fields (string, number, boolean, null)
2356
+ *
2357
+ * @example
2358
+ * ```typescript
2359
+ * const result = await client.executeTool('test_company_search', { domain: 'stripe.com' });
2360
+ * const summary = extractSummaryFields(result);
2361
+ * // { name: "Stripe", industry: "Financial Services", employeeCount: 8000 }
2362
+ * // (nested objects and arrays are excluded)
2363
+ * ```
2364
+ */
2365
+ declare function extractSummaryFields(payload: unknown): Record<string, Scalar>;
2366
+
2367
+ export { AuthError, type ClearPlayHistoryRequest, type ClearPlayHistoryResult, type ColumnMap, type ConditionalStepResolver, ConfigError, type CsvInput, Deepline, DeeplineClient, type DeeplineClientOptions, DeeplineContext, DeeplineError, type DeeplineNamedPlay, type DeeplinePlayRuntimeContext, type DefinePlayConfig, type DefinedPlay, type FileInput, type LiveEventEnvelope, type MapStepBuilder, type MapStepResolver, PROD_URL, type PlayBindings, type PlayDataset, type PlayDatasetInput, type PlayInputContract, type PlayJob, type PlayListItem, type PlayLiveEvent, type PlayRevisionSummary, type PlayRunResult, type PlayRunStart, type PlayStatus, type PlayStepProgramStep, type PrebuiltPlayRef, type PublishPlayVersionRequest, type PublishPlayVersionResult, RateLimitError, type ResolvedConfig, SDK_API_CONTRACT, SDK_VERSION, type StartPlayRunRequest, type StepProgram, type StepProgramResolver, type StepResolver, type ToolDefinition, type ToolExecuteResult, type ToolExecution, type ToolMetadata, defineInput, definePlay, defineWorkflow, extractSummaryFields, getDefinedPlayMetadata, resolveConfig, steps, tryConvertToList, when, writeCsvOutputFile, writeJsonOutputFile };