@deepagents/text2sql 0.36.0 → 0.37.1

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 (44) hide show
  1. package/README.md +46 -5
  2. package/dist/index.d.ts +4 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +404 -727
  5. package/dist/index.js.map +4 -4
  6. package/dist/lib/adapter-name.d.ts +4 -0
  7. package/dist/lib/adapter-name.d.ts.map +1 -0
  8. package/dist/lib/adapters/adapter.d.ts.map +1 -1
  9. package/dist/lib/adapters/bigquery/index.js +35 -6
  10. package/dist/lib/adapters/bigquery/index.js.map +2 -2
  11. package/dist/lib/adapters/mysql/index.js +35 -6
  12. package/dist/lib/adapters/mysql/index.js.map +2 -2
  13. package/dist/lib/adapters/postgres/index.js +35 -6
  14. package/dist/lib/adapters/postgres/index.js.map +2 -2
  15. package/dist/lib/adapters/spreadsheet/index.js +35 -6
  16. package/dist/lib/adapters/spreadsheet/index.js.map +2 -2
  17. package/dist/lib/adapters/sqlite/index.js +35 -6
  18. package/dist/lib/adapters/sqlite/index.js.map +2 -2
  19. package/dist/lib/adapters/sqlserver/index.js +35 -6
  20. package/dist/lib/adapters/sqlserver/index.js.map +2 -2
  21. package/dist/lib/agents/exceptions.d.ts +9 -0
  22. package/dist/lib/agents/exceptions.d.ts.map +1 -1
  23. package/dist/lib/agents/sql-command.d.ts +11 -0
  24. package/dist/lib/agents/sql-command.d.ts.map +1 -0
  25. package/dist/lib/agents/sql-transform-plugins.d.ts +4 -1
  26. package/dist/lib/agents/sql-transform-plugins.d.ts.map +1 -1
  27. package/dist/lib/demo.d.ts +2 -0
  28. package/dist/lib/demo.d.ts.map +1 -0
  29. package/dist/lib/fs/index.d.ts +0 -1
  30. package/dist/lib/fs/index.d.ts.map +1 -1
  31. package/dist/lib/instructions.d.ts.map +1 -1
  32. package/dist/lib/sandbox.d.ts +21 -0
  33. package/dist/lib/sandbox.d.ts.map +1 -0
  34. package/dist/lib/sql.d.ts +23 -37
  35. package/dist/lib/sql.d.ts.map +1 -1
  36. package/dist/lib/synthesis/index.js +12 -0
  37. package/dist/lib/synthesis/index.js.map +2 -2
  38. package/package.json +7 -7
  39. package/dist/lib/agents/explainer.agent.d.ts +0 -7
  40. package/dist/lib/agents/explainer.agent.d.ts.map +0 -1
  41. package/dist/lib/agents/result-tools.d.ts +0 -69
  42. package/dist/lib/agents/result-tools.d.ts.map +0 -1
  43. package/dist/lib/fs/tracked-fs.d.ts +0 -42
  44. package/dist/lib/fs/tracked-fs.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1,3 +1,18 @@
1
+ // packages/text2sql/src/lib/adapter-name.ts
2
+ var ADAPTER_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
3
+ function isValidAdapterName(name) {
4
+ return name != null && ADAPTER_NAME_PATTERN.test(name);
5
+ }
6
+ function validateAdapterNames(names) {
7
+ for (const name of names) {
8
+ if (!isValidAdapterName(name)) {
9
+ throw new Error(
10
+ `Invalid adapter name "${name}": must match ${ADAPTER_NAME_PATTERN}`
11
+ );
12
+ }
13
+ }
14
+ }
15
+
1
16
  // packages/text2sql/src/lib/adapters/adapter.ts
2
17
  import { format as formatSql } from "sql-formatter";
3
18
 
@@ -5,6 +20,7 @@ import { format as formatSql } from "sql-formatter";
5
20
  var sqlValidationMarker = Symbol("SQLValidationError");
6
21
  var unanswerableSqlMarker = Symbol("UnanswerableSQLError");
7
22
  var sqlScopeMarker = Symbol("SQLScopeError");
23
+ var sqlReadOnlyMarker = Symbol("SQLReadOnlyError");
8
24
  var SQLValidationError = class _SQLValidationError extends Error {
9
25
  [sqlValidationMarker];
10
26
  constructor(message) {
@@ -42,6 +58,17 @@ var SQLScopeError = class _SQLScopeError extends Error {
42
58
  return error instanceof _SQLScopeError && error[sqlScopeMarker] === true;
43
59
  }
44
60
  };
61
+ var SQLReadOnlyError = class _SQLReadOnlyError extends Error {
62
+ [sqlReadOnlyMarker];
63
+ constructor(message) {
64
+ super(message);
65
+ this.name = "SQLReadOnlyError";
66
+ this[sqlReadOnlyMarker] = true;
67
+ }
68
+ static isInstance(error) {
69
+ return error instanceof _SQLReadOnlyError && error[sqlReadOnlyMarker] === true;
70
+ }
71
+ };
45
72
 
46
73
  // packages/text2sql/src/lib/fragments/schema.ts
47
74
  function dialectInfo(input) {
@@ -468,12 +495,23 @@ var Adapter = class {
468
495
  });
469
496
  }
470
497
  format(sql) {
498
+ const decoded = this.#decodeShellEscapes(sql);
471
499
  try {
472
- return formatSql(sql, { language: this.formatterLanguage });
500
+ return formatSql(decoded, { language: this.formatterLanguage });
473
501
  } catch {
474
- return sql;
502
+ return decoded;
475
503
  }
476
504
  }
505
+ #decodeShellEscapes(sql) {
506
+ return sql.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\([().*])/g, "$1").replace(/\\(?=$)/gm, "");
507
+ }
508
+ #checkReadOnly(sql) {
509
+ const upper = sql.trimStart().toUpperCase();
510
+ if (!upper.startsWith("SELECT") && !upper.startsWith("WITH")) {
511
+ return "only SELECT or WITH queries allowed";
512
+ }
513
+ return null;
514
+ }
477
515
  #cachedAllowedEntities = null;
478
516
  async #resolveScope() {
479
517
  if (this.#cachedAllowedEntities) return this.#cachedAllowedEntities;
@@ -535,16 +573,22 @@ var Adapter = class {
535
573
  return buildOutOfScopePayload(sql, outOfScope, allowedEntities);
536
574
  }
537
575
  async validate(sql) {
576
+ const decoded = this.#decodeShellEscapes(sql);
577
+ const readOnlyError = this.#checkReadOnly(decoded);
578
+ if (readOnlyError) return readOnlyError;
538
579
  const allowed = await this.#resolveScope();
539
- const scopeError = await this.#checkScope(sql, allowed);
580
+ const scopeError = await this.#checkScope(decoded, allowed);
540
581
  if (scopeError) return JSON.stringify(scopeError);
541
- return this.validateImpl(sql);
582
+ return this.validateImpl(decoded);
542
583
  }
543
584
  async execute(sql) {
585
+ const decoded = this.#decodeShellEscapes(sql);
586
+ const readOnlyError = this.#checkReadOnly(decoded);
587
+ if (readOnlyError) throw new SQLReadOnlyError(readOnlyError);
544
588
  const allowed = await this.#resolveScope();
545
- const scopeError = await this.#checkScope(sql, allowed);
589
+ const scopeError = await this.#checkScope(decoded, allowed);
546
590
  if (scopeError) throw new SQLScopeError(scopeError);
547
- return this.executeImpl(sql);
591
+ return this.executeImpl(decoded);
548
592
  }
549
593
  /**
550
594
  * Convert unknown database value to number.
@@ -666,62 +710,148 @@ function getTablesWithRelated(allTables, relationships, filter) {
666
710
  return Array.from(result);
667
711
  }
668
712
 
669
- // packages/text2sql/src/lib/agents/result-tools.ts
670
- import { tool } from "ai";
671
- import { createBashTool } from "bash-tool";
672
- import chalk from "chalk";
673
- import {
674
- Bash,
675
- MountableFs,
676
- OverlayFs,
677
- defineCommand,
678
- parse as parse2
679
- } from "just-bash";
680
- import { AsyncLocalStorage } from "node:async_hooks";
681
- import * as path2 from "node:path";
713
+ // packages/text2sql/src/lib/agents/sql-command.ts
682
714
  import { v7 } from "uuid";
683
- import z from "zod";
684
-
685
- // packages/text2sql/src/lib/agents/sql-transform-plugins.ts
686
- import { parse, serialize } from "just-bash";
687
- import { createHash } from "node:crypto";
688
- import * as path from "node:path";
689
- function asStaticWordText(word) {
690
- if (!word) {
691
- return null;
715
+ import {
716
+ buildSubcommandRepair,
717
+ defineSubcommandGroup,
718
+ repairQuotedArg,
719
+ useBashMeta
720
+ } from "@deepagents/context";
721
+ var SQL_VALIDATE_REMINDER = 'Always run `sql validate <db> "..."` before `sql run <db> "..."` to catch syntax errors early.';
722
+ function repairDbNameAndQuotedArg(rawArgs) {
723
+ const trimmed = rawArgs.trim();
724
+ if (!trimmed) return null;
725
+ const firstSpace = trimmed.search(/\s/);
726
+ if (firstSpace === -1) return null;
727
+ const dbName = trimmed.slice(0, firstSpace);
728
+ const rest = trimmed.slice(firstSpace + 1);
729
+ const repaired = repairQuotedArg(rest);
730
+ if (repaired == null) return null;
731
+ return `${dbName} ${repaired}`;
732
+ }
733
+ function resolveAdapter(adapters, subcommand, args) {
734
+ const [name, ...rest] = args;
735
+ const available = Object.keys(adapters).join(", ");
736
+ if (!name) {
737
+ return {
738
+ error: `sql ${subcommand}: missing database name. Usage: sql ${subcommand} <db> "SELECT ...". Available: ${available}`
739
+ };
692
740
  }
693
- return asStaticWordPartText(
694
- word.parts
695
- );
741
+ const adapter = adapters[name];
742
+ if (!adapter) {
743
+ return {
744
+ error: `sql ${subcommand}: unknown database "${name}". Available: ${available}`
745
+ };
746
+ }
747
+ const sql = rest.join(" ").trim();
748
+ if (!sql) {
749
+ return { error: `sql ${subcommand}: no query provided` };
750
+ }
751
+ return { adapter, sql };
696
752
  }
697
- function asStaticWordPartText(parts) {
698
- let text = "";
699
- for (const part of parts) {
700
- const type = part.type;
701
- if (type === "Literal" || type === "SingleQuoted" || type === "Escaped") {
702
- if (typeof part.value !== "string") {
703
- return null;
704
- }
705
- text += part.value;
706
- continue;
707
- }
708
- if (type === "DoubleQuoted") {
709
- if (!Array.isArray(part.parts)) {
710
- return null;
753
+ function createSqlCommand(adapters, { outputDir = "/sql" } = {}) {
754
+ const subcommands = {
755
+ run: {
756
+ usage: 'run <db> "SELECT ..."',
757
+ description: "Execute query against <db> and store results",
758
+ repair: repairDbNameAndQuotedArg,
759
+ handler: async (args, ctx) => {
760
+ const meta = useBashMeta();
761
+ meta?.setReminder(SQL_VALIDATE_REMINDER);
762
+ const resolved = resolveAdapter(adapters, "run", args);
763
+ if ("error" in resolved) {
764
+ return { stdout: "", stderr: resolved.error, exitCode: 1 };
765
+ }
766
+ const { adapter, sql: rawQuery } = resolved;
767
+ const query = adapter.format(rawQuery);
768
+ meta?.setHidden({ formattedSql: query });
769
+ const syntaxError = await adapter.validate(query);
770
+ if (syntaxError) {
771
+ return {
772
+ stdout: "",
773
+ stderr: `sql run: ${syntaxError}`,
774
+ exitCode: 1
775
+ };
776
+ }
777
+ try {
778
+ const rows = await adapter.execute(query);
779
+ if (!Array.isArray(rows)) {
780
+ throw new Error("adapter.execute must return an array of rows");
781
+ }
782
+ const rowsArray = rows;
783
+ const content = JSON.stringify(rowsArray, null, 2);
784
+ const filename = `${v7()}.json`;
785
+ const sqlPath = `${outputDir}/${filename}`;
786
+ const mkdir = await ctx.sandbox.executeCommand(
787
+ `mkdir -p ${outputDir}`
788
+ );
789
+ if (mkdir.exitCode !== 0) {
790
+ return {
791
+ stdout: "",
792
+ stderr: `sql run: failed to create ${outputDir}: ${mkdir.stderr}`,
793
+ exitCode: 1
794
+ };
795
+ }
796
+ await ctx.sandbox.writeFiles([{ path: sqlPath, content }]);
797
+ const columns = rowsArray.length > 0 ? Object.keys(rowsArray[0]) : [];
798
+ return {
799
+ stdout: [
800
+ `results stored in ${sqlPath}`,
801
+ `columns: ${columns.join(", ") || "(none)"}`,
802
+ `rows: ${rowsArray.length}`
803
+ ].join("\n") + "\n",
804
+ stderr: "",
805
+ exitCode: 0
806
+ };
807
+ } catch (error) {
808
+ return {
809
+ stdout: "",
810
+ stderr: `sql run: ${error instanceof Error ? error.message : String(error)}`,
811
+ exitCode: 1
812
+ };
813
+ }
711
814
  }
712
- const inner = asStaticWordPartText(
713
- part.parts
714
- );
715
- if (inner == null) {
716
- return null;
815
+ },
816
+ validate: {
817
+ usage: 'validate <db> "SELECT ..."',
818
+ description: "Validate query syntax against <db>",
819
+ repair: repairDbNameAndQuotedArg,
820
+ handler: async (args) => {
821
+ const meta = useBashMeta();
822
+ const resolved = resolveAdapter(adapters, "validate", args);
823
+ if ("error" in resolved) {
824
+ return { stdout: "", stderr: resolved.error, exitCode: 1 };
825
+ }
826
+ const { adapter, sql: rawQuery } = resolved;
827
+ const query = adapter.format(rawQuery);
828
+ meta?.setHidden({ formattedSql: query });
829
+ const syntaxError = await adapter.validate(query);
830
+ if (syntaxError) {
831
+ return {
832
+ stdout: "",
833
+ stderr: `sql validate: ${syntaxError}`,
834
+ exitCode: 1
835
+ };
836
+ }
837
+ return {
838
+ stdout: "valid\n",
839
+ stderr: "",
840
+ exitCode: 0
841
+ };
717
842
  }
718
- text += inner;
719
- continue;
720
843
  }
721
- return null;
722
- }
723
- return text;
844
+ };
845
+ const command = defineSubcommandGroup("sql", subcommands);
846
+ const repair = buildSubcommandRepair("sql", subcommands);
847
+ return { command, repair };
724
848
  }
849
+
850
+ // packages/text2sql/src/lib/agents/sql-transform-plugins.ts
851
+ import { parse, serialize } from "just-bash";
852
+ import { createHash } from "node:crypto";
853
+ import * as path from "node:path";
854
+ import { BashException, asStaticWordText } from "@deepagents/context";
725
855
  function isScriptNode(value) {
726
856
  if (typeof value !== "object" || value === null) {
727
857
  return false;
@@ -748,14 +878,18 @@ var WRAPPER_COMMANDS = /* @__PURE__ */ new Set(["env", "command", "eval"]);
748
878
  var SQL_PROXY_ENFORCEMENT_MESSAGE = [
749
879
  "Direct database querying through bash is blocked.",
750
880
  "Use SQL proxy commands in this order:",
751
- '1) sql validate "SELECT ..."',
752
- '2) sql run "SELECT ..."'
881
+ '1) sql validate <db> "SELECT ..."',
882
+ '2) sql run <db> "SELECT ..."'
753
883
  ].join("\n");
754
- var SqlProxyViolationError = class extends Error {
884
+ var SqlProxyViolationError = class extends BashException {
755
885
  constructor() {
756
886
  super(SQL_PROXY_ENFORCEMENT_MESSAGE);
757
887
  this.name = "SqlProxyViolationError";
758
888
  }
889
+ format() {
890
+ return { stdout: "", stderr: `${this.message}
891
+ `, exitCode: 1 };
892
+ }
759
893
  };
760
894
  function cloneInspectionContext(context) {
761
895
  return {
@@ -1362,10 +1496,12 @@ function isSqlBacktickCommand(cmd) {
1362
1496
  if (cmd.type !== "SimpleCommand") return false;
1363
1497
  if (cmd.assignments.length > 0 || cmd.redirections.length > 0) return false;
1364
1498
  if (asStaticWordText(cmd.name) !== "sql") return false;
1365
- if (cmd.args.length < 2) return false;
1499
+ if (cmd.args.length < 3) return false;
1366
1500
  const subcommand = asStaticWordText(cmd.args[0]);
1367
1501
  if (subcommand !== "validate" && subcommand !== "run") return false;
1368
- const sqlArgs = cmd.args.slice(1);
1502
+ const dbName = asStaticWordText(cmd.args[1]);
1503
+ if (!isValidAdapterName(dbName)) return false;
1504
+ const sqlArgs = cmd.args.slice(2);
1369
1505
  return sqlArgs.some(
1370
1506
  (arg) => wordPartsContainBacktickSubstitution(
1371
1507
  arg.parts
@@ -1395,7 +1531,8 @@ function extractSqlText(args) {
1395
1531
  }
1396
1532
  function rewriteSqlBacktickCommand(cmd, ast) {
1397
1533
  const subcommand = asStaticWordText(cmd.args[0]);
1398
- const sqlArgs = cmd.args.slice(1);
1534
+ const dbName = asStaticWordText(cmd.args[1]);
1535
+ const sqlArgs = cmd.args.slice(2);
1399
1536
  const unquotedSql = extractSqlText(sqlArgs);
1400
1537
  const hash2 = createHash("sha256").update(serialize(ast)).digest("hex").slice(0, 12);
1401
1538
  const sqlPath = `/tmp/sql-inline-${subcommand}-${hash2}.sql`;
@@ -1404,7 +1541,7 @@ function rewriteSqlBacktickCommand(cmd, ast) {
1404
1541
  `{ cat > ${sqlPath} <<'${heredocTag}'`,
1405
1542
  unquotedSql,
1406
1543
  heredocTag,
1407
- `sql ${subcommand} "$(cat ${sqlPath})"; }`
1544
+ `sql ${subcommand} ${dbName} "$(cat ${sqlPath})"; }`
1408
1545
  ].join("\n");
1409
1546
  const groupAst = parse(groupScript);
1410
1547
  return groupAst.statements[0].pipelines[0].commands[0];
@@ -1462,296 +1599,6 @@ var SqlBacktickRewritePlugin = class {
1462
1599
  }
1463
1600
  };
1464
1601
 
1465
- // packages/text2sql/src/lib/agents/result-tools.ts
1466
- function createCommand(name, subcommands) {
1467
- const usageLines = Object.entries(subcommands).map(([, def]) => ` ${name} ${def.usage.padEnd(30)} ${def.description}`).join("\n");
1468
- return defineCommand(name, async (args, ctx) => {
1469
- const subcommand = args[0];
1470
- const restArgs = args.slice(1);
1471
- if (subcommand && subcommand in subcommands) {
1472
- return subcommands[subcommand].handler(restArgs, ctx);
1473
- }
1474
- return {
1475
- stdout: "",
1476
- stderr: `${name}: ${subcommand ? `unknown subcommand '${subcommand}'` : "missing subcommand"}
1477
-
1478
- Usage:
1479
- ${usageLines}`,
1480
- exitCode: 1
1481
- };
1482
- });
1483
- }
1484
- function escapeRegExp(s) {
1485
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1486
- }
1487
- function buildRepair(name, subcommands) {
1488
- const subNames = Object.keys(subcommands).map(escapeRegExp).join("|");
1489
- const pattern = new RegExp(
1490
- `^(\\s*${escapeRegExp(name)}\\s+(?:${subNames}))\\s+([\\s\\S]+)$`
1491
- );
1492
- return function repair(raw) {
1493
- const match = raw.match(pattern);
1494
- if (!match) return raw;
1495
- try {
1496
- parse2(raw);
1497
- return raw;
1498
- } catch {
1499
- }
1500
- const [, prefix, argsPart] = match;
1501
- const sub = prefix.trim().split(/\s+/).pop();
1502
- const repairFn = subcommands[sub]?.repair;
1503
- if (!repairFn) return raw;
1504
- const repairedArgs = repairFn(argsPart);
1505
- if (repairedArgs == null) return raw;
1506
- const repaired = `${prefix} ${repairedArgs}`;
1507
- try {
1508
- parse2(repaired);
1509
- return repaired;
1510
- } catch {
1511
- return raw;
1512
- }
1513
- };
1514
- }
1515
- function validateReadOnly(query) {
1516
- const upper = query.toUpperCase().trim();
1517
- if (!upper.startsWith("SELECT") && !upper.startsWith("WITH")) {
1518
- return { valid: false, error: "only SELECT or WITH queries allowed" };
1519
- }
1520
- return { valid: true };
1521
- }
1522
- var SQL_VALIDATE_REMINDER = "Always run `sql validate` before `sql run` to catch syntax errors early.";
1523
- function normalizeShellArtifacts(raw) {
1524
- return raw.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\([().*])/g, "$1").replace(/\\(?=$)/gm, "");
1525
- }
1526
- function stripQuoteArtifacts(raw) {
1527
- let sql = raw.trim();
1528
- if (sql.startsWith('"')) {
1529
- sql = sql.slice(1);
1530
- if (sql.endsWith('"')) sql = sql.slice(0, -1);
1531
- } else if (sql.startsWith("'")) {
1532
- sql = sql.slice(1);
1533
- if (sql.endsWith("'")) sql = sql.slice(0, -1);
1534
- }
1535
- return sql.trim();
1536
- }
1537
- function repairSqlArgs(rawArgs) {
1538
- const sql = stripQuoteArtifacts(rawArgs);
1539
- if (!sql) return null;
1540
- const escaped = sql.replace(/'/g, "'\\''");
1541
- return `'${escaped}'`;
1542
- }
1543
- function createSqlCommand(adapter, metaStore) {
1544
- const subcommands = {
1545
- run: {
1546
- usage: 'run "SELECT ..."',
1547
- description: "Execute query and store results",
1548
- repair: repairSqlArgs,
1549
- handler: async (args, ctx) => {
1550
- const store = metaStore.getStore();
1551
- if (store) {
1552
- store.value = { ...store.value, reminder: SQL_VALIDATE_REMINDER };
1553
- }
1554
- const rawQuery = normalizeShellArtifacts(args.join(" ").trim());
1555
- if (!rawQuery) {
1556
- return {
1557
- stdout: "",
1558
- stderr: "sql run: no query provided",
1559
- exitCode: 1
1560
- };
1561
- }
1562
- const validation = validateReadOnly(rawQuery);
1563
- if (!validation.valid) {
1564
- return {
1565
- stdout: "",
1566
- stderr: `sql run: ${validation.error}`,
1567
- exitCode: 1
1568
- };
1569
- }
1570
- const query = adapter.format(rawQuery);
1571
- if (store) {
1572
- store.value = { ...store.value, formattedSql: query };
1573
- }
1574
- const syntaxError = await adapter.validate(query);
1575
- if (syntaxError) {
1576
- return {
1577
- stdout: "",
1578
- stderr: `sql run: ${syntaxError}`,
1579
- exitCode: 1
1580
- };
1581
- }
1582
- try {
1583
- const rows = await adapter.execute(query);
1584
- const rowsArray = Array.isArray(rows) ? rows : [];
1585
- const content = JSON.stringify(rowsArray, null, 2);
1586
- const filename = `${v7()}.json`;
1587
- const sqlPath = `/sql/${filename}`;
1588
- await ctx.fs.mkdir("/sql", { recursive: true });
1589
- await ctx.fs.writeFile(sqlPath, content);
1590
- const columns = rowsArray.length > 0 ? Object.keys(rowsArray[0]) : [];
1591
- return {
1592
- stdout: [
1593
- `results stored in ${sqlPath}`,
1594
- `columns: ${columns.join(", ") || "(none)"}`,
1595
- `rows: ${rowsArray.length}`
1596
- ].join("\n") + "\n",
1597
- stderr: "",
1598
- exitCode: 0
1599
- };
1600
- } catch (error) {
1601
- return {
1602
- stdout: "",
1603
- stderr: `sql run: ${error instanceof Error ? error.message : String(error)}`,
1604
- exitCode: 1
1605
- };
1606
- }
1607
- }
1608
- },
1609
- validate: {
1610
- usage: 'validate "SELECT ..."',
1611
- description: "Validate query syntax",
1612
- repair: repairSqlArgs,
1613
- handler: async (args) => {
1614
- const rawQuery = normalizeShellArtifacts(args.join(" ").trim());
1615
- if (!rawQuery) {
1616
- return {
1617
- stdout: "",
1618
- stderr: "sql validate: no query provided",
1619
- exitCode: 1
1620
- };
1621
- }
1622
- const validation = validateReadOnly(rawQuery);
1623
- if (!validation.valid) {
1624
- return {
1625
- stdout: "",
1626
- stderr: `sql validate: ${validation.error}`,
1627
- exitCode: 1
1628
- };
1629
- }
1630
- const query = adapter.format(rawQuery);
1631
- const store = metaStore.getStore();
1632
- if (store) store.value = { ...store.value, formattedSql: query };
1633
- const syntaxError = await adapter.validate(query);
1634
- if (syntaxError) {
1635
- return {
1636
- stdout: "",
1637
- stderr: `sql validate: ${syntaxError}`,
1638
- exitCode: 1
1639
- };
1640
- }
1641
- return {
1642
- stdout: "valid\n",
1643
- stderr: "",
1644
- exitCode: 0
1645
- };
1646
- }
1647
- }
1648
- };
1649
- const command = createCommand("sql", subcommands);
1650
- const repair = buildRepair("sql", subcommands);
1651
- return { command, repair };
1652
- }
1653
- function toViolationResult(error) {
1654
- if (error instanceof SqlProxyViolationError) {
1655
- return { stdout: "", stderr: `${error.message}
1656
- `, exitCode: 1 };
1657
- }
1658
- return null;
1659
- }
1660
- async function createResultTools(options) {
1661
- const { adapter, skillMounts, filesystem: baseFs } = options;
1662
- const metaStore = new AsyncLocalStorage();
1663
- const { command: sqlCommand, repair: repairCommand } = createSqlCommand(
1664
- adapter,
1665
- metaStore
1666
- );
1667
- const fsMounts = skillMounts.map(({ host, sandbox: sandbox2 }) => ({
1668
- mountPoint: path2.dirname(sandbox2),
1669
- filesystem: new OverlayFs({
1670
- root: path2.dirname(host),
1671
- mountPoint: "/",
1672
- readOnly: true
1673
- })
1674
- }));
1675
- const filesystem = new MountableFs({
1676
- base: baseFs,
1677
- mounts: fsMounts
1678
- });
1679
- const bashInstance = new Bash({
1680
- customCommands: [sqlCommand],
1681
- fs: filesystem
1682
- });
1683
- bashInstance.registerTransformPlugin(new SqlBacktickRewritePlugin());
1684
- bashInstance.registerTransformPlugin(new SqlProxyEnforcementPlugin());
1685
- const { sandbox, tools } = await createBashTool({
1686
- sandbox: bashInstance,
1687
- destination: "/",
1688
- extraInstructions: 'Every bash tool call must include a brief non-empty "reasoning" input explaining why the command is needed.',
1689
- onBeforeBashCall: ({ command }) => {
1690
- const repaired = repairCommand(command);
1691
- console.log(chalk.cyan(`[onBeforeBashCall]: ${repaired}`));
1692
- return { command: repaired };
1693
- },
1694
- onAfterBashCall: ({ result }) => {
1695
- if (result.exitCode !== 0) {
1696
- console.log(chalk.yellow(`[onAfterBashCall]: ${result.exitCode}`));
1697
- }
1698
- return { result };
1699
- }
1700
- });
1701
- const guardedSandbox = {
1702
- ...sandbox,
1703
- executeCommand: async (command) => {
1704
- try {
1705
- return await sandbox.executeCommand(command);
1706
- } catch (error) {
1707
- const violation = toViolationResult(error);
1708
- if (violation) return violation;
1709
- throw error;
1710
- }
1711
- }
1712
- };
1713
- const bash = tool({
1714
- ...tools.bash,
1715
- inputSchema: z.object({
1716
- command: z.string().describe("The bash command to execute"),
1717
- reasoning: z.string().trim().describe("Brief reason for executing this command")
1718
- }),
1719
- execute: async ({ command }, execOptions) => {
1720
- const execute = tools.bash.execute;
1721
- if (!execute) {
1722
- throw new Error("bash tool execution is not available");
1723
- }
1724
- return metaStore.run({}, async () => {
1725
- try {
1726
- const result = await execute({ command }, execOptions);
1727
- const storeValue = metaStore.getStore()?.value;
1728
- if (!storeValue) return result;
1729
- const { reminder, ...meta } = storeValue;
1730
- return { ...result, meta, reminder };
1731
- } catch (error) {
1732
- const violation = toViolationResult(error);
1733
- if (violation) return violation;
1734
- throw error;
1735
- }
1736
- });
1737
- },
1738
- toModelOutput: ({ output }) => {
1739
- if (typeof output !== "object" || output === null) {
1740
- return { type: "json", value: output };
1741
- }
1742
- const { meta, ...rest } = output;
1743
- return { type: "json", value: rest };
1744
- }
1745
- });
1746
- return {
1747
- sandbox: guardedSandbox,
1748
- tools: {
1749
- ...tools,
1750
- bash
1751
- }
1752
- };
1753
- }
1754
-
1755
1602
  // packages/text2sql/src/lib/agents/sql.agent.ts
1756
1603
  import { groq } from "@ai-sdk/groq";
1757
1604
  import {
@@ -1766,7 +1613,7 @@ import {
1766
1613
  } from "ai";
1767
1614
  import dedent from "dedent";
1768
1615
  import pRetry from "p-retry";
1769
- import z2 from "zod";
1616
+ import z from "zod";
1770
1617
  import "@deepagents/agent";
1771
1618
  import {
1772
1619
  ContextEngine,
@@ -2043,14 +1890,14 @@ Question: ${options.input}
2043
1890
  const sqlOutput = structuredOutput({
2044
1891
  model,
2045
1892
  context,
2046
- schema: z2.object({
2047
- result: z2.union([
2048
- z2.object({
2049
- sql: z2.string().describe("The SQL query that answers the question"),
2050
- reasoning: z2.string().describe("The reasoning steps taken to generate the SQL")
1893
+ schema: z.object({
1894
+ result: z.union([
1895
+ z.object({
1896
+ sql: z.string().describe("The SQL query that answers the question"),
1897
+ reasoning: z.string().describe("The reasoning steps taken to generate the SQL")
2051
1898
  }),
2052
- z2.object({
2053
- error: z2.string().describe(
1899
+ z.object({
1900
+ error: z.string().describe(
2054
1901
  "Error message explaining why the question cannot be answered with the given schema"
2055
1902
  )
2056
1903
  })
@@ -2079,11 +1926,11 @@ Question: ${options.input}
2079
1926
  const forcedSqlOutput = structuredOutput({
2080
1927
  model,
2081
1928
  context,
2082
- schema: z2.object({
2083
- sql: z2.string().describe(
1929
+ schema: z.object({
1930
+ sql: z.string().describe(
2084
1931
  "Best-effort SQL query that answers the core intent using only available schema entities."
2085
1932
  ),
2086
- reasoning: z2.string().describe("Reasoning steps for best-effort schema mapping.")
1933
+ reasoning: z.string().describe("Reasoning steps for best-effort schema mapping.")
2087
1934
  })
2088
1935
  });
2089
1936
  try {
@@ -2168,17 +2015,17 @@ async function withRetry(computation, options = { retries: 3 }) {
2168
2015
  // packages/text2sql/src/lib/agents/suggestions.agents.ts
2169
2016
  import { groq as groq2 } from "@ai-sdk/groq";
2170
2017
  import dedent2 from "dedent";
2171
- import z3 from "zod";
2018
+ import z2 from "zod";
2172
2019
  import { agent, thirdPersonPrompt } from "@deepagents/agent";
2173
2020
  var suggestionsAgent = agent({
2174
2021
  name: "text2sql-suggestions",
2175
2022
  model: groq2("openai/gpt-oss-20b"),
2176
- output: z3.object({
2177
- suggestions: z3.array(
2178
- z3.object({
2179
- question: z3.string().describe("A complex, high-impact business question."),
2180
- sql: z3.string().describe("The SQL statement needed to answer the question."),
2181
- businessValue: z3.string().describe("Why the question matters to stakeholders.")
2023
+ output: z2.object({
2024
+ suggestions: z2.array(
2025
+ z2.object({
2026
+ question: z2.string().describe("A complex, high-impact business question."),
2027
+ sql: z2.string().describe("The SQL statement needed to answer the question."),
2028
+ businessValue: z2.string().describe("Why the question matters to stakeholders.")
2182
2029
  })
2183
2030
  ).min(1).max(5).describe("A set of up to two advanced question + SQL pairs.")
2184
2031
  }),
@@ -2225,9 +2072,9 @@ var Checkpoint = class _Checkpoint {
2225
2072
  points;
2226
2073
  path;
2227
2074
  configHash;
2228
- constructor(path7, configHash, points) {
2075
+ constructor(path6, configHash, points) {
2229
2076
  this.points = points;
2230
- this.path = path7;
2077
+ this.path = path6;
2231
2078
  this.configHash = configHash;
2232
2079
  }
2233
2080
  /**
@@ -2235,14 +2082,14 @@ var Checkpoint = class _Checkpoint {
2235
2082
  * Handles corrupted files and config changes gracefully.
2236
2083
  */
2237
2084
  static async load(options) {
2238
- const { path: path7, configHash } = options;
2239
- if (existsSync(path7)) {
2085
+ const { path: path6, configHash } = options;
2086
+ if (existsSync(path6)) {
2240
2087
  try {
2241
- const content = readFileSync(path7, "utf-8");
2088
+ const content = readFileSync(path6, "utf-8");
2242
2089
  const file = JSON.parse(content);
2243
2090
  if (configHash && file.configHash && file.configHash !== configHash) {
2244
2091
  console.log("\u26A0 Config changed, starting fresh");
2245
- return new _Checkpoint(path7, configHash, {});
2092
+ return new _Checkpoint(path6, configHash, {});
2246
2093
  }
2247
2094
  const points = file.points ?? {};
2248
2095
  const totalEntries = Object.values(points).reduce(
@@ -2250,14 +2097,14 @@ var Checkpoint = class _Checkpoint {
2250
2097
  0
2251
2098
  );
2252
2099
  console.log(`\u2713 Resuming from checkpoint (${totalEntries} entries)`);
2253
- return new _Checkpoint(path7, configHash, points);
2100
+ return new _Checkpoint(path6, configHash, points);
2254
2101
  } catch {
2255
2102
  console.log("\u26A0 Checkpoint corrupted, starting fresh");
2256
- return new _Checkpoint(path7, configHash, {});
2103
+ return new _Checkpoint(path6, configHash, {});
2257
2104
  }
2258
2105
  }
2259
2106
  console.log("Starting new checkpoint");
2260
- return new _Checkpoint(path7, configHash, {});
2107
+ return new _Checkpoint(path6, configHash, {});
2261
2108
  }
2262
2109
  /**
2263
2110
  * Run a single computation with checkpointing.
@@ -2391,12 +2238,12 @@ import { createHash as createHash3 } from "node:crypto";
2391
2238
  import { existsSync as existsSync2 } from "node:fs";
2392
2239
  import { readFile, writeFile } from "node:fs/promises";
2393
2240
  import { tmpdir } from "node:os";
2394
- import path3 from "node:path";
2241
+ import path2 from "node:path";
2395
2242
  var FileCache = class {
2396
2243
  path;
2397
2244
  constructor(watermark, extension = ".txt") {
2398
2245
  const hash2 = createHash3("md5").update(watermark).digest("hex");
2399
- this.path = path3.join(tmpdir(), `text2sql-${hash2}${extension}`);
2246
+ this.path = path2.join(tmpdir(), `text2sql-${hash2}${extension}`);
2400
2247
  }
2401
2248
  async get() {
2402
2249
  if (existsSync2(this.path)) {
@@ -2425,7 +2272,7 @@ var JsonCache = class extends FileCache {
2425
2272
  };
2426
2273
 
2427
2274
  // packages/text2sql/src/lib/fs/sqlite/sqlite-fs.ts
2428
- import * as path4 from "node:path";
2275
+ import * as path3 from "node:path";
2429
2276
  import { DatabaseSync } from "node:sqlite";
2430
2277
 
2431
2278
  // packages/text2sql/src/lib/fs/sqlite/ddl.sqlite-fs.sql
@@ -2473,7 +2320,7 @@ var SqliteFs = class {
2473
2320
  const segments = p.split("/").filter(Boolean);
2474
2321
  let currentPath = "/";
2475
2322
  for (let i = 0; i < segments.length - 1; i++) {
2476
- currentPath = path4.posix.join(currentPath, segments[i]);
2323
+ currentPath = path3.posix.join(currentPath, segments[i]);
2477
2324
  const exists = this.#stmt("SELECT 1 FROM fs_entries WHERE path = ?").get(
2478
2325
  currentPath
2479
2326
  );
@@ -2494,7 +2341,7 @@ var SqliteFs = class {
2494
2341
  return stmt;
2495
2342
  }
2496
2343
  #normalizeRoot(root) {
2497
- return path4.posix.resolve("/", root.trim());
2344
+ return path3.posix.resolve("/", root.trim());
2498
2345
  }
2499
2346
  #prefixPath(p) {
2500
2347
  if (!this.#root) {
@@ -2503,7 +2350,7 @@ var SqliteFs = class {
2503
2350
  if (p === "/") {
2504
2351
  return this.#root;
2505
2352
  }
2506
- return path4.posix.join(this.#root, p);
2353
+ return path3.posix.join(this.#root, p);
2507
2354
  }
2508
2355
  #unprefixPath(p) {
2509
2356
  if (!this.#root) {
@@ -2529,10 +2376,10 @@ var SqliteFs = class {
2529
2376
  }
2530
2377
  }
2531
2378
  #normalizePath(p) {
2532
- return path4.posix.resolve("/", p);
2379
+ return path3.posix.resolve("/", p);
2533
2380
  }
2534
2381
  #dirname(p) {
2535
- const dir = path4.posix.dirname(p);
2382
+ const dir = path3.posix.dirname(p);
2536
2383
  return dir === "" ? "/" : dir;
2537
2384
  }
2538
2385
  #ensureParentExists(filePath) {
@@ -2595,7 +2442,7 @@ var SqliteFs = class {
2595
2442
  }
2596
2443
  seen.add(p);
2597
2444
  const target = this.#normalizePath(
2598
- path4.posix.resolve(this.#dirname(p), entry.symlinkTarget)
2445
+ path3.posix.resolve(this.#dirname(p), entry.symlinkTarget)
2599
2446
  );
2600
2447
  return this.#resolveSymlink(target, seen);
2601
2448
  }
@@ -2747,11 +2594,11 @@ var SqliteFs = class {
2747
2594
  this.#useTransaction(() => {
2748
2595
  if (options?.recursive) {
2749
2596
  const rootPath = this.#root || "/";
2750
- const relativePath = path4.posix.relative(rootPath, prefixed);
2597
+ const relativePath = path3.posix.relative(rootPath, prefixed);
2751
2598
  const segments = relativePath.split("/").filter(Boolean);
2752
2599
  let currentPath = rootPath;
2753
2600
  for (const segment of segments) {
2754
- currentPath = path4.posix.join(currentPath, segment);
2601
+ currentPath = path3.posix.join(currentPath, segment);
2755
2602
  const exists = this.#stmt(
2756
2603
  "SELECT type FROM fs_entries WHERE path = ?"
2757
2604
  ).get(currentPath);
@@ -2802,7 +2649,7 @@ var SqliteFs = class {
2802
2649
  AND path != ?
2803
2650
  AND path NOT LIKE ? || '%/%'`
2804
2651
  ).all(prefix, resolved, prefix);
2805
- return rows.map((row) => path4.posix.basename(row.path));
2652
+ return rows.map((row) => path3.posix.basename(row.path));
2806
2653
  }
2807
2654
  async readdirWithFileTypes(dirPath) {
2808
2655
  const normalized = this.#normalizePath(dirPath);
@@ -2825,7 +2672,7 @@ var SqliteFs = class {
2825
2672
  AND path NOT LIKE ? || '%/%'`
2826
2673
  ).all(prefix, resolved, prefix);
2827
2674
  return rows.map((row) => ({
2828
- name: path4.posix.basename(row.path),
2675
+ name: path3.posix.basename(row.path),
2829
2676
  isFile: row.type === "file",
2830
2677
  isDirectory: row.type === "directory",
2831
2678
  isSymbolicLink: row.type === "symlink"
@@ -2880,8 +2727,8 @@ var SqliteFs = class {
2880
2727
  `SELECT * FROM fs_entries WHERE path = ? OR path LIKE ? || '/%'`
2881
2728
  ).all(srcPrefixed, srcPrefixed);
2882
2729
  for (const entry of allEntries) {
2883
- const relativePath = path4.posix.relative(srcPrefixed, entry.path);
2884
- const newPath = path4.posix.join(destPrefixed, relativePath);
2730
+ const relativePath = path3.posix.relative(srcPrefixed, entry.path);
2731
+ const newPath = path3.posix.join(destPrefixed, relativePath);
2885
2732
  this.#stmt(
2886
2733
  `INSERT OR REPLACE INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2887
2734
  VALUES (?, ?, ?, ?, ?, ?)`
@@ -2948,8 +2795,8 @@ var SqliteFs = class {
2948
2795
  `SELECT * FROM fs_entries WHERE path = ? OR path LIKE ? || '/%' ORDER BY path DESC`
2949
2796
  ).all(srcPrefixed, srcPrefixed);
2950
2797
  for (const entry of [...allEntries].reverse()) {
2951
- const relativePath = path4.posix.relative(srcPrefixed, entry.path);
2952
- const newPath = path4.posix.join(destPrefixed, relativePath);
2798
+ const relativePath = path3.posix.relative(srcPrefixed, entry.path);
2799
+ const newPath = path3.posix.join(destPrefixed, relativePath);
2953
2800
  this.#stmt(
2954
2801
  `INSERT INTO fs_entries (path, type, mode, size, mtime, symlinkTarget)
2955
2802
  VALUES (?, ?, ?, ?, ?, ?)`
@@ -3002,7 +2849,7 @@ var SqliteFs = class {
3002
2849
  });
3003
2850
  }
3004
2851
  resolvePath(base, relativePath) {
3005
- return path4.posix.resolve(base, relativePath);
2852
+ return path3.posix.resolve(base, relativePath);
3006
2853
  }
3007
2854
  getAllPaths() {
3008
2855
  const rows = this.#stmt(
@@ -3114,7 +2961,7 @@ var SqliteFs = class {
3114
2961
 
3115
2962
  // packages/text2sql/src/lib/fs/mssql/mssql-fs.ts
3116
2963
  import { createRequire } from "node:module";
3117
- import * as path5 from "node:path";
2964
+ import * as path4 from "node:path";
3118
2965
 
3119
2966
  // packages/text2sql/src/lib/fs/mssql/ddl.mssql-fs.ts
3120
2967
  function mssqlFsDDL(schema) {
@@ -3240,7 +3087,7 @@ var MssqlFs = class _MssqlFs {
3240
3087
  const segments = p.split("/").filter(Boolean);
3241
3088
  let currentPath = "/";
3242
3089
  for (let i = 0; i < segments.length - 1; i++) {
3243
- currentPath = path5.posix.join(currentPath, segments[i]);
3090
+ currentPath = path4.posix.join(currentPath, segments[i]);
3244
3091
  const exists = await this.#rawQuery(
3245
3092
  `SELECT CASE WHEN EXISTS(SELECT 1 FROM ${this.#t("fs_entries")} WHERE path = @p0) THEN 1 ELSE 0 END as [exists]`,
3246
3093
  [currentPath]
@@ -3292,7 +3139,7 @@ var MssqlFs = class _MssqlFs {
3292
3139
  }
3293
3140
  }
3294
3141
  #normalizeRoot(root) {
3295
- return path5.posix.resolve("/", root.trim());
3142
+ return path4.posix.resolve("/", root.trim());
3296
3143
  }
3297
3144
  #prefixPath(p) {
3298
3145
  if (!this.#root) {
@@ -3301,7 +3148,7 @@ var MssqlFs = class _MssqlFs {
3301
3148
  if (p === "/") {
3302
3149
  return this.#root;
3303
3150
  }
3304
- return path5.posix.join(this.#root, p);
3151
+ return path4.posix.join(this.#root, p);
3305
3152
  }
3306
3153
  #unprefixPath(p) {
3307
3154
  if (!this.#root) {
@@ -3316,10 +3163,10 @@ var MssqlFs = class _MssqlFs {
3316
3163
  return p;
3317
3164
  }
3318
3165
  #normalizePath(p) {
3319
- return path5.posix.resolve("/", p);
3166
+ return path4.posix.resolve("/", p);
3320
3167
  }
3321
3168
  #dirname(p) {
3322
- const dir = path5.posix.dirname(p);
3169
+ const dir = path4.posix.dirname(p);
3323
3170
  return dir === "" ? "/" : dir;
3324
3171
  }
3325
3172
  async #ensureParentExists(filePath, transaction) {
@@ -3408,7 +3255,7 @@ var MssqlFs = class _MssqlFs {
3408
3255
  }
3409
3256
  seen.add(p);
3410
3257
  const target = this.#normalizePath(
3411
- path5.posix.resolve(this.#dirname(p), entry.symlinkTarget)
3258
+ path4.posix.resolve(this.#dirname(p), entry.symlinkTarget)
3412
3259
  );
3413
3260
  return this.#resolveSymlink(target, seen);
3414
3261
  }
@@ -3591,11 +3438,11 @@ var MssqlFs = class _MssqlFs {
3591
3438
  await this.#useTransaction(async (transaction) => {
3592
3439
  if (options?.recursive) {
3593
3440
  const rootPath = this.#root || "/";
3594
- const relativePath = path5.posix.relative(rootPath, prefixed);
3441
+ const relativePath = path4.posix.relative(rootPath, prefixed);
3595
3442
  const segments = relativePath.split("/").filter(Boolean);
3596
3443
  let currentPath = rootPath;
3597
3444
  for (const segment of segments) {
3598
- currentPath = path5.posix.join(currentPath, segment);
3445
+ currentPath = path4.posix.join(currentPath, segment);
3599
3446
  const checkReq = transaction.request();
3600
3447
  checkReq.input("p0", currentPath);
3601
3448
  const result = await checkReq.query(
@@ -3659,7 +3506,7 @@ var MssqlFs = class _MssqlFs {
3659
3506
  AND path NOT LIKE @p0 + '%/%'`,
3660
3507
  [prefix, resolved]
3661
3508
  );
3662
- return rows.map((row) => path5.posix.basename(row.path));
3509
+ return rows.map((row) => path4.posix.basename(row.path));
3663
3510
  }
3664
3511
  async readdirWithFileTypes(dirPath) {
3665
3512
  const normalized = this.#normalizePath(dirPath);
@@ -3685,7 +3532,7 @@ var MssqlFs = class _MssqlFs {
3685
3532
  [prefix, resolved]
3686
3533
  );
3687
3534
  return rows.map((row) => ({
3688
- name: path5.posix.basename(row.path),
3535
+ name: path4.posix.basename(row.path),
3689
3536
  isFile: row.type === "file",
3690
3537
  isDirectory: row.type === "directory",
3691
3538
  isSymbolicLink: row.type === "symlink"
@@ -3754,8 +3601,8 @@ var MssqlFs = class _MssqlFs {
3754
3601
  `SELECT * FROM ${this.#t("fs_entries")} WHERE path = @p0 OR path LIKE @p0 + '/%'`
3755
3602
  );
3756
3603
  for (const entry of allEntriesResult.recordset) {
3757
- const relativePath = path5.posix.relative(srcPrefixed, entry.path);
3758
- const newPath = path5.posix.join(destPrefixed, relativePath);
3604
+ const relativePath = path4.posix.relative(srcPrefixed, entry.path);
3605
+ const newPath = path4.posix.join(destPrefixed, relativePath);
3759
3606
  const insertReq = transaction.request();
3760
3607
  insertReq.input("p0", newPath);
3761
3608
  insertReq.input("p1", entry.type);
@@ -3864,8 +3711,8 @@ var MssqlFs = class _MssqlFs {
3864
3711
  `DELETE FROM ${this.#t("fs_entries")} WHERE path = @dp0 OR path LIKE @dp0 + '/%'`
3865
3712
  );
3866
3713
  for (const entry of [...allEntriesResult.recordset].reverse()) {
3867
- const relativePath = path5.posix.relative(srcPrefixed, entry.path);
3868
- const newPath = path5.posix.join(destPrefixed, relativePath);
3714
+ const relativePath = path4.posix.relative(srcPrefixed, entry.path);
3715
+ const newPath = path4.posix.join(destPrefixed, relativePath);
3869
3716
  const insertReq = transaction.request();
3870
3717
  insertReq.input("p0", newPath);
3871
3718
  insertReq.input("p1", entry.type);
@@ -3958,7 +3805,7 @@ var MssqlFs = class _MssqlFs {
3958
3805
  });
3959
3806
  }
3960
3807
  resolvePath(base, relativePath) {
3961
- return path5.posix.resolve(base, relativePath);
3808
+ return path4.posix.resolve(base, relativePath);
3962
3809
  }
3963
3810
  getAllPaths() {
3964
3811
  throw new Error(
@@ -4099,7 +3946,7 @@ var MssqlFs = class _MssqlFs {
4099
3946
 
4100
3947
  // packages/text2sql/src/lib/fs/postgres/postgres-fs.ts
4101
3948
  import { createRequire as createRequire2 } from "node:module";
4102
- import * as path6 from "node:path";
3949
+ import * as path5 from "node:path";
4103
3950
 
4104
3951
  // packages/text2sql/src/lib/fs/postgres/ddl.postgres-fs.ts
4105
3952
  function postgresFsDDL(schema) {
@@ -4204,7 +4051,7 @@ var PostgresFs = class _PostgresFs {
4204
4051
  const segments = p.split("/").filter(Boolean);
4205
4052
  let currentPath = "/";
4206
4053
  for (let i = 0; i < segments.length - 1; i++) {
4207
- currentPath = path6.posix.join(currentPath, segments[i]);
4054
+ currentPath = path5.posix.join(currentPath, segments[i]);
4208
4055
  const exists = await this.#rawQuery(
4209
4056
  `SELECT EXISTS(SELECT 1 FROM ${this.#t("fs_entries")} WHERE path = $1) AS exists`,
4210
4057
  [currentPath]
@@ -4249,7 +4096,7 @@ var PostgresFs = class _PostgresFs {
4249
4096
  }
4250
4097
  }
4251
4098
  #normalizeRoot(root) {
4252
- return path6.posix.resolve("/", root.trim());
4099
+ return path5.posix.resolve("/", root.trim());
4253
4100
  }
4254
4101
  #prefixPath(p) {
4255
4102
  if (!this.#root) {
@@ -4258,7 +4105,7 @@ var PostgresFs = class _PostgresFs {
4258
4105
  if (p === "/") {
4259
4106
  return this.#root;
4260
4107
  }
4261
- return path6.posix.join(this.#root, p);
4108
+ return path5.posix.join(this.#root, p);
4262
4109
  }
4263
4110
  #unprefixPath(p) {
4264
4111
  if (!this.#root) {
@@ -4273,10 +4120,10 @@ var PostgresFs = class _PostgresFs {
4273
4120
  return p;
4274
4121
  }
4275
4122
  #normalizePath(p) {
4276
- return path6.posix.resolve("/", p);
4123
+ return path5.posix.resolve("/", p);
4277
4124
  }
4278
4125
  #dirname(p) {
4279
- const dir = path6.posix.dirname(p);
4126
+ const dir = path5.posix.dirname(p);
4280
4127
  return dir === "" ? "/" : dir;
4281
4128
  }
4282
4129
  async #ensureParentExists(filePath, client) {
@@ -4356,7 +4203,7 @@ var PostgresFs = class _PostgresFs {
4356
4203
  }
4357
4204
  seen.add(p);
4358
4205
  const target = this.#normalizePath(
4359
- path6.posix.resolve(this.#dirname(p), entry.symlink_target)
4206
+ path5.posix.resolve(this.#dirname(p), entry.symlink_target)
4360
4207
  );
4361
4208
  return this.#resolveSymlink(target, seen);
4362
4209
  }
@@ -4522,11 +4369,11 @@ var PostgresFs = class _PostgresFs {
4522
4369
  await this.#useTransaction(async (client) => {
4523
4370
  if (options?.recursive) {
4524
4371
  const rootPath = this.#root || "/";
4525
- const relativePath = path6.posix.relative(rootPath, prefixed);
4372
+ const relativePath = path5.posix.relative(rootPath, prefixed);
4526
4373
  const segments = relativePath.split("/").filter(Boolean);
4527
4374
  let currentPath = rootPath;
4528
4375
  for (const segment of segments) {
4529
- currentPath = path6.posix.join(currentPath, segment);
4376
+ currentPath = path5.posix.join(currentPath, segment);
4530
4377
  const result = await client.query(
4531
4378
  `SELECT type FROM ${this.#t("fs_entries")} WHERE path = $1`,
4532
4379
  [currentPath]
@@ -4584,7 +4431,7 @@ var PostgresFs = class _PostgresFs {
4584
4431
  AND path NOT LIKE $1 || '%/%'`,
4585
4432
  [prefix, resolved]
4586
4433
  );
4587
- return rows.map((row) => path6.posix.basename(row.path));
4434
+ return rows.map((row) => path5.posix.basename(row.path));
4588
4435
  }
4589
4436
  async readdirWithFileTypes(dirPath) {
4590
4437
  const normalized = this.#normalizePath(dirPath);
@@ -4610,7 +4457,7 @@ var PostgresFs = class _PostgresFs {
4610
4457
  [prefix, resolved]
4611
4458
  );
4612
4459
  return rows.map((row) => ({
4613
- name: path6.posix.basename(row.path),
4460
+ name: path5.posix.basename(row.path),
4614
4461
  isFile: row.type === "file",
4615
4462
  isDirectory: row.type === "directory",
4616
4463
  isSymbolicLink: row.type === "symlink"
@@ -4675,8 +4522,8 @@ var PostgresFs = class _PostgresFs {
4675
4522
  [srcPrefixed]
4676
4523
  );
4677
4524
  for (const entry of allEntriesResult.rows) {
4678
- const relativePath = path6.posix.relative(srcPrefixed, entry.path);
4679
- const newPath = path6.posix.join(destPrefixed, relativePath);
4525
+ const relativePath = path5.posix.relative(srcPrefixed, entry.path);
4526
+ const newPath = path5.posix.join(destPrefixed, relativePath);
4680
4527
  await client.query(
4681
4528
  `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime, symlink_target)
4682
4529
  VALUES ($1, $2, $3, $4, $5, $6)
@@ -4765,8 +4612,8 @@ var PostgresFs = class _PostgresFs {
4765
4612
  [destPrefixed]
4766
4613
  );
4767
4614
  for (const entry of [...allEntriesResult.rows].reverse()) {
4768
- const relativePath = path6.posix.relative(srcPrefixed, entry.path);
4769
- const newPath = path6.posix.join(destPrefixed, relativePath);
4615
+ const relativePath = path5.posix.relative(srcPrefixed, entry.path);
4616
+ const newPath = path5.posix.join(destPrefixed, relativePath);
4770
4617
  await client.query(
4771
4618
  `INSERT INTO ${this.#t("fs_entries")} (path, type, mode, size, mtime, symlink_target)
4772
4619
  VALUES ($1, $2, $3, $4, $5, $6)
@@ -4839,7 +4686,7 @@ var PostgresFs = class _PostgresFs {
4839
4686
  });
4840
4687
  }
4841
4688
  resolvePath(base, relativePath) {
4842
- return path6.posix.resolve(base, relativePath);
4689
+ return path5.posix.resolve(base, relativePath);
4843
4690
  }
4844
4691
  getAllPaths() {
4845
4692
  throw new Error(
@@ -4975,29 +4822,29 @@ var ScopedFs = class {
4975
4822
  this.#base = options.base;
4976
4823
  this.#prefix = options.prefix.replace(/\/$/, "");
4977
4824
  }
4978
- #scope(path7) {
4979
- return `${this.#prefix}${path7}`;
4825
+ #scope(path6) {
4826
+ return `${this.#prefix}${path6}`;
4980
4827
  }
4981
- #unscope(path7) {
4982
- if (path7 === this.#prefix) {
4828
+ #unscope(path6) {
4829
+ if (path6 === this.#prefix) {
4983
4830
  return "/";
4984
4831
  }
4985
- if (path7.startsWith(this.#prefix + "/")) {
4986
- return path7.slice(this.#prefix.length) || "/";
4832
+ if (path6.startsWith(this.#prefix + "/")) {
4833
+ return path6.slice(this.#prefix.length) || "/";
4987
4834
  }
4988
- return path7;
4835
+ return path6;
4989
4836
  }
4990
- async writeFile(path7, content, options) {
4991
- await this.#base.writeFile(this.#scope(path7), content, options);
4837
+ async writeFile(path6, content, options) {
4838
+ await this.#base.writeFile(this.#scope(path6), content, options);
4992
4839
  }
4993
- async appendFile(path7, content, options) {
4994
- await this.#base.appendFile(this.#scope(path7), content, options);
4840
+ async appendFile(path6, content, options) {
4841
+ await this.#base.appendFile(this.#scope(path6), content, options);
4995
4842
  }
4996
- async mkdir(path7, options) {
4997
- return this.#base.mkdir(this.#scope(path7), options);
4843
+ async mkdir(path6, options) {
4844
+ return this.#base.mkdir(this.#scope(path6), options);
4998
4845
  }
4999
- async rm(path7, options) {
5000
- await this.#base.rm(this.#scope(path7), options);
4846
+ async rm(path6, options) {
4847
+ await this.#base.rm(this.#scope(path6), options);
5001
4848
  }
5002
4849
  async cp(src, dest, options) {
5003
4850
  await this.#base.cp(this.#scope(src), this.#scope(dest), options);
@@ -5005,8 +4852,8 @@ var ScopedFs = class {
5005
4852
  async mv(src, dest) {
5006
4853
  await this.#base.mv(this.#scope(src), this.#scope(dest));
5007
4854
  }
5008
- async chmod(path7, mode) {
5009
- return this.#base.chmod(this.#scope(path7), mode);
4855
+ async chmod(path6, mode) {
4856
+ return this.#base.chmod(this.#scope(path6), mode);
5010
4857
  }
5011
4858
  async symlink(target, linkPath) {
5012
4859
  await this.#base.symlink(target, this.#scope(linkPath));
@@ -5014,35 +4861,35 @@ var ScopedFs = class {
5014
4861
  async link(existingPath, newPath) {
5015
4862
  await this.#base.link(this.#scope(existingPath), this.#scope(newPath));
5016
4863
  }
5017
- readFile(path7, options) {
5018
- return this.#base.readFile(this.#scope(path7), options);
4864
+ readFile(path6, options) {
4865
+ return this.#base.readFile(this.#scope(path6), options);
5019
4866
  }
5020
- readFileBuffer(path7) {
5021
- return this.#base.readFileBuffer(this.#scope(path7));
4867
+ readFileBuffer(path6) {
4868
+ return this.#base.readFileBuffer(this.#scope(path6));
5022
4869
  }
5023
- stat(path7) {
5024
- return this.#base.stat(this.#scope(path7));
4870
+ stat(path6) {
4871
+ return this.#base.stat(this.#scope(path6));
5025
4872
  }
5026
- lstat(path7) {
5027
- return this.#base.lstat(this.#scope(path7));
4873
+ lstat(path6) {
4874
+ return this.#base.lstat(this.#scope(path6));
5028
4875
  }
5029
- readdir(path7) {
5030
- return this.#base.readdir(this.#scope(path7));
4876
+ readdir(path6) {
4877
+ return this.#base.readdir(this.#scope(path6));
5031
4878
  }
5032
- readdirWithFileTypes(path7) {
5033
- return this.#base.readdirWithFileTypes(this.#scope(path7));
4879
+ readdirWithFileTypes(path6) {
4880
+ return this.#base.readdirWithFileTypes(this.#scope(path6));
5034
4881
  }
5035
- exists(path7) {
5036
- return this.#base.exists(this.#scope(path7));
4882
+ exists(path6) {
4883
+ return this.#base.exists(this.#scope(path6));
5037
4884
  }
5038
- readlink(path7) {
5039
- return this.#base.readlink(this.#scope(path7));
4885
+ readlink(path6) {
4886
+ return this.#base.readlink(this.#scope(path6));
5040
4887
  }
5041
- realpath(path7) {
5042
- return this.#base.realpath(this.#scope(path7)).then((p) => this.#unscope(p));
4888
+ realpath(path6) {
4889
+ return this.#base.realpath(this.#scope(path6)).then((p) => this.#unscope(p));
5043
4890
  }
5044
- utimes(path7, atime, mtime) {
5045
- return this.#base.utimes(this.#scope(path7), atime, mtime);
4891
+ utimes(path6, atime, mtime) {
4892
+ return this.#base.utimes(this.#scope(path6), atime, mtime);
5046
4893
  }
5047
4894
  resolvePath(base, relativePath) {
5048
4895
  return this.#base.resolvePath(base, relativePath);
@@ -5053,97 +4900,6 @@ var ScopedFs = class {
5053
4900
  }
5054
4901
  };
5055
4902
 
5056
- // packages/text2sql/src/lib/fs/tracked-fs.ts
5057
- var TrackedFs = class {
5058
- #base;
5059
- #createdFiles = /* @__PURE__ */ new Set();
5060
- constructor(base) {
5061
- this.#base = base;
5062
- }
5063
- getCreatedFiles() {
5064
- return [...this.#createdFiles];
5065
- }
5066
- async writeFile(path7, content, options) {
5067
- await this.#base.writeFile(path7, content, options);
5068
- this.#createdFiles.add(path7);
5069
- }
5070
- async appendFile(path7, content, options) {
5071
- await this.#base.appendFile(path7, content, options);
5072
- this.#createdFiles.add(path7);
5073
- }
5074
- async mkdir(path7, options) {
5075
- return this.#base.mkdir(path7, options);
5076
- }
5077
- async rm(path7, options) {
5078
- await this.#base.rm(path7, options);
5079
- this.#createdFiles.delete(path7);
5080
- if (options?.recursive) {
5081
- const prefix = path7.endsWith("/") ? path7 : path7 + "/";
5082
- for (const file of this.#createdFiles) {
5083
- if (file.startsWith(prefix)) {
5084
- this.#createdFiles.delete(file);
5085
- }
5086
- }
5087
- }
5088
- }
5089
- async cp(src, dest, options) {
5090
- await this.#base.cp(src, dest, options);
5091
- this.#createdFiles.add(dest);
5092
- }
5093
- async mv(src, dest) {
5094
- await this.#base.mv(src, dest);
5095
- this.#createdFiles.delete(src);
5096
- this.#createdFiles.add(dest);
5097
- }
5098
- async chmod(path7, mode) {
5099
- return this.#base.chmod(path7, mode);
5100
- }
5101
- async symlink(target, linkPath) {
5102
- await this.#base.symlink(target, linkPath);
5103
- this.#createdFiles.add(linkPath);
5104
- }
5105
- async link(existingPath, newPath) {
5106
- await this.#base.link(existingPath, newPath);
5107
- this.#createdFiles.add(newPath);
5108
- }
5109
- readFile(path7, options) {
5110
- return this.#base.readFile(path7, options);
5111
- }
5112
- readFileBuffer(path7) {
5113
- return this.#base.readFileBuffer(path7);
5114
- }
5115
- stat(path7) {
5116
- return this.#base.stat(path7);
5117
- }
5118
- lstat(path7) {
5119
- return this.#base.lstat(path7);
5120
- }
5121
- readdir(path7) {
5122
- return this.#base.readdir(path7);
5123
- }
5124
- readdirWithFileTypes(path7) {
5125
- return this.#base.readdirWithFileTypes(path7);
5126
- }
5127
- exists(path7) {
5128
- return this.#base.exists(path7);
5129
- }
5130
- readlink(path7) {
5131
- return this.#base.readlink(path7);
5132
- }
5133
- resolvePath(base, relativePath) {
5134
- return this.#base.resolvePath(base, relativePath);
5135
- }
5136
- getAllPaths() {
5137
- return this.#base.getAllPaths?.() ?? [];
5138
- }
5139
- realpath(path7) {
5140
- return this.#base.realpath(path7);
5141
- }
5142
- utimes(path7, atime, mtime) {
5143
- return this.#base.utimes(path7, atime, mtime);
5144
- }
5145
- };
5146
-
5147
4903
  // packages/text2sql/src/lib/instructions.ts
5148
4904
  import {
5149
4905
  clarification,
@@ -5382,7 +5138,8 @@ Action: Ask user: "Top by what metric\u2014total revenue, number of orders, or m
5382
5138
  workflow2({
5383
5139
  task: "Query execution",
5384
5140
  steps: [
5385
- 'Execute SQL through bash tool: sql run "SELECT ..."',
5141
+ "Pick the target database from the schema fragments (each parent fragment is named after a configured database).",
5142
+ 'Execute SQL through bash tool: sql run <db> "SELECT ..."',
5386
5143
  "Read the output: file path, column names, and row count.",
5387
5144
  "Use column names to construct jq filters: cat <path> | jq '.[] | {col1, col2}'",
5388
5145
  "For large results, slice first: cat <path> | jq '.[:10]'"
@@ -5391,7 +5148,7 @@ Action: Ask user: "Top by what metric\u2014total revenue, number of orders, or m
5391
5148
  guardrail2({
5392
5149
  rule: "Do not attempt SQL access through non-bash tools.",
5393
5150
  reason: "SQL access is only available through the virtual bash environment.",
5394
- action: 'Use "sql run" and "sql validate" through bash.'
5151
+ action: 'Use `sql run <db> "SELECT ..."` and `sql validate <db> "SELECT ..."` through bash, where `<db>` is the configured database name.'
5395
5152
  }),
5396
5153
  explain({
5397
5154
  concept: "sql command output format",
@@ -5429,214 +5186,128 @@ Action: Ask user: "Top by what metric\u2014total revenue, number of orders, or m
5429
5186
  return baseTeachings;
5430
5187
  }
5431
5188
 
5189
+ // packages/text2sql/src/lib/sandbox.ts
5190
+ function sqlSandboxExtension(adapters, options = {}) {
5191
+ const adapterNames = Object.keys(adapters);
5192
+ if (adapterNames.length === 0) {
5193
+ throw new Error("sqlSandboxExtension requires at least one adapter");
5194
+ }
5195
+ validateAdapterNames(adapterNames);
5196
+ const { command, repair } = createSqlCommand(adapters, options);
5197
+ return {
5198
+ commands: [command],
5199
+ plugins: [new SqlBacktickRewritePlugin(), new SqlProxyEnforcementPlugin()],
5200
+ onBeforeBashCall: ({ command: c }) => ({ command: repair(c) })
5201
+ };
5202
+ }
5203
+
5432
5204
  // packages/text2sql/src/lib/sql.ts
5433
- import {
5434
- APICallError as APICallError2,
5435
- InvalidToolInputError,
5436
- NoSuchToolError,
5437
- ToolCallRepairError,
5438
- createUIMessageStream,
5439
- generateId
5440
- } from "ai";
5441
- import "just-bash";
5442
5205
  import "@deepagents/agent";
5443
5206
  import {
5444
5207
  agent as agent2,
5445
- assistant,
5446
- chatMessageToUIMessage,
5208
+ chat,
5447
5209
  errorRecoveryGuardrail,
5448
- generateChatTitle,
5449
- staticChatTitle,
5450
- toMessageFragment
5210
+ fragment as fragment3
5451
5211
  } from "@deepagents/context";
5452
5212
  var Text2Sql = class {
5453
5213
  #config;
5214
+ #introspection;
5454
5215
  constructor(config) {
5216
+ const adapterNames = Object.keys(config.adapters);
5217
+ if (adapterNames.length === 0) {
5218
+ throw new Error("Text2Sql requires at least one adapter");
5219
+ }
5220
+ validateAdapterNames(adapterNames);
5455
5221
  this.#config = {
5456
- adapter: config.adapter,
5457
- context: config.context,
5458
- tools: config.tools ?? {},
5459
- model: config.model,
5460
- transform: config.transform,
5461
- filesystem: config.filesystem,
5462
- introspection: new JsonCache(
5463
- "introspection-" + config.version
5464
- )
5222
+ ...config,
5223
+ tools: config.tools ?? {}
5465
5224
  };
5225
+ this.#introspection = new Map(
5226
+ Object.keys(config.adapters).map((name) => [
5227
+ name,
5228
+ new JsonCache(
5229
+ `introspection-${config.version}-${name}`
5230
+ )
5231
+ ])
5232
+ );
5233
+ }
5234
+ #requireAdapter(name) {
5235
+ const adapter = this.#config.adapters[name];
5236
+ if (!adapter) {
5237
+ const available = Object.keys(this.#config.adapters).join(", ");
5238
+ throw new Error(`Unknown adapter "${name}". Available: ${available}`);
5239
+ }
5240
+ return adapter;
5466
5241
  }
5467
- async toSql(input) {
5468
- const schemaFragments = await this.index();
5242
+ async toSql(input, adapterName) {
5243
+ const adapter = this.#requireAdapter(adapterName);
5244
+ const fragments = await this.#indexAdapter(adapterName, adapter);
5469
5245
  const result = await toSql({
5470
5246
  input,
5471
- adapter: this.#config.adapter,
5472
- fragments: schemaFragments,
5247
+ adapter,
5248
+ fragments,
5473
5249
  model: this.#config.model
5474
5250
  });
5475
5251
  return result.sql;
5476
5252
  }
5477
- /**
5478
- * Introspect the database schema and return context fragments.
5479
- * Results are cached to avoid repeated introspection.
5480
- */
5481
5253
  async index() {
5482
- const cached = await this.#config.introspection.read();
5254
+ const entries = Object.entries(this.#config.adapters);
5255
+ const wrapped = await Promise.all(
5256
+ entries.map(async ([name, adapter]) => {
5257
+ const schema = await this.#indexAdapter(name, adapter);
5258
+ return fragment3(name, ...schema);
5259
+ })
5260
+ );
5261
+ return wrapped;
5262
+ }
5263
+ async #indexAdapter(name, adapter) {
5264
+ const cache = this.#introspection.get(name);
5265
+ if (!cache) {
5266
+ throw new Error(`no introspection cache registered for "${name}"`);
5267
+ }
5268
+ const cached = await cache.read();
5483
5269
  if (cached) {
5484
5270
  return cached;
5485
5271
  }
5486
- const fragments = await this.#config.adapter.introspect();
5487
- await this.#config.introspection.write(fragments);
5488
- return fragments;
5272
+ try {
5273
+ const fragments = await adapter.introspect();
5274
+ await cache.write(fragments);
5275
+ return fragments;
5276
+ } catch (error) {
5277
+ const reason = error instanceof Error ? error.message : String(error);
5278
+ throw new Error(`introspecting adapter "${name}": ${reason}`, {
5279
+ cause: error
5280
+ });
5281
+ }
5489
5282
  }
5490
- /**
5491
- * Generate training data pairs using a producer factory.
5492
- * The factory receives the configured adapter, so users don't need to pass it manually.
5493
- *
5494
- * @example
5495
- * // Generate questions for existing SQL
5496
- * const pairs = await text2sql.toPairs(
5497
- * (adapter) => new SqlExtractor(sqls, adapter, { validateSql: true })
5498
- * );
5499
- *
5500
- * @example
5501
- * // Extract from chat history with validation
5502
- * const pairs = await text2sql.toPairs(
5503
- * (adapter) => new ValidatedProducer(
5504
- * new MessageExtractor(messages),
5505
- * adapter
5506
- * )
5507
- * );
5508
- */
5509
- async toPairs(factory) {
5510
- const producer = factory(this.#config.adapter);
5283
+ async toPairs(adapterName, factory) {
5284
+ const adapter = this.#requireAdapter(adapterName);
5285
+ const producer = factory(adapter);
5511
5286
  return producer.toPairs();
5512
5287
  }
5513
5288
  async chat(messages, options) {
5514
5289
  if (messages.length === 0) {
5515
5290
  throw new Error("messages must not be empty");
5516
5291
  }
5517
- const trackedFs = new TrackedFs(this.#config.filesystem);
5518
5292
  const context = this.#config.context(
5519
5293
  ...guidelines(),
5520
5294
  ...await this.index()
5521
5295
  );
5522
- const lastItem = messages[messages.length - 1];
5523
- const lastFragment = toMessageFragment(lastItem);
5524
- const lastUIMessage = chatMessageToUIMessage(lastItem);
5525
- let assistantMsgId;
5526
- if (lastUIMessage.role === "assistant") {
5527
- context.set(lastFragment);
5528
- await context.save({ branch: false });
5529
- assistantMsgId = lastUIMessage.id;
5530
- } else {
5531
- context.set(lastFragment);
5532
- await context.save();
5533
- assistantMsgId = generateId();
5534
- }
5535
- const uiMessages = messages.map(chatMessageToUIMessage);
5536
- let title = null;
5537
- if (!context.chat?.title) {
5538
- const firstUserMsg = uiMessages.find((m) => m.role === "user");
5539
- if (firstUserMsg) {
5540
- if (options?.generateTitle) {
5541
- title = await generateChatTitle({
5542
- message: firstUserMsg,
5543
- model: this.#config.model,
5544
- abortSignal: options?.abortSignal
5545
- });
5546
- } else {
5547
- title = staticChatTitle(firstUserMsg);
5548
- }
5549
- await context.updateChat({ title });
5550
- }
5551
- }
5552
- const { mounts: skillMounts } = context.getSkillMounts();
5553
- const { tools } = await createResultTools({
5554
- adapter: this.#config.adapter,
5555
- skillMounts,
5556
- filesystem: trackedFs
5557
- });
5558
5296
  const chatAgent = agent2({
5559
5297
  name: "text2sql",
5298
+ sandbox: this.#config.sandbox,
5560
5299
  model: this.#config.model,
5561
5300
  context,
5562
- tools: {
5563
- ...tools,
5564
- ...this.#config.tools
5565
- },
5301
+ tools: this.#config.tools,
5566
5302
  guardrails: [errorRecoveryGuardrail],
5567
5303
  maxGuardrailRetries: 3
5568
5304
  });
5569
- const result = await chatAgent.stream(
5570
- {},
5571
- { abortSignal: options?.abortSignal, transform: this.#config.transform }
5572
- );
5573
- const uiStream = result.toUIMessageStream({
5574
- onError: (error) => this.#formatError(error),
5575
- sendStart: true,
5576
- sendFinish: true,
5577
- sendReasoning: true,
5578
- sendSources: true,
5579
- originalMessages: uiMessages,
5580
- generateMessageId: () => assistantMsgId,
5581
- messageMetadata: ({ part }) => {
5582
- if (part.type === "finish-step") {
5583
- return {
5584
- finishReason: part.finishReason,
5585
- usage: part.usage
5586
- };
5587
- }
5588
- if (part.type === "finish") {
5589
- return {
5590
- finishReason: part.finishReason,
5591
- totalUsage: part.totalUsage
5592
- };
5593
- }
5594
- return void 0;
5595
- }
5596
- });
5597
- return createUIMessageStream({
5598
- originalMessages: uiMessages,
5599
- generateId: () => assistantMsgId,
5600
- onStepFinish: async ({ responseMessage }) => {
5601
- context.set(assistant({ ...responseMessage, id: assistantMsgId }));
5602
- await context.save({ branch: false });
5603
- },
5604
- onFinish: async ({ responseMessage }) => {
5605
- const createdFiles = trackedFs.getCreatedFiles();
5606
- context.set(
5607
- assistant({
5608
- ...responseMessage,
5609
- id: assistantMsgId,
5610
- metadata: {
5611
- ...responseMessage.metadata ?? {},
5612
- createdFiles
5613
- }
5614
- })
5615
- );
5616
- await context.save({ branch: false });
5617
- await context.trackUsage(await result.totalUsage);
5618
- },
5619
- execute: async ({ writer }) => {
5620
- writer.merge(uiStream);
5621
- if (title) {
5622
- writer.write({ type: "data-chat-title", data: title });
5623
- }
5624
- }
5305
+ return chat(chatAgent, messages, {
5306
+ abortSignal: options?.abortSignal,
5307
+ generateTitle: options?.generateTitle,
5308
+ transform: this.#config.transform
5625
5309
  });
5626
5310
  }
5627
- #formatError(error) {
5628
- if (NoSuchToolError.isInstance(error)) {
5629
- return "The model tried to call an unknown tool.";
5630
- } else if (InvalidToolInputError.isInstance(error)) {
5631
- return "The model called a tool with invalid arguments.";
5632
- } else if (ToolCallRepairError.isInstance(error)) {
5633
- return "The model tried to call a tool with invalid arguments, but it was repaired.";
5634
- } else if (APICallError2.isInstance(error)) {
5635
- console.error("Upstream API call failed:", error);
5636
- return `Upstream API call failed with status ${error.statusCode}: ${error.message}`;
5637
- }
5638
- return JSON.stringify(error);
5639
- }
5640
5311
  };
5641
5312
  export {
5642
5313
  Adapter,
@@ -5646,17 +5317,20 @@ export {
5646
5317
  MssqlFs,
5647
5318
  Point,
5648
5319
  PostgresFs,
5320
+ SQLReadOnlyError,
5649
5321
  SQLScopeError,
5650
5322
  SQLValidationError,
5651
5323
  ScopedFs,
5324
+ SqlBacktickRewritePlugin,
5325
+ SqlProxyEnforcementPlugin,
5326
+ SqlProxyViolationError,
5652
5327
  SqliteFs,
5653
5328
  Text2Sql,
5654
- TrackedFs,
5655
5329
  UnanswerableSQLError,
5656
5330
  applyTablesFilter,
5657
5331
  column,
5658
5332
  constraint,
5659
- createResultTools,
5333
+ createSqlCommand,
5660
5334
  dialectInfo,
5661
5335
  filterRelationshipsByTables,
5662
5336
  filterTablesByName,
@@ -5664,11 +5338,14 @@ export {
5664
5338
  guidelines,
5665
5339
  hashConfig,
5666
5340
  index,
5341
+ isValidAdapterName,
5667
5342
  matchesFilter,
5668
5343
  relationship,
5344
+ sqlSandboxExtension,
5669
5345
  suggestionsAgent,
5670
5346
  table,
5671
5347
  toSql,
5348
+ validateAdapterNames,
5672
5349
  view
5673
5350
  };
5674
5351
  //# sourceMappingURL=index.js.map