@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/dist/index.d.cts CHANGED
@@ -731,12 +731,11 @@ interface AskOptions {
731
731
  */
732
732
  querypanelSessionId?: string;
733
733
  /**
734
- * Pipeline version for query generation.
735
- * Defaults to `"v2"` (`POST /v2/query`).
736
- * - `"v2"` (default): intent planning, hybrid retrieval, schema linking, SQL reflection
737
- * - `"v1"` (**deprecated**): legacy `POST /query` pipeline — prefer omitting or `"v2"`
734
+ * Query pipeline. Only `"v2"` is accepted (`POST /v2/query`).
735
+ * `"v1"` was removed: passing it fails typecheck and throws at runtime.
736
+ * Omit this field; asks always use v2.
738
737
  */
739
- pipeline?: "v1" | "v2";
738
+ pipeline?: "v2";
740
739
  /**
741
740
  * Optional model id for SQL generation (e.g. OpenAI or `gemini-*` when the API uses Gemini). Omit for server default.
742
741
  */
@@ -750,7 +749,7 @@ interface AskOptions {
750
749
  * Use this for tenant-specific policies (e.g. retention windows) that must
751
750
  * be enforced on every query.
752
751
  *
753
- * Sent when the resolved pipeline is `"v2"` (the default).
752
+ * Sent on every ask (`POST /v2/query`).
754
753
  */
755
754
  systemPrompt?: string;
756
755
  /**
@@ -828,9 +827,10 @@ interface AskResponse {
828
827
  trace?: PipelineTrace;
829
828
  }
830
829
  /**
831
- * Resolve ask/modify pipeline. Defaults to v2; `"v1"` remains available but deprecated.
830
+ * Resolve ask/modify pipeline. Always `"v2"` (`POST /v2/query`).
831
+ * Throws if a removed pipeline such as `"v1"` is passed.
832
832
  */
833
- declare function resolveQueryPipeline(pipeline?: "v1" | "v2"): "v1" | "v2";
833
+ declare function resolveQueryPipeline(pipeline?: "v2"): "v2";
834
834
  declare function anonymizeResults(rows: Array<Record<string, unknown>>): Array<Record<string, string>>;
835
835
 
836
836
  /**
@@ -985,12 +985,18 @@ interface ChartModifyOptions {
985
985
  /** Chart generation method: 'vega-lite' or 'vizspec' */
986
986
  chartType?: "vega-lite" | "vizspec";
987
987
  /**
988
- * Pipeline version for SQL regeneration.
989
- * Defaults to `"v2"` (`POST /v2/query`).
990
- * - `"v2"` (default): intent planning, hybrid retrieval, schema linking, SQL reflection
991
- * - `"v1"` (**deprecated**): legacy `POST /query` pipeline — prefer omitting or `"v2"`
988
+ * Query pipeline. Only `"v2"` is accepted (`POST /v2/query`).
989
+ * `"v1"` was removed: passing it fails typecheck and throws at runtime.
990
+ * Omit this field; chart modifications always use v2.
992
991
  */
993
- pipeline?: "v1" | "v2";
992
+ pipeline?: "v2";
993
+ /**
994
+ * Fast path for structured controls (pinned charts): date-only changes
995
+ * substitute params or call `/v2/rewrite-datefilter` instead of `/v2/query`,
996
+ * and chart generation is skipped when the caller keeps its own encoding
997
+ * (`chart.vizSpec` / `vegaLiteSpec` are then omitted). Default: false.
998
+ */
999
+ lightweight?: boolean;
994
1000
  /**
995
1001
  * QueryPanel session ID for context-aware follow-ups.
996
1002
  * Pass the querypanelSessionId from a previous ask() response
package/dist/index.d.ts CHANGED
@@ -731,12 +731,11 @@ interface AskOptions {
731
731
  */
732
732
  querypanelSessionId?: string;
733
733
  /**
734
- * Pipeline version for query generation.
735
- * Defaults to `"v2"` (`POST /v2/query`).
736
- * - `"v2"` (default): intent planning, hybrid retrieval, schema linking, SQL reflection
737
- * - `"v1"` (**deprecated**): legacy `POST /query` pipeline — prefer omitting or `"v2"`
734
+ * Query pipeline. Only `"v2"` is accepted (`POST /v2/query`).
735
+ * `"v1"` was removed: passing it fails typecheck and throws at runtime.
736
+ * Omit this field; asks always use v2.
738
737
  */
739
- pipeline?: "v1" | "v2";
738
+ pipeline?: "v2";
740
739
  /**
741
740
  * Optional model id for SQL generation (e.g. OpenAI or `gemini-*` when the API uses Gemini). Omit for server default.
742
741
  */
@@ -750,7 +749,7 @@ interface AskOptions {
750
749
  * Use this for tenant-specific policies (e.g. retention windows) that must
751
750
  * be enforced on every query.
752
751
  *
753
- * Sent when the resolved pipeline is `"v2"` (the default).
752
+ * Sent on every ask (`POST /v2/query`).
754
753
  */
755
754
  systemPrompt?: string;
756
755
  /**
@@ -828,9 +827,10 @@ interface AskResponse {
828
827
  trace?: PipelineTrace;
829
828
  }
830
829
  /**
831
- * Resolve ask/modify pipeline. Defaults to v2; `"v1"` remains available but deprecated.
830
+ * Resolve ask/modify pipeline. Always `"v2"` (`POST /v2/query`).
831
+ * Throws if a removed pipeline such as `"v1"` is passed.
832
832
  */
833
- declare function resolveQueryPipeline(pipeline?: "v1" | "v2"): "v1" | "v2";
833
+ declare function resolveQueryPipeline(pipeline?: "v2"): "v2";
834
834
  declare function anonymizeResults(rows: Array<Record<string, unknown>>): Array<Record<string, string>>;
835
835
 
836
836
  /**
@@ -985,12 +985,18 @@ interface ChartModifyOptions {
985
985
  /** Chart generation method: 'vega-lite' or 'vizspec' */
986
986
  chartType?: "vega-lite" | "vizspec";
987
987
  /**
988
- * Pipeline version for SQL regeneration.
989
- * Defaults to `"v2"` (`POST /v2/query`).
990
- * - `"v2"` (default): intent planning, hybrid retrieval, schema linking, SQL reflection
991
- * - `"v1"` (**deprecated**): legacy `POST /query` pipeline — prefer omitting or `"v2"`
988
+ * Query pipeline. Only `"v2"` is accepted (`POST /v2/query`).
989
+ * `"v1"` was removed: passing it fails typecheck and throws at runtime.
990
+ * Omit this field; chart modifications always use v2.
992
991
  */
993
- pipeline?: "v1" | "v2";
992
+ pipeline?: "v2";
993
+ /**
994
+ * Fast path for structured controls (pinned charts): date-only changes
995
+ * substitute params or call `/v2/rewrite-datefilter` instead of `/v2/query`,
996
+ * and chart generation is skipped when the caller keeps its own encoding
997
+ * (`chart.vizSpec` / `vegaLiteSpec` are then omitted). Default: false.
998
+ */
999
+ lightweight?: boolean;
994
1000
  /**
995
1001
  * QueryPanel session ID for context-aware follow-ups.
996
1002
  * Pass the querypanelSessionId from a previous ask() response
package/dist/index.js CHANGED
@@ -14,6 +14,13 @@ var BigQueryAdapter = class {
14
14
  );
15
15
  }
16
16
  }
17
+ clientFn;
18
+ projectId;
19
+ datasetProjectId;
20
+ defaultDataset;
21
+ databaseName;
22
+ kind;
23
+ allowedTables;
17
24
  async execute(sql, params) {
18
25
  if (this.allowedTables) {
19
26
  this.validateQueryTables(sql);
@@ -244,6 +251,11 @@ var ClickHouseAdapter = class {
244
251
  this.allowedTables = normalizeTableFilter2(options.allowedTables);
245
252
  }
246
253
  }
254
+ clientFn;
255
+ databaseName;
256
+ defaultFormat;
257
+ kind;
258
+ allowedTables;
247
259
  async execute(sql, params) {
248
260
  if (this.allowedTables) {
249
261
  this.validateQueryTables(sql);
@@ -497,6 +509,11 @@ var PostgresAdapter = class {
497
509
  );
498
510
  }
499
511
  }
512
+ clientFn;
513
+ databaseName;
514
+ defaultSchema;
515
+ kind;
516
+ allowedTables;
500
517
  async execute(sql, params) {
501
518
  if (this.allowedTables) {
502
519
  this.validateQueryTables(sql);
@@ -805,6 +822,9 @@ var QueryPipelineError = class extends Error {
805
822
  this.status = status;
806
823
  this.name = "QueryPipelineError";
807
824
  }
825
+ code;
826
+ details;
827
+ status;
808
828
  /**
809
829
  * Check if this is a moderation error
810
830
  */
@@ -857,8 +877,14 @@ var QueryPipelineError = class extends Error {
857
877
 
858
878
  // src/core/client.ts
859
879
  var ApiClient = class {
880
+ baseUrl;
881
+ privateKey;
882
+ organizationId;
883
+ defaultTenantId;
884
+ additionalHeaders;
885
+ fetchImpl;
886
+ cryptoKey = null;
860
887
  constructor(baseUrl, privateKey, organizationId, options) {
861
- this.cryptoKey = null;
862
888
  if (!baseUrl) {
863
889
  throw new Error("Base URL is required");
864
890
  }
@@ -1112,6 +1138,8 @@ var ApiClient = class {
1112
1138
 
1113
1139
  // src/core/callback-client.ts
1114
1140
  var CallbackApiClient = class {
1141
+ requestHandler;
1142
+ defaultTenantId;
1115
1143
  constructor(requestHandler, options) {
1116
1144
  this.requestHandler = requestHandler;
1117
1145
  this.defaultTenantId = options?.defaultTenantId;
@@ -1254,10 +1282,9 @@ function normalizeSqlParamsInput(params) {
1254
1282
 
1255
1283
  // src/core/query-engine.ts
1256
1284
  var QueryEngine = class {
1257
- constructor() {
1258
- this.databases = /* @__PURE__ */ new Map();
1259
- this.databaseMetadata = /* @__PURE__ */ new Map();
1260
- }
1285
+ databases = /* @__PURE__ */ new Map();
1286
+ databaseMetadata = /* @__PURE__ */ new Map();
1287
+ defaultDatabase;
1261
1288
  attachDatabase(name, adapter, metadata) {
1262
1289
  this.databases.set(name, adapter);
1263
1290
  this.databaseMetadata.set(name, metadata);
@@ -1943,7 +1970,13 @@ import crypto4 from "crypto";
1943
1970
  // src/routes/query.ts
1944
1971
  import crypto3 from "crypto";
1945
1972
  function resolveQueryPipeline(pipeline) {
1946
- return pipeline ?? "v2";
1973
+ const requested = pipeline;
1974
+ if (requested != null && requested !== "v2") {
1975
+ throw new Error(
1976
+ `Query pipeline "${requested}" was removed. ask() and modifyChart() always use POST /v2/query.`
1977
+ );
1978
+ }
1979
+ return "v2";
1947
1980
  }
1948
1981
  async function ask(client, queryEngine, question, options, signal) {
1949
1982
  const tenantId = resolveTenantId5(client, options.tenantId);
@@ -1953,8 +1986,9 @@ async function ask(client, queryEngine, question, options, signal) {
1953
1986
  let attempt = 0;
1954
1987
  let lastError = options.lastError;
1955
1988
  let previousSql = options.previousSql;
1956
- const pipeline = resolveQueryPipeline(options.pipeline);
1957
- const queryEndpoint = pipeline === "v2" ? "/v2/query" : "/query";
1989
+ let parentQueryId;
1990
+ resolveQueryPipeline(options.pipeline);
1991
+ const queryEndpoint = "/v2/query";
1958
1992
  while (attempt <= maxRetry) {
1959
1993
  const databaseName = options.database ?? queryEngine.getDefaultDatabase();
1960
1994
  const metadata = databaseName ? queryEngine.getDatabaseMetadata(databaseName) : void 0;
@@ -1984,7 +2018,8 @@ async function ask(client, queryEngine, question, options, signal) {
1984
2018
  ...databaseName ? { database: databaseName } : {},
1985
2019
  ...metadata?.dialect ? { dialect: metadata.dialect } : {},
1986
2020
  ...options.model?.trim() ? { model: options.model.trim() } : {},
1987
- ...pipeline === "v2" && options.systemPrompt?.trim() ? { system_prompt: options.systemPrompt.trim() } : {},
2021
+ ...options.systemPrompt?.trim() ? { system_prompt: options.systemPrompt.trim() } : {},
2022
+ ...parentQueryId ? { parent_query_id: parentQueryId } : {},
1988
2023
  debug: options.debug ?? false
1989
2024
  },
1990
2025
  tenantId,
@@ -2006,6 +2041,9 @@ async function ask(client, queryEngine, question, options, signal) {
2006
2041
  if (!sql || !dialect) {
2007
2042
  throw new Error("Query response missing required SQL or dialect");
2008
2043
  }
2044
+ if (queryResponse.data.queryId) {
2045
+ parentQueryId = queryResponse.data.queryId;
2046
+ }
2009
2047
  const dbName = queryResponse.data.database ?? options.database ?? queryEngine.getDefaultDatabase();
2010
2048
  if (!dbName) {
2011
2049
  throw new Error(
@@ -2165,35 +2203,35 @@ async function resolveQuery(client, queryEngine, queryId, options, signal) {
2165
2203
  dialect: response.dialect
2166
2204
  };
2167
2205
  }
2206
+ async function markQueryExecuted(client, queryId, options, signal) {
2207
+ try {
2208
+ await client.post(
2209
+ `/v2/queries/${encodeURIComponent(queryId)}/executed`,
2210
+ {},
2211
+ options.tenantId,
2212
+ options.userId,
2213
+ options.scopes,
2214
+ signal
2215
+ );
2216
+ } catch {
2217
+ }
2218
+ }
2168
2219
 
2169
2220
  // src/routes/modify.ts
2170
- function buildModifiedQuestion(originalQuestion, modifications, pipeline, hasSessionContext = false) {
2221
+ function buildModifiedQuestion(originalQuestion, modifications, hasSessionContext = false) {
2171
2222
  const hints = [];
2172
2223
  if (modifications.timeGranularity) {
2173
2224
  hints.push(`group results by ${modifications.timeGranularity}`);
2174
2225
  }
2175
2226
  if (modifications.dateRange) {
2176
- if (pipeline === "v2") {
2177
- const from = normalizeDateInput(modifications.dateRange.from);
2178
- const to = normalizeDateInput(modifications.dateRange.to);
2179
- if (from && to) {
2180
- hints.push(`change date range to ${from} through ${to}`);
2181
- } else if (from) {
2182
- hints.push(`change start date to ${from}`);
2183
- } else if (to) {
2184
- hints.push(`change end date to ${to}`);
2185
- }
2186
- } else {
2187
- const parts = [];
2188
- if (modifications.dateRange.from) {
2189
- parts.push(`from ${modifications.dateRange.from}`);
2190
- }
2191
- if (modifications.dateRange.to) {
2192
- parts.push(`to ${modifications.dateRange.to}`);
2193
- }
2194
- if (parts.length > 0) {
2195
- hints.push(`filter date range ${parts.join(" ")}`);
2196
- }
2227
+ const from = normalizeDateInput(modifications.dateRange.from);
2228
+ const to = normalizeDateInput(modifications.dateRange.to);
2229
+ if (from && to) {
2230
+ hints.push(`change date range to ${from} through ${to}`);
2231
+ } else if (from) {
2232
+ hints.push(`change start date to ${from}`);
2233
+ } else if (to) {
2234
+ hints.push(`change end date to ${to}`);
2197
2235
  }
2198
2236
  }
2199
2237
  if (modifications.additionalInstructions) {
@@ -2202,11 +2240,12 @@ function buildModifiedQuestion(originalQuestion, modifications, pipeline, hasSes
2202
2240
  if (hints.length === 0) {
2203
2241
  return originalQuestion;
2204
2242
  }
2205
- if (pipeline === "v2" && hasSessionContext) {
2243
+ if (hasSessionContext) {
2206
2244
  return hints.join(", ");
2207
2245
  }
2208
2246
  return `${originalQuestion} (${hints.join(", ")})`;
2209
2247
  }
2248
+ var REWRITE_DATEFILTER_ENDPOINT = "/v2/rewrite-datefilter";
2210
2249
  var START_PARAM_KEY_REGEX = /(^|_)(start|from)(_|$)/i;
2211
2250
  var END_PARAM_KEY_REGEX = /(^|_)(end|to)(_|$)/i;
2212
2251
  var ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?$/;
@@ -2243,31 +2282,118 @@ function normalizeGeneratedParamKey(param, index) {
2243
2282
  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);
2244
2283
  return nameCandidate.replace(/[{}]/g, "").replace(/(.+):.*$/, "$1").replace(/^[:$]/, "").trim();
2245
2284
  }
2246
- function applyDateRangeOverrides(dateRange, params, paramMetadata) {
2285
+ function collectParamKeys(params, paramMetadata) {
2286
+ const keys = new Set(Object.keys(params));
2287
+ for (let i = 0; i < paramMetadata.length; i++) {
2288
+ const param = paramMetadata[i];
2289
+ if (!param) continue;
2290
+ keys.add(normalizeGeneratedParamKey(param, i));
2291
+ }
2292
+ return [...keys];
2293
+ }
2294
+ function placeholderKey(token) {
2295
+ if (token.startsWith("$") || token.startsWith("@")) return token.slice(1);
2296
+ return token.slice(1, -1).replace(/:.+$/, "").trim();
2297
+ }
2298
+ function isDateLike(value) {
2299
+ return typeof value === "string" && /^\d{4}-\d{2}-\d{2}/.test(value.trim());
2300
+ }
2301
+ function dateBoundKeysFromSql(sql) {
2302
+ const start = /* @__PURE__ */ new Set();
2303
+ const end = /* @__PURE__ */ new Set();
2304
+ const comparison = /(>=|<=|>|<)\s*(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)/g;
2305
+ const between = /BETWEEN\s+(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)\s+AND\s+(\$\d+|\{[^}]+\}|@[A-Za-z_][\w]*)/gi;
2306
+ for (const match of sql.matchAll(comparison)) {
2307
+ const key = placeholderKey(match[2] ?? "");
2308
+ if (!key) continue;
2309
+ if (match[1] === ">=" || match[1] === ">") start.add(key);
2310
+ else end.add(key);
2311
+ }
2312
+ for (const match of sql.matchAll(between)) {
2313
+ const startKey = placeholderKey(match[1] ?? "");
2314
+ const endKey = placeholderKey(match[2] ?? "");
2315
+ if (startKey) start.add(startKey);
2316
+ if (endKey) end.add(endKey);
2317
+ }
2318
+ return { start, end };
2319
+ }
2320
+ function paramValueForKey(key, params, paramMetadata) {
2321
+ if (key in params) return params[key];
2322
+ for (let i = 0; i < paramMetadata.length; i++) {
2323
+ const param = paramMetadata[i];
2324
+ if (!param) continue;
2325
+ if (normalizeGeneratedParamKey(param, i) === key) return param.value;
2326
+ }
2327
+ return void 0;
2328
+ }
2329
+ function dateBoundKeys(sql, params, paramMetadata, boundary) {
2330
+ const fromSql = dateBoundKeysFromSql(sql)[boundary];
2331
+ const keys = [];
2332
+ for (const key of collectParamKeys(params, paramMetadata)) {
2333
+ const named = keyLooksLikeDateBoundary(key, boundary);
2334
+ if (!named && !fromSql.has(key)) continue;
2335
+ if (!isDateLike(paramValueForKey(key, params, paramMetadata))) continue;
2336
+ keys.push(key);
2337
+ }
2338
+ return keys;
2339
+ }
2340
+ function canSubstituteDateRangeParams(dateRange, sql, params, paramMetadata = []) {
2341
+ if (!dateRange) return false;
2342
+ const from = normalizeDateInput(dateRange.from);
2343
+ const to = normalizeDateInput(dateRange.to);
2344
+ if (!from && !to) return false;
2345
+ if (from && dateBoundKeys(sql, params, paramMetadata, "start").length === 0) {
2346
+ return false;
2347
+ }
2348
+ if (to && dateBoundKeys(sql, params, paramMetadata, "end").length === 0) {
2349
+ return false;
2350
+ }
2351
+ return true;
2352
+ }
2353
+ function isDateRangeOnlySqlModification(modifications) {
2354
+ if (!modifications?.dateRange) return false;
2355
+ if (modifications.customSql) return false;
2356
+ if (modifications.timeGranularity) return false;
2357
+ if (typeof modifications.additionalInstructions === "string" && modifications.additionalInstructions.trim().length > 0) {
2358
+ return false;
2359
+ }
2360
+ return true;
2361
+ }
2362
+ function applyDateRangeOverrides(dateRange, sql, params, paramMetadata) {
2247
2363
  if (!dateRange) return;
2248
2364
  const from = normalizeDateInput(dateRange.from);
2249
2365
  const to = normalizeDateInput(dateRange.to);
2250
2366
  if (!from && !to) return;
2367
+ const startKeys = new Set(
2368
+ from ? dateBoundKeys(sql, params, paramMetadata, "start") : []
2369
+ );
2370
+ const endKeys = new Set(
2371
+ to ? dateBoundKeys(sql, params, paramMetadata, "end") : []
2372
+ );
2251
2373
  for (const [key, value] of Object.entries(params)) {
2252
- if (from && keyLooksLikeDateBoundary(key, "start")) {
2253
- params[key] = formatDateOverride(from, "start", value);
2374
+ if (startKeys.has(key)) {
2375
+ params[key] = formatDateOverride(from ?? "", "start", value);
2254
2376
  }
2255
- if (to && keyLooksLikeDateBoundary(key, "end")) {
2256
- params[key] = formatDateOverride(to, "end", value);
2377
+ if (endKeys.has(key)) {
2378
+ params[key] = formatDateOverride(to ?? "", "end", value);
2257
2379
  }
2258
2380
  }
2259
2381
  for (let i = 0; i < paramMetadata.length; i++) {
2260
2382
  const param = paramMetadata[i];
2261
2383
  if (!param) continue;
2262
2384
  const key = normalizeGeneratedParamKey(param, i);
2263
- if (from && keyLooksLikeDateBoundary(key, "start")) {
2264
- param.value = formatDateOverride(from, "start", param.value);
2385
+ if (startKeys.has(key)) {
2386
+ param.value = formatDateOverride(from ?? "", "start", param.value);
2265
2387
  }
2266
- if (to && keyLooksLikeDateBoundary(key, "end")) {
2267
- param.value = formatDateOverride(to, "end", param.value);
2388
+ if (endKeys.has(key)) {
2389
+ param.value = formatDateOverride(to ?? "", "end", param.value);
2268
2390
  }
2269
2391
  }
2270
2392
  }
2393
+ function buildPreviousParams(params, paramMetadata) {
2394
+ if (paramMetadata.length > 0) return paramMetadata;
2395
+ return Object.entries(params).map(([name, value]) => ({ name, value }));
2396
+ }
2271
2397
  function buildVizHints(modifications) {
2272
2398
  const hints = {};
2273
2399
  if (modifications.kind) {
@@ -2318,8 +2444,11 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2318
2444
  const hasSqlMods = !!input.sqlModifications;
2319
2445
  const hasVizMods = !!input.vizModifications;
2320
2446
  const hasCustomSql = !!input.sqlModifications?.customSql;
2321
- const pipeline = resolveQueryPipeline(options?.pipeline);
2322
- const queryEndpoint = pipeline === "v2" ? "/v2/query" : "/query";
2447
+ const lightweight = options?.lightweight === true;
2448
+ const dateOnly = lightweight && isDateRangeOnlySqlModification(input.sqlModifications);
2449
+ const skipChartLlm = lightweight && !hasCustomSql && (dateOnly || hasVizMods && !hasSqlMods);
2450
+ resolveQueryPipeline(options?.pipeline);
2451
+ const queryEndpoint = "/v2/query";
2323
2452
  let currentSql = input.sql;
2324
2453
  let finalParams = input.params ?? {};
2325
2454
  let paramMetadata = [];
@@ -2371,28 +2500,57 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2371
2500
  paramMetadata = [];
2372
2501
  queryId = void 0;
2373
2502
  sqlChanged = true;
2503
+ } else if (dateOnly && canSubstituteDateRangeParams(
2504
+ input.sqlModifications?.dateRange,
2505
+ finalSql,
2506
+ finalParams,
2507
+ paramMetadata
2508
+ )) {
2509
+ finalParams = { ...finalParams };
2510
+ applyDateRangeOverrides(
2511
+ input.sqlModifications?.dateRange,
2512
+ finalSql,
2513
+ finalParams,
2514
+ paramMetadata
2515
+ );
2516
+ sqlChanged = false;
2374
2517
  } else if (hasSqlMods && !hasCustomSql) {
2375
2518
  const modifiedQuestion = buildModifiedQuestion(
2376
2519
  input.question,
2377
2520
  input.sqlModifications,
2378
- pipeline,
2379
2521
  hasQuerypanelSessionContext
2380
2522
  );
2381
- if (pipeline === "v2") {
2382
- finalQuestion = modifiedQuestion;
2383
- }
2384
- const queryResponse = await client.post(
2523
+ finalQuestion = modifiedQuestion;
2524
+ const sharedBody = {
2525
+ session_id: querypanelSessionId,
2526
+ previous_sql: currentSql,
2527
+ ...tenantSettings ? { tenant_settings: tenantSettings } : {},
2528
+ ...databaseName ? { database: databaseName } : {},
2529
+ ...metadata?.dialect ? { dialect: metadata.dialect } : {},
2530
+ debug: options?.debug ?? false
2531
+ };
2532
+ const [endpoint, body] = dateOnly ? [
2533
+ REWRITE_DATEFILTER_ENDPOINT,
2534
+ {
2535
+ ...sharedBody,
2536
+ question: input.question,
2537
+ previous_params: buildPreviousParams(finalParams, paramMetadata),
2538
+ date_range: {
2539
+ from: normalizeDateInput(input.sqlModifications?.dateRange?.from),
2540
+ to: normalizeDateInput(input.sqlModifications?.dateRange?.to)
2541
+ }
2542
+ }
2543
+ ] : [
2385
2544
  queryEndpoint,
2386
2545
  {
2546
+ ...sharedBody,
2387
2547
  question: modifiedQuestion,
2388
- session_id: querypanelSessionId,
2389
- previous_sql: currentSql,
2390
- ...options?.maxRetry ? { max_retry: options.maxRetry } : {},
2391
- ...tenantSettings ? { tenant_settings: tenantSettings } : {},
2392
- ...databaseName ? { database: databaseName } : {},
2393
- ...metadata?.dialect ? { dialect: metadata.dialect } : {},
2394
- debug: options?.debug ?? false
2395
- },
2548
+ ...options?.maxRetry ? { max_retry: options.maxRetry } : {}
2549
+ }
2550
+ ];
2551
+ const queryResponse = await client.post(
2552
+ endpoint,
2553
+ body,
2396
2554
  tenantId,
2397
2555
  options?.userId,
2398
2556
  options?.scopes,
@@ -2402,13 +2560,12 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2402
2560
  finalSql = queryResponse.sql;
2403
2561
  paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
2404
2562
  finalParams = queryEngine.mapGeneratedParams(paramMetadata);
2405
- if (pipeline === "v2") {
2406
- applyDateRangeOverrides(
2407
- input.sqlModifications?.dateRange,
2408
- finalParams,
2409
- paramMetadata
2410
- );
2411
- }
2563
+ applyDateRangeOverrides(
2564
+ input.sqlModifications?.dateRange,
2565
+ finalSql,
2566
+ finalParams,
2567
+ paramMetadata
2568
+ );
2412
2569
  rationale = queryResponse.rationale;
2413
2570
  queryId = queryResponse.queryId;
2414
2571
  sqlChanged = finalSql !== currentSql;
@@ -2426,7 +2583,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2426
2583
  };
2427
2584
  const vizHints = hasVizMods ? buildVizHints(input.vizModifications) : {};
2428
2585
  const vizHintsForChart = chartType === "vizspec" ? vizHints : stripVizSpecOnlyHints(vizHints);
2429
- if (chartType === "vizspec") {
2586
+ if (!skipChartLlm && chartType === "vizspec") {
2430
2587
  const vizspecResponse = await client.post(
2431
2588
  "/vizspec",
2432
2589
  {
@@ -2453,7 +2610,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
2453
2610
  specType: "vizspec",
2454
2611
  notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
2455
2612
  };
2456
- } else {
2613
+ } else if (!skipChartLlm) {
2457
2614
  const chartResponse = await client.post(
2458
2615
  "/chart",
2459
2616
  {
@@ -2626,6 +2783,9 @@ function resolveAttachEnforceTenantIsolation(tenantFieldName, enforceTenantIsola
2626
2783
  return tenantFieldName ? true : void 0;
2627
2784
  }
2628
2785
  var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
2786
+ client;
2787
+ queryEngine;
2788
+ supportedChartTypes;
2629
2789
  /**
2630
2790
  * @param workspaceId - Workspace UUID (same value as your org in the dashboard). Passed to the API as JWT claim `organizationId`.
2631
2791
  */
@@ -2877,6 +3037,11 @@ var QueryPanelSdkAPI = class _QueryPanelSdkAPI {
2877
3037
  databaseName,
2878
3038
  tenantId
2879
3039
  );
3040
+ if (input.queryId) {
3041
+ await markQueryExecuted(this.client, input.queryId, {
3042
+ tenantId
3043
+ });
3044
+ }
2880
3045
  return { rows: result.rows, fields: result.fields };
2881
3046
  }
2882
3047
  // VizSpec generation