@deepagents/text2sql 0.39.0 → 1.0.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 +130 -73
- package/dist/bin/sql.js +699 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3376 -3309
- package/dist/index.js.map +4 -4
- package/dist/lib/adapter-index.d.ts +35 -0
- package/dist/lib/adapter-index.d.ts.map +1 -0
- package/dist/lib/agents/question.agent.d.ts.map +1 -1
- package/dist/lib/agents/sql-transform-plugins.d.ts +3 -3
- package/dist/lib/agents/sql-transform-plugins.d.ts.map +1 -1
- package/dist/lib/agents/sql.agent.d.ts.map +1 -1
- package/dist/lib/instructions.d.ts +1 -1
- package/dist/lib/instructions.d.ts.map +1 -1
- package/dist/lib/sql-hooks.d.ts +15 -0
- package/dist/lib/sql-hooks.d.ts.map +1 -0
- package/dist/lib/sql-meta-hook.d.ts +20 -0
- package/dist/lib/sql-meta-hook.d.ts.map +1 -0
- package/dist/lib/sql-repair.d.ts +2 -0
- package/dist/lib/sql-repair.d.ts.map +1 -0
- package/dist/lib/sql-transform.d.ts +2 -0
- package/dist/lib/sql-transform.d.ts.map +1 -0
- package/dist/lib/sql.d.ts +5 -38
- package/dist/lib/sql.d.ts.map +1 -1
- package/dist/lib/synthesis/extractors/base-contextual-extractor.d.ts.map +1 -1
- package/dist/lib/synthesis/extractors/segmented-context-extractor.d.ts.map +1 -1
- package/dist/lib/synthesis/extractors/sql-extractor.d.ts.map +1 -1
- package/dist/lib/synthesis/index.js +59 -2
- package/dist/lib/synthesis/index.js.map +4 -4
- package/dist/lib/synthesis/synthesizers/breadth-evolver.d.ts.map +1 -1
- package/dist/lib/synthesis/synthesizers/depth-evolver.d.ts.map +1 -1
- package/dist/lib/synthesis/synthesizers/persona-generator.d.ts.map +1 -1
- package/package.json +8 -4
- package/dist/lib/agents/sql-command.d.ts +0 -11
- package/dist/lib/agents/sql-command.d.ts.map +0 -1
- package/dist/lib/demo.d.ts +0 -2
- package/dist/lib/demo.d.ts.map +0 -1
- package/dist/lib/sandbox.d.ts +0 -21
- package/dist/lib/sandbox.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -32,18 +32,9 @@ Requires Node.js LTS (20+).
|
|
|
32
32
|
|
|
33
33
|
```typescript
|
|
34
34
|
import { groq } from '@ai-sdk/groq';
|
|
35
|
-
import { InMemoryFs } from 'just-bash';
|
|
36
35
|
import pg from 'pg';
|
|
37
36
|
|
|
38
|
-
import {
|
|
39
|
-
ContextEngine,
|
|
40
|
-
InMemoryContextStore,
|
|
41
|
-
createBashTool,
|
|
42
|
-
createRoutingSandbox,
|
|
43
|
-
createVirtualSandbox,
|
|
44
|
-
user,
|
|
45
|
-
} from '@deepagents/context';
|
|
46
|
-
import { Text2Sql, sqlSandboxExtension } from '@deepagents/text2sql';
|
|
37
|
+
import { Text2Sql } from '@deepagents/text2sql';
|
|
47
38
|
import {
|
|
48
39
|
Postgres,
|
|
49
40
|
columnValues,
|
|
@@ -59,12 +50,6 @@ const pool = new pg.Pool({
|
|
|
59
50
|
connectionString: process.env.DATABASE_URL,
|
|
60
51
|
});
|
|
61
52
|
|
|
62
|
-
const store = new InMemoryContextStore();
|
|
63
|
-
const engine = new ContextEngine({
|
|
64
|
-
store,
|
|
65
|
-
chatId: 'chat-123',
|
|
66
|
-
userId: 'user-456',
|
|
67
|
-
});
|
|
68
53
|
const adapter = new Postgres({
|
|
69
54
|
execute: async (sql) => {
|
|
70
55
|
const result = await pool.query(sql);
|
|
@@ -80,19 +65,11 @@ const adapter = new Postgres({
|
|
|
80
65
|
columnValues(),
|
|
81
66
|
],
|
|
82
67
|
});
|
|
83
|
-
const sandbox = await createBashTool({
|
|
84
|
-
sandbox: await createRoutingSandbox({
|
|
85
|
-
backend: await createVirtualSandbox({ fs: new InMemoryFs() }),
|
|
86
|
-
hostExtensions: [sqlSandboxExtension({ main: adapter })],
|
|
87
|
-
}),
|
|
88
|
-
});
|
|
89
68
|
|
|
90
69
|
const text2sql = new Text2Sql({
|
|
91
70
|
version: 'v1',
|
|
92
71
|
model: groq('openai/gpt-oss-20b'),
|
|
93
|
-
sandbox,
|
|
94
72
|
adapters: { main: adapter },
|
|
95
|
-
context: engine,
|
|
96
73
|
});
|
|
97
74
|
|
|
98
75
|
// Generate SQL
|
|
@@ -105,32 +82,106 @@ console.log(sql);
|
|
|
105
82
|
|
|
106
83
|
The adapter-map key (`main` here) is the adapter name. Reuse that same key in
|
|
107
84
|
`text2sql.toSql(..., 'main')` and in any `sql validate <db> "..."` /
|
|
108
|
-
`sql run <db> "..."` sandbox
|
|
85
|
+
`sql run <db> "..."` calls from a sandbox where the package CLI is installed.
|
|
109
86
|
|
|
110
87
|
Adapter names must match `/^[A-Za-z_][A-Za-z0-9_]*$/`. If you build adapter
|
|
111
88
|
maps dynamically, use `isValidAdapterName(name)` to check one key or
|
|
112
89
|
`validateAdapterNames(names)` to fail fast before constructing `Text2Sql` or
|
|
113
|
-
`
|
|
90
|
+
the sandbox-side adapter module used by the `sql` CLI.
|
|
114
91
|
|
|
115
92
|
## AI Model Providers
|
|
116
93
|
|
|
117
94
|
Text2SQL works with any model provider supported by the [Vercel AI SDK](https://sdk.vercel.ai/docs), including OpenAI, Anthropic, Google, Groq, and more.
|
|
118
95
|
|
|
119
|
-
##
|
|
96
|
+
## Building a Conversational Agent
|
|
120
97
|
|
|
121
|
-
`Text2Sql`
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
98
|
+
`Text2Sql` ships only the SQL-aware primitives: `toSql`, `toPairs`,
|
|
99
|
+
`AdapterIndexer`, and `instructions()`. You build the chat agent yourself by
|
|
100
|
+
composing a `ContextEngine`, a sandbox, and `agent` + `chat` from
|
|
101
|
+
`@deepagents/context`:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import {
|
|
105
|
+
ContextEngine,
|
|
106
|
+
type ContextFragment,
|
|
107
|
+
InMemoryContextStore,
|
|
108
|
+
agent,
|
|
109
|
+
chat,
|
|
110
|
+
createContainerTool,
|
|
111
|
+
errorRecoveryGuardrail,
|
|
112
|
+
npm,
|
|
113
|
+
user,
|
|
114
|
+
} from '@deepagents/context';
|
|
115
|
+
import { createSqlCommandHooks, instructions } from '@deepagents/text2sql';
|
|
116
|
+
|
|
117
|
+
const store = new InMemoryContextStore();
|
|
118
|
+
const context = new ContextEngine({
|
|
119
|
+
store,
|
|
120
|
+
chatId: 'chat-123',
|
|
121
|
+
userId: 'user-456',
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const sandbox = await createContainerTool({
|
|
125
|
+
installers: [npm('@deepagents/text2sql', { ensureRuntime: true })],
|
|
126
|
+
env: {
|
|
127
|
+
TEXT2SQL_ADAPTERS: '/workspace/text2sql-adapters.ts',
|
|
128
|
+
},
|
|
129
|
+
...createSqlCommandHooks({ adapters: { main: adapter } }),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const indexResult = await sandbox.sandbox.executeCommand('sql index');
|
|
133
|
+
if (indexResult.exitCode !== 0) throw new Error(indexResult.stderr);
|
|
134
|
+
const manifest = JSON.parse(indexResult.stdout) as { fragmentsPath: string };
|
|
135
|
+
const fragments = JSON.parse(
|
|
136
|
+
await sandbox.sandbox.readFile(manifest.fragmentsPath),
|
|
137
|
+
) as ContextFragment[];
|
|
138
|
+
context.set(...instructions(), ...fragments);
|
|
139
|
+
|
|
140
|
+
const ai = agent({
|
|
141
|
+
name: 'sql-assistant',
|
|
142
|
+
sandbox,
|
|
143
|
+
model: groq('openai/gpt-oss-20b'),
|
|
144
|
+
context,
|
|
145
|
+
guardrails: [errorRecoveryGuardrail],
|
|
146
|
+
maxGuardrailRetries: 3,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
await context.continue(user('Show me the top 10 customers by revenue'));
|
|
150
|
+
const stream = await chat(ai);
|
|
151
|
+
|
|
152
|
+
for await (const chunk of stream) {
|
|
153
|
+
// handle streaming response
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`instructions()` returns the SQL-flavored system fragments (policies, workflows,
|
|
158
|
+
clarifications, style guides) — spread them into `context.set()` alongside the
|
|
159
|
+
schema fragments returned by `sql index`. Add or replace them with your
|
|
160
|
+
own domain fragments as needed.
|
|
161
|
+
|
|
162
|
+
## Advanced: SQL CLI in Sandboxes
|
|
163
|
+
|
|
164
|
+
`sql validate <db> "..."` and `sql run <db> "..."` are real commands from the
|
|
165
|
+
`@deepagents/text2sql` package. `sql index [adapter ...]` writes schema
|
|
166
|
+
fragments plus progress events for chat setup. Install the package inside the
|
|
167
|
+
sandbox and set `TEXT2SQL_ADAPTERS` to a module whose default export is
|
|
168
|
+
`Record<string, Adapter>`. Missing `sql` means the sandbox was not prepared
|
|
169
|
+
correctly.
|
|
170
|
+
|
|
171
|
+
Spread `createSqlCommandHooks({ adapters })` into `createBashTool()` or
|
|
172
|
+
`createContainerTool()` for model-driven bash calls. The before hook preserves
|
|
173
|
+
the old virtual-command tolerance for common LLM quote mistakes, rewrites SQL
|
|
174
|
+
identifier backticks so bash does not run them as command substitutions, and
|
|
175
|
+
blocks raw database access so read-only and scope checks stay behind
|
|
176
|
+
`sql validate` / `sql run`. The after hook restores hidden `formattedSql`
|
|
177
|
+
metadata from the host adapter map without putting that concern into the real
|
|
178
|
+
CLI.
|
|
128
179
|
|
|
129
180
|
## Fragments
|
|
130
181
|
|
|
131
|
-
Inject domain knowledge by setting fragments on the `ContextEngine` you
|
|
132
|
-
|
|
133
|
-
generation with extra fragments, use the lower-level `toSql({ fragments })`
|
|
182
|
+
Inject domain knowledge by setting fragments on the `ContextEngine` you build
|
|
183
|
+
for the agent. Those fragments affect every `chat()` turn. If you need direct
|
|
184
|
+
SQL generation with extra fragments, use the lower-level `toSql({ fragments })`
|
|
134
185
|
helper exported from `@deepagents/text2sql`.
|
|
135
186
|
|
|
136
187
|
```typescript
|
|
@@ -144,13 +195,13 @@ import {
|
|
|
144
195
|
} from '@deepagents/context';
|
|
145
196
|
|
|
146
197
|
const store = new InMemoryContextStore();
|
|
147
|
-
const
|
|
198
|
+
const context = new ContextEngine({
|
|
148
199
|
store,
|
|
149
200
|
chatId: 'chat-123',
|
|
150
201
|
userId: 'user-456',
|
|
151
202
|
});
|
|
152
203
|
|
|
153
|
-
|
|
204
|
+
context.set(
|
|
154
205
|
term('MRR', 'monthly recurring revenue'),
|
|
155
206
|
hint('Always exclude test accounts with email ending in @test.com'),
|
|
156
207
|
guardrail({
|
|
@@ -188,62 +239,69 @@ Control what schema metadata the AI receives:
|
|
|
188
239
|
|
|
189
240
|
## Conversations
|
|
190
241
|
|
|
191
|
-
`chat()` persists history through the
|
|
192
|
-
Reuse the same store, `chatId`, and
|
|
193
|
-
Before each turn, append only the new
|
|
194
|
-
replay earlier turns that are already
|
|
242
|
+
`chat()` (from `@deepagents/context`) persists history through the
|
|
243
|
+
`ContextEngine` you build for the agent. Reuse the same store, `chatId`, and
|
|
244
|
+
`userId` to continue the same thread. Before each turn, append only the new
|
|
245
|
+
incoming message to the engine; do not replay earlier turns that are already
|
|
246
|
+
stored in the context store:
|
|
195
247
|
|
|
196
248
|
```typescript
|
|
197
|
-
await
|
|
198
|
-
const stream = await
|
|
249
|
+
await context.continue(user('Show me orders from last month'));
|
|
250
|
+
const stream = await chat(ai);
|
|
199
251
|
|
|
200
252
|
for await (const chunk of stream) {
|
|
201
253
|
// handle streaming response
|
|
202
254
|
}
|
|
203
255
|
|
|
204
256
|
// Continue the same conversation
|
|
205
|
-
await
|
|
206
|
-
const followUp = await
|
|
257
|
+
await context.continue(user('Now filter to only completed ones'));
|
|
258
|
+
const followUp = await chat(ai);
|
|
207
259
|
for await (const chunk of followUp) {
|
|
208
260
|
// handle streaming response
|
|
209
261
|
}
|
|
210
262
|
```
|
|
211
263
|
|
|
212
|
-
|
|
213
|
-
|
|
264
|
+
## Streaming Index Progress
|
|
265
|
+
|
|
266
|
+
`AdapterIndexer#index({ onProgress })` emits progress events while it warms or reads
|
|
267
|
+
the schema cache for host-side indexing. The sandbox CLI writes the same event
|
|
268
|
+
shape to the `eventsPath` file returned by `sql index`:
|
|
214
269
|
|
|
215
270
|
```typescript
|
|
271
|
+
import { createUIMessageStream } from 'ai';
|
|
272
|
+
|
|
216
273
|
import {
|
|
274
|
+
AdapterIndexer,
|
|
217
275
|
TEXT2SQL_INDEX_PROGRESS_CHUNK,
|
|
218
276
|
type Text2SqlIndexProgressEvent,
|
|
219
277
|
} from '@deepagents/text2sql';
|
|
220
278
|
|
|
221
|
-
|
|
222
|
-
const stream = await text2sql.chat();
|
|
223
|
-
const startedAt = new Map<string, number>();
|
|
224
|
-
|
|
225
|
-
for await (const chunk of stream) {
|
|
226
|
-
if (chunk.type === TEXT2SQL_INDEX_PROGRESS_CHUNK) {
|
|
227
|
-
const event = chunk.data as Text2SqlIndexProgressEvent;
|
|
228
|
-
const scope =
|
|
229
|
-
[event.adapter, event.phase].filter(Boolean).join(':') || 'index';
|
|
279
|
+
const indexer = new AdapterIndexer({ adapters, version: 'v1' });
|
|
230
280
|
|
|
231
|
-
|
|
232
|
-
startedAt.set(scope, event.timestampMs ?? Date.now());
|
|
233
|
-
}
|
|
281
|
+
await context.continue(user('Show me top 10 customers'));
|
|
234
282
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
283
|
+
const stream = createUIMessageStream({
|
|
284
|
+
execute: async ({ writer }) => {
|
|
285
|
+
const head = await context.headMessage();
|
|
286
|
+
if (!head || head.name !== 'assistant') {
|
|
287
|
+
throw new Error(
|
|
288
|
+
'expected head to be an assistant message — call context.continue() before chat()',
|
|
289
|
+
);
|
|
240
290
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
291
|
+
writer.write({ type: 'start', messageId: head.id });
|
|
292
|
+
|
|
293
|
+
const fragments = await indexer.index({
|
|
294
|
+
onProgress: (event) =>
|
|
295
|
+
writer.write({
|
|
296
|
+
type: TEXT2SQL_INDEX_PROGRESS_CHUNK,
|
|
297
|
+
data: event,
|
|
298
|
+
}),
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
context.set(...instructions(), ...fragments);
|
|
302
|
+
writer.merge(await chat(ai));
|
|
303
|
+
},
|
|
304
|
+
});
|
|
247
305
|
```
|
|
248
306
|
|
|
249
307
|
Each progress event includes a generic Unix epoch `timestampMs` so clients can
|
|
@@ -281,7 +339,6 @@ Full documentation available at [januarylabs.github.io/deepagents](https://janua
|
|
|
281
339
|
|
|
282
340
|
- [Getting Started](https://januarylabs.github.io/deepagents/docs/text2sql/getting-started)
|
|
283
341
|
- [Generate SQL](https://januarylabs.github.io/deepagents/docs/text2sql/to-sql)
|
|
284
|
-
- [Caller-Owned Sandbox](https://januarylabs.github.io/deepagents/docs/text2sql/sqlv3)
|
|
285
342
|
- [Teach the System](https://januarylabs.github.io/deepagents/docs/text2sql/teach-the-system)
|
|
286
343
|
- [Build Conversations](https://januarylabs.github.io/deepagents/docs/text2sql/build-conversations)
|
|
287
344
|
- [Grounding](https://januarylabs.github.io/deepagents/docs/text2sql/grounding)
|