@@ -55,6 +55,15 @@ export interface AsyncQueryResponse {
55
55
queryId : string ;
56
56
}
57
57
58
+ export type ExplainResult = AIServiceResponse < any , ExplainPipelineStatus > ;
59
+
60
+ export enum ExplainPipelineStatus {
61
+ UNDERSTANDING = 'UNDERSTANDING' ,
62
+ GENERATING = 'GENERATING' ,
63
+ FINISHED = 'FINISHED' ,
64
+ FAILED = 'FAILED' ,
65
+ }
66
+
58
67
export enum AskResultStatus {
59
68
UNDERSTANDING = 'UNDERSTANDING' ,
60
69
SEARCHING = 'SEARCHING' ,
@@ -71,7 +80,21 @@ export enum AskCandidateType {
71
80
LLM = 'LLM' ,
72
81
}
73
82
74
- export interface AskResponse < R , S > {
83
+ export enum ExplainType {
84
+ FILTER = 'filter' ,
85
+ SELECT_ITEMS = 'selectItems' ,
86
+ RELATION = 'relation' ,
87
+ GROUP_BY_KEYS = 'groupByKeys' ,
88
+ SORTINGS = 'sortings' ,
89
+ }
90
+
91
+ // UI currently only support nl_expression
92
+ export enum ExpressionType {
93
+ SQL_EXPRESSION = 'sql_expression' ,
94
+ NL_EXPRESSION = 'nl_expression' ,
95
+ }
96
+
97
+ export interface AIServiceResponse < R , S > {
75
98
status : S ;
76
99
response : R | null ;
77
100
error : WrenAIError | null ;
@@ -83,15 +106,15 @@ export interface AskDetailInput {
83
106
summary : string ;
84
107
}
85
108
86
- export type AskDetailResult = AskResponse <
109
+ export type AskDetailResult = AIServiceResponse <
87
110
{
88
111
description : string ;
89
112
steps : AskStep [ ] ;
90
113
} ,
91
114
AskResultStatus
92
115
> ;
93
116
94
- export type AskResult = AskResponse <
117
+ export type AskResult = AIServiceResponse <
95
118
Array < {
96
119
type : AskCandidateType ;
97
120
sql : string ;
@@ -101,7 +124,26 @@ export type AskResult = AskResponse<
101
124
AskResultStatus
102
125
> ;
103
126
104
- const getAISerciceError = ( error : any ) => {
127
+ export interface CorrectionObject < T > {
128
+ type : T ;
129
+ value : string ;
130
+ }
131
+
132
+ export interface AskCorrection {
133
+ before : CorrectionObject < ExplainType > ;
134
+ after : CorrectionObject < ExpressionType > ;
135
+ }
136
+
137
+ export interface AskStepWithCorrections extends AskStep {
138
+ corrections : AskCorrection [ ] ;
139
+ }
140
+
141
+ export interface RegenerateAskDetailInput {
142
+ description : string ;
143
+ steps : AskStepWithCorrections [ ] ;
144
+ }
145
+
146
+ const getAIServiceError = ( error : any ) => {
105
147
const { data } = error . response || { } ;
106
148
return data ?. detail
107
149
? `${ error . message } , detail: ${ data . detail } `
@@ -129,6 +171,12 @@ export interface IWrenAIAdaptor {
129
171
*/
130
172
generateAskDetail ( input : AskDetailInput ) : Promise < AsyncQueryResponse > ;
131
173
getAskDetailResult ( queryId : string ) : Promise < AskDetailResult > ;
174
+ explain ( question : string , analysisResults : any ) : Promise < AsyncQueryResponse > ;
175
+ getExplainResult ( queryId : string ) : Promise < ExplainResult > ;
176
+ regenerateAskDetail (
177
+ input : RegenerateAskDetailInput ,
178
+ ) : Promise < AsyncQueryResponse > ;
179
+ getRegeneratedAskDetailResult ( queryId : string ) : Promise < AskDetailResult > ;
132
180
}
133
181
134
182
export class WrenAIAdaptor implements IWrenAIAdaptor {
@@ -148,11 +196,11 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
148
196
const res = await axios . post ( `${ this . wrenAIBaseEndpoint } /v1/asks` , {
149
197
query : input . query ,
150
198
id : input . deployId ,
151
- history : this . transfromHistoryInput ( input . history ) ,
199
+ history : this . transformHistoryInput ( input . history ) ,
152
200
} ) ;
153
201
return { queryId : res . data . query_id } ;
154
202
} catch ( err : any ) {
155
- logger . debug ( `Got error when asking wren AI: ${ getAISerciceError ( err ) } ` ) ;
203
+ logger . debug ( `Got error when asking wren AI: ${ getAIServiceError ( err ) } ` ) ;
156
204
throw err ;
157
205
}
158
206
}
@@ -164,7 +212,7 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
164
212
status : 'stopped' ,
165
213
} ) ;
166
214
} catch ( err : any ) {
167
- logger . debug ( `Got error when canceling ask: ${ getAISerciceError ( err ) } ` ) ;
215
+ logger . debug ( `Got error when canceling ask: ${ getAIServiceError ( err ) } ` ) ;
168
216
throw err ;
169
217
}
170
218
}
@@ -178,7 +226,7 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
178
226
return this . transformAskResult ( res . data ) ;
179
227
} catch ( err : any ) {
180
228
logger . debug (
181
- `Got error when getting ask result: ${ getAISerciceError ( err ) } ` ,
229
+ `Got error when getting ask result: ${ getAIServiceError ( err ) } ` ,
182
230
) ;
183
231
// throw err;
184
232
throw Errors . create ( Errors . GeneralErrorCodes . INTERNAL_SERVER_ERROR , {
@@ -187,6 +235,44 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
187
235
}
188
236
}
189
237
238
+ public async explain (
239
+ question : string ,
240
+ analysisResults : any ,
241
+ ) : Promise < AsyncQueryResponse > {
242
+ try {
243
+ const res = await axios . post (
244
+ `${ this . wrenAIBaseEndpoint } /v1/sql-explanations` ,
245
+ {
246
+ question,
247
+ steps_with_analysis_results : analysisResults ,
248
+ } ,
249
+ ) ;
250
+ return { queryId : res . data . query_id } ;
251
+ } catch ( err : any ) {
252
+ logger . debug ( `Got error when explaining: ${ getAIServiceError ( err ) } ` ) ;
253
+ throw err ;
254
+ }
255
+ }
256
+
257
+ public async getExplainResult ( queryId : string ) : Promise < ExplainResult > {
258
+ // make GET request /v1/sql-explanations/:query_id/result to get the result
259
+ try {
260
+ const res = await axios . get (
261
+ `${ this . wrenAIBaseEndpoint } /v1/sql-explanations/${ queryId } /result` ,
262
+ ) ;
263
+ return {
264
+ status : res . data . status as ExplainPipelineStatus ,
265
+ response : res . data . response ,
266
+ error : this . transformStatusAndError ( res . data ) . error ,
267
+ } ;
268
+ } catch ( err : any ) {
269
+ logger . debug (
270
+ `Got error when getting explain result: ${ getAIServiceError ( err ) } ` ,
271
+ ) ;
272
+ throw err ;
273
+ }
274
+ }
275
+
190
276
/**
191
277
* After you choose a candidate, you can request AI service to generate the detail.
192
278
*/
@@ -202,7 +288,7 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
202
288
return { queryId : res . data . query_id } ;
203
289
} catch ( err : any ) {
204
290
logger . debug (
205
- `Got error when generating ask detail: ${ getAISerciceError ( err ) } ` ,
291
+ `Got error when generating ask detail: ${ getAIServiceError ( err ) } ` ,
206
292
) ;
207
293
throw err ;
208
294
}
@@ -217,7 +303,37 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
217
303
return this . transformAskDetailResult ( res . data ) ;
218
304
} catch ( err : any ) {
219
305
logger . debug (
220
- `Got error when getting ask detail result: ${ getAISerciceError ( err ) } ` ,
306
+ `Got error when getting ask detail result: ${ getAIServiceError ( err ) } ` ,
307
+ ) ;
308
+ throw err ;
309
+ }
310
+ }
311
+
312
+ public async regenerateAskDetail ( input : RegenerateAskDetailInput ) {
313
+ try {
314
+ const res = await axios . post (
315
+ `${ this . wrenAIBaseEndpoint } /v1/sql-regenerations` ,
316
+ input ,
317
+ ) ;
318
+ return { queryId : res . data . query_id } ;
319
+ } catch ( err : any ) {
320
+ logger . debug (
321
+ `Got error when regenerating ask detail: ${ getAIServiceError ( err ) } ` ,
322
+ ) ;
323
+ throw err ;
324
+ }
325
+ }
326
+
327
+ public async getRegeneratedAskDetailResult ( queryId : string ) {
328
+ // make GET request /v1/sql-regenerations/:query_id/result to get the result
329
+ try {
330
+ const res = await axios . get (
331
+ `${ this . wrenAIBaseEndpoint } /v1/sql-regenerations/${ queryId } /result` ,
332
+ ) ;
333
+ return this . transformAskDetailResult ( res . data ) ;
334
+ } catch ( err : any ) {
335
+ logger . debug (
336
+ `Got error when getting regenerated ask detail result: ${ getAIServiceError ( err ) } ` ,
221
337
) ;
222
338
throw err ;
223
339
}
@@ -309,7 +425,7 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
309
425
} ) ) ;
310
426
311
427
return {
312
- status,
428
+ status : status as AskResultStatus ,
313
429
error,
314
430
response : candidates ,
315
431
} ;
@@ -326,7 +442,7 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
326
442
} ) ) ;
327
443
328
444
return {
329
- status,
445
+ status : status as AskResultStatus ,
330
446
error,
331
447
response : {
332
448
description : body ?. response ?. description ,
@@ -336,17 +452,19 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
336
452
}
337
453
338
454
private transformStatusAndError ( body : any ) : {
339
- status : AskResultStatus ;
455
+ status : AskResultStatus | ExplainPipelineStatus ;
340
456
error ?: {
341
457
code : Errors . GeneralErrorCodes ;
342
458
message : string ;
343
459
shortMessage : string ;
344
460
} | null ;
345
461
} {
346
462
// transform status to enum
347
- const status = AskResultStatus [
348
- body ?. status ?. toUpperCase ( )
349
- ] as AskResultStatus ;
463
+ const status =
464
+ ( AskResultStatus [ body ?. status ?. toUpperCase ( ) ] as AskResultStatus ) ||
465
+ ( ExplainPipelineStatus [
466
+ body . status
467
+ ] ?. toUpperCase ( ) as ExplainPipelineStatus ) ;
350
468
351
469
if ( ! status ) {
352
470
throw new Error ( `Unknown ask status: ${ body ?. status } ` ) ;
@@ -380,7 +498,7 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
380
498
} ;
381
499
}
382
500
383
- private transfromHistoryInput ( history : AskHistory ) {
501
+ private transformHistoryInput ( history : AskHistory ) {
384
502
if ( ! history ) {
385
503
return null ;
386
504
}
0 commit comments