@querypanel/node-sdk 1.0.52 → 1.0.54

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
@@ -191,8 +191,8 @@ type QueryErrorCode = (typeof QueryErrorCode)[keyof typeof QueryErrorCode];
191
191
  */
192
192
  declare class QueryPipelineError extends Error {
193
193
  readonly code: QueryErrorCode;
194
- readonly details?: Record<string, unknown> | undefined;
195
- constructor(message: string, code: QueryErrorCode, details?: Record<string, unknown> | undefined);
194
+ readonly details?: Record<string, unknown>;
195
+ constructor(message: string, code: QueryErrorCode, details?: Record<string, unknown>);
196
196
  /**
197
197
  * Check if this is a moderation error
198
198
  */
@@ -737,6 +737,12 @@ interface ChartModifyOptions {
737
737
  * - "v2": Improved pipeline with intent planning, hybrid retrieval, schema linking, and SQL reflection
738
738
  */
739
739
  pipeline?: "v1" | "v2";
740
+ /**
741
+ * QueryPanel session ID for context-aware follow-ups.
742
+ * Pass the querypanelSessionId from a previous ask() response
743
+ * to preserve conversation history when modifying charts.
744
+ */
745
+ querypanelSessionId?: string;
740
746
  }
741
747
  /**
742
748
  * Response from modifyChart(), extending AskResponse with modification metadata.
package/dist/index.d.ts CHANGED
@@ -191,8 +191,8 @@ type QueryErrorCode = (typeof QueryErrorCode)[keyof typeof QueryErrorCode];
191
191
  */
192
192
  declare class QueryPipelineError extends Error {
193
193
  readonly code: QueryErrorCode;
194
- readonly details?: Record<string, unknown> | undefined;
195
- constructor(message: string, code: QueryErrorCode, details?: Record<string, unknown> | undefined);
194
+ readonly details?: Record<string, unknown>;
195
+ constructor(message: string, code: QueryErrorCode, details?: Record<string, unknown>);
196
196
  /**
197
197
  * Check if this is a moderation error
198
198
  */
@@ -737,6 +737,12 @@ interface ChartModifyOptions {
737
737
  * - "v2": Improved pipeline with intent planning, hybrid retrieval, schema linking, and SQL reflection
738
738
  */
739
739
  pipeline?: "v1" | "v2";
740
+ /**
741
+ * QueryPanel session ID for context-aware follow-ups.
742
+ * Pass the querypanelSessionId from a previous ask() response
743
+ * to preserve conversation history when modifying charts.
744
+ */
745
+ querypanelSessionId?: string;
740
746
  }
741
747
  /**
742
748
  * Response from modifyChart(), extending AskResponse with modification metadata.
package/dist/index.js CHANGED
@@ -1414,21 +1414,33 @@ function anonymizeResults(rows) {
1414
1414
  }
1415
1415
 
1416
1416
  // src/routes/modify.ts
1417
- function buildModifiedQuestion(originalQuestion, modifications) {
1417
+ function buildModifiedQuestion(originalQuestion, modifications, pipeline) {
1418
1418
  const hints = [];
1419
1419
  if (modifications.timeGranularity) {
1420
1420
  hints.push(`group results by ${modifications.timeGranularity}`);
1421
1421
  }
1422
1422
  if (modifications.dateRange) {
1423
- const parts = [];
1424
- if (modifications.dateRange.from) {
1425
- parts.push(`from ${modifications.dateRange.from}`);
1426
- }
1427
- if (modifications.dateRange.to) {
1428
- parts.push(`to ${modifications.dateRange.to}`);
1429
- }
1430
- if (parts.length > 0) {
1431
- hints.push(`filter date range ${parts.join(" ")}`);
1423
+ if (pipeline === "v2") {
1424
+ const from = normalizeDateInput(modifications.dateRange.from);
1425
+ const to = normalizeDateInput(modifications.dateRange.to);
1426
+ if (from && to) {
1427
+ hints.push(`change date range to ${from} through ${to}`);
1428
+ } else if (from) {
1429
+ hints.push(`change start date to ${from}`);
1430
+ } else if (to) {
1431
+ hints.push(`change end date to ${to}`);
1432
+ }
1433
+ } else {
1434
+ const parts = [];
1435
+ if (modifications.dateRange.from) {
1436
+ parts.push(`from ${modifications.dateRange.from}`);
1437
+ }
1438
+ if (modifications.dateRange.to) {
1439
+ parts.push(`to ${modifications.dateRange.to}`);
1440
+ }
1441
+ if (parts.length > 0) {
1442
+ hints.push(`filter date range ${parts.join(" ")}`);
1443
+ }
1432
1444
  }
1433
1445
  }
1434
1446
  if (modifications.additionalInstructions) {
@@ -1439,6 +1451,67 @@ function buildModifiedQuestion(originalQuestion, modifications) {
1439
1451
  }
1440
1452
  return `${originalQuestion} (${hints.join(", ")})`;
1441
1453
  }
1454
+ var START_PARAM_KEY_REGEX = /(^|_)(start|from)(_|$)/i;
1455
+ var END_PARAM_KEY_REGEX = /(^|_)(end|to)(_|$)/i;
1456
+ var ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?$/;
1457
+ var SQL_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
1458
+ var SQL_DATETIME_RE = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
1459
+ function normalizeDateInput(value) {
1460
+ if (!value) return void 0;
1461
+ const trimmed = value.trim();
1462
+ if (!trimmed) return void 0;
1463
+ if (ISO_DATETIME_RE.test(trimmed)) {
1464
+ return trimmed.replace("T", " ").replace(/\.\d+Z?$/, "").replace(/Z$/, "");
1465
+ }
1466
+ return trimmed;
1467
+ }
1468
+ function keyLooksLikeDateBoundary(key, boundary) {
1469
+ return boundary === "start" ? START_PARAM_KEY_REGEX.test(key) : END_PARAM_KEY_REGEX.test(key);
1470
+ }
1471
+ function hasTimeComponent(value) {
1472
+ return typeof value === "string" && /\d{2}:\d{2}:\d{2}/.test(value);
1473
+ }
1474
+ function formatDateOverride(dateValue, boundary, existingValue) {
1475
+ if (SQL_DATE_RE.test(dateValue) && !hasTimeComponent(existingValue)) {
1476
+ return dateValue;
1477
+ }
1478
+ if (SQL_DATE_RE.test(dateValue)) {
1479
+ return `${dateValue} ${boundary === "start" ? "00:00:00" : "23:59:59"}`;
1480
+ }
1481
+ if (SQL_DATETIME_RE.test(dateValue)) {
1482
+ return dateValue;
1483
+ }
1484
+ return dateValue;
1485
+ }
1486
+ function normalizeGeneratedParamKey(param, index) {
1487
+ 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);
1488
+ return nameCandidate.replace(/[{}]/g, "").replace(/(.+):.*$/, "$1").replace(/^[:$]/, "").trim();
1489
+ }
1490
+ function applyDateRangeOverrides(dateRange, params, paramMetadata) {
1491
+ if (!dateRange) return;
1492
+ const from = normalizeDateInput(dateRange.from);
1493
+ const to = normalizeDateInput(dateRange.to);
1494
+ if (!from && !to) return;
1495
+ for (const [key, value] of Object.entries(params)) {
1496
+ if (from && keyLooksLikeDateBoundary(key, "start")) {
1497
+ params[key] = formatDateOverride(from, "start", value);
1498
+ }
1499
+ if (to && keyLooksLikeDateBoundary(key, "end")) {
1500
+ params[key] = formatDateOverride(to, "end", value);
1501
+ }
1502
+ }
1503
+ for (let i = 0; i < paramMetadata.length; i++) {
1504
+ const param = paramMetadata[i];
1505
+ if (!param) continue;
1506
+ const key = normalizeGeneratedParamKey(param, i);
1507
+ if (from && keyLooksLikeDateBoundary(key, "start")) {
1508
+ param.value = formatDateOverride(from, "start", param.value);
1509
+ }
1510
+ if (to && keyLooksLikeDateBoundary(key, "end")) {
1511
+ param.value = formatDateOverride(to, "end", param.value);
1512
+ }
1513
+ }
1514
+ }
1442
1515
  function buildVizHints(modifications) {
1443
1516
  const hints = {};
1444
1517
  if (modifications.kind) {
@@ -1483,6 +1556,7 @@ function resolveTenantId5(client, tenantId) {
1483
1556
  async function modifyChart(client, queryEngine, input, options, signal) {
1484
1557
  const tenantId = resolveTenantId5(client, options?.tenantId);
1485
1558
  const sessionId = crypto4.randomUUID();
1559
+ const querypanelSessionId = options?.querypanelSessionId ?? sessionId;
1486
1560
  const chartType = options?.chartType ?? "vega-lite";
1487
1561
  const hasSqlMods = !!input.sqlModifications;
1488
1562
  const hasVizMods = !!input.vizModifications;
@@ -1494,6 +1568,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1494
1568
  let rationale;
1495
1569
  let queryId;
1496
1570
  let sqlChanged = false;
1571
+ let finalQuestion = input.question;
1497
1572
  const databaseName = input.database ?? queryEngine.getDefaultDatabase();
1498
1573
  if (!databaseName) {
1499
1574
  throw new Error(
@@ -1517,12 +1592,17 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1517
1592
  } else if (hasSqlMods && !hasCustomSql) {
1518
1593
  const modifiedQuestion = buildModifiedQuestion(
1519
1594
  input.question,
1520
- input.sqlModifications
1595
+ input.sqlModifications,
1596
+ options?.pipeline
1521
1597
  );
1598
+ if (options?.pipeline === "v2") {
1599
+ finalQuestion = modifiedQuestion;
1600
+ }
1522
1601
  const queryResponse = await client.post(
1523
1602
  queryEndpoint,
1524
1603
  {
1525
1604
  question: modifiedQuestion,
1605
+ session_id: querypanelSessionId,
1526
1606
  previous_sql: input.sql,
1527
1607
  ...options?.maxRetry ? { max_retry: options.maxRetry } : {},
1528
1608
  ...tenantSettings ? { tenant_settings: tenantSettings } : {},
@@ -1538,6 +1618,13 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1538
1618
  finalSql = queryResponse.sql;
1539
1619
  paramMetadata = Array.isArray(queryResponse.params) ? queryResponse.params : [];
1540
1620
  finalParams = queryEngine.mapGeneratedParams(paramMetadata);
1621
+ if (options?.pipeline === "v2") {
1622
+ applyDateRangeOverrides(
1623
+ input.sqlModifications?.dateRange,
1624
+ finalParams,
1625
+ paramMetadata
1626
+ );
1627
+ }
1541
1628
  rationale = queryResponse.rationale;
1542
1629
  queryId = queryResponse.queryId;
1543
1630
  sqlChanged = finalSql !== input.sql;
@@ -1560,7 +1647,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1560
1647
  const vizspecResponse = await client.post(
1561
1648
  "/vizspec",
1562
1649
  {
1563
- question: input.question,
1650
+ question: finalQuestion,
1564
1651
  sql: finalSql,
1565
1652
  rationale,
1566
1653
  fields: execution.fields,
@@ -1585,7 +1672,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1585
1672
  const chartResponse = await client.post(
1586
1673
  "/chart",
1587
1674
  {
1588
- question: input.question,
1675
+ question: finalQuestion,
1589
1676
  sql: finalSql,
1590
1677
  rationale,
1591
1678
  fields: execution.fields,
@@ -1618,6 +1705,7 @@ async function modifyChart(client, queryEngine, input, options, signal) {
1618
1705
  rationale,
1619
1706
  dialect: metadata?.dialect ?? "unknown",
1620
1707
  queryId,
1708
+ querypanelSessionId,
1621
1709
  rows,
1622
1710
  fields: execution.fields,
1623
1711
  chart,