@querypanel/node-sdk 1.3.0 → 1.3.3
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 +1 -1
- package/dist/index.cjs +230 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -13
- package/dist/index.d.ts +19 -13
- package/dist/index.js +230 -65
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -544,7 +544,7 @@ Every request is signed with `RS256` using the private key you pass to the const
|
|
|
544
544
|
|
|
545
545
|
- HTTP errors propagate as thrown `Error` instances that include `status` (and `details` when available).
|
|
546
546
|
- `syncSchema` automatically skips embedding if the schema hasn't changed (drift detection). Use `syncSchema(..., { forceReindex: true })` to force updates.
|
|
547
|
-
- `ask()` raises immediately for guardrail/moderation errors because `/query` responds with 4xx/5xx.
|
|
547
|
+
- `ask()` raises immediately for guardrail/moderation errors because `/v2/query` responds with 4xx/5xx. `pipeline: "v1"` is not accepted.
|
|
548
548
|
|
|
549
549
|
### Automatic SQL repair and retry
|
|
550
550
|
|
package/dist/index.cjs
CHANGED
|
@@ -61,6 +61,13 @@ var BigQueryAdapter = class {
|
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
+
clientFn;
|
|
65
|
+
projectId;
|
|
66
|
+
datasetProjectId;
|
|
67
|
+
defaultDataset;
|
|
68
|
+
databaseName;
|
|
69
|
+
kind;
|
|
70
|
+
allowedTables;
|
|
64
71
|
async execute(sql, params) {
|
|
65
72
|
if (this.allowedTables) {
|
|
66
73
|
this.validateQueryTables(sql);
|
|
@@ -291,6 +298,11 @@ var ClickHouseAdapter = class {
|
|
|
291
298
|
this.allowedTables = normalizeTableFilter2(options.allowedTables);
|
|
292
299
|
}
|
|
293
300
|
}
|
|
301
|
+
clientFn;
|
|
302
|
+
databaseName;
|
|
303
|
+
defaultFormat;
|
|
304
|
+
kind;
|
|
305
|
+
allowedTables;
|
|
294
306
|
async execute(sql, params) {
|
|
295
307
|
if (this.allowedTables) {
|
|
296
308
|
this.validateQueryTables(sql);
|
|
@@ -544,6 +556,11 @@ var PostgresAdapter = class {
|
|
|
544
556
|
);
|
|
545
557
|
}
|
|
546
558
|
}
|
|
559
|
+
clientFn;
|
|
560
|
+
databaseName;
|
|
561
|
+
defaultSchema;
|
|
562
|
+
kind;
|
|
563
|
+
allowedTables;
|
|
547
564
|
async execute(sql, params) {
|
|
548
565
|
if (this.allowedTables) {
|
|
549
566
|
this.validateQueryTables(sql);
|
|
@@ -852,6 +869,9 @@ var QueryPipelineError = class extends Error {
|
|
|
852
869
|
this.status = status;
|
|
853
870
|
this.name = "QueryPipelineError";
|
|
854
871
|
}
|
|
872
|
+
code;
|
|
873
|
+
details;
|
|
874
|
+
status;
|
|
855
875
|
/**
|
|
856
876
|
* Check if this is a moderation error
|
|
857
877
|
*/
|
|
@@ -904,8 +924,14 @@ var QueryPipelineError = class extends Error {
|
|
|
904
924
|
|
|
905
925
|
// src/core/client.ts
|
|
906
926
|
var ApiClient = class {
|
|
927
|
+
baseUrl;
|
|
928
|
+
privateKey;
|
|
929
|
+
organizationId;
|
|
930
|
+
defaultTenantId;
|
|
931
|
+
additionalHeaders;
|
|
932
|
+
fetchImpl;
|
|
933
|
+
cryptoKey = null;
|
|
907
934
|
constructor(baseUrl, privateKey, organizationId, options) {
|
|
908
|
-
this.cryptoKey = null;
|
|
909
935
|
if (!baseUrl) {
|
|
910
936
|
throw new Error("Base URL is required");
|
|
911
937
|
}
|
|
@@ -1159,6 +1185,8 @@ var ApiClient = class {
|
|
|
1159
1185
|
|
|
1160
1186
|
// src/core/callback-client.ts
|
|
1161
1187
|
var CallbackApiClient = class {
|
|
1188
|
+
requestHandler;
|
|
1189
|
+
defaultTenantId;
|
|
1162
1190
|
constructor(requestHandler, options) {
|
|
1163
1191
|
this.requestHandler = requestHandler;
|
|
1164
1192
|
this.defaultTenantId = options?.defaultTenantId;
|
|
@@ -1301,10 +1329,9 @@ function normalizeSqlParamsInput(params) {
|
|
|
1301
1329
|
|
|
1302
1330
|
// src/core/query-engine.ts
|
|
1303
1331
|
var QueryEngine = class {
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
}
|
|
1332
|
+
databases = /* @__PURE__ */ new Map();
|
|
1333
|
+
databaseMetadata = /* @__PURE__ */ new Map();
|
|
1334
|
+
defaultDatabase;
|
|
1308
1335
|
attachDatabase(name, adapter, metadata) {
|
|
1309
1336
|
this.databases.set(name, adapter);
|
|
1310
1337
|
this.databaseMetadata.set(name, metadata);
|
|
@@ -1990,7 +2017,13 @@ var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
|
1990
2017
|
// src/routes/query.ts
|
|
1991
2018
|
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
1992
2019
|
function resolveQueryPipeline(pipeline) {
|
|
1993
|
-
|
|
2020
|
+
const requested = pipeline;
|
|
2021
|
+
if (requested != null && requested !== "v2") {
|
|
2022
|
+
throw new Error(
|
|
2023
|
+
`Query pipeline "${requested}" was removed. ask() and modifyChart() always use POST /v2/query.`
|
|
2024
|
+
);
|
|
2025
|
+
}
|
|
2026
|
+
return "v2";
|
|
1994
2027
|
}
|
|
1995
2028
|
async function ask(client, queryEngine, question, options, signal) {
|
|
1996
2029
|
const tenantId = resolveTenantId5(client, options.tenantId);
|
|
@@ -2000,8 +2033,9 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
2000
2033
|
let attempt = 0;
|
|
2001
2034
|
let lastError = options.lastError;
|
|
2002
2035
|
let previousSql = options.previousSql;
|
|
2003
|
-
|
|
2004
|
-
|
|
2036
|
+
let parentQueryId;
|
|
2037
|
+
resolveQueryPipeline(options.pipeline);
|
|
2038
|
+
const queryEndpoint = "/v2/query";
|
|
2005
2039
|
while (attempt <= maxRetry) {
|
|
2006
2040
|
const databaseName = options.database ?? queryEngine.getDefaultDatabase();
|
|
2007
2041
|
const metadata = databaseName ? queryEngine.getDatabaseMetadata(databaseName) : void 0;
|
|
@@ -2031,7 +2065,8 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
2031
2065
|
...databaseName ? { database: databaseName } : {},
|
|
2032
2066
|
...metadata?.dialect ? { dialect: metadata.dialect } : {},
|
|
2033
2067
|
...options.model?.trim() ? { model: options.model.trim() } : {},
|
|
2034
|
-
...
|
|
2068
|
+
...options.systemPrompt?.trim() ? { system_prompt: options.systemPrompt.trim() } : {},
|
|
2069
|
+
...parentQueryId ? { parent_query_id: parentQueryId } : {},
|
|
2035
2070
|
debug: options.debug ?? false
|
|
2036
2071
|
},
|
|
2037
2072
|
tenantId,
|
|
@@ -2053,6 +2088,9 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
2053
2088
|
if (!sql || !dialect) {
|
|
2054
2089
|
throw new Error("Query response missing required SQL or dialect");
|
|
2055
2090
|
}
|
|
2091
|
+
if (queryResponse.data.queryId) {
|
|
2092
|
+
parentQueryId = queryResponse.data.queryId;
|
|
2093
|
+
}
|
|
2056
2094
|
const dbName = queryResponse.data.database ?? options.database ?? queryEngine.getDefaultDatabase();
|
|
2057
2095
|
if (!dbName) {
|
|
2058
2096
|
throw new Error(
|
|
@@ -2212,35 +2250,35 @@ async function resolveQuery(client, queryEngine, queryId, options, signal) {
|
|
|
2212
2250
|
dialect: response.dialect
|
|
2213
2251
|
};
|
|
2214
2252
|
}
|
|
2253
|
+
async function markQueryExecuted(client, queryId, options, signal) {
|
|
2254
|
+
try {
|
|
2255
|
+
await client.post(
|
|
2256
|
+
`/v2/queries/${encodeURIComponent(queryId)}/executed`,
|
|
2257
|
+
{},
|
|
2258
|
+
options.tenantId,
|
|
2259
|
+
options.userId,
|
|
2260
|
+
options.scopes,
|
|
2261
|
+
signal
|
|
2262
|
+
);
|
|
2263
|
+
} catch {
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2215
2266
|
|
|
2216
2267
|
// src/routes/modify.ts
|
|
2217
|
-
function buildModifiedQuestion(originalQuestion, modifications,
|
|
2268
|
+
function buildModifiedQuestion(originalQuestion, modifications, hasSessionContext = false) {
|
|
2218
2269
|
const hints = [];
|
|
2219
2270
|
if (modifications.timeGranularity) {
|
|
2220
2271
|
hints.push(`group results by ${modifications.timeGranularity}`);
|
|
2221
2272
|
}
|
|
2222
2273
|
if (modifications.dateRange) {
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
hints.push(`change end date to ${to}`);
|
|
2232
|
-
}
|
|
2233
|
-
} else {
|
|
2234
|
-
const parts = [];
|
|
2235
|
-
if (modifications.dateRange.from) {
|
|
2236
|
-
parts.push(`from ${modifications.dateRange.from}`);
|
|
2237
|
-
}
|
|
2238
|
-
if (modifications.dateRange.to) {
|
|
2239
|
-
parts.push(`to ${modifications.dateRange.to}`);
|
|
2240
|
-
}
|
|
2241
|
-
if (parts.length > 0) {
|
|
2242
|
-
hints.push(`filter date range ${parts.join(" ")}`);
|
|
2243
|
-
}
|
|
2274
|
+
const from = normalizeDateInput(modifications.dateRange.from);
|
|
2275
|
+
const to = normalizeDateInput(modifications.dateRange.to);
|
|
2276
|
+
if (from && to) {
|
|
2277
|
+
hints.push(`change date range to ${from} through ${to}`);
|
|
2278
|
+
} else if (from) {
|
|
2279
|
+
hints.push(`change start date to ${from}`);
|
|
2280
|
+
} else if (to) {
|
|
2281
|
+
hints.push(`change end date to ${to}`);
|
|
2244
2282
|
}
|
|
2245
2283
|
}
|
|
2246
2284
|
if (modifications.additionalInstructions) {
|
|
@@ -2249,11 +2287,12 @@ function buildModifiedQuestion(originalQuestion, modifications, pipeline, hasSes
|
|
|
2249
2287
|
if (hints.length === 0) {
|
|
2250
2288
|
return originalQuestion;
|
|
2251
2289
|
}
|
|
2252
|
-
if (
|
|
2290
|
+
if (hasSessionContext) {
|
|
2253
2291
|
return hints.join(", ");
|
|
2254
2292
|
}
|
|
2255
2293
|
return `${originalQuestion} (${hints.join(", ")})`;
|
|
2256
2294
|
}
|
|
2295
|
+
var REWRITE_DATEFILTER_ENDPOINT = "/v2/rewrite-datefilter";
|
|
2257
2296
|
var START_PARAM_KEY_REGEX = /(^|_)(start|from)(_|$)/i;
|
|
2258
2297
|
var END_PARAM_KEY_REGEX = /(^|_)(end|to)(_|$)/i;
|
|
2259
2298
|
var ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?$/;
|
|
@@ -2290,31 +2329,118 @@ function normalizeGeneratedParamKey(param, index) {
|
|
|
2290
2329
|
const nameCandidate = typeof param.name === "string" && param.name.trim() || typeof param.placeholder === "string" && param.placeholder.trim() || typeof param.position === "number" && String(param.position) || String(index + 1);
|
|
2291
2330
|
return nameCandidate.replace(/[{}]/g, "").replace(/(.+):.*$/, "$1").replace(/^[:$]/, "").trim();
|
|
2292
2331
|
}
|
|
2293
|
-
function
|
|
2332
|
+
function collectParamKeys(params, paramMetadata) {
|
|
2333
|
+
const keys = new Set(Object.keys(params));
|
|
2334
|
+
for (let i = 0; i < paramMetadata.length; i++) {
|
|
2335
|
+
const param = paramMetadata[i];
|
|
2336
|
+
if (!param) continue;
|
|
2337
|
+
keys.add(normalizeGeneratedParamKey(param, i));
|
|
2338
|
+
}
|
|
2339
|
+
return [...keys];
|
|
2340
|
+
}
|
|
2341
|
+
function placeholderKey(token) {
|
|
2342
|
+
if (token.startsWith("$") || token.startsWith("@")) return token.slice(1);
|
|
2343
|
+
return token.slice(1, -1).replace(/:.+$/, "").trim();
|
|
2344
|
+
}
|
|
2345
|
+
function isDateLike(value) {
|
|
2346
|
+
return typeof value === "string" && /^\d{4}-\d{2}-\d{2}/.test(value.trim());
|
|
2347
|
+
}
|
|
2348
|
+
function dateBoundKeysFromSql(sql) {
|
|
2349
|
+
const start = /* @__PURE__ */ new Set();
|
|
2350
|
+
const end = /* @__PURE__ */ new Set();
|
|
2351
|
+
const comparison = /(>=|<=|>|<)\s*(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)/g;
|
|
2352
|
+
const between = /BETWEEN\s+(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)\s+AND\s+(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)/gi;
|
|
2353
|
+
for (const match of sql.matchAll(comparison)) {
|
|
2354
|
+
const key = placeholderKey(match[2] ?? "");
|
|
2355
|
+
if (!key) continue;
|
|
2356
|
+
if (match[1] === ">=" || match[1] === ">") start.add(key);
|
|
2357
|
+
else end.add(key);
|
|
2358
|
+
}
|
|
2359
|
+
for (const match of sql.matchAll(between)) {
|
|
2360
|
+
const startKey = placeholderKey(match[1] ?? "");
|
|
2361
|
+
const endKey = placeholderKey(match[2] ?? "");
|
|
2362
|
+
if (startKey) start.add(startKey);
|
|
2363
|
+
if (endKey) end.add(endKey);
|
|
2364
|
+
}
|
|
2365
|
+
return { start, end };
|
|
2366
|
+
}
|
|
2367
|
+
function paramValueForKey(key, params, paramMetadata) {
|
|
2368
|
+
if (key in params) return params[key];
|
|
2369
|
+
for (let i = 0; i < paramMetadata.length; i++) {
|
|
2370
|
+
const param = paramMetadata[i];
|
|
2371
|
+
if (!param) continue;
|
|
2372
|
+
if (normalizeGeneratedParamKey(param, i) === key) return param.value;
|
|
2373
|
+
}
|
|
2374
|
+
return void 0;
|
|
2375
|
+
}
|
|
2376
|
+
function dateBoundKeys(sql, params, paramMetadata, boundary) {
|
|
2377
|
+
const fromSql = dateBoundKeysFromSql(sql)[boundary];
|
|
2378
|
+
const keys = [];
|
|
2379
|
+
for (const key of collectParamKeys(params, paramMetadata)) {
|
|
2380
|
+
const named = keyLooksLikeDateBoundary(key, boundary);
|
|
2381
|
+
if (!named && !fromSql.has(key)) continue;
|
|
2382
|
+
if (!isDateLike(paramValueForKey(key, params, paramMetadata))) continue;
|
|
2383
|
+
keys.push(key);
|
|
2384
|
+
}
|
|
2385
|
+
return keys;
|
|
2386
|
+
}
|
|
2387
|
+
function canSubstituteDateRangeParams(dateRange, sql, params, paramMetadata = []) {
|
|
2388
|
+
if (!dateRange) return false;
|
|
2389
|
+
const from = normalizeDateInput(dateRange.from);
|
|
2390
|
+
const to = normalizeDateInput(dateRange.to);
|
|
2391
|
+
if (!from && !to) return false;
|
|
2392
|
+
if (from && dateBoundKeys(sql, params, paramMetadata, "start").length === 0) {
|
|
2393
|
+
return false;
|
|
2394
|
+
}
|
|
2395
|
+
if (to && dateBoundKeys(sql, params, paramMetadata, "end").length === 0) {
|
|
2396
|
+
return false;
|
|
2397
|
+
}
|
|
2398
|
+
return true;
|
|
2399
|
+
}
|
|
2400
|
+
function isDateRangeOnlySqlModification(modifications) {
|
|
2401
|
+
if (!modifications?.dateRange) return false;
|
|
2402
|
+
if (modifications.customSql) return false;
|
|
2403
|
+
if (modifications.timeGranularity) return false;
|
|
2404
|
+
if (typeof modifications.additionalInstructions === "string" && modifications.additionalInstructions.trim().length > 0) {
|
|
2405
|
+
return false;
|
|
2406
|
+
}
|
|
2407
|
+
return true;
|
|
2408
|
+
}
|
|
2409
|
+
function applyDateRangeOverrides(dateRange, sql, params, paramMetadata) {
|
|
2294
2410
|
if (!dateRange) return;
|
|
2295
2411
|
const from = normalizeDateInput(dateRange.from);
|
|
2296
2412
|
const to = normalizeDateInput(dateRange.to);
|
|
2297
2413
|
if (!from && !to) return;
|
|
2414
|
+
const startKeys = new Set(
|
|
2415
|
+
from ? dateBoundKeys(sql, params, paramMetadata, "start") : []
|
|
2416
|
+
);
|
|
2417
|
+
const endKeys = new Set(
|
|
2418
|
+
to ? dateBoundKeys(sql, params, paramMetadata, "end") : []
|
|
2419
|
+
);
|
|
2298
2420
|
for (const [key, value] of Object.entries(params)) {
|
|
2299
|
-
if (
|
|
2300
|
-
params[key] = formatDateOverride(from, "start", value);
|
|
2421
|
+
if (startKeys.has(key)) {
|
|
2422
|
+
params[key] = formatDateOverride(from ?? "", "start", value);
|
|
2301
2423
|
}
|
|
2302
|
-
if (
|
|
2303
|
-
params[key] = formatDateOverride(to, "end", value);
|
|
2424
|
+
if (endKeys.has(key)) {
|
|
2425
|
+
params[key] = formatDateOverride(to ?? "", "end", value);
|
|
2304
2426
|
}
|
|
2305
2427
|
}
|
|
2306
2428
|
for (let i = 0; i < paramMetadata.length; i++) {
|
|
2307
2429
|
const param = paramMetadata[i];
|
|
2308
2430
|
if (!param) continue;
|
|
2309
2431
|
const key = normalizeGeneratedParamKey(param, i);
|
|
2310
|
-
if (
|
|
2311
|
-
param.value = formatDateOverride(from, "start", param.value);
|
|
2432
|
+
if (startKeys.has(key)) {
|
|
2433
|
+
param.value = formatDateOverride(from ?? "", "start", param.value);
|
|
2312
2434
|
}
|
|
2313
|
-
if (
|
|
2314
|
-
param.value = formatDateOverride(to, "end", param.value);
|
|
2435
|
+
if (endKeys.has(key)) {
|
|
2436
|
+
param.value = formatDateOverride(to ?? "", "end", param.value);
|
|
2315
2437
|
}
|
|
2316
2438
|
}
|
|
2317
2439
|
}
|
|
2440
|
+
function buildPreviousParams(params, paramMetadata) {
|
|
2441
|
+
if (paramMetadata.length > 0) return paramMetadata;
|
|
2442
|
+
return Object.entries(params).map(([name, value]) => ({ name, value }));
|
|
2443
|
+
}
|
|
2318
2444
|
function buildVizHints(modifications) {
|
|
2319
2445
|
const hints = {};
|
|
2320
2446
|
if (modifications.kind) {
|
|
@@ -2365,8 +2491,11 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2365
2491
|
const hasSqlMods = !!input.sqlModifications;
|
|
2366
2492
|
const hasVizMods = !!input.vizModifications;
|
|
2367
2493
|
const hasCustomSql = !!input.sqlModifications?.customSql;
|
|
2368
|
-
const
|
|
2369
|
-
const
|
|
2494
|
+
const lightweight = options?.lightweight === true;
|
|
2495
|
+
const dateOnly = lightweight && isDateRangeOnlySqlModification(input.sqlModifications);
|
|
2496
|
+
const skipChartLlm = lightweight && !hasCustomSql && (dateOnly || hasVizMods && !hasSqlMods);
|
|
2497
|
+
resolveQueryPipeline(options?.pipeline);
|
|
2498
|
+
const queryEndpoint = "/v2/query";
|
|
2370
2499
|
let currentSql = input.sql;
|
|
2371
2500
|
let finalParams = input.params ?? {};
|
|
2372
2501
|
let paramMetadata = [];
|
|
@@ -2418,28 +2547,57 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2418
2547
|
paramMetadata = [];
|
|
2419
2548
|
queryId = void 0;
|
|
2420
2549
|
sqlChanged = true;
|
|
2550
|
+
} else if (dateOnly && canSubstituteDateRangeParams(
|
|
2551
|
+
input.sqlModifications?.dateRange,
|
|
2552
|
+
finalSql,
|
|
2553
|
+
finalParams,
|
|
2554
|
+
paramMetadata
|
|
2555
|
+
)) {
|
|
2556
|
+
finalParams = { ...finalParams };
|
|
2557
|
+
applyDateRangeOverrides(
|
|
2558
|
+
input.sqlModifications?.dateRange,
|
|
2559
|
+
finalSql,
|
|
2560
|
+
finalParams,
|
|
2561
|
+
paramMetadata
|
|
2562
|
+
);
|
|
2563
|
+
sqlChanged = false;
|
|
2421
2564
|
} else if (hasSqlMods && !hasCustomSql) {
|
|
2422
2565
|
const modifiedQuestion = buildModifiedQuestion(
|
|
2423
2566
|
input.question,
|
|
2424
2567
|
input.sqlModifications,
|
|
2425
|
-
pipeline,
|
|
2426
2568
|
hasQuerypanelSessionContext
|
|
2427
2569
|
);
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2570
|
+
finalQuestion = modifiedQuestion;
|
|
2571
|
+
const sharedBody = {
|
|
2572
|
+
session_id: querypanelSessionId,
|
|
2573
|
+
previous_sql: currentSql,
|
|
2574
|
+
...tenantSettings ? { tenant_settings: tenantSettings } : {},
|
|
2575
|
+
...databaseName ? { database: databaseName } : {},
|
|
2576
|
+
...metadata?.dialect ? { dialect: metadata.dialect } : {},
|
|
2577
|
+
debug: options?.debug ?? false
|
|
2578
|
+
};
|
|
2579
|
+
const [endpoint, body] = dateOnly ? [
|
|
2580
|
+
REWRITE_DATEFILTER_ENDPOINT,
|
|
2581
|
+
{
|
|
2582
|
+
...sharedBody,
|
|
2583
|
+
question: input.question,
|
|
2584
|
+
previous_params: buildPreviousParams(finalParams, paramMetadata),
|
|
2585
|
+
date_range: {
|
|
2586
|
+
from: normalizeDateInput(input.sqlModifications?.dateRange?.from),
|
|
2587
|
+
to: normalizeDateInput(input.sqlModifications?.dateRange?.to)
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
] : [
|
|
2432
2591
|
queryEndpoint,
|
|
2433
2592
|
{
|
|
2593
|
+
...sharedBody,
|
|
2434
2594
|
question: modifiedQuestion,
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
debug: options?.debug ?? false
|
|
2442
|
-
},
|
|
2595
|
+
...options?.maxRetry ? { max_retry: options.maxRetry } : {}
|
|
2596
|
+
}
|
|
2597
|
+
];
|
|
2598
|
+
const queryResponse = await client.post(
|
|
2599
|
+
endpoint,
|
|
2600
|
+
body,
|
|
2443
2601
|
tenantId,
|
|
2444
2602
|
options?.userId,
|
|
2445
2603
|
options?.scopes,
|
|
@@ -2449,13 +2607,12 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2449
2607
|
finalSql = queryResponse.sql;
|
|
2450
2608
|
paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
|
|
2451
2609
|
finalParams = queryEngine.mapGeneratedParams(paramMetadata);
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
}
|
|
2610
|
+
applyDateRangeOverrides(
|
|
2611
|
+
input.sqlModifications?.dateRange,
|
|
2612
|
+
finalSql,
|
|
2613
|
+
finalParams,
|
|
2614
|
+
paramMetadata
|
|
2615
|
+
);
|
|
2459
2616
|
rationale = queryResponse.rationale;
|
|
2460
2617
|
queryId = queryResponse.queryId;
|
|
2461
2618
|
sqlChanged = finalSql !== currentSql;
|
|
@@ -2473,7 +2630,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2473
2630
|
};
|
|
2474
2631
|
const vizHints = hasVizMods ? buildVizHints(input.vizModifications) : {};
|
|
2475
2632
|
const vizHintsForChart = chartType === "vizspec" ? vizHints : stripVizSpecOnlyHints(vizHints);
|
|
2476
|
-
if (chartType === "vizspec") {
|
|
2633
|
+
if (!skipChartLlm && chartType === "vizspec") {
|
|
2477
2634
|
const vizspecResponse = await client.post(
|
|
2478
2635
|
"/vizspec",
|
|
2479
2636
|
{
|
|
@@ -2500,7 +2657,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2500
2657
|
specType: "vizspec",
|
|
2501
2658
|
notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
|
|
2502
2659
|
};
|
|
2503
|
-
} else {
|
|
2660
|
+
} else if (!skipChartLlm) {
|
|
2504
2661
|
const chartResponse = await client.post(
|
|
2505
2662
|
"/chart",
|
|
2506
2663
|
{
|
|
@@ -2673,6 +2830,9 @@ function resolveAttachEnforceTenantIsolation(tenantFieldName, enforceTenantIsola
|
|
|
2673
2830
|
return tenantFieldName ? true : void 0;
|
|
2674
2831
|
}
|
|
2675
2832
|
var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
|
|
2833
|
+
client;
|
|
2834
|
+
queryEngine;
|
|
2835
|
+
supportedChartTypes;
|
|
2676
2836
|
/**
|
|
2677
2837
|
* @param workspaceId - Workspace UUID (same value as your org in the dashboard). Passed to the API as JWT claim `organizationId`.
|
|
2678
2838
|
*/
|
|
@@ -2924,6 +3084,11 @@ var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
|
|
|
2924
3084
|
databaseName,
|
|
2925
3085
|
tenantId
|
|
2926
3086
|
);
|
|
3087
|
+
if (input.queryId) {
|
|
3088
|
+
await markQueryExecuted(this.client, input.queryId, {
|
|
3089
|
+
tenantId
|
|
3090
|
+
});
|
|
3091
|
+
}
|
|
2927
3092
|
return { rows: result.rows, fields: result.fields };
|
|
2928
3093
|
}
|
|
2929
3094
|
// VizSpec generation
|