@duckcodeailabs/dql-agent 1.6.20 → 1.6.22
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/dist/agent-run-engine.d.ts +287 -0
- package/dist/agent-run-engine.d.ts.map +1 -0
- package/dist/agent-run-engine.js +916 -0
- package/dist/agent-run-engine.js.map +1 -0
- package/dist/agent-run-gates.d.ts +26 -0
- package/dist/agent-run-gates.d.ts.map +1 -0
- package/dist/agent-run-gates.js +170 -0
- package/dist/agent-run-gates.js.map +1 -0
- package/dist/agent-run-planner.d.ts +32 -0
- package/dist/agent-run-planner.d.ts.map +1 -0
- package/dist/agent-run-planner.js +280 -0
- package/dist/agent-run-planner.js.map +1 -0
- package/dist/answer-loop.d.ts +49 -0
- package/dist/answer-loop.d.ts.map +1 -1
- package/dist/answer-loop.js +292 -17
- package/dist/answer-loop.js.map +1 -1
- package/dist/app-builder.d.ts +44 -2
- package/dist/app-builder.d.ts.map +1 -1
- package/dist/app-builder.js +558 -123
- package/dist/app-builder.js.map +1 -1
- package/dist/app-planner.d.ts +78 -0
- package/dist/app-planner.d.ts.map +1 -0
- package/dist/app-planner.js +145 -0
- package/dist/app-planner.js.map +1 -0
- package/dist/embeddings/provider.d.ts +66 -0
- package/dist/embeddings/provider.d.ts.map +1 -0
- package/dist/embeddings/provider.js +105 -0
- package/dist/embeddings/provider.js.map +1 -0
- package/dist/hints/git-store.d.ts +69 -0
- package/dist/hints/git-store.d.ts.map +1 -0
- package/dist/hints/git-store.js +244 -0
- package/dist/hints/git-store.js.map +1 -0
- package/dist/hints/retrieval.d.ts +49 -0
- package/dist/hints/retrieval.d.ts.map +1 -0
- package/dist/hints/retrieval.js +60 -0
- package/dist/hints/retrieval.js.map +1 -0
- package/dist/hints/store.d.ts +39 -0
- package/dist/hints/store.d.ts.map +1 -0
- package/dist/hints/store.js +279 -0
- package/dist/hints/store.js.map +1 -0
- package/dist/hints/types.d.ts +147 -0
- package/dist/hints/types.d.ts.map +1 -0
- package/dist/hints/types.js +92 -0
- package/dist/hints/types.js.map +1 -0
- package/dist/index.d.ts +43 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -3
- package/dist/index.js.map +1 -1
- package/dist/intent-controller.d.ts +63 -0
- package/dist/intent-controller.d.ts.map +1 -0
- package/dist/intent-controller.js +150 -0
- package/dist/intent-controller.js.map +1 -0
- package/dist/kg/build.d.ts.map +1 -1
- package/dist/kg/build.js +2 -0
- package/dist/kg/build.js.map +1 -1
- package/dist/kg/sqlite-fts.js +4 -0
- package/dist/kg/sqlite-fts.js.map +1 -1
- package/dist/kg/types.d.ts +10 -0
- package/dist/kg/types.d.ts.map +1 -1
- package/dist/metadata/catalog.d.ts +81 -4
- package/dist/metadata/catalog.d.ts.map +1 -1
- package/dist/metadata/catalog.js +208 -1
- package/dist/metadata/catalog.js.map +1 -1
- package/dist/metadata/drafts.d.ts +22 -0
- package/dist/metadata/drafts.d.ts.map +1 -1
- package/dist/metadata/drafts.js +126 -2
- package/dist/metadata/drafts.js.map +1 -1
- package/dist/metadata/grain-gate.d.ts +61 -0
- package/dist/metadata/grain-gate.d.ts.map +1 -0
- package/dist/metadata/grain-gate.js +265 -0
- package/dist/metadata/grain-gate.js.map +1 -0
- package/dist/metadata/identity.d.ts +47 -0
- package/dist/metadata/identity.d.ts.map +1 -0
- package/dist/metadata/identity.js +147 -0
- package/dist/metadata/identity.js.map +1 -0
- package/dist/metadata/metric-match.d.ts +93 -0
- package/dist/metadata/metric-match.d.ts.map +1 -0
- package/dist/metadata/metric-match.js +233 -0
- package/dist/metadata/metric-match.js.map +1 -0
- package/dist/metadata/sql-grounding.d.ts +149 -0
- package/dist/metadata/sql-grounding.d.ts.map +1 -0
- package/dist/metadata/sql-grounding.js +397 -0
- package/dist/metadata/sql-grounding.js.map +1 -0
- package/dist/metadata/sql-retrieval.d.ts +29 -0
- package/dist/metadata/sql-retrieval.d.ts.map +1 -0
- package/dist/metadata/sql-retrieval.js +79 -0
- package/dist/metadata/sql-retrieval.js.map +1 -0
- package/dist/narrate.d.ts +52 -0
- package/dist/narrate.d.ts.map +1 -0
- package/dist/narrate.js +263 -0
- package/dist/narrate.js.map +1 -0
- package/dist/propose/build-from-prompt.d.ts +160 -0
- package/dist/propose/build-from-prompt.d.ts.map +1 -0
- package/dist/propose/build-from-prompt.js +815 -0
- package/dist/propose/build-from-prompt.js.map +1 -0
- package/dist/propose/classify.d.ts +55 -0
- package/dist/propose/classify.d.ts.map +1 -0
- package/dist/propose/classify.js +167 -0
- package/dist/propose/classify.js.map +1 -0
- package/dist/propose/config.d.ts +39 -0
- package/dist/propose/config.d.ts.map +1 -0
- package/dist/propose/config.js +52 -0
- package/dist/propose/config.js.map +1 -0
- package/dist/propose/dbt-artifacts.d.ts +134 -0
- package/dist/propose/dbt-artifacts.d.ts.map +1 -0
- package/dist/propose/dbt-artifacts.js +320 -0
- package/dist/propose/dbt-artifacts.js.map +1 -0
- package/dist/propose/edit-block.d.ts +74 -0
- package/dist/propose/edit-block.d.ts.map +1 -0
- package/dist/propose/edit-block.js +133 -0
- package/dist/propose/edit-block.js.map +1 -0
- package/dist/propose/enrich.d.ts +48 -0
- package/dist/propose/enrich.d.ts.map +1 -0
- package/dist/propose/enrich.js +125 -0
- package/dist/propose/enrich.js.map +1 -0
- package/dist/propose/generate-sql.d.ts +61 -0
- package/dist/propose/generate-sql.d.ts.map +1 -0
- package/dist/propose/generate-sql.js +180 -0
- package/dist/propose/generate-sql.js.map +1 -0
- package/dist/propose/index.d.ts +24 -0
- package/dist/propose/index.d.ts.map +1 -0
- package/dist/propose/index.js +15 -0
- package/dist/propose/index.js.map +1 -0
- package/dist/propose/propose.d.ts +226 -0
- package/dist/propose/propose.d.ts.map +1 -0
- package/dist/propose/propose.js +668 -0
- package/dist/propose/propose.js.map +1 -0
- package/dist/propose/reflect-block.d.ts +99 -0
- package/dist/propose/reflect-block.d.ts.map +1 -0
- package/dist/propose/reflect-block.js +220 -0
- package/dist/propose/reflect-block.js.map +1 -0
- package/dist/propose/write-draft.d.ts +90 -0
- package/dist/propose/write-draft.d.ts.map +1 -0
- package/dist/propose/write-draft.js +185 -0
- package/dist/propose/write-draft.js.map +1 -0
- package/dist/providers/claude.d.ts +13 -1
- package/dist/providers/claude.d.ts.map +1 -1
- package/dist/providers/claude.js +20 -2
- package/dist/providers/claude.js.map +1 -1
- package/dist/providers/gemini.d.ts +13 -1
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +24 -3
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/index.d.ts +3 -3
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +3 -3
- package/dist/providers/index.js.map +1 -1
- package/dist/research-loop.d.ts +62 -0
- package/dist/research-loop.d.ts.map +1 -0
- package/dist/research-loop.js +210 -0
- package/dist/research-loop.js.map +1 -0
- package/dist/skills/defaults.d.ts +37 -0
- package/dist/skills/defaults.d.ts.map +1 -0
- package/dist/skills/defaults.js +152 -0
- package/dist/skills/defaults.js.map +1 -0
- package/dist/skills/loader.d.ts +60 -0
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +164 -2
- package/dist/skills/loader.js.map +1 -1
- package/package.json +7 -5
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared SQL grounding (spec 15) — ONE grounding for BOTH the governed
|
|
3
|
+
* answer-loop and the AI build engine. There is no "weak path".
|
|
4
|
+
*
|
|
5
|
+
* The grounding takes dbt artifacts (+ an optional set of relevant model names)
|
|
6
|
+
* and produces, for each table:
|
|
7
|
+
* - the REAL qualified warehouse relation (`database.schema.alias`, e.g.
|
|
8
|
+
* `dev.order_items`) — never a bare model name,
|
|
9
|
+
* - the `{{ ref('<model>') }}` form for governed BLOCK SQL,
|
|
10
|
+
* - real columns + types (catalog.json preferred, manifest YAML fallback),
|
|
11
|
+
* - JOIN KEYS inferred from dbt `depends_on` and shared `*_id` / `*_key`
|
|
12
|
+
* columns,
|
|
13
|
+
* - a `certifiedBlock` flag (reserved for callers that pass certified models).
|
|
14
|
+
*
|
|
15
|
+
* On top of the grounding sit two deterministic, offline-safe primitives the
|
|
16
|
+
* build path was missing:
|
|
17
|
+
* - `resolveRelationsInSql` — rewrites any bare / unqualified table name to
|
|
18
|
+
* its real qualified relation (model name OR alias → `db.schema.alias`),
|
|
19
|
+
* - `validateSqlAgainstGrounding` — flags any table or column the generated
|
|
20
|
+
* SQL references that is not in the grounding.
|
|
21
|
+
*
|
|
22
|
+
* Both are pure string/AST helpers so they work with no provider and never
|
|
23
|
+
* crash the offline path.
|
|
24
|
+
*/
|
|
25
|
+
import { analyzeSqlReferences } from '@duckcodeailabs/dql-core';
|
|
26
|
+
function effectiveColumns(model, artifacts) {
|
|
27
|
+
const catalog = artifacts.catalogColumns.get(model.uniqueId) ?? [];
|
|
28
|
+
const source = catalog.length > 0 ? catalog : model.columns;
|
|
29
|
+
return source.map((c) => ({ name: c.name, type: c.type, description: c.description }));
|
|
30
|
+
}
|
|
31
|
+
function sourceColumns(source, artifacts) {
|
|
32
|
+
const catalog = artifacts.catalogColumns.get(source.uniqueId) ?? [];
|
|
33
|
+
return catalog.map((c) => ({ name: c.name, type: c.type, description: c.description }));
|
|
34
|
+
}
|
|
35
|
+
/** Lower-cased keys a relation can be referenced by (qualified, last 2, bare). */
|
|
36
|
+
export function relationKeys(relation) {
|
|
37
|
+
const normalized = relation.replace(/["`]/g, '').replace(/\s*\.\s*/g, '.').trim().toLowerCase();
|
|
38
|
+
const parts = normalized.split('.').filter(Boolean);
|
|
39
|
+
const keys = new Set();
|
|
40
|
+
if (normalized)
|
|
41
|
+
keys.add(normalized);
|
|
42
|
+
if (parts.length >= 2)
|
|
43
|
+
keys.add(parts.slice(-2).join('.'));
|
|
44
|
+
if (parts.length >= 1)
|
|
45
|
+
keys.add(parts[parts.length - 1]);
|
|
46
|
+
return Array.from(keys);
|
|
47
|
+
}
|
|
48
|
+
function isJoinKeyColumn(name) {
|
|
49
|
+
return /(^|_)(id|key|sk|pk|fk)$/i.test(name) || /_id$|_key$/i.test(name);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build the shared schema grounding for a set of dbt models (+ sources).
|
|
53
|
+
* `relevantModels`, when provided, restricts/orders the grounding to the
|
|
54
|
+
* retrieval-selected relations; otherwise all models are grounded (capped).
|
|
55
|
+
*/
|
|
56
|
+
export function buildSchemaGrounding(artifacts, relevantModels, options = {}) {
|
|
57
|
+
const empty = { tables: [], joinKeys: [], byKey: new Map() };
|
|
58
|
+
if (!artifacts)
|
|
59
|
+
return empty;
|
|
60
|
+
const limit = Math.max(1, options.limit ?? 24);
|
|
61
|
+
const certified = new Set(Array.from(options.certifiedModelNames ?? []).map((name) => name.toLowerCase()));
|
|
62
|
+
// Order models: relevant first (in given order), then the rest, capped.
|
|
63
|
+
const relevant = relevantModels ? Array.from(relevantModels).map((m) => m.toLowerCase()) : undefined;
|
|
64
|
+
const modelByLower = new Map();
|
|
65
|
+
for (const model of artifacts.models) {
|
|
66
|
+
modelByLower.set(model.name.toLowerCase(), model);
|
|
67
|
+
if (model.alias)
|
|
68
|
+
modelByLower.set(model.alias.toLowerCase(), model);
|
|
69
|
+
}
|
|
70
|
+
let ordered;
|
|
71
|
+
if (relevant && relevant.length > 0) {
|
|
72
|
+
const seen = new Set();
|
|
73
|
+
ordered = [];
|
|
74
|
+
for (const key of relevant) {
|
|
75
|
+
const model = modelByLower.get(key);
|
|
76
|
+
if (model && !seen.has(model.uniqueId)) {
|
|
77
|
+
seen.add(model.uniqueId);
|
|
78
|
+
ordered.push(model);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Backfill from the rest so a tiny retrieval set still has join partners.
|
|
82
|
+
for (const model of artifacts.models) {
|
|
83
|
+
if (ordered.length >= limit)
|
|
84
|
+
break;
|
|
85
|
+
if (!seen.has(model.uniqueId)) {
|
|
86
|
+
seen.add(model.uniqueId);
|
|
87
|
+
ordered.push(model);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
ordered = artifacts.models.slice();
|
|
93
|
+
}
|
|
94
|
+
ordered = ordered.slice(0, limit);
|
|
95
|
+
const tables = ordered.map((model) => ({
|
|
96
|
+
name: model.name,
|
|
97
|
+
qualifiedRelation: model.qualifiedRelation || model.name,
|
|
98
|
+
refForm: model.refForm,
|
|
99
|
+
columns: effectiveColumns(model, artifacts),
|
|
100
|
+
kind: 'model',
|
|
101
|
+
uniqueId: model.uniqueId,
|
|
102
|
+
certifiedBlock: certified.has(model.name.toLowerCase()) ||
|
|
103
|
+
(model.alias ? certified.has(model.alias.toLowerCase()) : false) ||
|
|
104
|
+
certified.has(model.qualifiedRelation.toLowerCase()),
|
|
105
|
+
}));
|
|
106
|
+
// Add sources that have catalog columns (referenced relations may be sources).
|
|
107
|
+
const remaining = Math.max(0, limit - tables.length);
|
|
108
|
+
for (const source of artifacts.sources.slice(0, remaining)) {
|
|
109
|
+
const cols = sourceColumns(source, artifacts);
|
|
110
|
+
if (cols.length === 0)
|
|
111
|
+
continue;
|
|
112
|
+
tables.push({
|
|
113
|
+
name: source.name,
|
|
114
|
+
qualifiedRelation: source.qualifiedRelation || source.name,
|
|
115
|
+
refForm: source.refForm,
|
|
116
|
+
columns: cols,
|
|
117
|
+
kind: 'source',
|
|
118
|
+
uniqueId: source.uniqueId,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
const byKey = new Map();
|
|
122
|
+
for (const table of tables) {
|
|
123
|
+
for (const key of [...relationKeys(table.qualifiedRelation), ...relationKeys(table.name)]) {
|
|
124
|
+
if (!byKey.has(key))
|
|
125
|
+
byKey.set(key, table);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const joinKeys = inferJoinKeys(tables, artifacts);
|
|
129
|
+
return { tables, joinKeys, byKey };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Infer join keys two ways:
|
|
133
|
+
* 1) dbt `depends_on` lineage: a model that depends on another and shares an
|
|
134
|
+
* `*_id` / `*_key` column joins on that column.
|
|
135
|
+
* 2) shared `*_id` / `*_key` columns between any two grounded relations.
|
|
136
|
+
* Deduped; lineage-derived keys are preferred (listed first).
|
|
137
|
+
*/
|
|
138
|
+
function inferJoinKeys(tables, artifacts) {
|
|
139
|
+
const byUniqueId = new Map(tables.map((t) => [t.uniqueId, t]));
|
|
140
|
+
const modelByUniqueId = new Map(artifacts.models.map((m) => [m.uniqueId, m]));
|
|
141
|
+
const out = [];
|
|
142
|
+
const seen = new Set();
|
|
143
|
+
const push = (key) => {
|
|
144
|
+
const id = [key.leftRelation, key.leftColumn, key.rightRelation, key.rightColumn]
|
|
145
|
+
.map((p) => p.toLowerCase())
|
|
146
|
+
.sort()
|
|
147
|
+
.join('|');
|
|
148
|
+
if (seen.has(id))
|
|
149
|
+
return;
|
|
150
|
+
seen.add(id);
|
|
151
|
+
out.push(key);
|
|
152
|
+
};
|
|
153
|
+
// 1) Lineage-derived: child depends_on parent; shared id/key column.
|
|
154
|
+
for (const table of tables) {
|
|
155
|
+
const model = modelByUniqueId.get(table.uniqueId);
|
|
156
|
+
if (!model)
|
|
157
|
+
continue;
|
|
158
|
+
for (const upstreamId of model.dependsOn) {
|
|
159
|
+
const upstream = byUniqueId.get(upstreamId);
|
|
160
|
+
if (!upstream)
|
|
161
|
+
continue;
|
|
162
|
+
for (const col of table.columns) {
|
|
163
|
+
if (!isJoinKeyColumn(col.name))
|
|
164
|
+
continue;
|
|
165
|
+
if (upstream.columns.some((u) => u.name.toLowerCase() === col.name.toLowerCase())) {
|
|
166
|
+
push({
|
|
167
|
+
leftRelation: table.qualifiedRelation,
|
|
168
|
+
leftColumn: col.name,
|
|
169
|
+
rightRelation: upstream.qualifiedRelation,
|
|
170
|
+
rightColumn: col.name,
|
|
171
|
+
reason: `dbt lineage: ${table.name} depends_on ${upstream.name}, shared key ${col.name}`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// 2) Shared *_id / *_key columns between any two relations.
|
|
178
|
+
for (let i = 0; i < tables.length; i += 1) {
|
|
179
|
+
for (let j = i + 1; j < tables.length; j += 1) {
|
|
180
|
+
const left = tables[i];
|
|
181
|
+
const right = tables[j];
|
|
182
|
+
for (const col of left.columns) {
|
|
183
|
+
if (!isJoinKeyColumn(col.name))
|
|
184
|
+
continue;
|
|
185
|
+
if (right.columns.some((r) => r.name.toLowerCase() === col.name.toLowerCase())) {
|
|
186
|
+
push({
|
|
187
|
+
leftRelation: left.qualifiedRelation,
|
|
188
|
+
leftColumn: col.name,
|
|
189
|
+
rightRelation: right.qualifiedRelation,
|
|
190
|
+
rightColumn: col.name,
|
|
191
|
+
reason: `shared key column ${col.name}`,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Build a `SchemaGrounding` from already-qualified runtime relations (the
|
|
201
|
+
* answer-loop receives these from the host as `schemaContext` /
|
|
202
|
+
* `allowedSqlContext`, so the relations are already real warehouse relations).
|
|
203
|
+
* This lets the governed answer-loop reuse the SAME resolver + validator as the
|
|
204
|
+
* build path without re-reading dbt artifacts. No join-key inference here —
|
|
205
|
+
* the answer-loop already renders join paths from its context pack.
|
|
206
|
+
*/
|
|
207
|
+
export function buildGroundingFromRuntimeRelations(relations) {
|
|
208
|
+
const tables = relations.map((rel) => ({
|
|
209
|
+
name: rel.name ?? rel.relation.split('.').at(-1) ?? rel.relation,
|
|
210
|
+
qualifiedRelation: rel.relation,
|
|
211
|
+
columns: rel.columns.map((c) => ({ name: c.name, type: c.type, description: c.description })),
|
|
212
|
+
kind: 'model',
|
|
213
|
+
uniqueId: rel.relation,
|
|
214
|
+
}));
|
|
215
|
+
const byKey = new Map();
|
|
216
|
+
for (const table of tables) {
|
|
217
|
+
for (const key of [...relationKeys(table.qualifiedRelation), ...relationKeys(table.name)]) {
|
|
218
|
+
if (!byKey.has(key))
|
|
219
|
+
byKey.set(key, table);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return { tables, joinKeys: [], byKey };
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Deterministically rewrite any bare / unqualified table name in `FROM` /
|
|
226
|
+
* `JOIN` clauses to its real qualified relation from the grounding. Maps both
|
|
227
|
+
* the model name and its alias to `database.schema.alias`. Already-qualified
|
|
228
|
+
* relations that match the grounding are left untouched.
|
|
229
|
+
*
|
|
230
|
+
* For BLOCK SQL the caller may request the `{{ ref() }}` form instead of the
|
|
231
|
+
* qualified relation via `prefer: 'ref'`.
|
|
232
|
+
*/
|
|
233
|
+
export function resolveRelationsInSql(sql, grounding, options = {}) {
|
|
234
|
+
if (!sql || grounding.tables.length === 0)
|
|
235
|
+
return { sql, rewrites: [] };
|
|
236
|
+
const prefer = options.prefer ?? 'qualified';
|
|
237
|
+
const rewrites = [];
|
|
238
|
+
// Match the relation token after FROM / JOIN (skip subqueries starting with `(`).
|
|
239
|
+
const pattern = /\b(from|join)\s+(?!\()([a-zA-Z_][\w]*(?:\s*\.\s*[a-zA-Z_][\w]*){0,2})/gi;
|
|
240
|
+
const resolved = sql.replace(pattern, (match, keyword, relation) => {
|
|
241
|
+
const normalized = relation.replace(/\s*\.\s*/g, '.');
|
|
242
|
+
// Already a {{ ref() }} / {{ source() }} macro? Leave it.
|
|
243
|
+
if (/\{\{/.test(normalized))
|
|
244
|
+
return match;
|
|
245
|
+
const table = lookupTable(normalized, grounding);
|
|
246
|
+
if (!table)
|
|
247
|
+
return match; // unknown relation — validator will flag it.
|
|
248
|
+
const target = prefer === 'ref' && table.refForm ? table.refForm : table.qualifiedRelation;
|
|
249
|
+
if (normalized.toLowerCase() === target.toLowerCase())
|
|
250
|
+
return match; // already correct.
|
|
251
|
+
rewrites.push({ from: normalized, to: target });
|
|
252
|
+
return `${keyword} ${target}`;
|
|
253
|
+
});
|
|
254
|
+
return { sql: resolved, rewrites };
|
|
255
|
+
}
|
|
256
|
+
function lookupTable(relation, grounding) {
|
|
257
|
+
for (const key of relationKeys(relation)) {
|
|
258
|
+
const hit = grounding.byKey.get(key);
|
|
259
|
+
if (hit)
|
|
260
|
+
return hit;
|
|
261
|
+
}
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Validate that generated SQL references ONLY relations and columns present in
|
|
266
|
+
* the shared grounding. Read-only safety is enforced too (no DML/DDL). Returns
|
|
267
|
+
* a precise `offending` token so the build path can re-prompt the model with
|
|
268
|
+
* the exact miss.
|
|
269
|
+
*/
|
|
270
|
+
export function validateSqlAgainstGrounding(sql, grounding) {
|
|
271
|
+
const analysis = analyzeSqlReferences(sql);
|
|
272
|
+
const referencedRelations = analysis.tables;
|
|
273
|
+
const warnings = [];
|
|
274
|
+
if (!analysis.parsed) {
|
|
275
|
+
return {
|
|
276
|
+
ok: false,
|
|
277
|
+
code: 'unparseable',
|
|
278
|
+
error: `SQL could not be parsed for grounding validation: ${analysis.error ?? 'unknown parse error'}`,
|
|
279
|
+
warnings,
|
|
280
|
+
referencedRelations,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const unsafe = analysis.statementTypes.find((type) => type !== 'select');
|
|
284
|
+
if (unsafe) {
|
|
285
|
+
return {
|
|
286
|
+
ok: false,
|
|
287
|
+
code: 'unsafe_sql',
|
|
288
|
+
error: `Grounded SQL must be a read-only SELECT or WITH query; parser found ${unsafe.toUpperCase()}.`,
|
|
289
|
+
warnings,
|
|
290
|
+
referencedRelations,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
if (grounding.tables.length === 0) {
|
|
294
|
+
return { ok: true, warnings: ['No grounding tables were available, so validation was advisory only.'], referencedRelations };
|
|
295
|
+
}
|
|
296
|
+
// Relation check — every referenced relation must be in the grounding.
|
|
297
|
+
for (const relation of referencedRelations) {
|
|
298
|
+
if (/\{\{/.test(relation))
|
|
299
|
+
continue; // `{{ ref() }}` macros resolve at execution.
|
|
300
|
+
if (!lookupTable(relation, grounding)) {
|
|
301
|
+
return {
|
|
302
|
+
ok: false,
|
|
303
|
+
code: 'unknown_relation',
|
|
304
|
+
error: `SQL references table "${relation}" which is not in the grounded schema. Use one of: ${grounding.tables
|
|
305
|
+
.slice(0, 8)
|
|
306
|
+
.map((t) => t.qualifiedRelation)
|
|
307
|
+
.join(', ')}.`,
|
|
308
|
+
warnings,
|
|
309
|
+
referencedRelations,
|
|
310
|
+
offending: { relation },
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Column check — qualified columns must exist on their relation; unqualified
|
|
315
|
+
// columns must exist on at least one grounded relation.
|
|
316
|
+
const outputAliases = extractSelectAliases(sql);
|
|
317
|
+
for (const column of analysis.columns) {
|
|
318
|
+
if (column.column === '*')
|
|
319
|
+
continue;
|
|
320
|
+
if (column.unqualified && outputAliases.has(column.column.toLowerCase()))
|
|
321
|
+
continue;
|
|
322
|
+
if (column.relation) {
|
|
323
|
+
const table = lookupTable(column.relation, grounding);
|
|
324
|
+
if (!table || table.columns.length === 0)
|
|
325
|
+
continue; // unknown relation already handled / no column info.
|
|
326
|
+
if (!table.columns.some((c) => c.name.toLowerCase() === column.column.toLowerCase())) {
|
|
327
|
+
return {
|
|
328
|
+
ok: false,
|
|
329
|
+
code: 'unknown_column',
|
|
330
|
+
error: `SQL references column "${column.column}" which does not exist on ${table.qualifiedRelation}.`,
|
|
331
|
+
warnings,
|
|
332
|
+
referencedRelations,
|
|
333
|
+
offending: { relation: table.qualifiedRelation, column: column.column },
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
const tablesWithCols = grounding.tables.filter((t) => t.columns.length > 0);
|
|
339
|
+
if (tablesWithCols.length === 0)
|
|
340
|
+
continue;
|
|
341
|
+
if (!tablesWithCols.some((t) => t.columns.some((c) => c.name.toLowerCase() === column.column.toLowerCase()))) {
|
|
342
|
+
return {
|
|
343
|
+
ok: false,
|
|
344
|
+
code: 'unknown_column',
|
|
345
|
+
error: `SQL references column "${column.column}" which is not present on any grounded relation.`,
|
|
346
|
+
warnings,
|
|
347
|
+
referencedRelations,
|
|
348
|
+
offending: { column: column.column },
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return { ok: true, warnings, referencedRelations };
|
|
353
|
+
}
|
|
354
|
+
function extractSelectAliases(sql) {
|
|
355
|
+
const aliases = new Set();
|
|
356
|
+
for (const section of sql.matchAll(/\bSELECT\b([\s\S]*?)\bFROM\b/gi)) {
|
|
357
|
+
for (const alias of (section[1] ?? '').matchAll(/\bAS\s+(["`]?\w+["`]?)/gi)) {
|
|
358
|
+
const name = (alias[1] ?? '').replace(/["`]/g, '').trim().toLowerCase();
|
|
359
|
+
if (name)
|
|
360
|
+
aliases.add(name);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return aliases;
|
|
364
|
+
}
|
|
365
|
+
// ─── Prompt rendering ─────────────────────────────────────────────────────────
|
|
366
|
+
/**
|
|
367
|
+
* Render the grounding as a prompt block. Each table is presented as BOTH its
|
|
368
|
+
* qualified relation AND its `{{ ref() }}` form with real columns+types, plus
|
|
369
|
+
* the inferred join keys. The convention line tells the model how to reference
|
|
370
|
+
* relations for the given target (CELL → qualified; BLOCK → `{{ ref() }}`).
|
|
371
|
+
*/
|
|
372
|
+
export function renderGroundingForPrompt(grounding, target = 'cell') {
|
|
373
|
+
if (grounding.tables.length === 0)
|
|
374
|
+
return '(no schema available)';
|
|
375
|
+
const convention = target === 'block'
|
|
376
|
+
? 'Reference each table by its {{ ref(\'<model>\') }} form (DQL resolves it at execution). Use ONLY these relations and columns.'
|
|
377
|
+
: 'Reference each table by its fully-qualified relation (database.schema.table). Use ONLY these relations and columns; never a bare model name.';
|
|
378
|
+
const lines = [`Use ONLY these relations and columns. ${convention}`, ''];
|
|
379
|
+
for (const table of grounding.tables) {
|
|
380
|
+
const cols = table.columns
|
|
381
|
+
.slice(0, 30)
|
|
382
|
+
.map((c) => `${c.name}${c.type ? ` ${c.type}` : ''}`)
|
|
383
|
+
.join(', ');
|
|
384
|
+
const ref = table.refForm ? ` | ref: ${table.refForm}` : '';
|
|
385
|
+
const certified = table.certifiedBlock ? ' [certified block]' : '';
|
|
386
|
+
lines.push(`- ${table.qualifiedRelation}${ref}${certified}`);
|
|
387
|
+
lines.push(` columns: ${cols || '(no columns available)'}`);
|
|
388
|
+
}
|
|
389
|
+
if (grounding.joinKeys.length > 0) {
|
|
390
|
+
lines.push('', 'Join keys:');
|
|
391
|
+
for (const join of grounding.joinKeys.slice(0, 12)) {
|
|
392
|
+
lines.push(`- ${join.leftRelation}.${join.leftColumn} = ${join.rightRelation}.${join.rightColumn} (${join.reason})`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return lines.join('\n');
|
|
396
|
+
}
|
|
397
|
+
//# sourceMappingURL=sql-grounding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-grounding.js","sourceRoot":"","sources":["../../src/metadata/sql-grounding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table retrieval (spec 15, part 3) — give the model the RELEVANT tables, not
|
|
3
|
+
* 40 arbitrary ones. Ranks dbt models against the request using lexical
|
|
4
|
+
* overlap (a lightweight, offline FTS/BM25-style score over model name +
|
|
5
|
+
* columns + description) blended with the spec-11 `EmbeddingProvider` cosine
|
|
6
|
+
* similarity via `hybridRank`. Returns the top-K model names to feed into
|
|
7
|
+
* `buildSchemaGrounding`.
|
|
8
|
+
*
|
|
9
|
+
* Deterministic + offline by default: the default embedding provider is the
|
|
10
|
+
* hashed-token vector, and `alpha` defaults to 0 (pure lexical) so tests are
|
|
11
|
+
* stable without a model.
|
|
12
|
+
*/
|
|
13
|
+
import { type EmbeddingProvider } from '../embeddings/provider.js';
|
|
14
|
+
import type { DbtArtifacts } from '../propose/dbt-artifacts.js';
|
|
15
|
+
export interface SelectRelevantModelsOptions {
|
|
16
|
+
/** Max models to return. */
|
|
17
|
+
topK?: number;
|
|
18
|
+
/** Vector-similarity weight in [0,1]; 0 (default) = pure lexical, offline-stable. */
|
|
19
|
+
alpha?: number;
|
|
20
|
+
provider?: EmbeddingProvider;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Rank models by relevance to `request` and return the top-K model names
|
|
24
|
+
* (logical `name`, suitable for `buildSchemaGrounding`'s `relevantModels`).
|
|
25
|
+
* When no model has any lexical overlap, returns the first K models so the
|
|
26
|
+
* grounding is never empty.
|
|
27
|
+
*/
|
|
28
|
+
export declare function selectRelevantModels(artifacts: DbtArtifacts | undefined, request: string, options?: SelectRelevantModelsOptions): Promise<string[]>;
|
|
29
|
+
//# sourceMappingURL=sql-retrieval.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-retrieval.d.ts","sourceRoot":"","sources":["../../src/metadata/sql-retrieval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAwC,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACzG,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,6BAA6B,CAAC;AAE9E,MAAM,WAAW,2BAA2B;IAC1C,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AA4CD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,YAAY,GAAG,SAAS,EACnC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBnB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table retrieval (spec 15, part 3) — give the model the RELEVANT tables, not
|
|
3
|
+
* 40 arbitrary ones. Ranks dbt models against the request using lexical
|
|
4
|
+
* overlap (a lightweight, offline FTS/BM25-style score over model name +
|
|
5
|
+
* columns + description) blended with the spec-11 `EmbeddingProvider` cosine
|
|
6
|
+
* similarity via `hybridRank`. Returns the top-K model names to feed into
|
|
7
|
+
* `buildSchemaGrounding`.
|
|
8
|
+
*
|
|
9
|
+
* Deterministic + offline by default: the default embedding provider is the
|
|
10
|
+
* hashed-token vector, and `alpha` defaults to 0 (pure lexical) so tests are
|
|
11
|
+
* stable without a model.
|
|
12
|
+
*/
|
|
13
|
+
import { defaultEmbeddingProvider, hybridRank } from '../embeddings/provider.js';
|
|
14
|
+
const TOKEN_RE = /[\p{L}\p{N}_]+/gu;
|
|
15
|
+
function tokenize(text) {
|
|
16
|
+
return (text.toLowerCase().match(TOKEN_RE) ?? []).filter((t) => t.length > 1);
|
|
17
|
+
}
|
|
18
|
+
/** Searchable text for a model: name, columns, description, tags, domain. */
|
|
19
|
+
function modelText(model, artifacts) {
|
|
20
|
+
const cols = (artifacts.catalogColumns.get(model.uniqueId) ?? model.columns).map((c) => c.name);
|
|
21
|
+
return [
|
|
22
|
+
model.name,
|
|
23
|
+
model.alias ?? '',
|
|
24
|
+
model.qualifiedRelation,
|
|
25
|
+
model.description ?? '',
|
|
26
|
+
model.domainHint ?? '',
|
|
27
|
+
model.folder ?? '',
|
|
28
|
+
...model.tags,
|
|
29
|
+
...cols,
|
|
30
|
+
]
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.join(' ');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A simple normalized lexical relevance: fraction of query tokens that appear
|
|
36
|
+
* in the model's searchable text, with a small boost for name matches. In [0,1].
|
|
37
|
+
*/
|
|
38
|
+
function lexicalScore(queryTokens, model, artifacts) {
|
|
39
|
+
if (queryTokens.length === 0)
|
|
40
|
+
return 0;
|
|
41
|
+
const text = modelText(model, artifacts).toLowerCase();
|
|
42
|
+
const nameTokens = new Set(tokenize(`${model.name} ${model.alias ?? ''}`));
|
|
43
|
+
let hits = 0;
|
|
44
|
+
let nameHits = 0;
|
|
45
|
+
for (const token of queryTokens) {
|
|
46
|
+
if (text.includes(token))
|
|
47
|
+
hits += 1;
|
|
48
|
+
if (nameTokens.has(token))
|
|
49
|
+
nameHits += 1;
|
|
50
|
+
}
|
|
51
|
+
const coverage = hits / queryTokens.length;
|
|
52
|
+
const nameBoost = nameHits > 0 ? 0.25 : 0;
|
|
53
|
+
return Math.min(1, coverage + nameBoost);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Rank models by relevance to `request` and return the top-K model names
|
|
57
|
+
* (logical `name`, suitable for `buildSchemaGrounding`'s `relevantModels`).
|
|
58
|
+
* When no model has any lexical overlap, returns the first K models so the
|
|
59
|
+
* grounding is never empty.
|
|
60
|
+
*/
|
|
61
|
+
export async function selectRelevantModels(artifacts, request, options = {}) {
|
|
62
|
+
if (!artifacts || artifacts.models.length === 0)
|
|
63
|
+
return [];
|
|
64
|
+
const topK = Math.max(1, options.topK ?? 12);
|
|
65
|
+
const queryTokens = tokenize(request);
|
|
66
|
+
const items = artifacts.models.map((model) => ({
|
|
67
|
+
item: model,
|
|
68
|
+
text: modelText(model, artifacts),
|
|
69
|
+
ftsScore: lexicalScore(queryTokens, model, artifacts),
|
|
70
|
+
}));
|
|
71
|
+
const ranked = await hybridRank(request, items, {
|
|
72
|
+
alpha: options.alpha ?? 0,
|
|
73
|
+
provider: options.provider ?? defaultEmbeddingProvider(),
|
|
74
|
+
});
|
|
75
|
+
const withSignal = ranked.filter((r) => r.score > 0);
|
|
76
|
+
const chosen = (withSignal.length > 0 ? withSignal : ranked).slice(0, topK);
|
|
77
|
+
return chosen.map((r) => r.item.name);
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=sql-retrieval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-retrieval.js","sourceRoot":"","sources":["../../src/metadata/sql-retrieval.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narrate service — turns a *grounded, executed* query result into a stakeholder
|
|
3
|
+
* story: a summary, key findings, an optional recommendation, and optional
|
|
4
|
+
* per-item (per-tile) insight captions.
|
|
5
|
+
*
|
|
6
|
+
* It is provider-agnostic by design (mirrors `createLlmAgentRunPlanner`): callers
|
|
7
|
+
* inject a plain text completion (`NarrateCompletion`); any parse/transport
|
|
8
|
+
* failure — or no injected LLM at all — falls back to a deterministic narration
|
|
9
|
+
* computed from the rows (totals, leader, concentration, range). That keeps
|
|
10
|
+
* Research and App storytelling fast, offline, and always-grounded: narration
|
|
11
|
+
* only ever describes data the loop already executed against governed sources.
|
|
12
|
+
*/
|
|
13
|
+
export interface NarrateResultData {
|
|
14
|
+
columns: string[];
|
|
15
|
+
rows: Array<Record<string, unknown>>;
|
|
16
|
+
}
|
|
17
|
+
export interface NarrateItem {
|
|
18
|
+
id: string;
|
|
19
|
+
title: string;
|
|
20
|
+
result?: NarrateResultData;
|
|
21
|
+
}
|
|
22
|
+
export interface NarrateInput {
|
|
23
|
+
question: string;
|
|
24
|
+
intent?: string;
|
|
25
|
+
result?: NarrateResultData;
|
|
26
|
+
/** Per-tile results, for App storytelling captions. */
|
|
27
|
+
items?: NarrateItem[];
|
|
28
|
+
/** Governed sources/evidence used, surfaced to keep the narration grounded. */
|
|
29
|
+
evidence?: string[];
|
|
30
|
+
/** True when the underlying SQL is review-required (uncertified). */
|
|
31
|
+
reviewRequired?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface NarrateResult {
|
|
34
|
+
summary: string;
|
|
35
|
+
keyFindings: string[];
|
|
36
|
+
recommendation?: string;
|
|
37
|
+
/** Keyed by item id → one-line insight caption. */
|
|
38
|
+
perItemInsight?: Record<string, string>;
|
|
39
|
+
source: "llm" | "deterministic";
|
|
40
|
+
}
|
|
41
|
+
export type NarrateCompletion = (input: {
|
|
42
|
+
system: string;
|
|
43
|
+
user: string;
|
|
44
|
+
signal?: AbortSignal;
|
|
45
|
+
}) => Promise<string>;
|
|
46
|
+
export interface NarrateOptions {
|
|
47
|
+
complete?: NarrateCompletion;
|
|
48
|
+
signal?: AbortSignal;
|
|
49
|
+
maxFindings?: number;
|
|
50
|
+
}
|
|
51
|
+
export declare function narrateResult(input: NarrateInput, options?: NarrateOptions): Promise<NarrateResult>;
|
|
52
|
+
//# sourceMappingURL=narrate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narrate.d.ts","sourceRoot":"","sources":["../src/narrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,uDAAuD;IACvD,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,EAAE,KAAK,GAAG,eAAe,CAAC;CACjC;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEtB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAyB7G"}
|