@deepagents/text2sql 5.0.0 → 6.1.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.
- package/CLICKHOUSE-DEPLOYMENT.md +181 -0
- package/README.md +32 -4
- package/dist/bin/sql.js +34 -51
- package/dist/index.js +58 -289
- package/dist/index.js.map +4 -4
- package/dist/lib/adapters/adapter.d.ts +9 -2
- package/dist/lib/adapters/adapter.d.ts.map +1 -1
- package/dist/lib/adapters/bigquery/bigquery.d.ts.map +1 -1
- package/dist/lib/adapters/bigquery/bigquery.sql-policy.d.ts +9 -0
- package/dist/lib/adapters/bigquery/bigquery.sql-policy.d.ts.map +1 -0
- package/dist/lib/adapters/bigquery/index.d.ts +1 -0
- package/dist/lib/adapters/bigquery/index.d.ts.map +1 -1
- package/dist/lib/adapters/bigquery/index.js +305 -259
- package/dist/lib/adapters/bigquery/index.js.map +4 -4
- package/dist/lib/adapters/clickhouse/clickhouse.d.ts +22 -0
- package/dist/lib/adapters/clickhouse/clickhouse.d.ts.map +1 -0
- package/dist/lib/adapters/clickhouse/clickhouse.sql-policy.d.ts +8 -0
- package/dist/lib/adapters/clickhouse/clickhouse.sql-policy.d.ts.map +1 -0
- package/dist/lib/adapters/clickhouse/constraint.clickhouse.grounding.d.ts +8 -0
- package/dist/lib/adapters/clickhouse/constraint.clickhouse.grounding.d.ts.map +1 -0
- package/dist/lib/adapters/clickhouse/index.d.ts +33 -0
- package/dist/lib/adapters/clickhouse/index.d.ts.map +1 -0
- package/dist/lib/adapters/clickhouse/index.js +1546 -0
- package/dist/lib/adapters/clickhouse/index.js.map +7 -0
- package/dist/lib/adapters/clickhouse/indexes.clickhouse.grounding.d.ts +8 -0
- package/dist/lib/adapters/clickhouse/indexes.clickhouse.grounding.d.ts.map +1 -0
- package/dist/lib/adapters/clickhouse/info.clickhouse.grounding.d.ts +8 -0
- package/dist/lib/adapters/clickhouse/info.clickhouse.grounding.d.ts.map +1 -0
- package/dist/lib/adapters/clickhouse/row-count.clickhouse.grounding.d.ts +8 -0
- package/dist/lib/adapters/clickhouse/row-count.clickhouse.grounding.d.ts.map +1 -0
- package/dist/lib/adapters/clickhouse/table.clickhouse.grounding.d.ts +11 -0
- package/dist/lib/adapters/clickhouse/table.clickhouse.grounding.d.ts.map +1 -0
- package/dist/lib/adapters/clickhouse/view.clickhouse.grounding.d.ts +9 -0
- package/dist/lib/adapters/clickhouse/view.clickhouse.grounding.d.ts.map +1 -0
- package/dist/lib/adapters/groundings/abstract.grounding.d.ts +11 -16
- package/dist/lib/adapters/groundings/abstract.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/context.d.ts +3 -0
- package/dist/lib/adapters/groundings/context.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/index.js +17 -0
- package/dist/lib/adapters/groundings/index.js.map +2 -2
- package/dist/lib/adapters/groundings/table.grounding.d.ts +1 -0
- package/dist/lib/adapters/groundings/table.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/view.grounding.d.ts +1 -0
- package/dist/lib/adapters/groundings/view.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/mysql/index.d.ts +1 -0
- package/dist/lib/adapters/mysql/index.d.ts.map +1 -1
- package/dist/lib/adapters/mysql/index.js +319 -259
- package/dist/lib/adapters/mysql/index.js.map +4 -4
- package/dist/lib/adapters/mysql/mysql.d.ts.map +1 -1
- package/dist/lib/adapters/mysql/mysql.sql-policy.d.ts +11 -0
- package/dist/lib/adapters/mysql/mysql.sql-policy.d.ts.map +1 -0
- package/dist/lib/adapters/parser-sql-policy.d.ts +23 -0
- package/dist/lib/adapters/parser-sql-policy.d.ts.map +1 -0
- package/dist/lib/adapters/postgres/index.d.ts +1 -0
- package/dist/lib/adapters/postgres/index.d.ts.map +1 -1
- package/dist/lib/adapters/postgres/index.js +325 -259
- package/dist/lib/adapters/postgres/index.js.map +4 -4
- package/dist/lib/adapters/postgres/postgres.d.ts.map +1 -1
- package/dist/lib/adapters/postgres/postgres.sql-policy.d.ts +10 -0
- package/dist/lib/adapters/postgres/postgres.sql-policy.d.ts.map +1 -0
- package/dist/lib/adapters/posthog/definitions.posthog.grounding.d.ts +19 -0
- package/dist/lib/adapters/posthog/definitions.posthog.grounding.d.ts.map +1 -0
- package/dist/lib/adapters/posthog/index.d.ts +22 -0
- package/dist/lib/adapters/posthog/index.d.ts.map +1 -0
- package/dist/lib/adapters/posthog/index.js +1303 -0
- package/dist/lib/adapters/posthog/index.js.map +7 -0
- package/dist/lib/adapters/posthog/info.posthog.grounding.d.ts +7 -0
- package/dist/lib/adapters/posthog/info.posthog.grounding.d.ts.map +1 -0
- package/dist/lib/adapters/posthog/posthog.d.ts +23 -0
- package/dist/lib/adapters/posthog/posthog.d.ts.map +1 -0
- package/dist/lib/adapters/posthog/posthog.sql-policy.d.ts +8 -0
- package/dist/lib/adapters/posthog/posthog.sql-policy.d.ts.map +1 -0
- package/dist/lib/adapters/posthog/schema.posthog.grounding.d.ts +16 -0
- package/dist/lib/adapters/posthog/schema.posthog.grounding.d.ts.map +1 -0
- package/dist/lib/adapters/posthog/transport.d.ts +16 -0
- package/dist/lib/adapters/posthog/transport.d.ts.map +1 -0
- package/dist/lib/adapters/posthog/types.d.ts +95 -0
- package/dist/lib/adapters/posthog/types.d.ts.map +1 -0
- package/dist/lib/adapters/spreadsheet/index.js +303 -259
- package/dist/lib/adapters/spreadsheet/index.js.map +4 -4
- package/dist/lib/adapters/spreadsheet/parser.d.ts.map +1 -1
- package/dist/lib/adapters/sql-policy.d.ts +19 -0
- package/dist/lib/adapters/sql-policy.d.ts.map +1 -0
- package/dist/lib/adapters/sqlite/index.d.ts +1 -0
- package/dist/lib/adapters/sqlite/index.d.ts.map +1 -1
- package/dist/lib/adapters/sqlite/index.js +305 -259
- package/dist/lib/adapters/sqlite/index.js.map +4 -4
- package/dist/lib/adapters/sqlite/sqlite.d.ts.map +1 -1
- package/dist/lib/adapters/sqlite/sqlite.sql-policy.d.ts +8 -0
- package/dist/lib/adapters/sqlite/sqlite.sql-policy.d.ts.map +1 -0
- package/dist/lib/adapters/sqlserver/index.d.ts +1 -0
- package/dist/lib/adapters/sqlserver/index.d.ts.map +1 -1
- package/dist/lib/adapters/sqlserver/index.js +312 -259
- package/dist/lib/adapters/sqlserver/index.js.map +4 -4
- package/dist/lib/adapters/sqlserver/sqlserver.d.ts.map +1 -1
- package/dist/lib/adapters/sqlserver/sqlserver.sql-policy.d.ts +11 -0
- package/dist/lib/adapters/sqlserver/sqlserver.sql-policy.d.ts.map +1 -0
- package/dist/lib/agents/exceptions.d.ts +1 -1
- package/dist/lib/agents/sql.agent.d.ts.map +1 -1
- package/dist/lib/sql-scope-error.d.ts +3 -0
- package/dist/lib/sql-scope-error.d.ts.map +1 -0
- package/dist/lib/synthesis/index.js +32 -38
- package/dist/lib/synthesis/index.js.map +4 -4
- package/package.json +35 -23
- package/dist/lib/adapters/runtime-scope.d.ts +0 -16
- package/dist/lib/adapters/runtime-scope.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -22,10 +22,10 @@ function validateAdapterNames(names) {
|
|
|
22
22
|
import { format as formatSql } from "sql-formatter";
|
|
23
23
|
|
|
24
24
|
// packages/text2sql/src/lib/agents/exceptions.ts
|
|
25
|
-
var sqlValidationMarker = Symbol("SQLValidationError");
|
|
26
|
-
var unanswerableSqlMarker = Symbol("UnanswerableSQLError");
|
|
27
|
-
var sqlScopeMarker = Symbol("SQLScopeError");
|
|
28
|
-
var sqlReadOnlyMarker = Symbol("SQLReadOnlyError");
|
|
25
|
+
var sqlValidationMarker = /* @__PURE__ */ Symbol("SQLValidationError");
|
|
26
|
+
var unanswerableSqlMarker = /* @__PURE__ */ Symbol("UnanswerableSQLError");
|
|
27
|
+
var sqlScopeMarker = /* @__PURE__ */ Symbol("SQLScopeError");
|
|
28
|
+
var sqlReadOnlyMarker = /* @__PURE__ */ Symbol("SQLReadOnlyError");
|
|
29
29
|
var SQLValidationError = class _SQLValidationError extends Error {
|
|
30
30
|
[sqlValidationMarker];
|
|
31
31
|
constructor(message) {
|
|
@@ -185,164 +185,21 @@ function createGroundingContext(options = {}) {
|
|
|
185
185
|
views: [],
|
|
186
186
|
relationships: [],
|
|
187
187
|
info: void 0,
|
|
188
|
+
fragments: [],
|
|
188
189
|
cache: /* @__PURE__ */ new Map(),
|
|
189
190
|
onProgress: timestampProgress(options.onProgress)
|
|
190
191
|
};
|
|
191
192
|
}
|
|
192
193
|
|
|
193
|
-
// packages/text2sql/src/lib/adapters/runtime-scope.ts
|
|
194
|
-
import nodeSqlParser from "node-sql-parser";
|
|
195
|
-
var { Parser } = nodeSqlParser;
|
|
196
|
-
var parser = new Parser();
|
|
197
|
-
function parseStatementTypes(sql, dialect) {
|
|
198
|
-
const ast = parser.astify(sql, { database: dialect });
|
|
199
|
-
const statements = Array.isArray(ast) ? ast : [ast];
|
|
200
|
-
return statements.flatMap(
|
|
201
|
-
(statement) => isAstLike(statement) && typeof statement.type === "string" ? [statement.type] : []
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
function extractBaseEntityReferences(sql, dialect) {
|
|
205
|
-
const ast = parser.astify(sql, { database: dialect });
|
|
206
|
-
const state = {
|
|
207
|
-
cteNames: /* @__PURE__ */ new Set(),
|
|
208
|
-
references: /* @__PURE__ */ new Map()
|
|
209
|
-
};
|
|
210
|
-
visitNode(ast, state);
|
|
211
|
-
return Array.from(state.references.values());
|
|
212
|
-
}
|
|
213
|
-
function buildOutOfScopePayload(sql, referencedEntities, allowedEntities) {
|
|
214
|
-
return {
|
|
215
|
-
error: `Query references entities outside grounded scope: ${referencedEntities.join(", ")}`,
|
|
216
|
-
error_type: "OUT_OF_SCOPE",
|
|
217
|
-
suggestion: "Restrict the query to grounded tables/views or expand grounding to include the referenced entities.",
|
|
218
|
-
sql_attempted: sql,
|
|
219
|
-
referenced_entities: referencedEntities,
|
|
220
|
-
allowed_entities: allowedEntities
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
function buildScopeParseErrorPayload(sql, dialect, error) {
|
|
224
|
-
const parserError = error instanceof Error ? error.message : String(error ?? "Unknown error");
|
|
225
|
-
return {
|
|
226
|
-
error: `SQL scope analysis failed before validation/execution: ${parserError}`,
|
|
227
|
-
error_type: "SQL_SCOPE_PARSE_ERROR",
|
|
228
|
-
suggestion: "Rewrite the query into simpler SQL that can be analyzed safely, or extend parser coverage for this dialect feature.",
|
|
229
|
-
sql_attempted: sql,
|
|
230
|
-
parser_dialect: dialect,
|
|
231
|
-
parser_error: parserError
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
function visitNode(node, state) {
|
|
235
|
-
if (Array.isArray(node)) {
|
|
236
|
-
for (const item of node) {
|
|
237
|
-
visitNode(item, state);
|
|
238
|
-
}
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
if (!isAstLike(node)) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
if (isStatementNode(node)) {
|
|
245
|
-
visitStatement(node, state);
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
if (isTableReferenceNode(node)) {
|
|
249
|
-
addReference(node, state);
|
|
250
|
-
}
|
|
251
|
-
for (const value of Object.values(node)) {
|
|
252
|
-
visitNode(value, state);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
function visitStatement(node, parentState) {
|
|
256
|
-
const localState = {
|
|
257
|
-
cteNames: new Set(parentState.cteNames),
|
|
258
|
-
references: parentState.references
|
|
259
|
-
};
|
|
260
|
-
const withItems = Array.isArray(node.with) ? node.with : [];
|
|
261
|
-
for (const item of withItems) {
|
|
262
|
-
if (!isAstLike(item)) {
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
const cteName = readCteName(item);
|
|
266
|
-
if (cteName) {
|
|
267
|
-
localState.cteNames.add(caseFold(cteName));
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
for (const item of withItems) {
|
|
271
|
-
if (!isAstLike(item)) {
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
visitNode(item.stmt, localState);
|
|
275
|
-
}
|
|
276
|
-
for (const [key, value] of Object.entries(node)) {
|
|
277
|
-
if (key === "with") {
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
visitNode(value, localState);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
function addReference(node, state) {
|
|
284
|
-
const table2 = typeof node.table === "string" ? node.table : null;
|
|
285
|
-
if (!table2) {
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
if (state.cteNames.has(caseFold(table2))) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
const db = typeof node.db === "string" ? node.db : null;
|
|
292
|
-
const key = db ? `${db}.${table2}` : table2;
|
|
293
|
-
if (!state.references.has(key)) {
|
|
294
|
-
state.references.set(key, { db, table: table2 });
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
function readCteName(node) {
|
|
298
|
-
const name = node.name;
|
|
299
|
-
if (typeof name === "string") {
|
|
300
|
-
return name;
|
|
301
|
-
}
|
|
302
|
-
if (!isAstLike(name)) {
|
|
303
|
-
return void 0;
|
|
304
|
-
}
|
|
305
|
-
const value = name.value;
|
|
306
|
-
return typeof value === "string" ? value : void 0;
|
|
307
|
-
}
|
|
308
|
-
function isStatementNode(node) {
|
|
309
|
-
const type = node.type;
|
|
310
|
-
return typeof type === "string" && ["delete", "insert", "replace", "select", "update"].includes(type);
|
|
311
|
-
}
|
|
312
|
-
function isTableReferenceNode(node) {
|
|
313
|
-
if (node.type === "column_ref") {
|
|
314
|
-
return false;
|
|
315
|
-
}
|
|
316
|
-
if (typeof node.table !== "string") {
|
|
317
|
-
return false;
|
|
318
|
-
}
|
|
319
|
-
return "addition" in node || "as" in node || "db" in node || "join" in node || "operator" in node || "surround" in node || "table_hint" in node || "temporal_table" in node;
|
|
320
|
-
}
|
|
321
|
-
function isAstLike(value) {
|
|
322
|
-
return typeof value === "object" && value !== null;
|
|
323
|
-
}
|
|
324
|
-
function caseFold(value) {
|
|
325
|
-
return value.toLowerCase();
|
|
326
|
-
}
|
|
327
|
-
|
|
328
194
|
// packages/text2sql/src/lib/adapters/adapter.ts
|
|
329
|
-
var PARSER_DIALECTS_BY_FORMATTER_LANGUAGE = {
|
|
330
|
-
sqlite: ["sqlite", "mysql"],
|
|
331
|
-
postgresql: ["postgresql"],
|
|
332
|
-
bigquery: ["bigquery"],
|
|
333
|
-
transactsql: ["transactsql"],
|
|
334
|
-
mysql: ["mysql"]
|
|
335
|
-
};
|
|
336
|
-
function parserDialectsFor(formatterLanguage) {
|
|
337
|
-
const candidates = PARSER_DIALECTS_BY_FORMATTER_LANGUAGE[formatterLanguage];
|
|
338
|
-
if (!candidates) {
|
|
339
|
-
throw new TypeError(
|
|
340
|
-
`No scope dialect mapping for formatter language "${formatterLanguage}". Add it to PARSER_DIALECTS_BY_FORMATTER_LANGUAGE in adapter.ts.`
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
return candidates;
|
|
344
|
-
}
|
|
345
195
|
var Adapter = class {
|
|
196
|
+
#policyAnalyzer;
|
|
197
|
+
/**
|
|
198
|
+
* Injects the strategy that guards validate() and execute().
|
|
199
|
+
*/
|
|
200
|
+
constructor(policyAnalyzer) {
|
|
201
|
+
this.#policyAnalyzer = policyAnalyzer;
|
|
202
|
+
}
|
|
346
203
|
/**
|
|
347
204
|
* Introspect the database schema and return context fragments.
|
|
348
205
|
*
|
|
@@ -378,14 +235,14 @@ var Adapter = class {
|
|
|
378
235
|
}
|
|
379
236
|
/**
|
|
380
237
|
* Resolve the allowed entity names (tables + views) from grounding config.
|
|
381
|
-
*
|
|
238
|
+
* Asks each grounding to contribute its entities; annotators contribute
|
|
239
|
+
* nothing, so their metadata scans are skipped.
|
|
382
240
|
* Results are NOT cached — call once and store the result.
|
|
383
241
|
*/
|
|
384
242
|
async resolveAllowedEntities() {
|
|
385
243
|
const ctx = createGroundingContext();
|
|
386
244
|
for (const fn of this.grounding) {
|
|
387
|
-
|
|
388
|
-
await grounding.execute(ctx);
|
|
245
|
+
await fn(this).contributeEntities(ctx);
|
|
389
246
|
}
|
|
390
247
|
return [...ctx.tables.map((t) => t.name), ...ctx.views.map((v) => v.name)];
|
|
391
248
|
}
|
|
@@ -430,6 +287,7 @@ var Adapter = class {
|
|
|
430
287
|
this.#relationshipToFragment(rel, sourceTable, targetTable)
|
|
431
288
|
);
|
|
432
289
|
}
|
|
290
|
+
fragments.push(...ctx.fragments ?? []);
|
|
433
291
|
return fragments;
|
|
434
292
|
}
|
|
435
293
|
/**
|
|
@@ -562,120 +420,33 @@ var Adapter = class {
|
|
|
562
420
|
#decodeShellEscapes(sql) {
|
|
563
421
|
return sql.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\([().*])/g, "$1").replace(/\\(?=$)/gm, "");
|
|
564
422
|
}
|
|
565
|
-
#checkReadOnly(sql) {
|
|
566
|
-
const statementTypes = this.#readParsedStatementTypes(sql);
|
|
567
|
-
if (statementTypes) {
|
|
568
|
-
if (statementTypes.length === 1 && statementTypes[0] === "select") {
|
|
569
|
-
return null;
|
|
570
|
-
}
|
|
571
|
-
return "only SELECT or WITH queries allowed";
|
|
572
|
-
}
|
|
573
|
-
const keyword = this.#firstStatementKeyword(sql);
|
|
574
|
-
if (keyword === "SELECT" || keyword === "WITH") return null;
|
|
575
|
-
return "only SELECT or WITH queries allowed";
|
|
576
|
-
}
|
|
577
|
-
#readParsedStatementTypes(sql) {
|
|
578
|
-
for (const dialect of parserDialectsFor(this.formatterLanguage)) {
|
|
579
|
-
try {
|
|
580
|
-
return parseStatementTypes(sql, dialect);
|
|
581
|
-
} catch {
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
return null;
|
|
585
|
-
}
|
|
586
|
-
#firstStatementKeyword(sql) {
|
|
587
|
-
let offset = 0;
|
|
588
|
-
while (offset < sql.length) {
|
|
589
|
-
if (/\s/.test(sql[offset])) {
|
|
590
|
-
offset++;
|
|
591
|
-
continue;
|
|
592
|
-
}
|
|
593
|
-
if (sql.startsWith("--", offset)) {
|
|
594
|
-
offset += 2;
|
|
595
|
-
while (offset < sql.length && sql[offset] !== "\n" && sql[offset] !== "\r") {
|
|
596
|
-
offset++;
|
|
597
|
-
}
|
|
598
|
-
continue;
|
|
599
|
-
}
|
|
600
|
-
if (sql.startsWith("/*", offset)) {
|
|
601
|
-
const commentEnd = sql.indexOf("*/", offset + 2);
|
|
602
|
-
if (commentEnd === -1) return null;
|
|
603
|
-
offset = commentEnd + 2;
|
|
604
|
-
continue;
|
|
605
|
-
}
|
|
606
|
-
const keyword = /^[A-Za-z]+/.exec(sql.slice(offset));
|
|
607
|
-
return keyword ? keyword[0].toUpperCase() : null;
|
|
608
|
-
}
|
|
609
|
-
return null;
|
|
610
|
-
}
|
|
611
423
|
#cachedAllowedEntities = null;
|
|
612
424
|
async #resolveScope() {
|
|
613
425
|
if (this.#cachedAllowedEntities) return this.#cachedAllowedEntities;
|
|
614
426
|
this.#cachedAllowedEntities = await this.resolveAllowedEntities();
|
|
615
427
|
return this.#cachedAllowedEntities;
|
|
616
428
|
}
|
|
617
|
-
async #
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
let lastError;
|
|
621
|
-
let lastDialect = candidates[0];
|
|
622
|
-
for (const candidate of candidates) {
|
|
623
|
-
try {
|
|
624
|
-
references = extractBaseEntityReferences(sql, candidate);
|
|
625
|
-
break;
|
|
626
|
-
} catch (error) {
|
|
627
|
-
lastDialect = candidate;
|
|
628
|
-
lastError = error;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
if (references === null) {
|
|
632
|
-
return buildScopeParseErrorPayload(sql, lastDialect, lastError);
|
|
633
|
-
}
|
|
634
|
-
if (references.length === 0) return null;
|
|
635
|
-
const allowedQualified = new Set(
|
|
636
|
-
allowedEntities.map((e) => e.toLowerCase())
|
|
637
|
-
);
|
|
638
|
-
const allowedUnqualified = /* @__PURE__ */ new Set();
|
|
639
|
-
for (const entity of allowedEntities) {
|
|
640
|
-
const dot = entity.lastIndexOf(".");
|
|
641
|
-
if (dot !== -1) {
|
|
642
|
-
allowedUnqualified.add(entity.slice(dot + 1).toLowerCase());
|
|
643
|
-
} else {
|
|
644
|
-
allowedUnqualified.add(entity.toLowerCase());
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
const outOfScope = references.map((ref) => ref.db ? `${ref.db}.${ref.table}` : ref.table).filter((name) => {
|
|
648
|
-
const lower = name.toLowerCase();
|
|
649
|
-
if (name.includes(".")) {
|
|
650
|
-
if (allowedQualified.has(lower)) return false;
|
|
651
|
-
const parts = lower.split(".");
|
|
652
|
-
if (parts.length >= 3) {
|
|
653
|
-
const datasetTable = parts.slice(-2).join(".");
|
|
654
|
-
if (allowedQualified.has(datasetTable)) return false;
|
|
655
|
-
}
|
|
656
|
-
return true;
|
|
657
|
-
}
|
|
658
|
-
return !allowedQualified.has(lower) && !allowedUnqualified.has(lower);
|
|
429
|
+
async #analyzePolicy(sql) {
|
|
430
|
+
return this.#policyAnalyzer.analyze(sql, {
|
|
431
|
+
resolveAllowedEntities: () => this.#resolveScope()
|
|
659
432
|
});
|
|
660
|
-
if (outOfScope.length === 0) return null;
|
|
661
|
-
return buildOutOfScopePayload(sql, outOfScope, allowedEntities);
|
|
662
433
|
}
|
|
663
434
|
async validate(sql) {
|
|
664
435
|
const decoded = this.#decodeShellEscapes(sql);
|
|
665
|
-
const
|
|
666
|
-
if (
|
|
667
|
-
|
|
668
|
-
const scopeError = await this.#checkScope(decoded, allowed);
|
|
669
|
-
if (scopeError) return JSON.stringify(scopeError);
|
|
436
|
+
const violation = await this.#analyzePolicy(decoded);
|
|
437
|
+
if (violation?.kind === "read-only") return violation.message;
|
|
438
|
+
if (violation?.kind === "scope") return JSON.stringify(violation.payload);
|
|
670
439
|
return this.validateImpl(decoded);
|
|
671
440
|
}
|
|
672
441
|
async execute(sql) {
|
|
673
442
|
const decoded = this.#decodeShellEscapes(sql);
|
|
674
|
-
const
|
|
675
|
-
if (
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
if (
|
|
443
|
+
const violation = await this.#analyzePolicy(decoded);
|
|
444
|
+
if (violation?.kind === "read-only") {
|
|
445
|
+
throw new SQLReadOnlyError(violation.message);
|
|
446
|
+
}
|
|
447
|
+
if (violation?.kind === "scope") {
|
|
448
|
+
throw new SQLScopeError(violation.payload);
|
|
449
|
+
}
|
|
679
450
|
return this.executeImpl(decoded);
|
|
680
451
|
}
|
|
681
452
|
/**
|
|
@@ -827,16 +598,24 @@ import {
|
|
|
827
598
|
user,
|
|
828
599
|
workflow
|
|
829
600
|
} from "@deepagents/context";
|
|
601
|
+
|
|
602
|
+
// packages/text2sql/src/lib/sql-scope-error.ts
|
|
603
|
+
function buildScopeParseErrorPayload(sql, parserDialect, error) {
|
|
604
|
+
const parserError = error instanceof Error ? error.message : String(error ?? "Unknown error");
|
|
605
|
+
return {
|
|
606
|
+
error: `SQL scope analysis failed before validation/execution: ${parserError}`,
|
|
607
|
+
error_type: "SQL_SCOPE_PARSE_ERROR",
|
|
608
|
+
suggestion: "Rewrite the query into simpler SQL that can be analyzed safely, or extend parser coverage for this dialect feature.",
|
|
609
|
+
sql_attempted: sql,
|
|
610
|
+
parser_dialect: parserDialect,
|
|
611
|
+
parser_error: parserError
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// packages/text2sql/src/lib/agents/sql.agent.ts
|
|
830
616
|
var RETRY_TEMPERATURES = [0, 0.2, 0.3];
|
|
831
617
|
var SQL_AGENT_ROLE = "Expert SQL query generator.";
|
|
832
618
|
var SQL_AGENT_OBJECTIVE = "Generate precise SQL grounded in provided schema.";
|
|
833
|
-
var FORMATTER_SCOPE_DIALECTS = /* @__PURE__ */ new Map([
|
|
834
|
-
["sqlite", "sqlite"],
|
|
835
|
-
["postgresql", "postgresql"],
|
|
836
|
-
["bigquery", "bigquery"],
|
|
837
|
-
["transactsql", "transactsql"],
|
|
838
|
-
["mysql", "mysql"]
|
|
839
|
-
]);
|
|
840
619
|
var SQL_AGENT_POLICIES = [
|
|
841
620
|
fragment(
|
|
842
621
|
"schema_mapping",
|
|
@@ -1042,26 +821,6 @@ function extractSql(output) {
|
|
|
1042
821
|
const match = output.match(/```sql\n?([\s\S]*?)```/);
|
|
1043
822
|
return match ? match[1].trim() : output.trim();
|
|
1044
823
|
}
|
|
1045
|
-
function scopeDialectFor(adapter) {
|
|
1046
|
-
const dialect = FORMATTER_SCOPE_DIALECTS.get(adapter.formatterLanguage);
|
|
1047
|
-
if (!dialect) {
|
|
1048
|
-
throw new TypeError(
|
|
1049
|
-
`No scope dialect mapping for formatter language "${adapter.formatterLanguage}".`
|
|
1050
|
-
);
|
|
1051
|
-
}
|
|
1052
|
-
return dialect;
|
|
1053
|
-
}
|
|
1054
|
-
function fencedMarkdownParseError(sql, adapter) {
|
|
1055
|
-
return new SQLValidationError(
|
|
1056
|
-
JSON.stringify(
|
|
1057
|
-
buildScopeParseErrorPayload(
|
|
1058
|
-
sql,
|
|
1059
|
-
scopeDialectFor(adapter),
|
|
1060
|
-
new Error("SQL response was fenced markdown, not executable SQL.")
|
|
1061
|
-
)
|
|
1062
|
-
)
|
|
1063
|
-
);
|
|
1064
|
-
}
|
|
1065
824
|
async function toSql(options) {
|
|
1066
825
|
const { maxRetries = 3 } = options;
|
|
1067
826
|
return withRetry(
|
|
@@ -1143,7 +902,17 @@ Question: ${options.input}
|
|
|
1143
902
|
}
|
|
1144
903
|
const sql = options.adapter.format(extractedSql);
|
|
1145
904
|
if (rawSql.trimStart().startsWith("```") && extractedSql === rawSql.trim()) {
|
|
1146
|
-
throw
|
|
905
|
+
throw new SQLValidationError(
|
|
906
|
+
JSON.stringify(
|
|
907
|
+
buildScopeParseErrorPayload(
|
|
908
|
+
sql,
|
|
909
|
+
options.adapter.formatterLanguage,
|
|
910
|
+
new Error(
|
|
911
|
+
"SQL response was fenced markdown, not executable SQL."
|
|
912
|
+
)
|
|
913
|
+
)
|
|
914
|
+
)
|
|
915
|
+
);
|
|
1147
916
|
}
|
|
1148
917
|
const validationError = await options.adapter.validate(sql);
|
|
1149
918
|
if (validationError) {
|
|
@@ -5623,8 +5392,8 @@ import {
|
|
|
5623
5392
|
|
|
5624
5393
|
// packages/text2sql/src/lib/sql.ts
|
|
5625
5394
|
import "@deepagents/agent";
|
|
5626
|
-
var text2SqlValidationMarker = Symbol("Text2SqlValidationError");
|
|
5627
|
-
var text2SqlUnknownAdapterMarker = Symbol("Text2SqlUnknownAdapterError");
|
|
5395
|
+
var text2SqlValidationMarker = /* @__PURE__ */ Symbol("Text2SqlValidationError");
|
|
5396
|
+
var text2SqlUnknownAdapterMarker = /* @__PURE__ */ Symbol("Text2SqlUnknownAdapterError");
|
|
5628
5397
|
var Text2SqlValidationError = class _Text2SqlValidationError extends Error {
|
|
5629
5398
|
[text2SqlValidationMarker];
|
|
5630
5399
|
constructor(message) {
|
|
@@ -5652,7 +5421,7 @@ var Text2SqlUnknownAdapterError = class _Text2SqlUnknownAdapterError extends Err
|
|
|
5652
5421
|
return error instanceof _Text2SqlUnknownAdapterError && error[text2SqlUnknownAdapterMarker] === true;
|
|
5653
5422
|
}
|
|
5654
5423
|
};
|
|
5655
|
-
var text2SqlUnknownDatabaseMarker = Symbol("Text2SqlUnknownDatabaseError");
|
|
5424
|
+
var text2SqlUnknownDatabaseMarker = /* @__PURE__ */ Symbol("Text2SqlUnknownDatabaseError");
|
|
5656
5425
|
var Text2SqlUnknownDatabaseError = class _Text2SqlUnknownDatabaseError extends Error {
|
|
5657
5426
|
[text2SqlUnknownDatabaseMarker];
|
|
5658
5427
|
requested;
|