@querypanel/node-sdk 1.2.8 → 1.2.10
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 +242 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +242 -174
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -749,6 +749,118 @@ function sanitize2(value) {
|
|
|
749
749
|
|
|
750
750
|
// src/core/client.ts
|
|
751
751
|
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
752
|
+
|
|
753
|
+
// src/errors.ts
|
|
754
|
+
var QueryErrorCode = {
|
|
755
|
+
// Moderation errors
|
|
756
|
+
MODERATION_FAILED: "MODERATION_FAILED",
|
|
757
|
+
// Guardrail errors
|
|
758
|
+
RELEVANCE_CHECK_FAILED: "RELEVANCE_CHECK_FAILED",
|
|
759
|
+
SECURITY_CHECK_FAILED: "SECURITY_CHECK_FAILED",
|
|
760
|
+
// SQL generation errors
|
|
761
|
+
SQL_GENERATION_FAILED: "SQL_GENERATION_FAILED",
|
|
762
|
+
// SQL validation errors
|
|
763
|
+
SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED",
|
|
764
|
+
// Context retrieval errors
|
|
765
|
+
CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED",
|
|
766
|
+
// Clarification errors (v2)
|
|
767
|
+
CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED",
|
|
768
|
+
// Bring-your-own-key / provider errors
|
|
769
|
+
AI_PROVIDER_AUTH_FAILED: "AI_PROVIDER_AUTH_FAILED",
|
|
770
|
+
AI_PROVIDER_RATE_LIMITED: "AI_PROVIDER_RATE_LIMITED",
|
|
771
|
+
AI_PROVIDER_UNAVAILABLE: "AI_PROVIDER_UNAVAILABLE",
|
|
772
|
+
// General errors
|
|
773
|
+
INTERNAL_ERROR: "INTERNAL_ERROR",
|
|
774
|
+
AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED",
|
|
775
|
+
VALIDATION_ERROR: "VALIDATION_ERROR"
|
|
776
|
+
};
|
|
777
|
+
function isQueryErrorCode(code) {
|
|
778
|
+
return typeof code === "string" && Object.values(QueryErrorCode).includes(code);
|
|
779
|
+
}
|
|
780
|
+
function isAiProviderErrorCode(code) {
|
|
781
|
+
return code === QueryErrorCode.AI_PROVIDER_AUTH_FAILED || code === QueryErrorCode.AI_PROVIDER_RATE_LIMITED || code === QueryErrorCode.AI_PROVIDER_UNAVAILABLE;
|
|
782
|
+
}
|
|
783
|
+
function isAiProviderPipelineError(error) {
|
|
784
|
+
if (error instanceof QueryPipelineError) {
|
|
785
|
+
return isAiProviderErrorCode(error.code);
|
|
786
|
+
}
|
|
787
|
+
if (error && typeof error === "object" && "code" in error) {
|
|
788
|
+
return isAiProviderErrorCode(error.code);
|
|
789
|
+
}
|
|
790
|
+
return false;
|
|
791
|
+
}
|
|
792
|
+
function throwIfGenerationErrorResponse(response) {
|
|
793
|
+
if (!response || typeof response !== "object") {
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
const record = response;
|
|
797
|
+
if (typeof record.error !== "string") {
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
if (isQueryErrorCode(record.code)) {
|
|
801
|
+
throw new QueryPipelineError(record.error, record.code);
|
|
802
|
+
}
|
|
803
|
+
throw new Error(record.error);
|
|
804
|
+
}
|
|
805
|
+
var QueryPipelineError = class extends Error {
|
|
806
|
+
constructor(message, code, details, status) {
|
|
807
|
+
super(message);
|
|
808
|
+
this.code = code;
|
|
809
|
+
this.details = details;
|
|
810
|
+
this.status = status;
|
|
811
|
+
this.name = "QueryPipelineError";
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Check if this is a moderation error
|
|
815
|
+
*/
|
|
816
|
+
isModeration() {
|
|
817
|
+
return this.code === QueryErrorCode.MODERATION_FAILED;
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* Check if this is a relevance error (question not related to database)
|
|
821
|
+
*/
|
|
822
|
+
isRelevanceError() {
|
|
823
|
+
return this.code === QueryErrorCode.RELEVANCE_CHECK_FAILED;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Check if this is a security error (SQL injection, prompt injection, etc.)
|
|
827
|
+
*/
|
|
828
|
+
isSecurityError() {
|
|
829
|
+
return this.code === QueryErrorCode.SECURITY_CHECK_FAILED;
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Check if this is any guardrail error (relevance or security)
|
|
833
|
+
*/
|
|
834
|
+
isGuardrailError() {
|
|
835
|
+
return this.isRelevanceError() || this.isSecurityError();
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Check if this is a clarification needed error (v2 pipeline)
|
|
839
|
+
*/
|
|
840
|
+
isClarificationNeeded() {
|
|
841
|
+
return this.code === QueryErrorCode.CLARIFICATION_NEEDED;
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Check if this is a BYOK / provider credential error
|
|
845
|
+
*/
|
|
846
|
+
isAiProviderAuthError() {
|
|
847
|
+
return this.code === QueryErrorCode.AI_PROVIDER_AUTH_FAILED;
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* Check if this is a BYOK / provider rate-limit error
|
|
851
|
+
*/
|
|
852
|
+
isAiProviderRateLimited() {
|
|
853
|
+
return this.code === QueryErrorCode.AI_PROVIDER_RATE_LIMITED;
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Check if this is any BYOK / provider error (auth, rate limit, or unavailable)
|
|
857
|
+
*/
|
|
858
|
+
isAiProviderError() {
|
|
859
|
+
return isAiProviderErrorCode(this.code);
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
|
|
863
|
+
// src/core/client.ts
|
|
752
864
|
var ApiClient = class {
|
|
753
865
|
constructor(baseUrl, privateKey, organizationId, options) {
|
|
754
866
|
this.cryptoKey = null;
|
|
@@ -880,10 +992,18 @@ var ApiClient = class {
|
|
|
880
992
|
json = void 0;
|
|
881
993
|
}
|
|
882
994
|
if (!response.ok) {
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
|
|
995
|
+
const message = json?.error || response.statusText || "Request failed";
|
|
996
|
+
if (isQueryErrorCode(json?.code)) {
|
|
997
|
+
throw new QueryPipelineError(
|
|
998
|
+
message,
|
|
999
|
+
json.code,
|
|
1000
|
+
json?.details,
|
|
1001
|
+
response.status
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
const error = new Error(message);
|
|
886
1005
|
error.status = response.status;
|
|
1006
|
+
if (json?.code) error.code = json.code;
|
|
887
1007
|
if (json?.details) error.details = json.details;
|
|
888
1008
|
throw error;
|
|
889
1009
|
}
|
|
@@ -1212,65 +1332,6 @@ var QueryEngine = class {
|
|
|
1212
1332
|
}
|
|
1213
1333
|
};
|
|
1214
1334
|
|
|
1215
|
-
// src/errors.ts
|
|
1216
|
-
var QueryErrorCode = {
|
|
1217
|
-
// Moderation errors
|
|
1218
|
-
MODERATION_FAILED: "MODERATION_FAILED",
|
|
1219
|
-
// Guardrail errors
|
|
1220
|
-
RELEVANCE_CHECK_FAILED: "RELEVANCE_CHECK_FAILED",
|
|
1221
|
-
SECURITY_CHECK_FAILED: "SECURITY_CHECK_FAILED",
|
|
1222
|
-
// SQL generation errors
|
|
1223
|
-
SQL_GENERATION_FAILED: "SQL_GENERATION_FAILED",
|
|
1224
|
-
// SQL validation errors
|
|
1225
|
-
SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED",
|
|
1226
|
-
// Context retrieval errors
|
|
1227
|
-
CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED",
|
|
1228
|
-
// Clarification errors (v2)
|
|
1229
|
-
CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED",
|
|
1230
|
-
// General errors
|
|
1231
|
-
INTERNAL_ERROR: "INTERNAL_ERROR",
|
|
1232
|
-
AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED",
|
|
1233
|
-
VALIDATION_ERROR: "VALIDATION_ERROR"
|
|
1234
|
-
};
|
|
1235
|
-
var QueryPipelineError = class extends Error {
|
|
1236
|
-
constructor(message, code, details) {
|
|
1237
|
-
super(message);
|
|
1238
|
-
this.code = code;
|
|
1239
|
-
this.details = details;
|
|
1240
|
-
this.name = "QueryPipelineError";
|
|
1241
|
-
}
|
|
1242
|
-
/**
|
|
1243
|
-
* Check if this is a moderation error
|
|
1244
|
-
*/
|
|
1245
|
-
isModeration() {
|
|
1246
|
-
return this.code === QueryErrorCode.MODERATION_FAILED;
|
|
1247
|
-
}
|
|
1248
|
-
/**
|
|
1249
|
-
* Check if this is a relevance error (question not related to database)
|
|
1250
|
-
*/
|
|
1251
|
-
isRelevanceError() {
|
|
1252
|
-
return this.code === QueryErrorCode.RELEVANCE_CHECK_FAILED;
|
|
1253
|
-
}
|
|
1254
|
-
/**
|
|
1255
|
-
* Check if this is a security error (SQL injection, prompt injection, etc.)
|
|
1256
|
-
*/
|
|
1257
|
-
isSecurityError() {
|
|
1258
|
-
return this.code === QueryErrorCode.SECURITY_CHECK_FAILED;
|
|
1259
|
-
}
|
|
1260
|
-
/**
|
|
1261
|
-
* Check if this is any guardrail error (relevance or security)
|
|
1262
|
-
*/
|
|
1263
|
-
isGuardrailError() {
|
|
1264
|
-
return this.isRelevanceError() || this.isSecurityError();
|
|
1265
|
-
}
|
|
1266
|
-
/**
|
|
1267
|
-
* Check if this is a clarification needed error (v2 pipeline)
|
|
1268
|
-
*/
|
|
1269
|
-
isClarificationNeeded() {
|
|
1270
|
-
return this.code === QueryErrorCode.CLARIFICATION_NEEDED;
|
|
1271
|
-
}
|
|
1272
|
-
};
|
|
1273
|
-
|
|
1274
1335
|
// src/routes/charts.ts
|
|
1275
1336
|
async function createChart(client, body, options, signal) {
|
|
1276
1337
|
const tenantId = resolveTenantId(client, options?.tenantId);
|
|
@@ -1907,60 +1968,60 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1907
1968
|
specType: chartType,
|
|
1908
1969
|
notes: rows.length === 0 ? "Query returned no rows." : null
|
|
1909
1970
|
};
|
|
1910
|
-
if (
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
}
|
|
1971
|
+
if (chartType === "vizspec") {
|
|
1972
|
+
const vizspecResponse = await client.post(
|
|
1973
|
+
"/vizspec",
|
|
1974
|
+
{
|
|
1975
|
+
question,
|
|
1976
|
+
sql,
|
|
1977
|
+
rationale: queryResponse.data.rationale,
|
|
1978
|
+
fields: execution.fields,
|
|
1979
|
+
rows: anonymizeResults(rows),
|
|
1980
|
+
max_retries: options.chartMaxRetries ?? 3,
|
|
1981
|
+
query_id: queryResponse.data.queryId,
|
|
1982
|
+
...options.supportedChartTypes?.length ? {
|
|
1983
|
+
supported_chart_types: options.supportedChartTypes
|
|
1984
|
+
} : {}
|
|
1985
|
+
},
|
|
1986
|
+
tenantId,
|
|
1987
|
+
options.userId,
|
|
1988
|
+
options.scopes,
|
|
1989
|
+
signal,
|
|
1990
|
+
sessionId
|
|
1991
|
+
);
|
|
1992
|
+
throwIfGenerationErrorResponse(vizspecResponse);
|
|
1993
|
+
chart = {
|
|
1994
|
+
vizSpec: vizspecResponse.spec,
|
|
1995
|
+
specType: "vizspec",
|
|
1996
|
+
notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
|
|
1997
|
+
};
|
|
1998
|
+
} else {
|
|
1999
|
+
const chartResponse = await client.post(
|
|
2000
|
+
"/chart",
|
|
2001
|
+
{
|
|
2002
|
+
question,
|
|
2003
|
+
sql,
|
|
2004
|
+
rationale: queryResponse.data.rationale,
|
|
2005
|
+
fields: execution.fields,
|
|
2006
|
+
rows: anonymizeResults(rows),
|
|
2007
|
+
max_retries: options.chartMaxRetries ?? 3,
|
|
2008
|
+
query_id: queryResponse.data.queryId
|
|
2009
|
+
},
|
|
2010
|
+
tenantId,
|
|
2011
|
+
options.userId,
|
|
2012
|
+
options.scopes,
|
|
2013
|
+
signal,
|
|
2014
|
+
sessionId
|
|
2015
|
+
);
|
|
2016
|
+
throwIfGenerationErrorResponse(chartResponse);
|
|
2017
|
+
chart = {
|
|
2018
|
+
vegaLiteSpec: chartResponse.chart ? {
|
|
2019
|
+
...chartResponse.chart,
|
|
2020
|
+
data: { values: rows }
|
|
2021
|
+
} : null,
|
|
2022
|
+
specType: "vega-lite",
|
|
2023
|
+
notes: rows.length === 0 ? chartResponse.notes ?? "Query returned no rows." : chartResponse.notes
|
|
2024
|
+
};
|
|
1964
2025
|
}
|
|
1965
2026
|
return {
|
|
1966
2027
|
sql,
|
|
@@ -1980,6 +2041,13 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1980
2041
|
trace: queryResponse.data.trace
|
|
1981
2042
|
};
|
|
1982
2043
|
} catch (error) {
|
|
2044
|
+
if (isAiProviderPipelineError(error)) {
|
|
2045
|
+
if (error instanceof QueryPipelineError) {
|
|
2046
|
+
throw error;
|
|
2047
|
+
}
|
|
2048
|
+
const providerError = error;
|
|
2049
|
+
throw new QueryPipelineError(providerError.message, providerError.code);
|
|
2050
|
+
}
|
|
1983
2051
|
attempt++;
|
|
1984
2052
|
if (attempt > maxRetry) {
|
|
1985
2053
|
throw error;
|
|
@@ -2253,64 +2321,64 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2253
2321
|
specType: chartType,
|
|
2254
2322
|
notes: rows.length === 0 ? "Query returned no rows." : null
|
|
2255
2323
|
};
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
}
|
|
2324
|
+
const vizHints = hasVizMods ? buildVizHints(input.vizModifications) : {};
|
|
2325
|
+
const vizHintsForChart = chartType === "vizspec" ? vizHints : stripVizSpecOnlyHints(vizHints);
|
|
2326
|
+
if (chartType === "vizspec") {
|
|
2327
|
+
const vizspecResponse = await client.post(
|
|
2328
|
+
"/vizspec",
|
|
2329
|
+
{
|
|
2330
|
+
question: finalQuestion,
|
|
2331
|
+
sql: finalSql,
|
|
2332
|
+
rationale,
|
|
2333
|
+
fields: execution.fields,
|
|
2334
|
+
rows: anonymizeResults(rows),
|
|
2335
|
+
max_retries: options?.chartMaxRetries ?? 3,
|
|
2336
|
+
query_id: queryId,
|
|
2337
|
+
// Include viz hints for the chart generator
|
|
2338
|
+
...hasVizMods ? { encoding_hints: vizHintsForChart } : {},
|
|
2339
|
+
...options?.supportedChartTypes?.length ? { supported_chart_types: options.supportedChartTypes } : {}
|
|
2340
|
+
},
|
|
2341
|
+
tenantId,
|
|
2342
|
+
options?.userId,
|
|
2343
|
+
options?.scopes,
|
|
2344
|
+
signal,
|
|
2345
|
+
sessionId
|
|
2346
|
+
);
|
|
2347
|
+
throwIfGenerationErrorResponse(vizspecResponse);
|
|
2348
|
+
chart = {
|
|
2349
|
+
vizSpec: vizspecResponse.spec,
|
|
2350
|
+
specType: "vizspec",
|
|
2351
|
+
notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
|
|
2352
|
+
};
|
|
2353
|
+
} else {
|
|
2354
|
+
const chartResponse = await client.post(
|
|
2355
|
+
"/chart",
|
|
2356
|
+
{
|
|
2357
|
+
question: finalQuestion,
|
|
2358
|
+
sql: finalSql,
|
|
2359
|
+
rationale,
|
|
2360
|
+
fields: execution.fields,
|
|
2361
|
+
rows: anonymizeResults(rows),
|
|
2362
|
+
max_retries: options?.chartMaxRetries ?? 3,
|
|
2363
|
+
query_id: queryId,
|
|
2364
|
+
// Include viz hints for the chart generator
|
|
2365
|
+
...hasVizMods ? { encoding_hints: vizHintsForChart } : {}
|
|
2366
|
+
},
|
|
2367
|
+
tenantId,
|
|
2368
|
+
options?.userId,
|
|
2369
|
+
options?.scopes,
|
|
2370
|
+
signal,
|
|
2371
|
+
sessionId
|
|
2372
|
+
);
|
|
2373
|
+
throwIfGenerationErrorResponse(chartResponse);
|
|
2374
|
+
chart = {
|
|
2375
|
+
vegaLiteSpec: chartResponse.chart ? {
|
|
2376
|
+
...chartResponse.chart,
|
|
2377
|
+
data: { values: rows }
|
|
2378
|
+
} : null,
|
|
2379
|
+
specType: "vega-lite",
|
|
2380
|
+
notes: rows.length === 0 ? chartResponse.notes ?? "Query returned no rows." : chartResponse.notes
|
|
2381
|
+
};
|
|
2314
2382
|
}
|
|
2315
2383
|
return {
|
|
2316
2384
|
sql: finalSql,
|