@sqlrooms/ai 0.5.1 → 0.7.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/README.md ADDED
@@ -0,0 +1,114 @@
1
+ An AI integration package for SQLRooms that provides components and utilities for adding AI-powered features to your data applications. This package enables natural language querying, data analysis, and AI-assisted insights.
2
+
3
+ ## Features
4
+
5
+ - 🤖 **AI Query Interface**: Natural language to SQL conversion
6
+ - 📊 **Automated Analysis**: AI-powered data analysis and insights
7
+ - 🔄 **State Management**: Zustand-based state management for AI features
8
+ - 🧩 **UI Components**: Ready-to-use components for AI interactions
9
+ - 📝 **Query History**: Track and manage AI query history
10
+ - 🎯 **Tool Integration**: Framework for AI tools and actions
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @sqlrooms/ai
16
+ # or
17
+ yarn add @sqlrooms/ai
18
+ ```
19
+
20
+ ## Basic Usage
21
+
22
+ ### Setting Up AI Integration
23
+
24
+ ```tsx
25
+ import {createAiSlice, createDefaultAiConfig, useAiStore} from '@sqlrooms/ai';
26
+ import {createProjectStore} from '@sqlrooms/project-builder';
27
+
28
+ // Create a project store with AI capabilities
29
+ const useStore = createProjectStore({
30
+ ai: createAiSlice(createDefaultAiConfig()),
31
+ });
32
+
33
+ function MyApp() {
34
+ return (
35
+ <ProjectStateProvider projectStore={useStore}>
36
+ <MyDataApp />
37
+ </ProjectStateProvider>
38
+ );
39
+ }
40
+ ```
41
+
42
+ ### Using AI Query Controls
43
+
44
+ ```tsx
45
+ import {QueryControls} from '@sqlrooms/ai';
46
+
47
+ function AiQueryPanel() {
48
+ return (
49
+ <div className="p-4 border rounded-lg">
50
+ <h2 className="text-xl font-bold mb-4">Ask AI</h2>
51
+ <QueryControls
52
+ placeholder="Ask a question about your data..."
53
+ onSubmit={(query) => console.log('Processing query:', query)}
54
+ />
55
+ </div>
56
+ );
57
+ }
58
+ ```
59
+
60
+ ### Displaying Analysis Results
61
+
62
+ ```tsx
63
+ import {AnalysisResultsContainer, AnalysisResult} from '@sqlrooms/ai';
64
+ import {useAiStore} from '@sqlrooms/ai';
65
+
66
+ function AnalysisPanel() {
67
+ const {analysisResults} = useAiStore();
68
+
69
+ return (
70
+ <div className="p-4 border rounded-lg">
71
+ <h2 className="text-xl font-bold mb-4">AI Analysis</h2>
72
+ <AnalysisResultsContainer>
73
+ {analysisResults.map((result, index) => (
74
+ <AnalysisResult key={index} result={result} />
75
+ ))}
76
+ </AnalysisResultsContainer>
77
+ </div>
78
+ );
79
+ }
80
+ ```
81
+
82
+ ### Working with AI State
83
+
84
+ ```tsx
85
+ import {useAiStore} from '@sqlrooms/ai';
86
+
87
+ function AiStatusIndicator() {
88
+ const {isProcessing, lastQuery, error} = useAiStore();
89
+
90
+ if (isProcessing) {
91
+ return <div>AI is thinking...</div>;
92
+ }
93
+
94
+ if (error) {
95
+ return <div>Error: {error.message}</div>;
96
+ }
97
+
98
+ if (lastQuery) {
99
+ return <div>Last query: "{lastQuery}"</div>;
100
+ }
101
+
102
+ return <div>Ask AI a question about your data</div>;
103
+ }
104
+ ```
105
+
106
+ ## Advanced Features
107
+
108
+ - **Custom AI Tools**: Define custom tools for AI to use
109
+ - **Query Templates**: Create and manage reusable query templates
110
+ - **Result Visualization**: Automatically visualize AI analysis results
111
+ - **Conversation Context**: Maintain context across multiple queries
112
+ - **Feedback Loop**: Collect user feedback to improve AI responses
113
+
114
+ For more information, visit the SQLRooms documentation.
package/dist/AiSlice.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { ProjectState, type StateCreator } from '@sqlrooms/project-builder';
2
2
  import { BaseProjectConfig } from '@sqlrooms/project-config';
3
- import { CoreAssistantMessage, CoreToolMessage, CoreUserMessage, LanguageModelV1 } from 'ai';
3
+ import { CoreAssistantMessage, CoreToolMessage, CoreUserMessage } from 'ai';
4
4
  import { z } from 'zod';
5
5
  type AiMessage = (CoreToolMessage | CoreAssistantMessage | CoreUserMessage) & {
6
6
  id: string;
7
7
  };
8
8
  export declare const AiSliceConfig: z.ZodObject<{
9
9
  ai: z.ZodObject<{
10
+ modelProvider: z.ZodString;
10
11
  model: z.ZodString;
11
12
  analysisResults: z.ZodArray<z.ZodObject<{
12
13
  id: z.ZodString;
@@ -73,32 +74,17 @@ export declare const AiSliceConfig: z.ZodObject<{
73
74
  sqlQuery: string;
74
75
  reasoning: string;
75
76
  }>, 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]>;
77
+ sqlQuery: z.ZodString;
78
+ vegaLiteSpec: z.ZodString;
79
+ reasoning: z.ZodString;
88
80
  }, "strip", z.ZodTypeAny, {
89
- type: "answer";
90
- answer: string;
91
- chart: {
92
- sqlQuery: string;
93
- vegaLiteSpec: string;
94
- } | null;
81
+ sqlQuery: string;
82
+ reasoning: string;
83
+ vegaLiteSpec: string;
95
84
  }, {
96
- type: "answer";
97
- answer: string;
98
- chart: {
99
- sqlQuery: string;
100
- vegaLiteSpec: string;
101
- } | null;
85
+ sqlQuery: string;
86
+ reasoning: string;
87
+ vegaLiteSpec: string;
102
88
  }>]>;
103
89
  }, "strip", z.ZodTypeAny, {
104
90
  toolName: string;
@@ -108,12 +94,9 @@ export declare const AiSliceConfig: z.ZodObject<{
108
94
  sqlQuery: string;
109
95
  reasoning: string;
110
96
  } | {
111
- type: "answer";
112
- answer: string;
113
- chart: {
114
- sqlQuery: string;
115
- vegaLiteSpec: string;
116
- } | null;
97
+ sqlQuery: string;
98
+ reasoning: string;
99
+ vegaLiteSpec: string;
117
100
  };
118
101
  }, {
119
102
  toolName: string;
@@ -123,14 +106,23 @@ export declare const AiSliceConfig: z.ZodObject<{
123
106
  sqlQuery: string;
124
107
  reasoning: string;
125
108
  } | {
126
- type: "answer";
127
- answer: string;
128
- chart: {
129
- sqlQuery: string;
130
- vegaLiteSpec: string;
131
- } | null;
109
+ sqlQuery: string;
110
+ reasoning: string;
111
+ vegaLiteSpec: string;
132
112
  };
133
113
  }>, "many">;
114
+ toolCallMessages: z.ZodArray<z.ZodObject<{
115
+ toolCallId: z.ZodString;
116
+ element: z.ZodAny;
117
+ }, "strip", z.ZodTypeAny, {
118
+ toolCallId: string;
119
+ element?: any;
120
+ }, {
121
+ toolCallId: string;
122
+ element?: any;
123
+ }>, "many">;
124
+ analysis: z.ZodString;
125
+ isCompleted: z.ZodBoolean;
134
126
  }, "strip", z.ZodTypeAny, {
135
127
  id: string;
136
128
  prompt: string;
@@ -154,14 +146,17 @@ export declare const AiSliceConfig: z.ZodObject<{
154
146
  sqlQuery: string;
155
147
  reasoning: string;
156
148
  } | {
157
- type: "answer";
158
- answer: string;
159
- chart: {
160
- sqlQuery: string;
161
- vegaLiteSpec: string;
162
- } | null;
149
+ sqlQuery: string;
150
+ reasoning: string;
151
+ vegaLiteSpec: string;
163
152
  };
164
153
  }[];
154
+ toolCallMessages: {
155
+ toolCallId: string;
156
+ element?: any;
157
+ }[];
158
+ analysis: string;
159
+ isCompleted: boolean;
165
160
  }, {
166
161
  id: string;
167
162
  prompt: string;
@@ -185,16 +180,20 @@ export declare const AiSliceConfig: z.ZodObject<{
185
180
  sqlQuery: string;
186
181
  reasoning: string;
187
182
  } | {
188
- type: "answer";
189
- answer: string;
190
- chart: {
191
- sqlQuery: string;
192
- vegaLiteSpec: string;
193
- } | null;
183
+ sqlQuery: string;
184
+ reasoning: string;
185
+ vegaLiteSpec: string;
194
186
  };
195
187
  }[];
188
+ toolCallMessages: {
189
+ toolCallId: string;
190
+ element?: any;
191
+ }[];
192
+ analysis: string;
193
+ isCompleted: boolean;
196
194
  }>, "many">;
197
195
  }, "strip", z.ZodTypeAny, {
196
+ modelProvider: string;
198
197
  model: string;
199
198
  analysisResults: {
200
199
  id: string;
@@ -219,16 +218,20 @@ export declare const AiSliceConfig: z.ZodObject<{
219
218
  sqlQuery: string;
220
219
  reasoning: string;
221
220
  } | {
222
- type: "answer";
223
- answer: string;
224
- chart: {
225
- sqlQuery: string;
226
- vegaLiteSpec: string;
227
- } | null;
221
+ sqlQuery: string;
222
+ reasoning: string;
223
+ vegaLiteSpec: string;
228
224
  };
229
225
  }[];
226
+ toolCallMessages: {
227
+ toolCallId: string;
228
+ element?: any;
229
+ }[];
230
+ analysis: string;
231
+ isCompleted: boolean;
230
232
  }[];
231
233
  }, {
234
+ modelProvider: string;
232
235
  model: string;
233
236
  analysisResults: {
234
237
  id: string;
@@ -253,18 +256,22 @@ export declare const AiSliceConfig: z.ZodObject<{
253
256
  sqlQuery: string;
254
257
  reasoning: string;
255
258
  } | {
256
- type: "answer";
257
- answer: string;
258
- chart: {
259
- sqlQuery: string;
260
- vegaLiteSpec: string;
261
- } | null;
259
+ sqlQuery: string;
260
+ reasoning: string;
261
+ vegaLiteSpec: string;
262
262
  };
263
263
  }[];
264
+ toolCallMessages: {
265
+ toolCallId: string;
266
+ element?: any;
267
+ }[];
268
+ analysis: string;
269
+ isCompleted: boolean;
264
270
  }[];
265
271
  }>;
266
272
  }, "strip", z.ZodTypeAny, {
267
273
  ai: {
274
+ modelProvider: string;
268
275
  model: string;
269
276
  analysisResults: {
270
277
  id: string;
@@ -289,18 +296,22 @@ export declare const AiSliceConfig: z.ZodObject<{
289
296
  sqlQuery: string;
290
297
  reasoning: string;
291
298
  } | {
292
- type: "answer";
293
- answer: string;
294
- chart: {
295
- sqlQuery: string;
296
- vegaLiteSpec: string;
297
- } | null;
299
+ sqlQuery: string;
300
+ reasoning: string;
301
+ vegaLiteSpec: string;
298
302
  };
299
303
  }[];
304
+ toolCallMessages: {
305
+ toolCallId: string;
306
+ element?: any;
307
+ }[];
308
+ analysis: string;
309
+ isCompleted: boolean;
300
310
  }[];
301
311
  };
302
312
  }, {
303
313
  ai: {
314
+ modelProvider: string;
304
315
  model: string;
305
316
  analysisResults: {
306
317
  id: string;
@@ -325,14 +336,17 @@ export declare const AiSliceConfig: z.ZodObject<{
325
336
  sqlQuery: string;
326
337
  reasoning: string;
327
338
  } | {
328
- type: "answer";
329
- answer: string;
330
- chart: {
331
- sqlQuery: string;
332
- vegaLiteSpec: string;
333
- } | null;
339
+ sqlQuery: string;
340
+ reasoning: string;
341
+ vegaLiteSpec: string;
334
342
  };
335
343
  }[];
344
+ toolCallMessages: {
345
+ toolCallId: string;
346
+ element?: any;
347
+ }[];
348
+ analysis: string;
349
+ isCompleted: boolean;
336
350
  }[];
337
351
  };
338
352
  }>;
@@ -349,10 +363,11 @@ export type AiSliceState = {
349
363
  messagesById: Map<string, AiMessage>;
350
364
  addMessages: (messages: AiMessage[]) => void;
351
365
  getMessages: () => AiMessage[];
366
+ setAiModel: (model: string) => void;
352
367
  };
353
368
  };
354
- export declare function createAiSlice<PC extends BaseProjectConfig & AiSliceConfig>({ createModel, initialAnalysisPrompt, }: {
355
- createModel: (model: string) => LanguageModelV1;
369
+ export declare function createAiSlice<PC extends BaseProjectConfig & AiSliceConfig>({ getApiKey, initialAnalysisPrompt, }: {
370
+ getApiKey: () => string;
356
371
  initialAnalysisPrompt?: string;
357
372
  }): StateCreator<AiSliceState>;
358
373
  type ProjectConfigWithAi = BaseProjectConfig & AiSliceConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"AiSlice.d.ts","sourceRoot":"","sources":["../src/AiSlice.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,YAAY,EAEZ,KAAK,YAAY,EAClB,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,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,uBAAuB,CAAC,EAAE,eAAe,CAAC;QAC1C,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5C,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,WAAW,EACX,qBAAgI,GACjI,EAAE;IACD,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,eAAe,CAAC;IAChD,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,GAAG,YAAY,CAAC,YAAY,CAAC,CAuJ7B;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"}
1
+ {"version":3,"file":"AiSlice.d.ts","sourceRoot":"","sources":["../src/AiSlice.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,YAAY,EAEZ,KAAK,YAAY,EAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,eAAe,EAGhB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,wBAAgB,qBAAqB,IAAI,aAAa,CAQrD;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE;QACF,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,uBAAuB,CAAC,EAAE,eAAe,CAAC;QAC1C,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5C,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;QAC/B,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;KACrC,CAAC;CACH,CAAC;AAwFF,wBAAgB,aAAa,CAAC,EAAE,SAAS,iBAAiB,GAAG,aAAa,EAAE,EAC1E,SAAS,EACT,qBAAgI,GACjI,EAAE;IACD,SAAS,EAAE,MAAM,MAAM,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,GAAG,YAAY,CAAC,YAAY,CAAC,CAiH7B;AA+DD,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 CHANGED
@@ -6,6 +6,7 @@ import { runAnalysis } from './analysis';
6
6
  import { AnalysisResultSchema, } from './schemas';
7
7
  export const AiSliceConfig = z.object({
8
8
  ai: z.object({
9
+ modelProvider: z.string(),
9
10
  model: z.string(),
10
11
  analysisResults: z.array(AnalysisResultSchema),
11
12
  }),
@@ -13,23 +14,86 @@ export const AiSliceConfig = z.object({
13
14
  export function createDefaultAiConfig() {
14
15
  return {
15
16
  ai: {
17
+ modelProvider: 'openai',
16
18
  model: 'gpt-4o-mini',
17
19
  analysisResults: [],
18
20
  },
19
21
  };
20
22
  }
21
- export function createAiSlice({ createModel, initialAnalysisPrompt = 'Describe the data in the tables and make a chart providing an overview of the most important features.', }) {
23
+ /**
24
+ * Execute the analysis. It will be used by the action `startAnalysis`.
25
+ *
26
+ * Each analysis contains an array of toolCalls and the results of the tool calls (toolResults).
27
+ * After all the tool calls have been executed, the LLM will stream the results as text stored in `analysis`.
28
+ *
29
+ * @param resultId - The result id
30
+ * @param prompt - The prompt
31
+ * @param model - The model
32
+ * @param apiKey - The api key
33
+ * @param abortController - The abort controller
34
+ * @param addMessages - The add messages function
35
+ * @param set - The set function
36
+ */
37
+ async function executeAnalysis({ resultId, prompt, modelProvider, model, apiKey, abortController, addMessages, set, }) {
38
+ try {
39
+ await runAnalysis({
40
+ modelProvider,
41
+ model,
42
+ apiKey,
43
+ prompt,
44
+ abortController,
45
+ onStepFinish: (event, toolCallMessages) => {
46
+ addMessages(event.response.messages);
47
+ set(makeResultsAppender({
48
+ resultId,
49
+ toolResults: event.toolResults,
50
+ toolCalls: event.toolCalls,
51
+ toolCallMessages,
52
+ }));
53
+ },
54
+ onStreamResult: (message, isCompleted) => {
55
+ set(makeResultsAppender({
56
+ resultId,
57
+ analysis: message,
58
+ isCompleted,
59
+ }));
60
+ },
61
+ });
62
+ }
63
+ catch (err) {
64
+ set(makeResultsAppender({
65
+ resultId,
66
+ isCompleted: true,
67
+ toolResults: [
68
+ {
69
+ toolName: 'error',
70
+ toolCallId: createId(),
71
+ args: {},
72
+ result: {
73
+ success: false,
74
+ error: err instanceof Error ? err.message : String(err),
75
+ },
76
+ },
77
+ ],
78
+ toolCalls: [],
79
+ }));
80
+ }
81
+ }
82
+ export function createAiSlice({ getApiKey, initialAnalysisPrompt = 'Describe the data in the tables and make a chart providing an overview of the most important features.', }) {
22
83
  return createSlice((set, get) => ({
23
84
  ai: {
24
85
  analysisPrompt: initialAnalysisPrompt,
25
86
  isRunningAnalysis: false,
26
87
  messagesById: new Map(),
27
- apiKey: null,
28
88
  setAnalysisPrompt: (prompt) => {
29
89
  set((state) => produce(state, (draft) => {
30
90
  draft.ai.analysisPrompt = prompt;
31
91
  }));
32
92
  },
93
+ /**
94
+ * Set the AI model
95
+ * @param model - The model to set
96
+ */
33
97
  setAiModel: (model) => {
34
98
  set((state) => produce(state, (draft) => {
35
99
  draft.project.config.ai.model = model;
@@ -49,7 +113,6 @@ export function createAiSlice({ createModel, initialAnalysisPrompt = 'Describe t
49
113
  }
50
114
  newMessagesById.set(m.id, m);
51
115
  }
52
- console.log('newMessagesById', Array.from(newMessagesById.values()));
53
116
  return {
54
117
  ai: {
55
118
  ...state.ai,
@@ -72,6 +135,9 @@ export function createAiSlice({ createModel, initialAnalysisPrompt = 'Describe t
72
135
  prompt: get().ai.analysisPrompt,
73
136
  toolResults: [],
74
137
  toolCalls: [],
138
+ toolCallMessages: [],
139
+ analysis: '',
140
+ isCompleted: false,
75
141
  });
76
142
  }));
77
143
  get().ai.addMessages([
@@ -81,63 +147,22 @@ export function createAiSlice({ createModel, initialAnalysisPrompt = 'Describe t
81
147
  content: get().ai.analysisPrompt,
82
148
  },
83
149
  ]);
84
- set((state) => produce(state, (draft) => {
85
- draft.ai.analysisPrompt = '';
86
- }));
87
150
  try {
88
- const { toolResults, toolCalls, ...rest } = await runAnalysis({
89
- model: createModel(get().project.config.ai.model),
90
- // prompt: get().analysisPrompt,
91
- messages: get().ai.getMessages(),
92
- onStepFinish: (event) => {
93
- console.log('onStepFinish', event);
94
- get().ai.addMessages(event.response.messages);
95
- set(makeResultsAppender({
96
- resultId,
97
- toolResults: event.toolResults,
98
- toolCalls: event.toolCalls,
99
- }));
100
- },
101
- abortSignal: abortController.signal,
102
- });
103
- console.log('final result', { toolResults, toolCalls, ...rest });
104
- // get().ai.addMessages([
105
- // {
106
- // id: createId(),
107
- // role: 'tool',
108
- // content: [],
109
- // // @ts-ignore
110
- // tool_call_id: toolCalls[toolCalls.length - 1].toolCallId,
111
- // } satisfies AiMessage,
112
- // ]);
113
- // set(
114
- // makeResultsAppender({
115
- // resultId,
116
- // toolResults,
117
- // toolCalls: rest.toolCalls,
118
- // }),
119
- // );
120
- }
121
- catch (err) {
122
- set(makeResultsAppender({
151
+ await executeAnalysis({
123
152
  resultId,
124
- toolResults: [
125
- {
126
- toolName: 'answer',
127
- toolCallId: createId(),
128
- args: {},
129
- result: {
130
- success: false,
131
- error: err instanceof Error ? err.message : String(err),
132
- },
133
- },
134
- ],
135
- toolCalls: [],
136
- }));
153
+ prompt: get().ai.analysisPrompt,
154
+ modelProvider: get().project.config.ai.modelProvider,
155
+ model: get().project.config.ai.model,
156
+ apiKey: getApiKey(),
157
+ abortController,
158
+ addMessages: get().ai.addMessages,
159
+ set,
160
+ });
137
161
  }
138
162
  finally {
139
163
  set((state) => produce(state, (draft) => {
140
164
  draft.ai.isRunningAnalysis = false;
165
+ draft.ai.analysisPrompt = '';
141
166
  }));
142
167
  }
143
168
  },
@@ -154,19 +179,38 @@ function findResultById(analysisResults, id) {
154
179
  return analysisResults.find((r) => r.id === id);
155
180
  }
156
181
  /**
157
- * Returns a function that will update the state by appending new results
158
- * to the analysis results.
182
+ * Returns a function that will update the state by appending new results to the analysis results.
183
+ *
159
184
  * @param resultId - The result id
160
- * @param toolResults - The new tool results
161
- * @param toolCalls - The new tool calls
185
+ * @param toolCalls - The tool calls that were executed by the LLM, e.g. "query" or "chart" ("map" will be added soon). See {@link ToolCallSchema} for more details.
186
+ * @param toolResults - The results of the tool calls that were executed by the LLM. See {@link ToolResultSchema} for more details.
187
+ * @param toolCallMessages - The tool call messages that were created by some of our defined TOOLS, e.g. the table with query result. It's an array of React/JSX elements. It is linked to the tool call by the toolCallId.
188
+ * @param analysis - The analysis is the content generated after all the tool calls have been executed
189
+ * @param isCompleted - Whether the analysis is completed
162
190
  * @returns The new state
163
191
  */
164
- function makeResultsAppender({ resultId, toolResults, toolCalls, }) {
192
+ function makeResultsAppender({ resultId, toolResults, toolCalls, analysis, isCompleted, toolCallMessages, }) {
165
193
  return (state) => produce(state, (draft) => {
166
194
  const result = findResultById(draft.project.config.ai.analysisResults, resultId);
167
195
  if (result) {
168
- result.toolResults = [...result.toolResults, ...toolResults];
169
- result.toolCalls = [...result.toolCalls, ...toolCalls];
196
+ if (toolResults) {
197
+ result.toolResults = [...result.toolResults, ...toolResults];
198
+ }
199
+ if (toolCalls) {
200
+ result.toolCalls = [...result.toolCalls, ...toolCalls];
201
+ }
202
+ if (toolCallMessages) {
203
+ result.toolCallMessages = [
204
+ ...result.toolCallMessages,
205
+ ...toolCallMessages,
206
+ ];
207
+ }
208
+ if (analysis) {
209
+ result.analysis = analysis;
210
+ }
211
+ if (isCompleted) {
212
+ result.isCompleted = isCompleted;
213
+ }
170
214
  }
171
215
  else {
172
216
  console.error('Result not found', resultId);