@deepagents/text2sql 4.0.0 → 4.2.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/README.md +11 -1
- package/dist/bin/sql.js +43 -18
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +121 -54
- package/dist/index.js.map +4 -4
- package/dist/lib/sql-command.d.ts.map +1 -1
- package/dist/lib/sql-invocation.d.ts +15 -0
- package/dist/lib/sql-invocation.d.ts.map +1 -0
- package/dist/lib/sql-meta-hook.d.ts.map +1 -1
- package/dist/lib/sql-validate-reminder.d.ts +22 -0
- package/dist/lib/sql-validate-reminder.d.ts.map +1 -0
- package/dist/lib/sql.d.ts +25 -0
- package/dist/lib/sql.d.ts.map +1 -1
- package/package.json +10 -10
- package/dist/lib/resolve-adapter.d.ts +0 -14
- package/dist/lib/resolve-adapter.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -114,7 +114,11 @@ import {
|
|
|
114
114
|
npm,
|
|
115
115
|
user,
|
|
116
116
|
} from '@deepagents/context';
|
|
117
|
-
import {
|
|
117
|
+
import {
|
|
118
|
+
createSqlCommandHooks,
|
|
119
|
+
instructions,
|
|
120
|
+
sqlValidateReminder,
|
|
121
|
+
} from '@deepagents/text2sql';
|
|
118
122
|
|
|
119
123
|
const store = new InMemoryContextStore();
|
|
120
124
|
const context = new ContextEngine({
|
|
@@ -149,6 +153,7 @@ const fragments = JSON.parse(
|
|
|
149
153
|
await sandbox.sandbox.readFile(manifest.fragmentsPath),
|
|
150
154
|
) as ContextFragment[];
|
|
151
155
|
context.set(...instructions(), ...fragments);
|
|
156
|
+
context.set(sqlValidateReminder());
|
|
152
157
|
|
|
153
158
|
const ai = agent({
|
|
154
159
|
name: 'sql-assistant',
|
|
@@ -178,6 +183,11 @@ schema fragments returned by `sql index`. The index output starts with an
|
|
|
178
183
|
model must pass to `sql validate <db>` and `sql run <db>`. Add or replace the
|
|
179
184
|
instructions with your own domain fragments as needed.
|
|
180
185
|
|
|
186
|
+
`sqlValidateReminder()` returns a context reminder fragment backed by
|
|
187
|
+
`SQL_VALIDATE_REMINDER`. It adds a tool-output system reminder when the current
|
|
188
|
+
assistant turn calls `sql run <db> "..."` without a prior `sql validate <db>
|
|
189
|
+
"..."` for the same configured adapter name and exact SQL text.
|
|
190
|
+
|
|
181
191
|
## Advanced: SQL CLI in Sandboxes
|
|
182
192
|
|
|
183
193
|
`sql validate <db> "..."` and `sql run <db> "..."` are real commands from the
|
package/dist/bin/sql.js
CHANGED
|
@@ -896,6 +896,25 @@ var Text2SqlUnknownAdapterError = class _Text2SqlUnknownAdapterError extends Err
|
|
|
896
896
|
return error instanceof _Text2SqlUnknownAdapterError && error[text2SqlUnknownAdapterMarker] === true;
|
|
897
897
|
}
|
|
898
898
|
};
|
|
899
|
+
var text2SqlUnknownDatabaseMarker = Symbol("Text2SqlUnknownDatabaseError");
|
|
900
|
+
var Text2SqlUnknownDatabaseError = class _Text2SqlUnknownDatabaseError extends Error {
|
|
901
|
+
[text2SqlUnknownDatabaseMarker];
|
|
902
|
+
requested;
|
|
903
|
+
available;
|
|
904
|
+
constructor(requested, available) {
|
|
905
|
+
const list = available.join(", ") || "(none configured)";
|
|
906
|
+
super(
|
|
907
|
+
requested ? `unknown database "${requested}". Available: ${list}` : `no database specified. Available: ${list}`
|
|
908
|
+
);
|
|
909
|
+
this.name = "Text2SqlUnknownDatabaseError";
|
|
910
|
+
this.requested = requested;
|
|
911
|
+
this.available = available;
|
|
912
|
+
this[text2SqlUnknownDatabaseMarker] = true;
|
|
913
|
+
}
|
|
914
|
+
static isInstance(error) {
|
|
915
|
+
return error instanceof _Text2SqlUnknownDatabaseError && error[text2SqlUnknownDatabaseMarker] === true;
|
|
916
|
+
}
|
|
917
|
+
};
|
|
899
918
|
var Text2Sql = class {
|
|
900
919
|
#config;
|
|
901
920
|
#indexer;
|
|
@@ -932,6 +951,29 @@ var Text2Sql = class {
|
|
|
932
951
|
hasAdapter(name) {
|
|
933
952
|
return name in this.#config.adapters;
|
|
934
953
|
}
|
|
954
|
+
/**
|
|
955
|
+
* Resolve a user-supplied `<db>` token to a configured adapter name for the
|
|
956
|
+
* surfaces that accept one (CLI, sandbox `sql` command, JSON-RPC daemon, MCP):
|
|
957
|
+
* - exact match → that name
|
|
958
|
+
* - no match (or omitted) but exactly one adapter configured → route to it
|
|
959
|
+
* - otherwise → throw with the user-facing "unknown database" message
|
|
960
|
+
*
|
|
961
|
+
* Internal execution paths keep using the strict {@link Text2Sql.run}/
|
|
962
|
+
* {@link Text2Sql.validate}, which reject an unknown name outright.
|
|
963
|
+
*/
|
|
964
|
+
resolveAdapterName(db) {
|
|
965
|
+
if (!db || db.trim() === "") {
|
|
966
|
+
const names2 = this.adapterNames();
|
|
967
|
+
if (names2.length === 1) return names2[0];
|
|
968
|
+
throw new Text2SqlUnknownDatabaseError(db, names2);
|
|
969
|
+
}
|
|
970
|
+
if (this.hasAdapter(db)) {
|
|
971
|
+
return db;
|
|
972
|
+
}
|
|
973
|
+
const names = this.adapterNames();
|
|
974
|
+
if (names.length === 1) return names[0];
|
|
975
|
+
throw new Text2SqlUnknownDatabaseError(db, names);
|
|
976
|
+
}
|
|
935
977
|
async validate(name, sql) {
|
|
936
978
|
const adapter = this.#requireAdapter(name);
|
|
937
979
|
const result = this.#validateWith(adapter, sql);
|
|
@@ -980,17 +1022,6 @@ var Text2Sql = class {
|
|
|
980
1022
|
|
|
981
1023
|
// packages/text2sql/src/bin/command.ts
|
|
982
1024
|
import * as path3 from "node:path";
|
|
983
|
-
|
|
984
|
-
// packages/text2sql/src/lib/resolve-adapter.ts
|
|
985
|
-
function resolveAdapter(text2Sql, db) {
|
|
986
|
-
if (text2Sql.hasAdapter(db)) return db;
|
|
987
|
-
const names = text2Sql.adapterNames();
|
|
988
|
-
if (names.length === 1) return names[0];
|
|
989
|
-
const available = names.join(", ") || "(none configured)";
|
|
990
|
-
throw new Error(`unknown database "${db}". Available: ${available}`);
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
// packages/text2sql/src/bin/command.ts
|
|
994
1025
|
var OUT_DIR_OPTION = {
|
|
995
1026
|
flag: "--out-dir <path>",
|
|
996
1027
|
description: "Output directory (default: $TEXT2SQL_OUT_DIR or ./sql)"
|
|
@@ -1023,14 +1054,8 @@ var SqlCommand = class {
|
|
|
1023
1054
|
throw new CommandError(this.name, message, exitCode);
|
|
1024
1055
|
}
|
|
1025
1056
|
resolveAdapterName(text2Sql, db) {
|
|
1026
|
-
if (!db) {
|
|
1027
|
-
const available = text2Sql.adapterNames().join(", ") || "(none configured)";
|
|
1028
|
-
this.fail(
|
|
1029
|
-
`missing database name. Usage: sql ${this.name} ${this.usage}. Available: ${available}`
|
|
1030
|
-
);
|
|
1031
|
-
}
|
|
1032
1057
|
try {
|
|
1033
|
-
return
|
|
1058
|
+
return text2Sql.resolveAdapterName(db);
|
|
1034
1059
|
} catch (error) {
|
|
1035
1060
|
this.fail(errorMessage2(error));
|
|
1036
1061
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,5 +13,6 @@ export * from './lib/fs/index.ts';
|
|
|
13
13
|
export * from './lib/instructions.ts';
|
|
14
14
|
export * from './lib/sql-hooks.ts';
|
|
15
15
|
export { type CreateSqlCommandOptions, type CreateSqlCommandResult, createSqlCommand, } from './lib/sql-command.ts';
|
|
16
|
+
export { SQL_VALIDATE_REMINDER, sqlValidateReminder, } from './lib/sql-validate-reminder.ts';
|
|
16
17
|
export * from './lib/sql.ts';
|
|
17
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AACnD,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oCAAoC,CAAC;AACnD,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AACxC,cAAc,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4684,39 +4684,11 @@ Action: Ask user: "Top by what metric\u2014total revenue, number of orders, or m
|
|
|
4684
4684
|
}
|
|
4685
4685
|
|
|
4686
4686
|
// packages/text2sql/src/lib/sql-meta-hook.ts
|
|
4687
|
+
import { useBashMeta } from "@deepagents/context";
|
|
4688
|
+
|
|
4689
|
+
// packages/text2sql/src/lib/sql-invocation.ts
|
|
4687
4690
|
import { parse } from "just-bash";
|
|
4688
|
-
import { asStaticWordText
|
|
4689
|
-
var SQL_VALIDATE_REMINDER = 'Always run `sql validate <db> "..."` before `sql run <db> "..."` to catch syntax errors early.';
|
|
4690
|
-
function createSqlMetaHook({ adapters }) {
|
|
4691
|
-
const pendingByCommand = /* @__PURE__ */ new Map();
|
|
4692
|
-
return {
|
|
4693
|
-
track({ repaired, transformed }) {
|
|
4694
|
-
const invocation = parseSqlQueryInvocation(repaired);
|
|
4695
|
-
if (!invocation) return;
|
|
4696
|
-
const pending = pendingByCommand.get(transformed) ?? [];
|
|
4697
|
-
pending.push(invocation);
|
|
4698
|
-
pendingByCommand.set(transformed, pending);
|
|
4699
|
-
},
|
|
4700
|
-
onAfterBashCall({ command }) {
|
|
4701
|
-
const pending = pendingByCommand.get(command);
|
|
4702
|
-
const invocation = pending?.shift();
|
|
4703
|
-
if (pending?.length === 0) pendingByCommand.delete(command);
|
|
4704
|
-
if (!invocation) return void 0;
|
|
4705
|
-
if (invocation.subcommand === "run") {
|
|
4706
|
-
useBashMeta()?.setReminder(SQL_VALIDATE_REMINDER);
|
|
4707
|
-
}
|
|
4708
|
-
const adapter = adapters[invocation.dbName];
|
|
4709
|
-
if (!adapter) return void 0;
|
|
4710
|
-
try {
|
|
4711
|
-
useBashMeta()?.setHidden({
|
|
4712
|
-
formattedSql: adapter.format(invocation.sql)
|
|
4713
|
-
});
|
|
4714
|
-
} catch {
|
|
4715
|
-
}
|
|
4716
|
-
return void 0;
|
|
4717
|
-
}
|
|
4718
|
-
};
|
|
4719
|
-
}
|
|
4691
|
+
import { asStaticWordText } from "@deepagents/context";
|
|
4720
4692
|
function parseSqlQueryInvocation(command) {
|
|
4721
4693
|
const simpleCommand = parseSingleSimpleCommand(command);
|
|
4722
4694
|
if (!simpleCommand) return null;
|
|
@@ -4767,6 +4739,35 @@ function joinSqlWords(words) {
|
|
|
4767
4739
|
return sql || null;
|
|
4768
4740
|
}
|
|
4769
4741
|
|
|
4742
|
+
// packages/text2sql/src/lib/sql-meta-hook.ts
|
|
4743
|
+
function createSqlMetaHook({ adapters }) {
|
|
4744
|
+
const pendingByCommand = /* @__PURE__ */ new Map();
|
|
4745
|
+
return {
|
|
4746
|
+
track({ repaired, transformed }) {
|
|
4747
|
+
const invocation = parseSqlQueryInvocation(repaired);
|
|
4748
|
+
if (!invocation) return;
|
|
4749
|
+
const pending = pendingByCommand.get(transformed) ?? [];
|
|
4750
|
+
pending.push(invocation);
|
|
4751
|
+
pendingByCommand.set(transformed, pending);
|
|
4752
|
+
},
|
|
4753
|
+
onAfterBashCall({ command }) {
|
|
4754
|
+
const pending = pendingByCommand.get(command);
|
|
4755
|
+
const invocation = pending?.shift();
|
|
4756
|
+
if (pending?.length === 0) pendingByCommand.delete(command);
|
|
4757
|
+
if (!invocation) return void 0;
|
|
4758
|
+
const adapter = adapters[invocation.dbName];
|
|
4759
|
+
if (!adapter) return void 0;
|
|
4760
|
+
try {
|
|
4761
|
+
useBashMeta()?.setHidden({
|
|
4762
|
+
formattedSql: adapter.format(invocation.sql)
|
|
4763
|
+
});
|
|
4764
|
+
} catch {
|
|
4765
|
+
}
|
|
4766
|
+
return void 0;
|
|
4767
|
+
}
|
|
4768
|
+
};
|
|
4769
|
+
}
|
|
4770
|
+
|
|
4770
4771
|
// packages/text2sql/src/lib/sql-repair.ts
|
|
4771
4772
|
import {
|
|
4772
4773
|
buildSubcommandRepair,
|
|
@@ -5617,8 +5618,7 @@ import {
|
|
|
5617
5618
|
BashException as BashException2,
|
|
5618
5619
|
buildSubcommandRepair as buildSubcommandRepair2,
|
|
5619
5620
|
defineSubcommandGroup,
|
|
5620
|
-
repairQuotedArg as repairQuotedArg2
|
|
5621
|
-
useBashMeta as useBashMeta2
|
|
5621
|
+
repairQuotedArg as repairQuotedArg2
|
|
5622
5622
|
} from "@deepagents/context";
|
|
5623
5623
|
|
|
5624
5624
|
// packages/text2sql/src/lib/sql.ts
|
|
@@ -5652,6 +5652,25 @@ var Text2SqlUnknownAdapterError = class _Text2SqlUnknownAdapterError extends Err
|
|
|
5652
5652
|
return error instanceof _Text2SqlUnknownAdapterError && error[text2SqlUnknownAdapterMarker] === true;
|
|
5653
5653
|
}
|
|
5654
5654
|
};
|
|
5655
|
+
var text2SqlUnknownDatabaseMarker = Symbol("Text2SqlUnknownDatabaseError");
|
|
5656
|
+
var Text2SqlUnknownDatabaseError = class _Text2SqlUnknownDatabaseError extends Error {
|
|
5657
|
+
[text2SqlUnknownDatabaseMarker];
|
|
5658
|
+
requested;
|
|
5659
|
+
available;
|
|
5660
|
+
constructor(requested, available) {
|
|
5661
|
+
const list = available.join(", ") || "(none configured)";
|
|
5662
|
+
super(
|
|
5663
|
+
requested ? `unknown database "${requested}". Available: ${list}` : `no database specified. Available: ${list}`
|
|
5664
|
+
);
|
|
5665
|
+
this.name = "Text2SqlUnknownDatabaseError";
|
|
5666
|
+
this.requested = requested;
|
|
5667
|
+
this.available = available;
|
|
5668
|
+
this[text2SqlUnknownDatabaseMarker] = true;
|
|
5669
|
+
}
|
|
5670
|
+
static isInstance(error) {
|
|
5671
|
+
return error instanceof _Text2SqlUnknownDatabaseError && error[text2SqlUnknownDatabaseMarker] === true;
|
|
5672
|
+
}
|
|
5673
|
+
};
|
|
5655
5674
|
var Text2Sql = class {
|
|
5656
5675
|
#config;
|
|
5657
5676
|
#indexer;
|
|
@@ -5688,6 +5707,29 @@ var Text2Sql = class {
|
|
|
5688
5707
|
hasAdapter(name) {
|
|
5689
5708
|
return name in this.#config.adapters;
|
|
5690
5709
|
}
|
|
5710
|
+
/**
|
|
5711
|
+
* Resolve a user-supplied `<db>` token to a configured adapter name for the
|
|
5712
|
+
* surfaces that accept one (CLI, sandbox `sql` command, JSON-RPC daemon, MCP):
|
|
5713
|
+
* - exact match → that name
|
|
5714
|
+
* - no match (or omitted) but exactly one adapter configured → route to it
|
|
5715
|
+
* - otherwise → throw with the user-facing "unknown database" message
|
|
5716
|
+
*
|
|
5717
|
+
* Internal execution paths keep using the strict {@link Text2Sql.run}/
|
|
5718
|
+
* {@link Text2Sql.validate}, which reject an unknown name outright.
|
|
5719
|
+
*/
|
|
5720
|
+
resolveAdapterName(db) {
|
|
5721
|
+
if (!db || db.trim() === "") {
|
|
5722
|
+
const names2 = this.adapterNames();
|
|
5723
|
+
if (names2.length === 1) return names2[0];
|
|
5724
|
+
throw new Text2SqlUnknownDatabaseError(db, names2);
|
|
5725
|
+
}
|
|
5726
|
+
if (this.hasAdapter(db)) {
|
|
5727
|
+
return db;
|
|
5728
|
+
}
|
|
5729
|
+
const names = this.adapterNames();
|
|
5730
|
+
if (names.length === 1) return names[0];
|
|
5731
|
+
throw new Text2SqlUnknownDatabaseError(db, names);
|
|
5732
|
+
}
|
|
5691
5733
|
async validate(name, sql) {
|
|
5692
5734
|
const adapter = this.#requireAdapter(name);
|
|
5693
5735
|
const result = this.#validateWith(adapter, sql);
|
|
@@ -5734,17 +5776,7 @@ var Text2Sql = class {
|
|
|
5734
5776
|
}
|
|
5735
5777
|
};
|
|
5736
5778
|
|
|
5737
|
-
// packages/text2sql/src/lib/resolve-adapter.ts
|
|
5738
|
-
function resolveAdapter(text2Sql, db) {
|
|
5739
|
-
if (text2Sql.hasAdapter(db)) return db;
|
|
5740
|
-
const names = text2Sql.adapterNames();
|
|
5741
|
-
if (names.length === 1) return names[0];
|
|
5742
|
-
const available = names.join(", ") || "(none configured)";
|
|
5743
|
-
throw new Error(`unknown database "${db}". Available: ${available}`);
|
|
5744
|
-
}
|
|
5745
|
-
|
|
5746
5779
|
// packages/text2sql/src/lib/sql-command.ts
|
|
5747
|
-
var SQL_VALIDATE_REMINDER2 = 'Always run `sql validate <db> "..."` before `sql run <db> "..."` to catch syntax errors early.';
|
|
5748
5780
|
var SqlCommandError = class extends BashException2 {
|
|
5749
5781
|
#subcommand;
|
|
5750
5782
|
#exitCode;
|
|
@@ -5809,8 +5841,6 @@ function resolveOutputDir(ctx, flags, fallback) {
|
|
|
5809
5841
|
async function handleRun(text2Sql, defaultOutputDir, args, ctx) {
|
|
5810
5842
|
return runHandler("run", async () => {
|
|
5811
5843
|
const flags = parseFlags("run", args);
|
|
5812
|
-
const meta = useBashMeta2();
|
|
5813
|
-
meta?.setReminder(SQL_VALIDATE_REMINDER2);
|
|
5814
5844
|
const { name, sql } = takeDbAndSql("run", flags.positional, text2Sql);
|
|
5815
5845
|
const outputDir = resolveOutputDir(ctx, flags, defaultOutputDir);
|
|
5816
5846
|
const { rows, columns } = await text2Sql.run(name, sql);
|
|
@@ -5849,14 +5879,7 @@ async function runHandler(subcommand, fn) {
|
|
|
5849
5879
|
}
|
|
5850
5880
|
function takeDbAndSql(subcommand, positional, text2Sql) {
|
|
5851
5881
|
const [db, ...rest] = positional;
|
|
5852
|
-
|
|
5853
|
-
const available = text2Sql.adapterNames().join(", ");
|
|
5854
|
-
throw new SqlCommandError(
|
|
5855
|
-
subcommand,
|
|
5856
|
-
`missing database name. Usage: sql ${subcommand} <db> "SELECT ...". Available: ${available}`
|
|
5857
|
-
);
|
|
5858
|
-
}
|
|
5859
|
-
const name = resolveAdapter(text2Sql, db);
|
|
5882
|
+
const name = text2Sql.resolveAdapterName(db);
|
|
5860
5883
|
const sql = rest.join(" ").trim();
|
|
5861
5884
|
if (!sql) {
|
|
5862
5885
|
throw new SqlCommandError(subcommand, "no query provided");
|
|
@@ -5874,6 +5897,47 @@ function repairDbNameAndQuotedArg(rawArgs) {
|
|
|
5874
5897
|
if (repaired == null) return null;
|
|
5875
5898
|
return `${dbName} ${repaired}`;
|
|
5876
5899
|
}
|
|
5900
|
+
|
|
5901
|
+
// packages/text2sql/src/lib/sql-validate-reminder.ts
|
|
5902
|
+
import { isToolUIPart } from "ai";
|
|
5903
|
+
import { reminder } from "@deepagents/context";
|
|
5904
|
+
var SQL_VALIDATE_REMINDER = 'Always run `sql validate <db> "..."` before `sql run <db> "..."` to catch syntax errors early.';
|
|
5905
|
+
function extractSqlInvocation(command) {
|
|
5906
|
+
if (typeof command !== "string") return null;
|
|
5907
|
+
return parseSqlQueryInvocation(repairSqlCommand(command));
|
|
5908
|
+
}
|
|
5909
|
+
function inputCommand(input) {
|
|
5910
|
+
return input?.command;
|
|
5911
|
+
}
|
|
5912
|
+
function alreadyValidated(messages, run) {
|
|
5913
|
+
for (const message of messages ?? []) {
|
|
5914
|
+
for (const part of message.parts) {
|
|
5915
|
+
if (!isToolUIPart(part)) continue;
|
|
5916
|
+
const invocation = extractSqlInvocation(
|
|
5917
|
+
inputCommand(part.input)
|
|
5918
|
+
);
|
|
5919
|
+
if (invocation?.subcommand === "validate" && invocation.dbName === run.dbName && invocation.sql === run.sql) {
|
|
5920
|
+
return true;
|
|
5921
|
+
}
|
|
5922
|
+
}
|
|
5923
|
+
}
|
|
5924
|
+
return false;
|
|
5925
|
+
}
|
|
5926
|
+
function sqlRunMissingValidate() {
|
|
5927
|
+
return (ctx) => {
|
|
5928
|
+
const call = ctx.executingTool;
|
|
5929
|
+
if (!call || call.name !== "bash") return false;
|
|
5930
|
+
const run = extractSqlInvocation(inputCommand(call.input));
|
|
5931
|
+
if (run?.subcommand !== "run") return false;
|
|
5932
|
+
return !alreadyValidated(ctx.lastAssistantMessages, run);
|
|
5933
|
+
};
|
|
5934
|
+
}
|
|
5935
|
+
function sqlValidateReminder() {
|
|
5936
|
+
return reminder(SQL_VALIDATE_REMINDER, {
|
|
5937
|
+
target: "tool-output",
|
|
5938
|
+
when: sqlRunMissingValidate()
|
|
5939
|
+
});
|
|
5940
|
+
}
|
|
5877
5941
|
export {
|
|
5878
5942
|
Adapter,
|
|
5879
5943
|
AdapterIndexer,
|
|
@@ -5888,11 +5952,13 @@ export {
|
|
|
5888
5952
|
SQLReadOnlyError,
|
|
5889
5953
|
SQLScopeError,
|
|
5890
5954
|
SQLValidationError,
|
|
5955
|
+
SQL_VALIDATE_REMINDER,
|
|
5891
5956
|
ScopedFs,
|
|
5892
5957
|
SqliteFs,
|
|
5893
5958
|
TEXT2SQL_INDEX_PROGRESS_CHUNK,
|
|
5894
5959
|
Text2Sql,
|
|
5895
5960
|
Text2SqlUnknownAdapterError,
|
|
5961
|
+
Text2SqlUnknownDatabaseError,
|
|
5896
5962
|
Text2SqlValidationError,
|
|
5897
5963
|
UnanswerableSQLError,
|
|
5898
5964
|
applyTablesFilter,
|
|
@@ -5912,6 +5978,7 @@ export {
|
|
|
5912
5978
|
matchesFilter,
|
|
5913
5979
|
relationship,
|
|
5914
5980
|
repairSqlCommand,
|
|
5981
|
+
sqlValidateReminder,
|
|
5915
5982
|
suggestionsAgent,
|
|
5916
5983
|
table,
|
|
5917
5984
|
toSql,
|