@deepagents/text2sql 0.37.0 → 0.38.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 +10 -1
- package/dist/index.js +159 -40
- package/dist/index.js.map +2 -2
- package/dist/lib/adapters/adapter.d.ts +4 -4
- package/dist/lib/adapters/adapter.d.ts.map +1 -1
- package/dist/lib/adapters/bigquery/constraint.bigquery.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/bigquery/index.js +160 -31
- package/dist/lib/adapters/bigquery/index.js.map +3 -3
- package/dist/lib/adapters/bigquery/indexes.bigquery.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/bigquery/row-count.bigquery.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/abstract.grounding.d.ts +3 -1
- package/dist/lib/adapters/groundings/abstract.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/column-stats.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/column-values.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/constraint.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/context.d.ts +6 -2
- package/dist/lib/adapters/groundings/context.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/index.js +96 -20
- package/dist/lib/adapters/groundings/index.js.map +2 -2
- package/dist/lib/adapters/groundings/indexes.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/row-count.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/table.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/groundings/view.grounding.d.ts.map +1 -1
- package/dist/lib/adapters/mysql/index.js +145 -35
- package/dist/lib/adapters/mysql/index.js.map +3 -3
- package/dist/lib/adapters/postgres/index.js +151 -35
- package/dist/lib/adapters/postgres/index.js.map +3 -3
- package/dist/lib/adapters/postgres/postgres.d.ts.map +1 -1
- package/dist/lib/adapters/spreadsheet/index.js +109 -27
- package/dist/lib/adapters/spreadsheet/index.js.map +3 -3
- package/dist/lib/adapters/sqlite/index.js +145 -35
- package/dist/lib/adapters/sqlite/index.js.map +3 -3
- package/dist/lib/adapters/sqlserver/index.js +151 -35
- package/dist/lib/adapters/sqlserver/index.js.map +3 -3
- package/dist/lib/adapters/sqlserver/sqlserver.d.ts.map +1 -1
- package/dist/lib/sql.d.ts +14 -2
- package/dist/lib/sql.d.ts.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -100,6 +100,11 @@ The adapter-map key (`main` here) is the adapter name. Reuse that same key in
|
|
|
100
100
|
`text2sql.toSql(..., 'main')` and in any `sql validate <db> "..."` /
|
|
101
101
|
`sql run <db> "..."` sandbox calls.
|
|
102
102
|
|
|
103
|
+
Adapter names must match `/^[A-Za-z_][A-Za-z0-9_]*$/`. If you build adapter
|
|
104
|
+
maps dynamically, use `isValidAdapterName(name)` to check one key or
|
|
105
|
+
`validateAdapterNames(names)` to fail fast before constructing `Text2Sql` or
|
|
106
|
+
`sqlSandboxExtension`.
|
|
107
|
+
|
|
103
108
|
## AI Model Providers
|
|
104
109
|
|
|
105
110
|
Text2SQL works with any model provider supported by the [Vercel AI SDK](https://sdk.vercel.ai/docs), including OpenAI, Anthropic, Google, Groq, and more.
|
|
@@ -111,7 +116,8 @@ returns a `SandboxExtension` that bundles the `sql` subcommand, transform
|
|
|
111
116
|
plugins, and arg-repair hook. In the simplest case, that map is
|
|
112
117
|
`{ main: adapter }`. Compose it (alongside any of your own extensions) via
|
|
113
118
|
`createBashTool` + `createRoutingSandbox` + `createVirtualSandbox`.
|
|
114
|
-
See [
|
|
119
|
+
See [Caller-Owned Sandbox](https://januarylabs.github.io/deepagents/docs/text2sql/sqlv3)
|
|
120
|
+
for composition patterns.
|
|
115
121
|
|
|
116
122
|
## Fragments
|
|
117
123
|
|
|
@@ -203,6 +209,9 @@ write messages, titles, or usage into your context store.
|
|
|
203
209
|
|
|
204
210
|
## Direct SQL Generation with Extra Fragments
|
|
205
211
|
|
|
212
|
+
This lower-level helper still takes a single `adapter` because it bypasses the
|
|
213
|
+
multi-adapter `Text2Sql` wrapper entirely.
|
|
214
|
+
|
|
206
215
|
```typescript
|
|
207
216
|
import { term } from '@deepagents/context';
|
|
208
217
|
import { toSql } from '@deepagents/text2sql';
|
package/dist/index.js
CHANGED
|
@@ -163,13 +163,14 @@ function relationship(input) {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
// packages/text2sql/src/lib/adapters/groundings/context.ts
|
|
166
|
-
function createGroundingContext() {
|
|
166
|
+
function createGroundingContext(options = {}) {
|
|
167
167
|
return {
|
|
168
168
|
tables: [],
|
|
169
169
|
views: [],
|
|
170
170
|
relationships: [],
|
|
171
171
|
info: void 0,
|
|
172
|
-
cache: /* @__PURE__ */ new Map()
|
|
172
|
+
cache: /* @__PURE__ */ new Map(),
|
|
173
|
+
onProgress: options.onProgress
|
|
173
174
|
};
|
|
174
175
|
}
|
|
175
176
|
|
|
@@ -315,7 +316,24 @@ var Adapter = class {
|
|
|
315
316
|
async introspect(ctx = createGroundingContext()) {
|
|
316
317
|
for (const fn of this.grounding) {
|
|
317
318
|
const grounding = fn(this);
|
|
318
|
-
|
|
319
|
+
if (grounding.phase) {
|
|
320
|
+
ctx.onProgress?.({
|
|
321
|
+
type: "phase:start",
|
|
322
|
+
phase: grounding.phase,
|
|
323
|
+
message: `Starting ${grounding.name} introspection...`
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
await grounding.execute(ctx);
|
|
328
|
+
} finally {
|
|
329
|
+
if (grounding.phase) {
|
|
330
|
+
ctx.onProgress?.({
|
|
331
|
+
type: "phase:end",
|
|
332
|
+
phase: grounding.phase,
|
|
333
|
+
message: `Finished ${grounding.name} introspection.`
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
319
337
|
}
|
|
320
338
|
return this.#toSchemaFragments(ctx);
|
|
321
339
|
}
|
|
@@ -521,26 +539,33 @@ var Adapter = class {
|
|
|
521
539
|
async #checkScope(sql, allowedEntities) {
|
|
522
540
|
const dialect = this.formatterLanguage;
|
|
523
541
|
const scopeDialects = {
|
|
524
|
-
sqlite: "mysql",
|
|
525
|
-
postgresql: "postgresql",
|
|
526
|
-
bigquery: "bigquery",
|
|
527
|
-
transactsql: "transactsql",
|
|
528
|
-
mysql: "mysql"
|
|
542
|
+
sqlite: ["sqlite", "mysql"],
|
|
543
|
+
postgresql: ["postgresql"],
|
|
544
|
+
bigquery: ["bigquery"],
|
|
545
|
+
transactsql: ["transactsql"],
|
|
546
|
+
mysql: ["mysql"]
|
|
529
547
|
};
|
|
530
|
-
const
|
|
531
|
-
if (!
|
|
548
|
+
const candidates = scopeDialects[dialect];
|
|
549
|
+
if (!candidates) {
|
|
532
550
|
throw new TypeError(
|
|
533
551
|
`No scope dialect mapping for formatter language "${dialect}". Add it to the scopeDialects map in Adapter.#checkScope.`
|
|
534
552
|
);
|
|
535
553
|
}
|
|
536
|
-
let references;
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
554
|
+
let references = null;
|
|
555
|
+
let lastError;
|
|
556
|
+
for (const candidate of candidates) {
|
|
557
|
+
try {
|
|
558
|
+
references = extractBaseEntityReferences(sql, candidate);
|
|
559
|
+
break;
|
|
560
|
+
} catch (error) {
|
|
561
|
+
lastError = error;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (references === null) {
|
|
540
565
|
return buildScopeParseErrorPayload(
|
|
541
566
|
sql,
|
|
542
567
|
dialect,
|
|
543
|
-
|
|
568
|
+
lastError
|
|
544
569
|
);
|
|
545
570
|
}
|
|
546
571
|
if (references.length === 0) return null;
|
|
@@ -5202,6 +5227,9 @@ function sqlSandboxExtension(adapters, options = {}) {
|
|
|
5202
5227
|
}
|
|
5203
5228
|
|
|
5204
5229
|
// packages/text2sql/src/lib/sql.ts
|
|
5230
|
+
import {
|
|
5231
|
+
createUIMessageStream
|
|
5232
|
+
} from "ai";
|
|
5205
5233
|
import "@deepagents/agent";
|
|
5206
5234
|
import {
|
|
5207
5235
|
agent as agent2,
|
|
@@ -5209,6 +5237,7 @@ import {
|
|
|
5209
5237
|
errorRecoveryGuardrail,
|
|
5210
5238
|
fragment as fragment3
|
|
5211
5239
|
} from "@deepagents/context";
|
|
5240
|
+
var TEXT2SQL_INDEX_PROGRESS_CHUNK = "data-text2sql-index-progress";
|
|
5212
5241
|
var Text2Sql = class {
|
|
5213
5242
|
#config;
|
|
5214
5243
|
#introspection;
|
|
@@ -5251,35 +5280,113 @@ var Text2Sql = class {
|
|
|
5251
5280
|
return result.sql;
|
|
5252
5281
|
}
|
|
5253
5282
|
async index() {
|
|
5283
|
+
return this.#index();
|
|
5284
|
+
}
|
|
5285
|
+
async #index(onProgress) {
|
|
5254
5286
|
const entries = Object.entries(this.#config.adapters);
|
|
5255
|
-
|
|
5287
|
+
onProgress?.({
|
|
5288
|
+
type: "index:start",
|
|
5289
|
+
message: `Indexing ${entries.length} adapter${entries.length === 1 ? "" : "s"}...`,
|
|
5290
|
+
current: 0,
|
|
5291
|
+
total: entries.length
|
|
5292
|
+
});
|
|
5293
|
+
const settled = await Promise.allSettled(
|
|
5256
5294
|
entries.map(async ([name, adapter]) => {
|
|
5257
|
-
const schema = await this.#indexAdapter(name, adapter);
|
|
5295
|
+
const schema = await this.#indexAdapter(name, adapter, onProgress);
|
|
5258
5296
|
return fragment3(name, ...schema);
|
|
5259
5297
|
})
|
|
5260
5298
|
);
|
|
5299
|
+
const failed = settled.find((result) => result.status === "rejected");
|
|
5300
|
+
if (failed) {
|
|
5301
|
+
onProgress?.({
|
|
5302
|
+
type: "index:error",
|
|
5303
|
+
message: failed.reason instanceof Error ? failed.reason.message : String(failed.reason)
|
|
5304
|
+
});
|
|
5305
|
+
throw failed.reason;
|
|
5306
|
+
}
|
|
5307
|
+
const wrapped = settled.map((result) => {
|
|
5308
|
+
if (result.status === "rejected") {
|
|
5309
|
+
throw result.reason;
|
|
5310
|
+
}
|
|
5311
|
+
return result.value;
|
|
5312
|
+
});
|
|
5313
|
+
onProgress?.({
|
|
5314
|
+
type: "index:end",
|
|
5315
|
+
message: "Finished indexing adapters.",
|
|
5316
|
+
current: entries.length,
|
|
5317
|
+
total: entries.length
|
|
5318
|
+
});
|
|
5261
5319
|
return wrapped;
|
|
5262
5320
|
}
|
|
5263
|
-
async #indexAdapter(name, adapter) {
|
|
5321
|
+
async #indexAdapter(name, adapter, onProgress) {
|
|
5322
|
+
onProgress?.({
|
|
5323
|
+
type: "adapter:start",
|
|
5324
|
+
adapter: name,
|
|
5325
|
+
message: `Indexing adapter "${name}"...`
|
|
5326
|
+
});
|
|
5264
5327
|
const cache = this.#introspection.get(name);
|
|
5265
5328
|
if (!cache) {
|
|
5266
5329
|
throw new Error(`no introspection cache registered for "${name}"`);
|
|
5267
5330
|
}
|
|
5268
|
-
const cached = await cache.read();
|
|
5269
|
-
if (cached) {
|
|
5270
|
-
return cached;
|
|
5271
|
-
}
|
|
5272
5331
|
try {
|
|
5273
|
-
const
|
|
5332
|
+
const cached = await cache.read();
|
|
5333
|
+
if (cached) {
|
|
5334
|
+
onProgress?.({
|
|
5335
|
+
type: "adapter:cache-hit",
|
|
5336
|
+
adapter: name,
|
|
5337
|
+
message: `Using cached index for adapter "${name}".`,
|
|
5338
|
+
cached: true
|
|
5339
|
+
});
|
|
5340
|
+
onProgress?.({
|
|
5341
|
+
type: "adapter:end",
|
|
5342
|
+
adapter: name,
|
|
5343
|
+
message: `Finished indexing adapter "${name}".`,
|
|
5344
|
+
cached: true
|
|
5345
|
+
});
|
|
5346
|
+
return cached;
|
|
5347
|
+
}
|
|
5348
|
+
onProgress?.({
|
|
5349
|
+
type: "adapter:cache-miss",
|
|
5350
|
+
adapter: name,
|
|
5351
|
+
message: `No cached index for adapter "${name}".`,
|
|
5352
|
+
cached: false
|
|
5353
|
+
});
|
|
5354
|
+
const ctx = createGroundingContext({
|
|
5355
|
+
onProgress: (progress) => onProgress?.(this.#adapterProgressEvent(name, progress))
|
|
5356
|
+
});
|
|
5357
|
+
const fragments = await adapter.introspect(ctx);
|
|
5274
5358
|
await cache.write(fragments);
|
|
5359
|
+
onProgress?.({
|
|
5360
|
+
type: "adapter:end",
|
|
5361
|
+
adapter: name,
|
|
5362
|
+
message: `Finished indexing adapter "${name}".`,
|
|
5363
|
+
cached: false
|
|
5364
|
+
});
|
|
5275
5365
|
return fragments;
|
|
5276
5366
|
} catch (error) {
|
|
5277
5367
|
const reason = error instanceof Error ? error.message : String(error);
|
|
5368
|
+
onProgress?.({
|
|
5369
|
+
type: "adapter:error",
|
|
5370
|
+
adapter: name,
|
|
5371
|
+
message: `Failed indexing adapter "${name}": ${reason}`
|
|
5372
|
+
});
|
|
5278
5373
|
throw new Error(`introspecting adapter "${name}": ${reason}`, {
|
|
5279
5374
|
cause: error
|
|
5280
5375
|
});
|
|
5281
5376
|
}
|
|
5282
5377
|
}
|
|
5378
|
+
#adapterProgressEvent(adapter, progress) {
|
|
5379
|
+
return {
|
|
5380
|
+
type: progress.type,
|
|
5381
|
+
adapter,
|
|
5382
|
+
phase: progress.phase,
|
|
5383
|
+
table: progress.table,
|
|
5384
|
+
message: progress.message,
|
|
5385
|
+
current: progress.current,
|
|
5386
|
+
total: progress.total,
|
|
5387
|
+
cached: false
|
|
5388
|
+
};
|
|
5389
|
+
}
|
|
5283
5390
|
async toPairs(adapterName, factory) {
|
|
5284
5391
|
const adapter = this.#requireAdapter(adapterName);
|
|
5285
5392
|
const producer = factory(adapter);
|
|
@@ -5289,23 +5396,34 @@ var Text2Sql = class {
|
|
|
5289
5396
|
if (messages.length === 0) {
|
|
5290
5397
|
throw new Error("messages must not be empty");
|
|
5291
5398
|
}
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5399
|
+
return createUIMessageStream({
|
|
5400
|
+
execute: async ({ writer }) => {
|
|
5401
|
+
const progress = (event) => {
|
|
5402
|
+
writer.write({
|
|
5403
|
+
type: TEXT2SQL_INDEX_PROGRESS_CHUNK,
|
|
5404
|
+
data: event
|
|
5405
|
+
});
|
|
5406
|
+
};
|
|
5407
|
+
const context = this.#config.context(
|
|
5408
|
+
...guidelines(),
|
|
5409
|
+
...await this.#index(progress)
|
|
5410
|
+
);
|
|
5411
|
+
const chatAgent = agent2({
|
|
5412
|
+
name: "text2sql",
|
|
5413
|
+
sandbox: this.#config.sandbox,
|
|
5414
|
+
model: this.#config.model,
|
|
5415
|
+
context,
|
|
5416
|
+
tools: this.#config.tools,
|
|
5417
|
+
guardrails: [errorRecoveryGuardrail],
|
|
5418
|
+
maxGuardrailRetries: 3
|
|
5419
|
+
});
|
|
5420
|
+
const chatStream = await chat(chatAgent, messages, {
|
|
5421
|
+
abortSignal: options?.abortSignal,
|
|
5422
|
+
generateTitle: options?.generateTitle,
|
|
5423
|
+
transform: this.#config.transform
|
|
5424
|
+
});
|
|
5425
|
+
writer.merge(chatStream);
|
|
5426
|
+
}
|
|
5309
5427
|
});
|
|
5310
5428
|
}
|
|
5311
5429
|
};
|
|
@@ -5325,6 +5443,7 @@ export {
|
|
|
5325
5443
|
SqlProxyEnforcementPlugin,
|
|
5326
5444
|
SqlProxyViolationError,
|
|
5327
5445
|
SqliteFs,
|
|
5446
|
+
TEXT2SQL_INDEX_PROGRESS_CHUNK,
|
|
5328
5447
|
Text2Sql,
|
|
5329
5448
|
UnanswerableSQLError,
|
|
5330
5449
|
applyTablesFilter,
|