@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.cjs +101 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -2
- package/dist/index.d.ts +8 -2
- package/dist/index.js +101 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
195
|
-
constructor(message: string, code: QueryErrorCode, details?: Record<string, unknown>
|
|
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
|
|
195
|
-
constructor(message: string, code: QueryErrorCode, details?: Record<string, unknown>
|
|
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
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
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:
|
|
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:
|
|
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,
|