@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.d.cts
CHANGED
|
@@ -288,6 +288,9 @@ declare const QueryErrorCode: {
|
|
|
288
288
|
readonly SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED";
|
|
289
289
|
readonly CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED";
|
|
290
290
|
readonly CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED";
|
|
291
|
+
readonly AI_PROVIDER_AUTH_FAILED: "AI_PROVIDER_AUTH_FAILED";
|
|
292
|
+
readonly AI_PROVIDER_RATE_LIMITED: "AI_PROVIDER_RATE_LIMITED";
|
|
293
|
+
readonly AI_PROVIDER_UNAVAILABLE: "AI_PROVIDER_UNAVAILABLE";
|
|
291
294
|
readonly INTERNAL_ERROR: "INTERNAL_ERROR";
|
|
292
295
|
readonly AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED";
|
|
293
296
|
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
@@ -299,7 +302,8 @@ type QueryErrorCode = (typeof QueryErrorCode)[keyof typeof QueryErrorCode];
|
|
|
299
302
|
declare class QueryPipelineError extends Error {
|
|
300
303
|
readonly code: QueryErrorCode;
|
|
301
304
|
readonly details?: Record<string, unknown> | undefined;
|
|
302
|
-
|
|
305
|
+
readonly status?: number | undefined;
|
|
306
|
+
constructor(message: string, code: QueryErrorCode, details?: Record<string, unknown> | undefined, status?: number | undefined);
|
|
303
307
|
/**
|
|
304
308
|
* Check if this is a moderation error
|
|
305
309
|
*/
|
|
@@ -320,6 +324,18 @@ declare class QueryPipelineError extends Error {
|
|
|
320
324
|
* Check if this is a clarification needed error (v2 pipeline)
|
|
321
325
|
*/
|
|
322
326
|
isClarificationNeeded(): boolean;
|
|
327
|
+
/**
|
|
328
|
+
* Check if this is a BYOK / provider credential error
|
|
329
|
+
*/
|
|
330
|
+
isAiProviderAuthError(): boolean;
|
|
331
|
+
/**
|
|
332
|
+
* Check if this is a BYOK / provider rate-limit error
|
|
333
|
+
*/
|
|
334
|
+
isAiProviderRateLimited(): boolean;
|
|
335
|
+
/**
|
|
336
|
+
* Check if this is any BYOK / provider error (auth, rate limit, or unavailable)
|
|
337
|
+
*/
|
|
338
|
+
isAiProviderError(): boolean;
|
|
323
339
|
}
|
|
324
340
|
|
|
325
341
|
type ParamValue = string | number | boolean | string[] | number[];
|
package/dist/index.d.ts
CHANGED
|
@@ -288,6 +288,9 @@ declare const QueryErrorCode: {
|
|
|
288
288
|
readonly SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED";
|
|
289
289
|
readonly CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED";
|
|
290
290
|
readonly CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED";
|
|
291
|
+
readonly AI_PROVIDER_AUTH_FAILED: "AI_PROVIDER_AUTH_FAILED";
|
|
292
|
+
readonly AI_PROVIDER_RATE_LIMITED: "AI_PROVIDER_RATE_LIMITED";
|
|
293
|
+
readonly AI_PROVIDER_UNAVAILABLE: "AI_PROVIDER_UNAVAILABLE";
|
|
291
294
|
readonly INTERNAL_ERROR: "INTERNAL_ERROR";
|
|
292
295
|
readonly AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED";
|
|
293
296
|
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
@@ -299,7 +302,8 @@ type QueryErrorCode = (typeof QueryErrorCode)[keyof typeof QueryErrorCode];
|
|
|
299
302
|
declare class QueryPipelineError extends Error {
|
|
300
303
|
readonly code: QueryErrorCode;
|
|
301
304
|
readonly details?: Record<string, unknown> | undefined;
|
|
302
|
-
|
|
305
|
+
readonly status?: number | undefined;
|
|
306
|
+
constructor(message: string, code: QueryErrorCode, details?: Record<string, unknown> | undefined, status?: number | undefined);
|
|
303
307
|
/**
|
|
304
308
|
* Check if this is a moderation error
|
|
305
309
|
*/
|
|
@@ -320,6 +324,18 @@ declare class QueryPipelineError extends Error {
|
|
|
320
324
|
* Check if this is a clarification needed error (v2 pipeline)
|
|
321
325
|
*/
|
|
322
326
|
isClarificationNeeded(): boolean;
|
|
327
|
+
/**
|
|
328
|
+
* Check if this is a BYOK / provider credential error
|
|
329
|
+
*/
|
|
330
|
+
isAiProviderAuthError(): boolean;
|
|
331
|
+
/**
|
|
332
|
+
* Check if this is a BYOK / provider rate-limit error
|
|
333
|
+
*/
|
|
334
|
+
isAiProviderRateLimited(): boolean;
|
|
335
|
+
/**
|
|
336
|
+
* Check if this is any BYOK / provider error (auth, rate limit, or unavailable)
|
|
337
|
+
*/
|
|
338
|
+
isAiProviderError(): boolean;
|
|
323
339
|
}
|
|
324
340
|
|
|
325
341
|
type ParamValue = string | number | boolean | string[] | number[];
|
package/dist/index.js
CHANGED
|
@@ -705,6 +705,118 @@ function sanitize2(value) {
|
|
|
705
705
|
|
|
706
706
|
// src/core/client.ts
|
|
707
707
|
import crypto from "crypto";
|
|
708
|
+
|
|
709
|
+
// src/errors.ts
|
|
710
|
+
var QueryErrorCode = {
|
|
711
|
+
// Moderation errors
|
|
712
|
+
MODERATION_FAILED: "MODERATION_FAILED",
|
|
713
|
+
// Guardrail errors
|
|
714
|
+
RELEVANCE_CHECK_FAILED: "RELEVANCE_CHECK_FAILED",
|
|
715
|
+
SECURITY_CHECK_FAILED: "SECURITY_CHECK_FAILED",
|
|
716
|
+
// SQL generation errors
|
|
717
|
+
SQL_GENERATION_FAILED: "SQL_GENERATION_FAILED",
|
|
718
|
+
// SQL validation errors
|
|
719
|
+
SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED",
|
|
720
|
+
// Context retrieval errors
|
|
721
|
+
CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED",
|
|
722
|
+
// Clarification errors (v2)
|
|
723
|
+
CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED",
|
|
724
|
+
// Bring-your-own-key / provider errors
|
|
725
|
+
AI_PROVIDER_AUTH_FAILED: "AI_PROVIDER_AUTH_FAILED",
|
|
726
|
+
AI_PROVIDER_RATE_LIMITED: "AI_PROVIDER_RATE_LIMITED",
|
|
727
|
+
AI_PROVIDER_UNAVAILABLE: "AI_PROVIDER_UNAVAILABLE",
|
|
728
|
+
// General errors
|
|
729
|
+
INTERNAL_ERROR: "INTERNAL_ERROR",
|
|
730
|
+
AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED",
|
|
731
|
+
VALIDATION_ERROR: "VALIDATION_ERROR"
|
|
732
|
+
};
|
|
733
|
+
function isQueryErrorCode(code) {
|
|
734
|
+
return typeof code === "string" && Object.values(QueryErrorCode).includes(code);
|
|
735
|
+
}
|
|
736
|
+
function isAiProviderErrorCode(code) {
|
|
737
|
+
return code === QueryErrorCode.AI_PROVIDER_AUTH_FAILED || code === QueryErrorCode.AI_PROVIDER_RATE_LIMITED || code === QueryErrorCode.AI_PROVIDER_UNAVAILABLE;
|
|
738
|
+
}
|
|
739
|
+
function isAiProviderPipelineError(error) {
|
|
740
|
+
if (error instanceof QueryPipelineError) {
|
|
741
|
+
return isAiProviderErrorCode(error.code);
|
|
742
|
+
}
|
|
743
|
+
if (error && typeof error === "object" && "code" in error) {
|
|
744
|
+
return isAiProviderErrorCode(error.code);
|
|
745
|
+
}
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
function throwIfGenerationErrorResponse(response) {
|
|
749
|
+
if (!response || typeof response !== "object") {
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
const record = response;
|
|
753
|
+
if (typeof record.error !== "string") {
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
if (isQueryErrorCode(record.code)) {
|
|
757
|
+
throw new QueryPipelineError(record.error, record.code);
|
|
758
|
+
}
|
|
759
|
+
throw new Error(record.error);
|
|
760
|
+
}
|
|
761
|
+
var QueryPipelineError = class extends Error {
|
|
762
|
+
constructor(message, code, details, status) {
|
|
763
|
+
super(message);
|
|
764
|
+
this.code = code;
|
|
765
|
+
this.details = details;
|
|
766
|
+
this.status = status;
|
|
767
|
+
this.name = "QueryPipelineError";
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Check if this is a moderation error
|
|
771
|
+
*/
|
|
772
|
+
isModeration() {
|
|
773
|
+
return this.code === QueryErrorCode.MODERATION_FAILED;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Check if this is a relevance error (question not related to database)
|
|
777
|
+
*/
|
|
778
|
+
isRelevanceError() {
|
|
779
|
+
return this.code === QueryErrorCode.RELEVANCE_CHECK_FAILED;
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Check if this is a security error (SQL injection, prompt injection, etc.)
|
|
783
|
+
*/
|
|
784
|
+
isSecurityError() {
|
|
785
|
+
return this.code === QueryErrorCode.SECURITY_CHECK_FAILED;
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Check if this is any guardrail error (relevance or security)
|
|
789
|
+
*/
|
|
790
|
+
isGuardrailError() {
|
|
791
|
+
return this.isRelevanceError() || this.isSecurityError();
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Check if this is a clarification needed error (v2 pipeline)
|
|
795
|
+
*/
|
|
796
|
+
isClarificationNeeded() {
|
|
797
|
+
return this.code === QueryErrorCode.CLARIFICATION_NEEDED;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Check if this is a BYOK / provider credential error
|
|
801
|
+
*/
|
|
802
|
+
isAiProviderAuthError() {
|
|
803
|
+
return this.code === QueryErrorCode.AI_PROVIDER_AUTH_FAILED;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Check if this is a BYOK / provider rate-limit error
|
|
807
|
+
*/
|
|
808
|
+
isAiProviderRateLimited() {
|
|
809
|
+
return this.code === QueryErrorCode.AI_PROVIDER_RATE_LIMITED;
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Check if this is any BYOK / provider error (auth, rate limit, or unavailable)
|
|
813
|
+
*/
|
|
814
|
+
isAiProviderError() {
|
|
815
|
+
return isAiProviderErrorCode(this.code);
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
// src/core/client.ts
|
|
708
820
|
var ApiClient = class {
|
|
709
821
|
constructor(baseUrl, privateKey, organizationId, options) {
|
|
710
822
|
this.cryptoKey = null;
|
|
@@ -836,10 +948,18 @@ var ApiClient = class {
|
|
|
836
948
|
json = void 0;
|
|
837
949
|
}
|
|
838
950
|
if (!response.ok) {
|
|
839
|
-
const
|
|
840
|
-
|
|
841
|
-
|
|
951
|
+
const message = json?.error || response.statusText || "Request failed";
|
|
952
|
+
if (isQueryErrorCode(json?.code)) {
|
|
953
|
+
throw new QueryPipelineError(
|
|
954
|
+
message,
|
|
955
|
+
json.code,
|
|
956
|
+
json?.details,
|
|
957
|
+
response.status
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
const error = new Error(message);
|
|
842
961
|
error.status = response.status;
|
|
962
|
+
if (json?.code) error.code = json.code;
|
|
843
963
|
if (json?.details) error.details = json.details;
|
|
844
964
|
throw error;
|
|
845
965
|
}
|
|
@@ -1168,65 +1288,6 @@ var QueryEngine = class {
|
|
|
1168
1288
|
}
|
|
1169
1289
|
};
|
|
1170
1290
|
|
|
1171
|
-
// src/errors.ts
|
|
1172
|
-
var QueryErrorCode = {
|
|
1173
|
-
// Moderation errors
|
|
1174
|
-
MODERATION_FAILED: "MODERATION_FAILED",
|
|
1175
|
-
// Guardrail errors
|
|
1176
|
-
RELEVANCE_CHECK_FAILED: "RELEVANCE_CHECK_FAILED",
|
|
1177
|
-
SECURITY_CHECK_FAILED: "SECURITY_CHECK_FAILED",
|
|
1178
|
-
// SQL generation errors
|
|
1179
|
-
SQL_GENERATION_FAILED: "SQL_GENERATION_FAILED",
|
|
1180
|
-
// SQL validation errors
|
|
1181
|
-
SQL_VALIDATION_FAILED: "SQL_VALIDATION_FAILED",
|
|
1182
|
-
// Context retrieval errors
|
|
1183
|
-
CONTEXT_RETRIEVAL_FAILED: "CONTEXT_RETRIEVAL_FAILED",
|
|
1184
|
-
// Clarification errors (v2)
|
|
1185
|
-
CLARIFICATION_NEEDED: "CLARIFICATION_NEEDED",
|
|
1186
|
-
// General errors
|
|
1187
|
-
INTERNAL_ERROR: "INTERNAL_ERROR",
|
|
1188
|
-
AUTHENTICATION_REQUIRED: "AUTHENTICATION_REQUIRED",
|
|
1189
|
-
VALIDATION_ERROR: "VALIDATION_ERROR"
|
|
1190
|
-
};
|
|
1191
|
-
var QueryPipelineError = class extends Error {
|
|
1192
|
-
constructor(message, code, details) {
|
|
1193
|
-
super(message);
|
|
1194
|
-
this.code = code;
|
|
1195
|
-
this.details = details;
|
|
1196
|
-
this.name = "QueryPipelineError";
|
|
1197
|
-
}
|
|
1198
|
-
/**
|
|
1199
|
-
* Check if this is a moderation error
|
|
1200
|
-
*/
|
|
1201
|
-
isModeration() {
|
|
1202
|
-
return this.code === QueryErrorCode.MODERATION_FAILED;
|
|
1203
|
-
}
|
|
1204
|
-
/**
|
|
1205
|
-
* Check if this is a relevance error (question not related to database)
|
|
1206
|
-
*/
|
|
1207
|
-
isRelevanceError() {
|
|
1208
|
-
return this.code === QueryErrorCode.RELEVANCE_CHECK_FAILED;
|
|
1209
|
-
}
|
|
1210
|
-
/**
|
|
1211
|
-
* Check if this is a security error (SQL injection, prompt injection, etc.)
|
|
1212
|
-
*/
|
|
1213
|
-
isSecurityError() {
|
|
1214
|
-
return this.code === QueryErrorCode.SECURITY_CHECK_FAILED;
|
|
1215
|
-
}
|
|
1216
|
-
/**
|
|
1217
|
-
* Check if this is any guardrail error (relevance or security)
|
|
1218
|
-
*/
|
|
1219
|
-
isGuardrailError() {
|
|
1220
|
-
return this.isRelevanceError() || this.isSecurityError();
|
|
1221
|
-
}
|
|
1222
|
-
/**
|
|
1223
|
-
* Check if this is a clarification needed error (v2 pipeline)
|
|
1224
|
-
*/
|
|
1225
|
-
isClarificationNeeded() {
|
|
1226
|
-
return this.code === QueryErrorCode.CLARIFICATION_NEEDED;
|
|
1227
|
-
}
|
|
1228
|
-
};
|
|
1229
|
-
|
|
1230
1291
|
// src/routes/charts.ts
|
|
1231
1292
|
async function createChart(client, body, options, signal) {
|
|
1232
1293
|
const tenantId = resolveTenantId(client, options?.tenantId);
|
|
@@ -1863,60 +1924,60 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1863
1924
|
specType: chartType,
|
|
1864
1925
|
notes: rows.length === 0 ? "Query returned no rows." : null
|
|
1865
1926
|
};
|
|
1866
|
-
if (
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
}
|
|
1927
|
+
if (chartType === "vizspec") {
|
|
1928
|
+
const vizspecResponse = await client.post(
|
|
1929
|
+
"/vizspec",
|
|
1930
|
+
{
|
|
1931
|
+
question,
|
|
1932
|
+
sql,
|
|
1933
|
+
rationale: queryResponse.data.rationale,
|
|
1934
|
+
fields: execution.fields,
|
|
1935
|
+
rows: anonymizeResults(rows),
|
|
1936
|
+
max_retries: options.chartMaxRetries ?? 3,
|
|
1937
|
+
query_id: queryResponse.data.queryId,
|
|
1938
|
+
...options.supportedChartTypes?.length ? {
|
|
1939
|
+
supported_chart_types: options.supportedChartTypes
|
|
1940
|
+
} : {}
|
|
1941
|
+
},
|
|
1942
|
+
tenantId,
|
|
1943
|
+
options.userId,
|
|
1944
|
+
options.scopes,
|
|
1945
|
+
signal,
|
|
1946
|
+
sessionId
|
|
1947
|
+
);
|
|
1948
|
+
throwIfGenerationErrorResponse(vizspecResponse);
|
|
1949
|
+
chart = {
|
|
1950
|
+
vizSpec: vizspecResponse.spec,
|
|
1951
|
+
specType: "vizspec",
|
|
1952
|
+
notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
|
|
1953
|
+
};
|
|
1954
|
+
} else {
|
|
1955
|
+
const chartResponse = await client.post(
|
|
1956
|
+
"/chart",
|
|
1957
|
+
{
|
|
1958
|
+
question,
|
|
1959
|
+
sql,
|
|
1960
|
+
rationale: queryResponse.data.rationale,
|
|
1961
|
+
fields: execution.fields,
|
|
1962
|
+
rows: anonymizeResults(rows),
|
|
1963
|
+
max_retries: options.chartMaxRetries ?? 3,
|
|
1964
|
+
query_id: queryResponse.data.queryId
|
|
1965
|
+
},
|
|
1966
|
+
tenantId,
|
|
1967
|
+
options.userId,
|
|
1968
|
+
options.scopes,
|
|
1969
|
+
signal,
|
|
1970
|
+
sessionId
|
|
1971
|
+
);
|
|
1972
|
+
throwIfGenerationErrorResponse(chartResponse);
|
|
1973
|
+
chart = {
|
|
1974
|
+
vegaLiteSpec: chartResponse.chart ? {
|
|
1975
|
+
...chartResponse.chart,
|
|
1976
|
+
data: { values: rows }
|
|
1977
|
+
} : null,
|
|
1978
|
+
specType: "vega-lite",
|
|
1979
|
+
notes: rows.length === 0 ? chartResponse.notes ?? "Query returned no rows." : chartResponse.notes
|
|
1980
|
+
};
|
|
1920
1981
|
}
|
|
1921
1982
|
return {
|
|
1922
1983
|
sql,
|
|
@@ -1936,6 +1997,13 @@ async function ask(client, queryEngine, question, options, signal) {
|
|
|
1936
1997
|
trace: queryResponse.data.trace
|
|
1937
1998
|
};
|
|
1938
1999
|
} catch (error) {
|
|
2000
|
+
if (isAiProviderPipelineError(error)) {
|
|
2001
|
+
if (error instanceof QueryPipelineError) {
|
|
2002
|
+
throw error;
|
|
2003
|
+
}
|
|
2004
|
+
const providerError = error;
|
|
2005
|
+
throw new QueryPipelineError(providerError.message, providerError.code);
|
|
2006
|
+
}
|
|
1939
2007
|
attempt++;
|
|
1940
2008
|
if (attempt > maxRetry) {
|
|
1941
2009
|
throw error;
|
|
@@ -2209,64 +2277,64 @@ async function modifyChart(client, queryEngine, input, options, signal) {
|
|
|
2209
2277
|
specType: chartType,
|
|
2210
2278
|
notes: rows.length === 0 ? "Query returned no rows." : null
|
|
2211
2279
|
};
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
}
|
|
2280
|
+
const vizHints = hasVizMods ? buildVizHints(input.vizModifications) : {};
|
|
2281
|
+
const vizHintsForChart = chartType === "vizspec" ? vizHints : stripVizSpecOnlyHints(vizHints);
|
|
2282
|
+
if (chartType === "vizspec") {
|
|
2283
|
+
const vizspecResponse = await client.post(
|
|
2284
|
+
"/vizspec",
|
|
2285
|
+
{
|
|
2286
|
+
question: finalQuestion,
|
|
2287
|
+
sql: finalSql,
|
|
2288
|
+
rationale,
|
|
2289
|
+
fields: execution.fields,
|
|
2290
|
+
rows: anonymizeResults(rows),
|
|
2291
|
+
max_retries: options?.chartMaxRetries ?? 3,
|
|
2292
|
+
query_id: queryId,
|
|
2293
|
+
// Include viz hints for the chart generator
|
|
2294
|
+
...hasVizMods ? { encoding_hints: vizHintsForChart } : {},
|
|
2295
|
+
...options?.supportedChartTypes?.length ? { supported_chart_types: options.supportedChartTypes } : {}
|
|
2296
|
+
},
|
|
2297
|
+
tenantId,
|
|
2298
|
+
options?.userId,
|
|
2299
|
+
options?.scopes,
|
|
2300
|
+
signal,
|
|
2301
|
+
sessionId
|
|
2302
|
+
);
|
|
2303
|
+
throwIfGenerationErrorResponse(vizspecResponse);
|
|
2304
|
+
chart = {
|
|
2305
|
+
vizSpec: vizspecResponse.spec,
|
|
2306
|
+
specType: "vizspec",
|
|
2307
|
+
notes: rows.length === 0 ? vizspecResponse.notes ?? "Query returned no rows." : vizspecResponse.notes
|
|
2308
|
+
};
|
|
2309
|
+
} else {
|
|
2310
|
+
const chartResponse = await client.post(
|
|
2311
|
+
"/chart",
|
|
2312
|
+
{
|
|
2313
|
+
question: finalQuestion,
|
|
2314
|
+
sql: finalSql,
|
|
2315
|
+
rationale,
|
|
2316
|
+
fields: execution.fields,
|
|
2317
|
+
rows: anonymizeResults(rows),
|
|
2318
|
+
max_retries: options?.chartMaxRetries ?? 3,
|
|
2319
|
+
query_id: queryId,
|
|
2320
|
+
// Include viz hints for the chart generator
|
|
2321
|
+
...hasVizMods ? { encoding_hints: vizHintsForChart } : {}
|
|
2322
|
+
},
|
|
2323
|
+
tenantId,
|
|
2324
|
+
options?.userId,
|
|
2325
|
+
options?.scopes,
|
|
2326
|
+
signal,
|
|
2327
|
+
sessionId
|
|
2328
|
+
);
|
|
2329
|
+
throwIfGenerationErrorResponse(chartResponse);
|
|
2330
|
+
chart = {
|
|
2331
|
+
vegaLiteSpec: chartResponse.chart ? {
|
|
2332
|
+
...chartResponse.chart,
|
|
2333
|
+
data: { values: rows }
|
|
2334
|
+
} : null,
|
|
2335
|
+
specType: "vega-lite",
|
|
2336
|
+
notes: rows.length === 0 ? chartResponse.notes ?? "Query returned no rows." : chartResponse.notes
|
|
2337
|
+
};
|
|
2270
2338
|
}
|
|
2271
2339
|
return {
|
|
2272
2340
|
sql: finalSql,
|