@sqlrooms/ai 0.1.0
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/LICENSE.md +9 -0
- package/dist/AiSlice.d.ts +366 -0
- package/dist/AiSlice.d.ts.map +1 -0
- package/dist/AiSlice.js +191 -0
- package/dist/AnalysisResult.d.ts +7 -0
- package/dist/AnalysisResult.d.ts.map +1 -0
- package/dist/AnalysisResult.js +10 -0
- package/dist/AnalysisResultsContainer.d.ts +2 -0
- package/dist/AnalysisResultsContainer.d.ts.map +1 -0
- package/dist/AnalysisResultsContainer.js +14 -0
- package/dist/QueryControls.d.ts +6 -0
- package/dist/QueryControls.d.ts.map +1 -0
- package/dist/QueryControls.js +36 -0
- package/dist/ToolCall.d.ts +7 -0
- package/dist/ToolCall.d.ts.map +1 -0
- package/dist/ToolCall.js +13 -0
- package/dist/ToolResult.d.ts +7 -0
- package/dist/ToolResult.d.ts.map +1 -0
- package/dist/ToolResult.js +8 -0
- package/dist/analysis.d.ts +143 -0
- package/dist/analysis.d.ts.map +1 -0
- package/dist/analysis.js +87 -0
- package/dist/hooks/use-scroll-to-bottom.d.ts +7 -0
- package/dist/hooks/use-scroll-to-bottom.d.ts.map +1 -0
- package/dist/hooks/use-scroll-to-bottom.js +50 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/schemas.d.ts +354 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +43 -0
- package/package.json +47 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright 2025 Ilya Boyandin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { ProjectState } from '@sqlrooms/project-builder';
|
|
2
|
+
import { BaseProjectConfig } from '@sqlrooms/project-config';
|
|
3
|
+
import { CoreAssistantMessage, CoreToolMessage, CoreUserMessage, LanguageModelV1 } from 'ai';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
type AiMessage = (CoreToolMessage | CoreAssistantMessage | CoreUserMessage) & {
|
|
6
|
+
id: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const AiSliceConfig: z.ZodObject<{
|
|
9
|
+
ai: z.ZodObject<{
|
|
10
|
+
model: z.ZodString;
|
|
11
|
+
analysisResults: z.ZodArray<z.ZodObject<{
|
|
12
|
+
id: z.ZodString;
|
|
13
|
+
prompt: z.ZodString;
|
|
14
|
+
toolResults: z.ZodArray<z.ZodObject<{
|
|
15
|
+
toolName: z.ZodString;
|
|
16
|
+
toolCallId: z.ZodString;
|
|
17
|
+
args: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
18
|
+
result: z.ZodUnion<[z.ZodObject<{
|
|
19
|
+
success: z.ZodLiteral<false>;
|
|
20
|
+
error: z.ZodString;
|
|
21
|
+
}, "strip", z.ZodTypeAny, {
|
|
22
|
+
success: false;
|
|
23
|
+
error: string;
|
|
24
|
+
}, {
|
|
25
|
+
success: false;
|
|
26
|
+
error: string;
|
|
27
|
+
}>, z.ZodObject<{
|
|
28
|
+
success: z.ZodLiteral<true>;
|
|
29
|
+
data: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
30
|
+
}, "strip", z.ZodTypeAny, {
|
|
31
|
+
success: true;
|
|
32
|
+
data: Record<string, any>;
|
|
33
|
+
}, {
|
|
34
|
+
success: true;
|
|
35
|
+
data: Record<string, any>;
|
|
36
|
+
}>]>;
|
|
37
|
+
}, "strip", z.ZodTypeAny, {
|
|
38
|
+
toolName: string;
|
|
39
|
+
toolCallId: string;
|
|
40
|
+
args: Record<string, any>;
|
|
41
|
+
result: {
|
|
42
|
+
success: false;
|
|
43
|
+
error: string;
|
|
44
|
+
} | {
|
|
45
|
+
success: true;
|
|
46
|
+
data: Record<string, any>;
|
|
47
|
+
};
|
|
48
|
+
}, {
|
|
49
|
+
toolName: string;
|
|
50
|
+
toolCallId: string;
|
|
51
|
+
args: Record<string, any>;
|
|
52
|
+
result: {
|
|
53
|
+
success: false;
|
|
54
|
+
error: string;
|
|
55
|
+
} | {
|
|
56
|
+
success: true;
|
|
57
|
+
data: Record<string, any>;
|
|
58
|
+
};
|
|
59
|
+
}>, "many">;
|
|
60
|
+
toolCalls: z.ZodArray<z.ZodObject<{
|
|
61
|
+
toolName: z.ZodString;
|
|
62
|
+
toolCallId: z.ZodString;
|
|
63
|
+
args: z.ZodUnion<[z.ZodObject<{
|
|
64
|
+
type: z.ZodLiteral<"query">;
|
|
65
|
+
sqlQuery: z.ZodString;
|
|
66
|
+
reasoning: z.ZodString;
|
|
67
|
+
}, "strip", z.ZodTypeAny, {
|
|
68
|
+
type: "query";
|
|
69
|
+
sqlQuery: string;
|
|
70
|
+
reasoning: string;
|
|
71
|
+
}, {
|
|
72
|
+
type: "query";
|
|
73
|
+
sqlQuery: string;
|
|
74
|
+
reasoning: string;
|
|
75
|
+
}>, z.ZodObject<{
|
|
76
|
+
type: z.ZodLiteral<"answer">;
|
|
77
|
+
answer: z.ZodString;
|
|
78
|
+
chart: z.ZodUnion<[z.ZodObject<{
|
|
79
|
+
sqlQuery: z.ZodString;
|
|
80
|
+
vegaLiteSpec: z.ZodString;
|
|
81
|
+
}, "strip", z.ZodTypeAny, {
|
|
82
|
+
sqlQuery: string;
|
|
83
|
+
vegaLiteSpec: string;
|
|
84
|
+
}, {
|
|
85
|
+
sqlQuery: string;
|
|
86
|
+
vegaLiteSpec: string;
|
|
87
|
+
}>, z.ZodNull]>;
|
|
88
|
+
}, "strip", z.ZodTypeAny, {
|
|
89
|
+
type: "answer";
|
|
90
|
+
answer: string;
|
|
91
|
+
chart: {
|
|
92
|
+
sqlQuery: string;
|
|
93
|
+
vegaLiteSpec: string;
|
|
94
|
+
} | null;
|
|
95
|
+
}, {
|
|
96
|
+
type: "answer";
|
|
97
|
+
answer: string;
|
|
98
|
+
chart: {
|
|
99
|
+
sqlQuery: string;
|
|
100
|
+
vegaLiteSpec: string;
|
|
101
|
+
} | null;
|
|
102
|
+
}>]>;
|
|
103
|
+
}, "strip", z.ZodTypeAny, {
|
|
104
|
+
toolName: string;
|
|
105
|
+
toolCallId: string;
|
|
106
|
+
args: {
|
|
107
|
+
type: "query";
|
|
108
|
+
sqlQuery: string;
|
|
109
|
+
reasoning: string;
|
|
110
|
+
} | {
|
|
111
|
+
type: "answer";
|
|
112
|
+
answer: string;
|
|
113
|
+
chart: {
|
|
114
|
+
sqlQuery: string;
|
|
115
|
+
vegaLiteSpec: string;
|
|
116
|
+
} | null;
|
|
117
|
+
};
|
|
118
|
+
}, {
|
|
119
|
+
toolName: string;
|
|
120
|
+
toolCallId: string;
|
|
121
|
+
args: {
|
|
122
|
+
type: "query";
|
|
123
|
+
sqlQuery: string;
|
|
124
|
+
reasoning: string;
|
|
125
|
+
} | {
|
|
126
|
+
type: "answer";
|
|
127
|
+
answer: string;
|
|
128
|
+
chart: {
|
|
129
|
+
sqlQuery: string;
|
|
130
|
+
vegaLiteSpec: string;
|
|
131
|
+
} | null;
|
|
132
|
+
};
|
|
133
|
+
}>, "many">;
|
|
134
|
+
}, "strip", z.ZodTypeAny, {
|
|
135
|
+
id: string;
|
|
136
|
+
prompt: string;
|
|
137
|
+
toolResults: {
|
|
138
|
+
toolName: string;
|
|
139
|
+
toolCallId: string;
|
|
140
|
+
args: Record<string, any>;
|
|
141
|
+
result: {
|
|
142
|
+
success: false;
|
|
143
|
+
error: string;
|
|
144
|
+
} | {
|
|
145
|
+
success: true;
|
|
146
|
+
data: Record<string, any>;
|
|
147
|
+
};
|
|
148
|
+
}[];
|
|
149
|
+
toolCalls: {
|
|
150
|
+
toolName: string;
|
|
151
|
+
toolCallId: string;
|
|
152
|
+
args: {
|
|
153
|
+
type: "query";
|
|
154
|
+
sqlQuery: string;
|
|
155
|
+
reasoning: string;
|
|
156
|
+
} | {
|
|
157
|
+
type: "answer";
|
|
158
|
+
answer: string;
|
|
159
|
+
chart: {
|
|
160
|
+
sqlQuery: string;
|
|
161
|
+
vegaLiteSpec: string;
|
|
162
|
+
} | null;
|
|
163
|
+
};
|
|
164
|
+
}[];
|
|
165
|
+
}, {
|
|
166
|
+
id: string;
|
|
167
|
+
prompt: string;
|
|
168
|
+
toolResults: {
|
|
169
|
+
toolName: string;
|
|
170
|
+
toolCallId: string;
|
|
171
|
+
args: Record<string, any>;
|
|
172
|
+
result: {
|
|
173
|
+
success: false;
|
|
174
|
+
error: string;
|
|
175
|
+
} | {
|
|
176
|
+
success: true;
|
|
177
|
+
data: Record<string, any>;
|
|
178
|
+
};
|
|
179
|
+
}[];
|
|
180
|
+
toolCalls: {
|
|
181
|
+
toolName: string;
|
|
182
|
+
toolCallId: string;
|
|
183
|
+
args: {
|
|
184
|
+
type: "query";
|
|
185
|
+
sqlQuery: string;
|
|
186
|
+
reasoning: string;
|
|
187
|
+
} | {
|
|
188
|
+
type: "answer";
|
|
189
|
+
answer: string;
|
|
190
|
+
chart: {
|
|
191
|
+
sqlQuery: string;
|
|
192
|
+
vegaLiteSpec: string;
|
|
193
|
+
} | null;
|
|
194
|
+
};
|
|
195
|
+
}[];
|
|
196
|
+
}>, "many">;
|
|
197
|
+
}, "strip", z.ZodTypeAny, {
|
|
198
|
+
model: string;
|
|
199
|
+
analysisResults: {
|
|
200
|
+
id: string;
|
|
201
|
+
prompt: string;
|
|
202
|
+
toolResults: {
|
|
203
|
+
toolName: string;
|
|
204
|
+
toolCallId: string;
|
|
205
|
+
args: Record<string, any>;
|
|
206
|
+
result: {
|
|
207
|
+
success: false;
|
|
208
|
+
error: string;
|
|
209
|
+
} | {
|
|
210
|
+
success: true;
|
|
211
|
+
data: Record<string, any>;
|
|
212
|
+
};
|
|
213
|
+
}[];
|
|
214
|
+
toolCalls: {
|
|
215
|
+
toolName: string;
|
|
216
|
+
toolCallId: string;
|
|
217
|
+
args: {
|
|
218
|
+
type: "query";
|
|
219
|
+
sqlQuery: string;
|
|
220
|
+
reasoning: string;
|
|
221
|
+
} | {
|
|
222
|
+
type: "answer";
|
|
223
|
+
answer: string;
|
|
224
|
+
chart: {
|
|
225
|
+
sqlQuery: string;
|
|
226
|
+
vegaLiteSpec: string;
|
|
227
|
+
} | null;
|
|
228
|
+
};
|
|
229
|
+
}[];
|
|
230
|
+
}[];
|
|
231
|
+
}, {
|
|
232
|
+
model: string;
|
|
233
|
+
analysisResults: {
|
|
234
|
+
id: string;
|
|
235
|
+
prompt: string;
|
|
236
|
+
toolResults: {
|
|
237
|
+
toolName: string;
|
|
238
|
+
toolCallId: string;
|
|
239
|
+
args: Record<string, any>;
|
|
240
|
+
result: {
|
|
241
|
+
success: false;
|
|
242
|
+
error: string;
|
|
243
|
+
} | {
|
|
244
|
+
success: true;
|
|
245
|
+
data: Record<string, any>;
|
|
246
|
+
};
|
|
247
|
+
}[];
|
|
248
|
+
toolCalls: {
|
|
249
|
+
toolName: string;
|
|
250
|
+
toolCallId: string;
|
|
251
|
+
args: {
|
|
252
|
+
type: "query";
|
|
253
|
+
sqlQuery: string;
|
|
254
|
+
reasoning: string;
|
|
255
|
+
} | {
|
|
256
|
+
type: "answer";
|
|
257
|
+
answer: string;
|
|
258
|
+
chart: {
|
|
259
|
+
sqlQuery: string;
|
|
260
|
+
vegaLiteSpec: string;
|
|
261
|
+
} | null;
|
|
262
|
+
};
|
|
263
|
+
}[];
|
|
264
|
+
}[];
|
|
265
|
+
}>;
|
|
266
|
+
}, "strip", z.ZodTypeAny, {
|
|
267
|
+
ai: {
|
|
268
|
+
model: string;
|
|
269
|
+
analysisResults: {
|
|
270
|
+
id: string;
|
|
271
|
+
prompt: string;
|
|
272
|
+
toolResults: {
|
|
273
|
+
toolName: string;
|
|
274
|
+
toolCallId: string;
|
|
275
|
+
args: Record<string, any>;
|
|
276
|
+
result: {
|
|
277
|
+
success: false;
|
|
278
|
+
error: string;
|
|
279
|
+
} | {
|
|
280
|
+
success: true;
|
|
281
|
+
data: Record<string, any>;
|
|
282
|
+
};
|
|
283
|
+
}[];
|
|
284
|
+
toolCalls: {
|
|
285
|
+
toolName: string;
|
|
286
|
+
toolCallId: string;
|
|
287
|
+
args: {
|
|
288
|
+
type: "query";
|
|
289
|
+
sqlQuery: string;
|
|
290
|
+
reasoning: string;
|
|
291
|
+
} | {
|
|
292
|
+
type: "answer";
|
|
293
|
+
answer: string;
|
|
294
|
+
chart: {
|
|
295
|
+
sqlQuery: string;
|
|
296
|
+
vegaLiteSpec: string;
|
|
297
|
+
} | null;
|
|
298
|
+
};
|
|
299
|
+
}[];
|
|
300
|
+
}[];
|
|
301
|
+
};
|
|
302
|
+
}, {
|
|
303
|
+
ai: {
|
|
304
|
+
model: string;
|
|
305
|
+
analysisResults: {
|
|
306
|
+
id: string;
|
|
307
|
+
prompt: string;
|
|
308
|
+
toolResults: {
|
|
309
|
+
toolName: string;
|
|
310
|
+
toolCallId: string;
|
|
311
|
+
args: Record<string, any>;
|
|
312
|
+
result: {
|
|
313
|
+
success: false;
|
|
314
|
+
error: string;
|
|
315
|
+
} | {
|
|
316
|
+
success: true;
|
|
317
|
+
data: Record<string, any>;
|
|
318
|
+
};
|
|
319
|
+
}[];
|
|
320
|
+
toolCalls: {
|
|
321
|
+
toolName: string;
|
|
322
|
+
toolCallId: string;
|
|
323
|
+
args: {
|
|
324
|
+
type: "query";
|
|
325
|
+
sqlQuery: string;
|
|
326
|
+
reasoning: string;
|
|
327
|
+
} | {
|
|
328
|
+
type: "answer";
|
|
329
|
+
answer: string;
|
|
330
|
+
chart: {
|
|
331
|
+
sqlQuery: string;
|
|
332
|
+
vegaLiteSpec: string;
|
|
333
|
+
} | null;
|
|
334
|
+
};
|
|
335
|
+
}[];
|
|
336
|
+
}[];
|
|
337
|
+
};
|
|
338
|
+
}>;
|
|
339
|
+
export type AiSliceConfig = z.infer<typeof AiSliceConfig>;
|
|
340
|
+
export declare function createDefaultAiConfig(): AiSliceConfig;
|
|
341
|
+
export type AiSliceState = {
|
|
342
|
+
ai: {
|
|
343
|
+
supportedModels: string[];
|
|
344
|
+
analysisPrompt: string;
|
|
345
|
+
isRunningAnalysis: boolean;
|
|
346
|
+
analysisAbortController?: AbortController;
|
|
347
|
+
apiKey: string | null;
|
|
348
|
+
setAiModel: (model: string) => void;
|
|
349
|
+
setAnalysisPrompt: (prompt: string) => void;
|
|
350
|
+
setApiKey: (key: string) => void;
|
|
351
|
+
startAnalysis: () => Promise<void>;
|
|
352
|
+
cancelAnalysis: () => void;
|
|
353
|
+
messagesById: Map<string, AiMessage>;
|
|
354
|
+
addMessages: (messages: AiMessage[]) => void;
|
|
355
|
+
getMessages: () => AiMessage[];
|
|
356
|
+
};
|
|
357
|
+
};
|
|
358
|
+
export declare function createAiSlice<PC extends BaseProjectConfig & AiSliceConfig>({ supportedModels, createModel, }: {
|
|
359
|
+
supportedModels: string[];
|
|
360
|
+
createModel: (model: string, apiKey: string) => LanguageModelV1;
|
|
361
|
+
}): import("zustand").StateCreator<AiSliceState>;
|
|
362
|
+
type ProjectConfigWithAi = BaseProjectConfig & AiSliceConfig;
|
|
363
|
+
type ProjectStateWithAi = ProjectState<ProjectConfigWithAi> & AiSliceState;
|
|
364
|
+
export declare function useStoreWithAi<T>(selector: (state: ProjectStateWithAi) => T): T;
|
|
365
|
+
export {};
|
|
366
|
+
//# sourceMappingURL=AiSlice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiSlice.d.ts","sourceRoot":"","sources":["../src/AiSlice.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,YAAY,EAEb,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,eAAe,EAChB,MAAM,IAAI,CAAC;AAEZ,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAQtB,KAAK,SAAS,GAAG,CAAC,eAAe,GAAG,oBAAoB,GAAG,eAAe,CAAC,GAAG;IAC5E,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,wBAAgB,qBAAqB,IAAI,aAAa,CAOrD;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE;QACF,eAAe,EAAE,MAAM,EAAE,CAAC;QAC1B,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,uBAAuB,CAAC,EAAE,eAAe,CAAC;QAC1C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QACpC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5C,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QACjC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QACnC,cAAc,EAAE,MAAM,IAAI,CAAC;QAC3B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACrC,WAAW,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;QAC7C,WAAW,EAAE,MAAM,SAAS,EAAE,CAAC;KAChC,CAAC;CACH,CAAC;AAEF,wBAAgB,aAAa,CAAC,EAAE,SAAS,iBAAiB,GAAG,aAAa,EAAE,EAC1E,eAAe,EACf,WAAW,GACZ,EAAE;IACD,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,eAAe,CAAC;CACjE,gDAuKA;AAsCD,KAAK,mBAAmB,GAAG,iBAAiB,GAAG,aAAa,CAAC;AAC7D,KAAK,kBAAkB,GAAG,YAAY,CAAC,mBAAmB,CAAC,GAAG,YAAY,CAAC;AAE3E,wBAAgB,cAAc,CAAC,CAAC,EAC9B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,CAAC,GACzC,CAAC,CAMH"}
|
package/dist/AiSlice.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { createId } from '@paralleldrive/cuid2';
|
|
2
|
+
import { createProjectSlice, useBaseProjectStore, } from '@sqlrooms/project-builder';
|
|
3
|
+
import { produce } from 'immer';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { runAnalysis } from './analysis';
|
|
6
|
+
import { AnalysisResultSchema, } from './schemas';
|
|
7
|
+
export const AiSliceConfig = z.object({
|
|
8
|
+
ai: z.object({
|
|
9
|
+
model: z.string(),
|
|
10
|
+
analysisResults: z.array(AnalysisResultSchema),
|
|
11
|
+
}),
|
|
12
|
+
});
|
|
13
|
+
export function createDefaultAiConfig() {
|
|
14
|
+
return {
|
|
15
|
+
ai: {
|
|
16
|
+
model: 'gpt-4o-mini',
|
|
17
|
+
analysisResults: [],
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function createAiSlice({ supportedModels, createModel, }) {
|
|
22
|
+
return createProjectSlice((set, get) => ({
|
|
23
|
+
ai: {
|
|
24
|
+
supportedModels,
|
|
25
|
+
analysisPrompt: 'Describe the data in the table and make a chart providing an overview.',
|
|
26
|
+
isRunningAnalysis: false,
|
|
27
|
+
messagesById: new Map(),
|
|
28
|
+
apiKey: typeof window !== 'undefined'
|
|
29
|
+
? localStorage.getItem('ai_api_key')
|
|
30
|
+
: null,
|
|
31
|
+
setApiKey: (key) => {
|
|
32
|
+
localStorage.setItem('ai_api_key', key);
|
|
33
|
+
set((state) => produce(state, (draft) => {
|
|
34
|
+
draft.ai.apiKey = key;
|
|
35
|
+
}));
|
|
36
|
+
},
|
|
37
|
+
setAnalysisPrompt: (prompt) => {
|
|
38
|
+
set((state) => produce(state, (draft) => {
|
|
39
|
+
draft.ai.analysisPrompt = prompt;
|
|
40
|
+
}));
|
|
41
|
+
},
|
|
42
|
+
setAiModel: (model) => {
|
|
43
|
+
set({ projectConfig: { ...get().projectConfig, model: model } });
|
|
44
|
+
},
|
|
45
|
+
/**
|
|
46
|
+
* Add messages to the project store uniquely by id
|
|
47
|
+
* @param messages - The messages to add.
|
|
48
|
+
*/
|
|
49
|
+
addMessages: (messages) => {
|
|
50
|
+
set((state) => {
|
|
51
|
+
const newMessages = messages.filter((m) => !state.ai.messagesById.has(m.id));
|
|
52
|
+
const newMessagesById = new Map(state.ai.messagesById);
|
|
53
|
+
for (const m of newMessages) {
|
|
54
|
+
if (!m.id) {
|
|
55
|
+
console.warn('Message has no id', m);
|
|
56
|
+
}
|
|
57
|
+
newMessagesById.set(m.id, m);
|
|
58
|
+
}
|
|
59
|
+
console.log('newMessagesById', Array.from(newMessagesById.values()));
|
|
60
|
+
return {
|
|
61
|
+
ai: {
|
|
62
|
+
...state.ai,
|
|
63
|
+
messagesById: newMessagesById,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
getMessages: () => {
|
|
69
|
+
return Array.from(get().ai.messagesById.values());
|
|
70
|
+
},
|
|
71
|
+
startAnalysis: async () => {
|
|
72
|
+
const resultId = createId();
|
|
73
|
+
const abortController = new AbortController();
|
|
74
|
+
const { apiKey } = get().ai;
|
|
75
|
+
const model = get().projectConfig.ai.model;
|
|
76
|
+
if (!apiKey) {
|
|
77
|
+
throw new Error('OpenAI API key is required');
|
|
78
|
+
}
|
|
79
|
+
set((state) => produce(state, (draft) => {
|
|
80
|
+
draft.ai.analysisAbortController = abortController;
|
|
81
|
+
draft.ai.isRunningAnalysis = true;
|
|
82
|
+
draft.projectConfig.ai.analysisResults.push({
|
|
83
|
+
id: resultId,
|
|
84
|
+
prompt: get().ai.analysisPrompt,
|
|
85
|
+
toolResults: [],
|
|
86
|
+
toolCalls: [],
|
|
87
|
+
});
|
|
88
|
+
}));
|
|
89
|
+
get().ai.addMessages([
|
|
90
|
+
{
|
|
91
|
+
id: createId(),
|
|
92
|
+
role: 'user',
|
|
93
|
+
content: get().ai.analysisPrompt,
|
|
94
|
+
},
|
|
95
|
+
]);
|
|
96
|
+
set((state) => produce(state, (draft) => {
|
|
97
|
+
draft.ai.analysisPrompt = '';
|
|
98
|
+
}));
|
|
99
|
+
try {
|
|
100
|
+
const { toolResults, toolCalls, ...rest } = await runAnalysis({
|
|
101
|
+
model: createModel(model, apiKey),
|
|
102
|
+
// prompt: get().analysisPrompt,
|
|
103
|
+
messages: get().ai.getMessages(),
|
|
104
|
+
onStepFinish: (event) => {
|
|
105
|
+
console.log('onStepFinish', event);
|
|
106
|
+
get().ai.addMessages(event.response.messages);
|
|
107
|
+
set(makeResultsAppender({
|
|
108
|
+
resultId,
|
|
109
|
+
toolResults: event.toolResults,
|
|
110
|
+
toolCalls: event.toolCalls,
|
|
111
|
+
}));
|
|
112
|
+
},
|
|
113
|
+
abortSignal: abortController.signal,
|
|
114
|
+
apiKey,
|
|
115
|
+
});
|
|
116
|
+
console.log('final result', { toolResults, toolCalls, ...rest });
|
|
117
|
+
get().ai.addMessages([
|
|
118
|
+
{
|
|
119
|
+
id: createId(),
|
|
120
|
+
role: 'tool',
|
|
121
|
+
content: [],
|
|
122
|
+
// @ts-ignore
|
|
123
|
+
tool_call_id: toolCalls[toolCalls.length - 1].toolCallId,
|
|
124
|
+
},
|
|
125
|
+
]);
|
|
126
|
+
// set(
|
|
127
|
+
// makeResultsAppender({
|
|
128
|
+
// resultId,
|
|
129
|
+
// toolResults,
|
|
130
|
+
// toolCalls: rest.toolCalls,
|
|
131
|
+
// }),
|
|
132
|
+
// );
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
set(makeResultsAppender({
|
|
136
|
+
resultId,
|
|
137
|
+
toolResults: [
|
|
138
|
+
{
|
|
139
|
+
toolName: 'answer',
|
|
140
|
+
toolCallId: createId(),
|
|
141
|
+
args: {},
|
|
142
|
+
result: {
|
|
143
|
+
success: false,
|
|
144
|
+
error: err instanceof Error ? err.message : String(err),
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
toolCalls: [],
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
set((state) => produce(state, (draft) => {
|
|
153
|
+
draft.ai.isRunningAnalysis = false;
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
cancelAnalysis: () => {
|
|
158
|
+
set((state) => produce(state, (draft) => {
|
|
159
|
+
draft.ai.isRunningAnalysis = false;
|
|
160
|
+
}));
|
|
161
|
+
get().ai.analysisAbortController?.abort('Analysis cancelled');
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
function findResultById(analysisResults, id) {
|
|
167
|
+
return analysisResults.find((r) => r.id === id);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Returns a function that will update the state by appending new results
|
|
171
|
+
* to the analysis results.
|
|
172
|
+
* @param resultId - The result id
|
|
173
|
+
* @param toolResults - The new tool results
|
|
174
|
+
* @param toolCalls - The new tool calls
|
|
175
|
+
* @returns The new state
|
|
176
|
+
*/
|
|
177
|
+
function makeResultsAppender({ resultId, toolResults, toolCalls, }) {
|
|
178
|
+
return (state) => produce(state, (draft) => {
|
|
179
|
+
const result = findResultById(draft.projectConfig.ai.analysisResults, resultId);
|
|
180
|
+
if (result) {
|
|
181
|
+
result.toolResults = [...result.toolResults, ...toolResults];
|
|
182
|
+
result.toolCalls = [...result.toolCalls, ...toolCalls];
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
console.error('Result not found', resultId);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
export function useStoreWithAi(selector) {
|
|
190
|
+
return useBaseProjectStore((state) => selector(state));
|
|
191
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalysisResult.d.ts","sourceRoot":"","sources":["../src/AnalysisResult.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAC,MAAM,WAAW,CAAC;AAM/C,UAAU,mBAAmB;IAC3B,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAmCxD,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ToolCall } from './ToolCall';
|
|
3
|
+
import { ToolResult } from './ToolResult';
|
|
4
|
+
import { SquareTerminalIcon, CodeIcon } from 'lucide-react';
|
|
5
|
+
import { Button, Popover, PopoverContent, PopoverTrigger } from '@sqlrooms/ui';
|
|
6
|
+
export const AnalysisResult = ({ result }) => {
|
|
7
|
+
return (_jsxs("div", { className: "flex flex-col w-full text-sm gap-5 border py-6 px-4 rounded-md", children: [_jsxs("div", { className: "bg-gray-700 p-2 mb-2 rounded-md text-gray-100 flex items-center gap-2", children: [_jsx(SquareTerminalIcon, { className: "w-4 h-4" }), _jsx("div", { className: "text-sm flex-1", children: result.prompt }), _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "w-6 h-6", children: _jsx(CodeIcon, { className: "w-4 h-4" }) }) }), _jsx(PopoverContent, { className: "w-[400px] max-h-[400px] overflow-auto", align: "end", side: "right", children: _jsx("pre", { className: "text-xs", children: JSON.stringify(result, null, 2) }) })] })] }), _jsx("div", { className: "flex flex-col gap-5 px-4", children: result.toolResults.map((toolResult) => (_jsx(ToolResult, { toolResult: toolResult }, toolResult.toolCallId))) }), _jsx("div", { className: "flex flex-col gap-5 px-4", children: result.toolCalls
|
|
8
|
+
.filter((toolCall) => toolCall.toolName === 'answer')
|
|
9
|
+
.map((toolCall) => (_jsx(ToolCall, { toolCall: toolCall }, toolCall.toolCallId))) })] }));
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalysisResultsContainer.d.ts","sourceRoot":"","sources":["../src/AnalysisResultsContainer.tsx"],"names":[],"mappings":"AAUA,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EA6C5C,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn, SkeletonPane } from '@sqlrooms/ui';
|
|
4
|
+
import { ChevronDown } from 'lucide-react';
|
|
5
|
+
import { useStoreWithAi } from './AiSlice';
|
|
6
|
+
import { AnalysisResult } from './AnalysisResult';
|
|
7
|
+
import { useScrollToBottom, useScrollToBottomButton, } from './hooks/use-scroll-to-bottom';
|
|
8
|
+
export const AnalysisResultsContainer = () => {
|
|
9
|
+
const isRunningAnalysis = useStoreWithAi((s) => s.ai.isRunningAnalysis);
|
|
10
|
+
const analysisResults = useStoreWithAi((s) => s.projectConfig.ai.analysisResults);
|
|
11
|
+
const [messagesContainerRef, messagesEndRef] = useScrollToBottom();
|
|
12
|
+
const { showButton, scrollToBottom } = useScrollToBottomButton(messagesContainerRef);
|
|
13
|
+
return (_jsxs("div", { className: "flex relative h-full w-full overflow-hidden", children: [_jsxs("div", { className: "flex flex-grow flex-col w-full gap-4 p-4 overflow-auto", ref: messagesContainerRef, children: [_jsxs("div", { className: "flex flex-col gap-10 ", children: [analysisResults.map((result) => (_jsx(AnalysisResult, { result: result }, result.id))), _jsx("div", { className: "h-20" }), messagesEndRef && (_jsx("div", { ref: messagesEndRef, className: "shrink-0 min-w-[24px] min-h-[24px]" }))] }), isRunningAnalysis && _jsx(SkeletonPane, { className: "p-4" })] }), _jsx("div", { className: "absolute inset-x-0 bottom-0 pointer-events-none flex justify-center", children: _jsx("button", { onClick: scrollToBottom, className: cn('pointer-events-auto bg-primary hover:bg-primary/90 text-primary-foreground z-50', 'rounded-full p-2 shadow-md transition-all duration-200 opacity-0 translate-y-4 mb-6', showButton && 'opacity-100 translate-y-0'), "aria-label": "Scroll to bottom", children: _jsx(ChevronDown, { className: "w-5 h-5" }) }) })] }));
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryControls.d.ts","sourceRoot":"","sources":["../src/QueryControls.tsx"],"names":[],"mappings":"AAgBA,UAAU,kBAAkB;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAgHtD,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, cn, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Spinner, Textarea, } from '@sqlrooms/ui';
|
|
3
|
+
import { KeyIcon, OctagonXIcon } from 'lucide-react';
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
import { useStoreWithAi } from './AiSlice';
|
|
6
|
+
export const QueryControls = ({ className }) => {
|
|
7
|
+
const isRunningAnalysis = useStoreWithAi((s) => s.ai.isRunningAnalysis);
|
|
8
|
+
const runAnalysis = useStoreWithAi((s) => s.ai.startAnalysis);
|
|
9
|
+
const cancelAnalysis = useStoreWithAi((s) => s.ai.cancelAnalysis);
|
|
10
|
+
const analysisPrompt = useStoreWithAi((s) => s.ai.analysisPrompt);
|
|
11
|
+
const setAnalysisPrompt = useStoreWithAi((s) => s.ai.setAnalysisPrompt);
|
|
12
|
+
const apiKey = useStoreWithAi((s) => s.ai.apiKey);
|
|
13
|
+
const setApiKey = useStoreWithAi((s) => s.ai.setApiKey);
|
|
14
|
+
const model = useStoreWithAi((s) => s.projectConfig.ai.model);
|
|
15
|
+
const setAiModel = useStoreWithAi((s) => s.ai.setAiModel);
|
|
16
|
+
const supportedModels = useStoreWithAi((s) => s.ai.supportedModels);
|
|
17
|
+
const handleKeyDown = useCallback((e) => {
|
|
18
|
+
if (e.key === 'Enter' &&
|
|
19
|
+
!e.shiftKey &&
|
|
20
|
+
!e.ctrlKey &&
|
|
21
|
+
!e.altKey &&
|
|
22
|
+
!e.metaKey) {
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
if (!isRunningAnalysis &&
|
|
25
|
+
apiKey &&
|
|
26
|
+
model &&
|
|
27
|
+
analysisPrompt.trim().length) {
|
|
28
|
+
runAnalysis();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}, [isRunningAnalysis, apiKey, model, analysisPrompt, runAnalysis]);
|
|
32
|
+
return (_jsxs("div", { className: cn('flex flex-col items-center justify-center gap-4 w-full p-4', className), children: [_jsxs("div", { className: "flex items-center justify-between gap-4 w-full", children: [_jsx("div", { className: "font-semibold text-lg pl-1", children: "What would you like to learn about the data?" }), _jsx("div", { className: "flex-col items-center gap-2", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: "relative flex items-center", children: [_jsx(KeyIcon, { className: "w-4 h-4 absolute left-2 text-gray-400" }), _jsx(Input, { type: "password", placeholder: "OpenAI API Key", value: apiKey || '', onChange: (e) => setApiKey(e.target.value), className: "pl-8 w-[150px] bg-gray-800" })] }), _jsxs(Select, { value: model || '', onValueChange: setAiModel, children: [_jsx(SelectTrigger, { className: "w-[140px] bg-gray-800", children: _jsx(SelectValue, { placeholder: "Select model" }) }), _jsx(SelectContent, { children: supportedModels.map((model) => (_jsx(SelectItem, { value: model, children: model }, model))) })] })] }) })] }), _jsxs("div", { className: "relative w-full", children: [_jsx(Textarea, { disabled: isRunningAnalysis, className: "h-[100px] bg-gray-800", value: analysisPrompt, onChange: (e) => setAnalysisPrompt(e.target.value), onKeyDown: handleKeyDown }), _jsxs("div", { className: "absolute top-1 right-1 flex items-center gap-2", children: [isRunningAnalysis && (_jsxs(Button, { variant: "outline", onClick: cancelAnalysis, children: [_jsx(OctagonXIcon, { className: "w-4 h-4" }), "Stop"] })), _jsx(Button, { variant: "outline", onClick: runAnalysis, disabled: isRunningAnalysis ||
|
|
33
|
+
!apiKey ||
|
|
34
|
+
!model ||
|
|
35
|
+
!analysisPrompt.trim().length, children: isRunningAnalysis ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Spinner, { className: "w-4 h-4" }), " Running\u2026"] })) : ('Start Analysis') })] })] })] }));
|
|
36
|
+
};
|