@deepagents/text2sql 0.13.1 → 0.14.0

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 (32) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1060 -218
  4. package/dist/index.js.map +4 -4
  5. package/dist/lib/adapters/groundings/index.js +166 -154
  6. package/dist/lib/adapters/groundings/index.js.map +4 -4
  7. package/dist/lib/adapters/mysql/index.js +166 -154
  8. package/dist/lib/adapters/mysql/index.js.map +4 -4
  9. package/dist/lib/adapters/postgres/index.js +168 -155
  10. package/dist/lib/adapters/postgres/index.js.map +4 -4
  11. package/dist/lib/adapters/postgres/info.postgres.grounding.d.ts.map +1 -1
  12. package/dist/lib/adapters/spreadsheet/index.js +22 -2
  13. package/dist/lib/adapters/spreadsheet/index.js.map +4 -4
  14. package/dist/lib/adapters/sqlite/index.js +166 -154
  15. package/dist/lib/adapters/sqlite/index.js.map +4 -4
  16. package/dist/lib/adapters/sqlserver/index.js +166 -154
  17. package/dist/lib/adapters/sqlserver/index.js.map +4 -4
  18. package/dist/lib/agents/result-tools.d.ts +20 -23
  19. package/dist/lib/agents/result-tools.d.ts.map +1 -1
  20. package/dist/lib/fs/index.d.ts +4 -0
  21. package/dist/lib/fs/index.d.ts.map +1 -0
  22. package/dist/lib/fs/scoped-fs.d.ts +53 -0
  23. package/dist/lib/fs/scoped-fs.d.ts.map +1 -0
  24. package/dist/lib/fs/sqlite-fs.d.ts +66 -0
  25. package/dist/lib/fs/sqlite-fs.d.ts.map +1 -0
  26. package/dist/lib/fs/tracked-fs.d.ts +40 -0
  27. package/dist/lib/fs/tracked-fs.d.ts.map +1 -0
  28. package/dist/lib/sql.d.ts +3 -4
  29. package/dist/lib/sql.d.ts.map +1 -1
  30. package/dist/lib/synthesis/index.js +181 -181
  31. package/dist/lib/synthesis/index.js.map +4 -4
  32. package/package.json +5 -5
@@ -554,7 +554,7 @@ var ColumnValuesGrounding = class extends AbstractGrounding {
554
554
  // packages/text2sql/src/lib/adapters/groundings/report.grounding.ts
555
555
  import { groq as groq2 } from "@ai-sdk/groq";
556
556
  import { tool } from "ai";
557
- import dedent from "dedent";
557
+ import dedent2 from "dedent";
558
558
  import z from "zod";
559
559
  import "@deepagents/agent";
560
560
 
@@ -572,6 +572,7 @@ import spawn2 from "nano-spawn";
572
572
  import {
573
573
  createBashTool
574
574
  } from "bash-tool";
575
+ import dedent from "dedent";
575
576
  import YAML from "yaml";
576
577
  import { DatabaseSync } from "node:sqlite";
577
578
  import { groq } from "@ai-sdk/groq";
@@ -793,7 +794,7 @@ function assistantText(content, options) {
793
794
  parts: [{ type: "text", text: content }]
794
795
  });
795
796
  }
796
- var LAZY_ID = Symbol("lazy-id");
797
+ var LAZY_ID = Symbol.for("@deepagents/context:lazy-id");
797
798
  function isLazyFragment(fragment2) {
798
799
  return LAZY_ID in fragment2;
799
800
  }
@@ -1180,7 +1181,7 @@ var ContextEngine = class {
1180
1181
  async #createBranchFrom(messageId, switchTo) {
1181
1182
  const branches = await this.#store.listBranches(this.#chatId);
1182
1183
  const samePrefix = branches.filter(
1183
- (b) => b.name === this.#branchName || b.name.startsWith(`${this.#branchName}-v`)
1184
+ (it) => it.name === this.#branchName || it.name.startsWith(`${this.#branchName}-v`)
1184
1185
  );
1185
1186
  const newBranchName = `${this.#branchName}-v${samePrefix.length + 1}`;
1186
1187
  const newBranch = {
@@ -1208,6 +1209,15 @@ var ContextEngine = class {
1208
1209
  createdAt: newBranch.createdAt
1209
1210
  };
1210
1211
  }
1212
+ /**
1213
+ * Rewind to a message without clearing pending messages.
1214
+ * Used internally when saving an update to an existing message.
1215
+ */
1216
+ async #rewindForUpdate(messageId) {
1217
+ const pendingBackup = [...this.#pendingMessages];
1218
+ await this.rewind(messageId);
1219
+ this.#pendingMessages = pendingBackup;
1220
+ }
1211
1221
  /**
1212
1222
  * Get the current chat ID.
1213
1223
  */
@@ -1292,7 +1302,18 @@ var ContextEngine = class {
1292
1302
  messages.push(message(msg.data).codec?.decode());
1293
1303
  }
1294
1304
  }
1305
+ for (let i = 0; i < this.#pendingMessages.length; i++) {
1306
+ const fragment2 = this.#pendingMessages[i];
1307
+ if (isLazyFragment(fragment2)) {
1308
+ this.#pendingMessages[i] = await this.#resolveLazyFragment(fragment2);
1309
+ }
1310
+ }
1295
1311
  for (const fragment2 of this.#pendingMessages) {
1312
+ if (!fragment2.codec) {
1313
+ throw new Error(
1314
+ `Fragment "${fragment2.name}" is missing codec. Lazy fragments must be resolved before decode.`
1315
+ );
1316
+ }
1296
1317
  const decoded = fragment2.codec.decode();
1297
1318
  messages.push(decoded);
1298
1319
  }
@@ -1323,9 +1344,24 @@ var ContextEngine = class {
1323
1344
  this.#pendingMessages[i] = await this.#resolveLazyFragment(fragment2);
1324
1345
  }
1325
1346
  }
1347
+ for (const fragment2 of this.#pendingMessages) {
1348
+ if (fragment2.id) {
1349
+ const existing = await this.#store.getMessage(fragment2.id);
1350
+ if (existing && existing.parentId) {
1351
+ await this.#rewindForUpdate(existing.parentId);
1352
+ fragment2.id = crypto.randomUUID();
1353
+ break;
1354
+ }
1355
+ }
1356
+ }
1326
1357
  let parentId = this.#branch.headMessageId;
1327
1358
  const now = Date.now();
1328
1359
  for (const fragment2 of this.#pendingMessages) {
1360
+ if (!fragment2.codec) {
1361
+ throw new Error(
1362
+ `Fragment "${fragment2.name}" is missing codec. Lazy fragments must be resolved before encode.`
1363
+ );
1364
+ }
1329
1365
  const messageData = {
1330
1366
  id: fragment2.id ?? crypto.randomUUID(),
1331
1367
  chatId: this.#chatId,
@@ -1685,33 +1721,28 @@ var ContextEngine = class {
1685
1721
  return void 0;
1686
1722
  }
1687
1723
  /**
1688
- * Extract skill path mappings from available_skills fragments.
1689
- * Returns array of { host, sandbox } for mounting in sandbox filesystem.
1690
- *
1691
- * Reads the original `paths` configuration stored in fragment metadata
1692
- * by the skills() fragment helper.
1724
+ * Extract skill mounts from available_skills fragments.
1725
+ * Returns unified mount array where entries with `name` are individual skills.
1693
1726
  *
1694
1727
  * @example
1695
1728
  * ```ts
1696
1729
  * const context = new ContextEngine({ store, chatId, userId })
1697
1730
  * .set(skills({ paths: [{ host: './skills', sandbox: '/skills' }] }));
1698
1731
  *
1699
- * const mounts = context.getSkillMounts();
1700
- * // [{ host: './skills', sandbox: '/skills' }]
1732
+ * const { mounts } = context.getSkillMounts();
1733
+ * // mounts: [{ name: 'bi-dashboards', host: './skills/bi-dashboards/SKILL.md', sandbox: '/skills/bi-dashboards/SKILL.md' }]
1734
+ *
1735
+ * // Extract skills only (entries with name)
1736
+ * const skills = mounts.filter(m => m.name);
1701
1737
  * ```
1702
1738
  */
1703
1739
  getSkillMounts() {
1704
- const mounts = [];
1705
1740
  for (const fragment2 of this.#fragments) {
1706
- if (fragment2.name === "available_skills" && fragment2.metadata && Array.isArray(fragment2.metadata.paths)) {
1707
- for (const mapping of fragment2.metadata.paths) {
1708
- if (typeof mapping === "object" && mapping !== null && typeof mapping.host === "string" && typeof mapping.sandbox === "string") {
1709
- mounts.push({ host: mapping.host, sandbox: mapping.sandbox });
1710
- }
1711
- }
1741
+ if (fragment2.name === "available_skills" && fragment2.metadata?.mounts) {
1742
+ return { mounts: fragment2.metadata.mounts };
1712
1743
  }
1713
1744
  }
1714
- return mounts;
1745
+ return { mounts: [] };
1715
1746
  }
1716
1747
  /**
1717
1748
  * Inspect the full context state for debugging.
@@ -1780,91 +1811,53 @@ function runGuardrailChain(part, guardrails, context) {
1780
1811
  let currentPart = part;
1781
1812
  for (const guardrail2 of guardrails) {
1782
1813
  const result = guardrail2.handle(currentPart, context);
1783
- if (result.type === "fail") {
1814
+ if (result.type === "fail" || result.type === "stop") {
1784
1815
  return result;
1785
1816
  }
1786
1817
  currentPart = result.part;
1787
1818
  }
1788
1819
  return pass(currentPart);
1789
1820
  }
1790
- var STORE_DDL = `
1791
- -- Chats table
1792
- -- createdAt/updatedAt: DEFAULT for insert, inline SET for updates
1793
- CREATE TABLE IF NOT EXISTS chats (
1794
- id TEXT PRIMARY KEY,
1795
- userId TEXT NOT NULL,
1796
- title TEXT,
1797
- metadata TEXT,
1798
- createdAt INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),
1799
- updatedAt INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000)
1800
- );
1801
-
1802
- CREATE INDEX IF NOT EXISTS idx_chats_updatedAt ON chats(updatedAt);
1803
- CREATE INDEX IF NOT EXISTS idx_chats_userId ON chats(userId);
1804
-
1805
- -- Messages table (nodes in the DAG)
1806
- CREATE TABLE IF NOT EXISTS messages (
1807
- id TEXT PRIMARY KEY,
1808
- chatId TEXT NOT NULL,
1809
- parentId TEXT,
1810
- name TEXT NOT NULL,
1811
- type TEXT,
1812
- data TEXT NOT NULL,
1813
- createdAt INTEGER NOT NULL,
1814
- FOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADE,
1815
- FOREIGN KEY (parentId) REFERENCES messages(id)
1816
- );
1817
-
1818
- CREATE INDEX IF NOT EXISTS idx_messages_chatId ON messages(chatId);
1819
- CREATE INDEX IF NOT EXISTS idx_messages_parentId ON messages(parentId);
1820
-
1821
- -- Branches table (pointers to head messages)
1822
- CREATE TABLE IF NOT EXISTS branches (
1823
- id TEXT PRIMARY KEY,
1824
- chatId TEXT NOT NULL,
1825
- name TEXT NOT NULL,
1826
- headMessageId TEXT,
1827
- isActive INTEGER NOT NULL DEFAULT 0,
1828
- createdAt INTEGER NOT NULL,
1829
- FOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADE,
1830
- FOREIGN KEY (headMessageId) REFERENCES messages(id),
1831
- UNIQUE(chatId, name)
1832
- );
1833
-
1834
- CREATE INDEX IF NOT EXISTS idx_branches_chatId ON branches(chatId);
1821
+ var SKILLS_INSTRUCTIONS = dedent`A skill is a set of local instructions to follow that is stored in a \`SKILL.md\` file. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.
1835
1822
 
1836
- -- Checkpoints table (pointers to message nodes)
1837
- CREATE TABLE IF NOT EXISTS checkpoints (
1838
- id TEXT PRIMARY KEY,
1839
- chatId TEXT NOT NULL,
1840
- name TEXT NOT NULL,
1841
- messageId TEXT NOT NULL,
1842
- createdAt INTEGER NOT NULL,
1843
- FOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADE,
1844
- FOREIGN KEY (messageId) REFERENCES messages(id),
1845
- UNIQUE(chatId, name)
1846
- );
1847
-
1848
- CREATE INDEX IF NOT EXISTS idx_checkpoints_chatId ON checkpoints(chatId);
1849
-
1850
- -- FTS5 virtual table for full-text search
1851
- -- messageId/chatId/name are UNINDEXED (stored but not searchable, used for filtering/joining)
1852
- -- Only 'content' is indexed for full-text search
1853
- CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(
1854
- messageId UNINDEXED,
1855
- chatId UNINDEXED,
1856
- name UNINDEXED,
1857
- content,
1858
- tokenize='porter unicode61'
1859
- );
1860
- `;
1823
+ ### How to use skills
1824
+ - Discovery: The list below shows the skills available in this session (name + description + file path). Skill bodies live on disk at the listed paths.
1825
+ - Trigger rules: If the user names a skill (with \`$SkillName\` or plain text) OR the task clearly matches a skill's description shown below, you must use that skill for that turn before doing anything else. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned.
1826
+ - Missing/blocked: If a named skill isn't in the list or the path can't be read, say so briefly and continue with the best fallback.
1827
+ - How to use a skill (progressive disclosure):
1828
+ 1) After deciding to use a skill, open its \`SKILL.md\`. Read only enough to follow the workflow.
1829
+ 2) If \`SKILL.md\` points to extra folders such as \`references/\`, load only the specific files needed for the request; don't bulk-load everything.
1830
+ 3) If \`scripts/\` exist, prefer running or patching them instead of retyping large code blocks.
1831
+ 4) If \`assets/\` or templates exist, reuse them instead of recreating from scratch.
1832
+ - Coordination and sequencing:
1833
+ - If multiple skills apply, choose the minimal set that covers the request and state the order you'll use them.
1834
+ - Announce which skill(s) you're using and why (one short line). If you skip an obvious skill, say why.
1835
+ - Context hygiene:
1836
+ - Keep context small: summarize long sections instead of pasting them; only load extra files when needed.
1837
+ - Avoid deep reference-chasing: prefer opening only files directly linked from \`SKILL.md\` unless you're blocked.
1838
+ - When variants exist (frameworks, providers, domains), pick only the relevant reference file(s) and note that choice.
1839
+ - Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), state the issue, pick the next-best approach, and continue.`;
1840
+ var ddl_sqlite_default = "-- Context Store DDL for SQLite\n-- This schema implements a DAG-based message history with branching and checkpoints.\n\n-- Performance PRAGMAs (session-level, run on each connection)\nPRAGMA journal_mode = WAL;\nPRAGMA synchronous = NORMAL;\nPRAGMA cache_size = -64000;\nPRAGMA temp_store = MEMORY;\nPRAGMA mmap_size = 268435456;\n\n-- Integrity\nPRAGMA foreign_keys = ON;\n\n-- Chats table\n-- createdAt/updatedAt: DEFAULT for insert, inline SET for updates\nCREATE TABLE IF NOT EXISTS chats (\n id TEXT PRIMARY KEY,\n userId TEXT NOT NULL,\n title TEXT,\n metadata TEXT,\n createdAt INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n updatedAt INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000)\n);\n\nCREATE INDEX IF NOT EXISTS idx_chats_updatedAt ON chats(updatedAt);\nCREATE INDEX IF NOT EXISTS idx_chats_userId ON chats(userId);\n-- Composite index for listChats(): WHERE userId = ? ORDER BY updatedAt DESC\nCREATE INDEX IF NOT EXISTS idx_chats_userId_updatedAt ON chats(userId, updatedAt DESC);\n\n-- Messages table (nodes in the DAG)\nCREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n chatId TEXT NOT NULL,\n parentId TEXT,\n name TEXT NOT NULL,\n type TEXT,\n data TEXT NOT NULL,\n createdAt INTEGER NOT NULL,\n FOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADE,\n FOREIGN KEY (parentId) REFERENCES messages(id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_messages_chatId ON messages(chatId);\nCREATE INDEX IF NOT EXISTS idx_messages_parentId ON messages(parentId);\n-- Composite index for recursive CTE parent traversal in getMessageChain()\nCREATE INDEX IF NOT EXISTS idx_messages_chatId_parentId ON messages(chatId, parentId);\n\n-- Branches table (pointers to head messages)\nCREATE TABLE IF NOT EXISTS branches (\n id TEXT PRIMARY KEY,\n chatId TEXT NOT NULL,\n name TEXT NOT NULL,\n headMessageId TEXT,\n isActive INTEGER NOT NULL DEFAULT 0,\n createdAt INTEGER NOT NULL,\n FOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADE,\n FOREIGN KEY (headMessageId) REFERENCES messages(id),\n UNIQUE(chatId, name)\n);\n\nCREATE INDEX IF NOT EXISTS idx_branches_chatId ON branches(chatId);\n-- Composite index for getActiveBranch(): WHERE chatId = ? AND isActive = 1\nCREATE INDEX IF NOT EXISTS idx_branches_chatId_isActive ON branches(chatId, isActive);\n\n-- Checkpoints table (pointers to message nodes)\nCREATE TABLE IF NOT EXISTS checkpoints (\n id TEXT PRIMARY KEY,\n chatId TEXT NOT NULL,\n name TEXT NOT NULL,\n messageId TEXT NOT NULL,\n createdAt INTEGER NOT NULL,\n FOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADE,\n FOREIGN KEY (messageId) REFERENCES messages(id),\n UNIQUE(chatId, name)\n);\n\nCREATE INDEX IF NOT EXISTS idx_checkpoints_chatId ON checkpoints(chatId);\n\n-- FTS5 virtual table for full-text search\n-- messageId/chatId/name are UNINDEXED (stored but not searchable, used for filtering/joining)\n-- Only 'content' is indexed for full-text search\nCREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(\n messageId UNINDEXED,\n chatId UNINDEXED,\n name UNINDEXED,\n content,\n tokenize='porter unicode61'\n);\n";
1861
1841
  var SqliteContextStore = class extends ContextStore {
1862
1842
  #db;
1843
+ #statements = /* @__PURE__ */ new Map();
1844
+ /**
1845
+ * Get or create a prepared statement.
1846
+ * Statements are cached for the lifetime of the store to avoid
1847
+ * repeated SQL parsing and compilation overhead.
1848
+ */
1849
+ #stmt(sql) {
1850
+ let stmt = this.#statements.get(sql);
1851
+ if (!stmt) {
1852
+ stmt = this.#db.prepare(sql);
1853
+ this.#statements.set(sql, stmt);
1854
+ }
1855
+ return stmt;
1856
+ }
1863
1857
  constructor(path3) {
1864
1858
  super();
1865
1859
  this.#db = new DatabaseSync(path3);
1866
- this.#db.exec("PRAGMA foreign_keys = ON");
1867
- this.#db.exec(STORE_DDL);
1860
+ this.#db.exec(ddl_sqlite_default);
1868
1861
  }
1869
1862
  /**
1870
1863
  * Execute a function within a transaction.
@@ -1885,11 +1878,12 @@ var SqliteContextStore = class extends ContextStore {
1885
1878
  // Chat Operations
1886
1879
  // ==========================================================================
1887
1880
  async createChat(chat) {
1888
- this.#useTransaction(() => {
1889
- this.#db.prepare(
1881
+ return this.#useTransaction(() => {
1882
+ const row = this.#db.prepare(
1890
1883
  `INSERT INTO chats (id, userId, title, metadata)
1891
- VALUES (?, ?, ?, ?)`
1892
- ).run(
1884
+ VALUES (?, ?, ?, ?)
1885
+ RETURNING *`
1886
+ ).get(
1893
1887
  chat.id,
1894
1888
  chat.userId,
1895
1889
  chat.title ?? null,
@@ -1899,6 +1893,14 @@ var SqliteContextStore = class extends ContextStore {
1899
1893
  `INSERT INTO branches (id, chatId, name, headMessageId, isActive, createdAt)
1900
1894
  VALUES (?, ?, 'main', NULL, 1, ?)`
1901
1895
  ).run(crypto.randomUUID(), chat.id, Date.now());
1896
+ return {
1897
+ id: row.id,
1898
+ userId: row.userId,
1899
+ title: row.title ?? void 0,
1900
+ metadata: row.metadata ? JSON.parse(row.metadata) : void 0,
1901
+ createdAt: row.createdAt,
1902
+ updatedAt: row.updatedAt
1903
+ };
1902
1904
  });
1903
1905
  }
1904
1906
  async upsertChat(chat) {
@@ -2041,21 +2043,16 @@ var SqliteContextStore = class extends ContextStore {
2041
2043
  // Message Operations (Graph Nodes)
2042
2044
  // ==========================================================================
2043
2045
  async addMessage(message2) {
2044
- this.#db.prepare(
2046
+ if (message2.parentId === message2.id) {
2047
+ throw new Error(`Message ${message2.id} cannot be its own parent`);
2048
+ }
2049
+ this.#stmt(
2045
2050
  `INSERT INTO messages (id, chatId, parentId, name, type, data, createdAt)
2046
- VALUES (
2047
- ?1,
2048
- ?2,
2049
- CASE WHEN ?3 = ?1 THEN (SELECT parentId FROM messages WHERE id = ?1) ELSE ?3 END,
2050
- ?4,
2051
- ?5,
2052
- ?6,
2053
- ?7
2054
- )
2055
- ON CONFLICT(id) DO UPDATE SET
2056
- name = excluded.name,
2057
- type = excluded.type,
2058
- data = excluded.data`
2051
+ VALUES (?, ?, ?, ?, ?, ?, ?)
2052
+ ON CONFLICT(id) DO UPDATE SET
2053
+ name = excluded.name,
2054
+ type = excluded.type,
2055
+ data = excluded.data`
2059
2056
  ).run(
2060
2057
  message2.id,
2061
2058
  message2.chatId,
@@ -2066,14 +2063,16 @@ var SqliteContextStore = class extends ContextStore {
2066
2063
  message2.createdAt
2067
2064
  );
2068
2065
  const content = typeof message2.data === "string" ? message2.data : JSON.stringify(message2.data);
2069
- this.#db.prepare(`DELETE FROM messages_fts WHERE messageId = ?`).run(message2.id);
2070
- this.#db.prepare(
2066
+ this.#stmt(`DELETE FROM messages_fts WHERE messageId = ?`).run(message2.id);
2067
+ this.#stmt(
2071
2068
  `INSERT INTO messages_fts(messageId, chatId, name, content)
2072
- VALUES (?, ?, ?, ?)`
2069
+ VALUES (?, ?, ?, ?)`
2073
2070
  ).run(message2.id, message2.chatId, message2.name, content);
2074
2071
  }
2075
2072
  async getMessage(messageId) {
2076
- const row = this.#db.prepare("SELECT * FROM messages WHERE id = ?").get(messageId);
2073
+ const row = this.#stmt("SELECT * FROM messages WHERE id = ?").get(
2074
+ messageId
2075
+ );
2077
2076
  if (!row) {
2078
2077
  return void 0;
2079
2078
  }
@@ -2088,15 +2087,16 @@ var SqliteContextStore = class extends ContextStore {
2088
2087
  };
2089
2088
  }
2090
2089
  async getMessageChain(headId) {
2091
- const rows = this.#db.prepare(
2090
+ const rows = this.#stmt(
2092
2091
  `WITH RECURSIVE chain AS (
2093
- SELECT *, 0 as depth FROM messages WHERE id = ?
2094
- UNION ALL
2095
- SELECT m.*, c.depth + 1 FROM messages m
2096
- INNER JOIN chain c ON m.id = c.parentId
2097
- )
2098
- SELECT * FROM chain
2099
- ORDER BY depth DESC`
2092
+ SELECT *, 0 as depth FROM messages WHERE id = ?
2093
+ UNION ALL
2094
+ SELECT m.*, c.depth + 1 FROM messages m
2095
+ INNER JOIN chain c ON m.id = c.parentId
2096
+ WHERE c.depth < 100000
2097
+ )
2098
+ SELECT * FROM chain
2099
+ ORDER BY depth DESC`
2100
2100
  ).all(headId);
2101
2101
  return rows.map((row) => ({
2102
2102
  id: row.id,
@@ -2109,7 +2109,7 @@ var SqliteContextStore = class extends ContextStore {
2109
2109
  }));
2110
2110
  }
2111
2111
  async hasChildren(messageId) {
2112
- const row = this.#db.prepare(
2112
+ const row = this.#stmt(
2113
2113
  "SELECT EXISTS(SELECT 1 FROM messages WHERE parentId = ?) as hasChildren"
2114
2114
  ).get(messageId);
2115
2115
  return row.hasChildren === 1;
@@ -2156,7 +2156,9 @@ var SqliteContextStore = class extends ContextStore {
2156
2156
  };
2157
2157
  }
2158
2158
  async getActiveBranch(chatId) {
2159
- const row = this.#db.prepare("SELECT * FROM branches WHERE chatId = ? AND isActive = 1").get(chatId);
2159
+ const row = this.#stmt(
2160
+ "SELECT * FROM branches WHERE chatId = ? AND isActive = 1"
2161
+ ).get(chatId);
2160
2162
  if (!row) {
2161
2163
  return void 0;
2162
2164
  }
@@ -2174,45 +2176,43 @@ var SqliteContextStore = class extends ContextStore {
2174
2176
  this.#db.prepare("UPDATE branches SET isActive = 1 WHERE id = ?").run(branchId);
2175
2177
  }
2176
2178
  async updateBranchHead(branchId, messageId) {
2177
- this.#db.prepare("UPDATE branches SET headMessageId = ? WHERE id = ?").run(messageId, branchId);
2179
+ this.#stmt("UPDATE branches SET headMessageId = ? WHERE id = ?").run(
2180
+ messageId,
2181
+ branchId
2182
+ );
2178
2183
  }
2179
2184
  async listBranches(chatId) {
2180
- const branches = this.#db.prepare(
2185
+ const rows = this.#db.prepare(
2181
2186
  `SELECT
2182
2187
  b.id,
2183
2188
  b.name,
2184
2189
  b.headMessageId,
2185
2190
  b.isActive,
2186
- b.createdAt
2191
+ b.createdAt,
2192
+ COALESCE(
2193
+ (
2194
+ WITH RECURSIVE chain AS (
2195
+ SELECT id, parentId FROM messages WHERE id = b.headMessageId
2196
+ UNION ALL
2197
+ SELECT m.id, m.parentId FROM messages m
2198
+ INNER JOIN chain c ON m.id = c.parentId
2199
+ )
2200
+ SELECT COUNT(*) FROM chain
2201
+ ),
2202
+ 0
2203
+ ) as messageCount
2187
2204
  FROM branches b
2188
2205
  WHERE b.chatId = ?
2189
2206
  ORDER BY b.createdAt ASC`
2190
2207
  ).all(chatId);
2191
- const result = [];
2192
- for (const branch of branches) {
2193
- let messageCount = 0;
2194
- if (branch.headMessageId) {
2195
- const countRow = this.#db.prepare(
2196
- `WITH RECURSIVE chain AS (
2197
- SELECT id, parentId FROM messages WHERE id = ?
2198
- UNION ALL
2199
- SELECT m.id, m.parentId FROM messages m
2200
- INNER JOIN chain c ON m.id = c.parentId
2201
- )
2202
- SELECT COUNT(*) as count FROM chain`
2203
- ).get(branch.headMessageId);
2204
- messageCount = countRow.count;
2205
- }
2206
- result.push({
2207
- id: branch.id,
2208
- name: branch.name,
2209
- headMessageId: branch.headMessageId,
2210
- isActive: branch.isActive === 1,
2211
- messageCount,
2212
- createdAt: branch.createdAt
2213
- });
2214
- }
2215
- return result;
2208
+ return rows.map((row) => ({
2209
+ id: row.id,
2210
+ name: row.name,
2211
+ headMessageId: row.headMessageId,
2212
+ isActive: row.isActive === 1,
2213
+ messageCount: row.messageCount,
2214
+ createdAt: row.createdAt
2215
+ }));
2216
2216
  }
2217
2217
  // ==========================================================================
2218
2218
  // Checkpoint Operations
@@ -2480,8 +2480,10 @@ var Agent = class _Agent {
2480
2480
  execute: async ({ writer }) => {
2481
2481
  let currentResult = result;
2482
2482
  let attempt = 0;
2483
+ const { mounts } = context.getSkillMounts();
2483
2484
  const guardrailContext = {
2484
- availableTools: Object.keys(this.tools)
2485
+ availableTools: Object.keys(this.tools),
2486
+ availableSkills: mounts
2485
2487
  };
2486
2488
  while (attempt < maxRetries) {
2487
2489
  if (config?.abortSignal?.aborted) {
@@ -2509,10 +2511,20 @@ var Agent = class _Agent {
2509
2511
  );
2510
2512
  break;
2511
2513
  }
2514
+ if (checkResult.type === "stop") {
2515
+ console.log(
2516
+ chalk2.red(
2517
+ `[${this.#options.name}] Guardrail stopped - unrecoverable error, no retry`
2518
+ )
2519
+ );
2520
+ writer.write(part);
2521
+ writer.write({ type: "finish" });
2522
+ return;
2523
+ }
2512
2524
  if (checkResult.part.type === "text-delta") {
2513
2525
  accumulatedText += checkResult.part.delta;
2514
2526
  }
2515
- writer.write(checkResult.part);
2527
+ writer.write(part);
2516
2528
  }
2517
2529
  if (!guardrailFailed) {
2518
2530
  writer.write({ type: "finish" });
@@ -2640,7 +2652,7 @@ var ReportGrounding = class extends AbstractGrounding {
2640
2652
  }),
2641
2653
  fragment(
2642
2654
  "instructions",
2643
- dedent`
2655
+ dedent2`
2644
2656
  Write a business context that helps another agent answer questions accurately.
2645
2657
 
2646
2658
  For EACH table, do queries ONE AT A TIME:
@@ -3061,7 +3073,8 @@ var PostgresInfoGrounding = class extends InfoGrounding {
3061
3073
  version: versionRows[0]?.version,
3062
3074
  database: dbRows[0]?.db,
3063
3075
  details: {
3064
- parameterPlaceholder: "$1, $2, $3, ..."
3076
+ parameterPlaceholder: "$1, $2, $3, ...",
3077
+ identifierQuoting: 'PostgreSQL lowercases unquoted identifiers. To preserve mixed-case names, wrap table and column names in double quotes: SELECT "columnName" FROM "TableName"'
3065
3078
  }
3066
3079
  };
3067
3080
  }