@sqlrooms/ai 0.7.0 → 0.8.1

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.
Files changed (121) hide show
  1. package/README.md +377 -25
  2. package/dist/AiSlice.d.ts +489 -307
  3. package/dist/AiSlice.d.ts.map +1 -1
  4. package/dist/AiSlice.js +267 -177
  5. package/dist/AiSlice.js.map +1 -1
  6. package/dist/analysis.d.ts +25 -19
  7. package/dist/analysis.d.ts.map +1 -1
  8. package/dist/analysis.js +86 -145
  9. package/dist/analysis.js.map +1 -1
  10. package/dist/components/AnalysisAnswer.d.ts +14 -0
  11. package/dist/components/AnalysisAnswer.d.ts.map +1 -0
  12. package/dist/components/AnalysisAnswer.js +14 -0
  13. package/dist/components/AnalysisAnswer.js.map +1 -0
  14. package/dist/{AnalysisResult.d.ts → components/AnalysisResult.d.ts} +2 -1
  15. package/dist/components/AnalysisResult.d.ts.map +1 -0
  16. package/dist/components/AnalysisResult.js +46 -0
  17. package/dist/components/AnalysisResult.js.map +1 -0
  18. package/dist/components/AnalysisResultsContainer.d.ts +5 -0
  19. package/dist/components/AnalysisResultsContainer.d.ts.map +1 -0
  20. package/dist/components/AnalysisResultsContainer.js +27 -0
  21. package/dist/components/AnalysisResultsContainer.js.map +1 -0
  22. package/dist/components/ErrorMessage.d.ts +4 -0
  23. package/dist/components/ErrorMessage.d.ts.map +1 -0
  24. package/dist/components/ErrorMessage.js +7 -0
  25. package/dist/components/ErrorMessage.js.map +1 -0
  26. package/dist/components/MessageContainer.d.ts +10 -0
  27. package/dist/components/MessageContainer.d.ts.map +1 -0
  28. package/dist/components/MessageContainer.js +17 -0
  29. package/dist/components/MessageContainer.js.map +1 -0
  30. package/dist/components/ModelSelector.d.ts +13 -0
  31. package/dist/components/ModelSelector.d.ts.map +1 -0
  32. package/dist/components/ModelSelector.js +29 -0
  33. package/dist/components/ModelSelector.js.map +1 -0
  34. package/dist/components/QueryControls.d.ts +8 -0
  35. package/dist/components/QueryControls.d.ts.map +1 -0
  36. package/dist/components/QueryControls.js +45 -0
  37. package/dist/components/QueryControls.js.map +1 -0
  38. package/dist/components/SessionControls.d.ts +17 -0
  39. package/dist/components/SessionControls.d.ts.map +1 -0
  40. package/dist/components/SessionControls.js +20 -0
  41. package/dist/components/SessionControls.js.map +1 -0
  42. package/dist/components/session/DeleteSessionButton.d.ts +19 -0
  43. package/dist/components/session/DeleteSessionButton.d.ts.map +1 -0
  44. package/dist/components/session/DeleteSessionButton.js +54 -0
  45. package/dist/components/session/DeleteSessionButton.js.map +1 -0
  46. package/dist/components/session/DeleteSessionDialog.d.ts +27 -0
  47. package/dist/components/session/DeleteSessionDialog.d.ts.map +1 -0
  48. package/dist/components/session/DeleteSessionDialog.js +19 -0
  49. package/dist/components/session/DeleteSessionDialog.js.map +1 -0
  50. package/dist/components/session/SessionActions.d.ts +18 -0
  51. package/dist/components/session/SessionActions.d.ts.map +1 -0
  52. package/dist/components/session/SessionActions.js +19 -0
  53. package/dist/components/session/SessionActions.js.map +1 -0
  54. package/dist/components/session/SessionDropdown.d.ts +18 -0
  55. package/dist/components/session/SessionDropdown.d.ts.map +1 -0
  56. package/dist/components/session/SessionDropdown.js +21 -0
  57. package/dist/components/session/SessionDropdown.js.map +1 -0
  58. package/dist/components/session/SessionTitle.d.ts +18 -0
  59. package/dist/components/session/SessionTitle.d.ts.map +1 -0
  60. package/dist/components/session/SessionTitle.js +22 -0
  61. package/dist/components/session/SessionTitle.js.map +1 -0
  62. package/dist/components/session/SessionType.d.ts +24 -0
  63. package/dist/components/session/SessionType.d.ts.map +1 -0
  64. package/dist/components/session/SessionType.js +2 -0
  65. package/dist/components/session/SessionType.js.map +1 -0
  66. package/dist/components/session/index.d.ts +7 -0
  67. package/dist/components/session/index.d.ts.map +1 -0
  68. package/dist/components/session/index.js +7 -0
  69. package/dist/components/session/index.js.map +1 -0
  70. package/dist/components/tools/QueryToolResult.d.ts +7 -0
  71. package/dist/components/tools/QueryToolResult.d.ts.map +1 -0
  72. package/dist/components/tools/QueryToolResult.js +9 -0
  73. package/dist/components/tools/QueryToolResult.js.map +1 -0
  74. package/dist/components/tools/ToolResult.d.ts +9 -0
  75. package/dist/components/tools/ToolResult.d.ts.map +1 -0
  76. package/dist/components/tools/ToolResult.js +32 -0
  77. package/dist/components/tools/ToolResult.js.map +1 -0
  78. package/dist/components/tools/ToolResultErrorBoundary.d.ts +19 -0
  79. package/dist/components/tools/ToolResultErrorBoundary.d.ts.map +1 -0
  80. package/dist/components/tools/ToolResultErrorBoundary.js +23 -0
  81. package/dist/components/tools/ToolResultErrorBoundary.js.map +1 -0
  82. package/dist/hooks/useScrollToBottom.d.ts +82 -0
  83. package/dist/hooks/useScrollToBottom.d.ts.map +1 -0
  84. package/dist/hooks/useScrollToBottom.js +140 -0
  85. package/dist/hooks/useScrollToBottom.js.map +1 -0
  86. package/dist/index.d.ts +16 -5
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +15 -5
  89. package/dist/index.js.map +1 -1
  90. package/dist/schemas.d.ts +592 -201
  91. package/dist/schemas.d.ts.map +1 -1
  92. package/dist/schemas.js +36 -11
  93. package/dist/schemas.js.map +1 -1
  94. package/package.json +11 -10
  95. package/dist/AnalysisResult.d.ts.map +0 -1
  96. package/dist/AnalysisResult.js +0 -56
  97. package/dist/AnalysisResult.js.map +0 -1
  98. package/dist/AnalysisResultsContainer.d.ts +0 -2
  99. package/dist/AnalysisResultsContainer.d.ts.map +0 -1
  100. package/dist/AnalysisResultsContainer.js +0 -15
  101. package/dist/AnalysisResultsContainer.js.map +0 -1
  102. package/dist/QueryControls.d.ts +0 -6
  103. package/dist/QueryControls.d.ts.map +0 -1
  104. package/dist/QueryControls.js +0 -28
  105. package/dist/QueryControls.js.map +0 -1
  106. package/dist/QueryResult.d.ts +0 -9
  107. package/dist/QueryResult.d.ts.map +0 -1
  108. package/dist/QueryResult.js +0 -46
  109. package/dist/QueryResult.js.map +0 -1
  110. package/dist/ToolCall.d.ts +0 -66
  111. package/dist/ToolCall.d.ts.map +0 -1
  112. package/dist/ToolCall.js +0 -59
  113. package/dist/ToolCall.js.map +0 -1
  114. package/dist/ToolResult.d.ts +0 -10
  115. package/dist/ToolResult.d.ts.map +0 -1
  116. package/dist/ToolResult.js +0 -39
  117. package/dist/ToolResult.js.map +0 -1
  118. package/dist/hooks/use-scroll-to-bottom.d.ts +0 -7
  119. package/dist/hooks/use-scroll-to-bottom.d.ts.map +0 -1
  120. package/dist/hooks/use-scroll-to-bottom.js +0 -51
  121. package/dist/hooks/use-scroll-to-bottom.js.map +0 -1
@@ -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,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"}
1
+ {"version":3,"file":"AiSlice.d.ts","sourceRoot":"","sources":["../src/AiSlice.ts"],"names":[],"mappings":"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"}
package/dist/AiSlice.js CHANGED
@@ -2,211 +2,301 @@ import { createId } from '@paralleldrive/cuid2';
2
2
  import { createSlice, useBaseProjectStore, } from '@sqlrooms/project-builder';
3
3
  import { produce } from 'immer';
4
4
  import { z } from 'zod';
5
- import { runAnalysis } from './analysis';
6
- import { AnalysisResultSchema, } from './schemas';
5
+ import { getDefaultTools, runAnalysis, TOOLS } from './analysis';
6
+ import { AnalysisSessionSchema, } from './schemas';
7
7
  export const AiSliceConfig = z.object({
8
8
  ai: z.object({
9
- modelProvider: z.string(),
10
- model: z.string(),
11
- analysisResults: z.array(AnalysisResultSchema),
9
+ sessions: z.array(AnalysisSessionSchema),
10
+ currentSessionId: z.string().optional(),
12
11
  }),
13
12
  });
14
- export function createDefaultAiConfig() {
13
+ export function createDefaultAiConfig(props) {
14
+ const defaultSessionId = createId();
15
15
  return {
16
16
  ai: {
17
- modelProvider: 'openai',
18
- model: 'gpt-4o-mini',
19
- analysisResults: [],
20
- },
21
- };
22
- }
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: [
17
+ sessions: [
68
18
  {
69
- toolName: 'error',
70
- toolCallId: createId(),
71
- args: {},
72
- result: {
73
- success: false,
74
- error: err instanceof Error ? err.message : String(err),
75
- },
19
+ id: defaultSessionId,
20
+ name: 'Default Session',
21
+ modelProvider: 'openai',
22
+ model: 'gpt-4o-mini',
23
+ analysisResults: [],
24
+ createdAt: new Date(),
76
25
  },
77
26
  ],
78
- toolCalls: [],
79
- }));
80
- }
27
+ currentSessionId: defaultSessionId,
28
+ ...props,
29
+ },
30
+ };
81
31
  }
82
- export function createAiSlice({ getApiKey, initialAnalysisPrompt = 'Describe the data in the tables and make a chart providing an overview of the most important features.', }) {
83
- return createSlice((set, get) => ({
84
- ai: {
85
- analysisPrompt: initialAnalysisPrompt,
86
- isRunningAnalysis: false,
87
- messagesById: new Map(),
88
- setAnalysisPrompt: (prompt) => {
89
- set((state) => produce(state, (draft) => {
90
- draft.ai.analysisPrompt = prompt;
91
- }));
92
- },
93
- /**
94
- * Set the AI model
95
- * @param model - The model to set
96
- */
97
- setAiModel: (model) => {
98
- set((state) => produce(state, (draft) => {
99
- draft.project.config.ai.model = model;
100
- }));
101
- },
102
- /**
103
- * Add messages to the project store uniquely by id
104
- * @param messages - The messages to add.
105
- */
106
- addMessages: (messages) => {
107
- set((state) => {
108
- const newMessages = messages.filter((m) => !state.ai.messagesById.has(m.id));
109
- const newMessagesById = new Map(state.ai.messagesById);
110
- for (const m of newMessages) {
111
- if (!m.id) {
112
- console.warn('Message has no id', m);
32
+ export function createAiSlice({ getApiKey, initialAnalysisPrompt = '', customTools = {}, getInstructions, }) {
33
+ return createSlice((set, get) => {
34
+ return {
35
+ ai: {
36
+ analysisPrompt: initialAnalysisPrompt,
37
+ isRunningAnalysis: false,
38
+ tools: {
39
+ ...getDefaultTools(),
40
+ ...customTools,
41
+ },
42
+ setAnalysisPrompt: (prompt) => {
43
+ set((state) => produce(state, (draft) => {
44
+ draft.ai.analysisPrompt = prompt;
45
+ }));
46
+ },
47
+ /**
48
+ * Set the AI model for the current session
49
+ * @param model - The model to set
50
+ */
51
+ setAiModel: (modelProvider, model) => {
52
+ set((state) => produce(state, (draft) => {
53
+ const currentSession = getCurrentSessionFromState(draft);
54
+ if (currentSession) {
55
+ currentSession.modelProvider = modelProvider;
56
+ currentSession.model = model;
113
57
  }
114
- newMessagesById.set(m.id, m);
58
+ }));
59
+ },
60
+ /**
61
+ * Get the current active session
62
+ */
63
+ getCurrentSession: () => {
64
+ const state = get();
65
+ const { currentSessionId, sessions } = state.config.ai;
66
+ return sessions.find((session) => session.id === currentSessionId);
67
+ },
68
+ /**
69
+ * Create a new session with the given name and model settings
70
+ */
71
+ createSession: (name, modelProvider, model) => {
72
+ const currentSession = get().ai.getCurrentSession();
73
+ const newSessionId = createId();
74
+ // Generate a default name if none is provided
75
+ let sessionName = name;
76
+ if (!sessionName) {
77
+ // Generate a human-readable date and time for the session name
78
+ const now = new Date();
79
+ const formattedDate = now.toLocaleDateString('en-US', {
80
+ month: 'short',
81
+ day: 'numeric',
82
+ year: 'numeric',
83
+ });
84
+ const formattedTime = now.toLocaleTimeString('en-US', {
85
+ hour: 'numeric',
86
+ minute: 'numeric',
87
+ hour12: true,
88
+ });
89
+ sessionName = `Session ${formattedDate} at ${formattedTime}`;
115
90
  }
116
- return {
117
- ai: {
118
- ...state.ai,
119
- messagesById: newMessagesById,
120
- },
121
- };
122
- });
123
- },
124
- getMessages: () => {
125
- return Array.from(get().ai.messagesById.values());
126
- },
127
- startAnalysis: async () => {
128
- const resultId = createId();
129
- const abortController = new AbortController();
130
- set((state) => produce(state, (draft) => {
131
- draft.ai.analysisAbortController = abortController;
132
- draft.ai.isRunningAnalysis = true;
133
- draft.project.config.ai.analysisResults.push({
134
- id: resultId,
135
- prompt: get().ai.analysisPrompt,
136
- toolResults: [],
137
- toolCalls: [],
138
- toolCallMessages: [],
139
- analysis: '',
140
- isCompleted: false,
141
- });
142
- }));
143
- get().ai.addMessages([
144
- {
145
- id: createId(),
146
- role: 'user',
147
- content: get().ai.analysisPrompt,
148
- },
149
- ]);
150
- try {
151
- await executeAnalysis({
152
- resultId,
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
- });
161
- }
162
- finally {
91
+ set((state) => produce(state, (draft) => {
92
+ draft.config.ai.sessions.unshift({
93
+ id: newSessionId,
94
+ name: sessionName,
95
+ modelProvider: modelProvider || currentSession?.modelProvider || 'openai',
96
+ model: model || currentSession?.model || 'gpt-4o-mini',
97
+ analysisResults: [],
98
+ createdAt: new Date(),
99
+ });
100
+ draft.config.ai.currentSessionId = newSessionId;
101
+ }));
102
+ },
103
+ /**
104
+ * Switch to a different session
105
+ */
106
+ switchSession: (sessionId) => {
107
+ set((state) => produce(state, (draft) => {
108
+ draft.config.ai.currentSessionId = sessionId;
109
+ }));
110
+ },
111
+ /**
112
+ * Rename an existing session
113
+ */
114
+ renameSession: (sessionId, name) => {
115
+ set((state) => produce(state, (draft) => {
116
+ const session = draft.config.ai.sessions.find((s) => s.id === sessionId);
117
+ if (session) {
118
+ session.name = name;
119
+ }
120
+ }));
121
+ },
122
+ /**
123
+ * Delete a session
124
+ */
125
+ deleteSession: (sessionId) => {
126
+ set((state) => produce(state, (draft) => {
127
+ const sessionIndex = draft.config.ai.sessions.findIndex((s) => s.id === sessionId);
128
+ if (sessionIndex !== -1) {
129
+ // Don't delete the last session
130
+ if (draft.config.ai.sessions.length > 1) {
131
+ draft.config.ai.sessions.splice(sessionIndex, 1);
132
+ // If we deleted the current session, switch to another one
133
+ if (draft.config.ai.currentSessionId === sessionId) {
134
+ // Make sure there's at least one session before accessing its id
135
+ if (draft.config.ai.sessions.length > 0) {
136
+ const firstSession = draft.config.ai.sessions[0];
137
+ if (firstSession) {
138
+ draft.config.ai.currentSessionId = firstSession.id;
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }));
145
+ },
146
+ /**
147
+ * Start the analysis
148
+ * TODO: how to pass the history analysisResults?
149
+ */
150
+ startAnalysis: async () => {
151
+ const resultId = createId();
152
+ const abortController = new AbortController();
153
+ const currentSession = get().ai.getCurrentSession();
154
+ if (!currentSession) {
155
+ console.error('No current session found');
156
+ return;
157
+ }
158
+ set((state) => produce(state, (draft) => {
159
+ draft.ai.analysisAbortController = abortController;
160
+ draft.ai.isRunningAnalysis = true;
161
+ const session = draft.config.ai.sessions.find((s) => s.id === draft.config.ai.currentSessionId);
162
+ if (session) {
163
+ session.analysisResults.push({
164
+ id: resultId,
165
+ prompt: get().ai.analysisPrompt,
166
+ streamMessage: {
167
+ toolCallMessages: [],
168
+ reasoning: '',
169
+ text: '',
170
+ },
171
+ isCompleted: false,
172
+ });
173
+ }
174
+ }));
175
+ try {
176
+ await runAnalysis({
177
+ modelProvider: currentSession.modelProvider || 'openai',
178
+ model: currentSession.model || 'gpt-4o-mini',
179
+ apiKey: getApiKey(currentSession.modelProvider || 'openai'),
180
+ prompt: get().ai.analysisPrompt,
181
+ abortController,
182
+ tools: get().ai.tools,
183
+ getInstructions,
184
+ onStreamResult: (isCompleted, streamMessage) => {
185
+ set(makeResultsAppender({
186
+ resultId,
187
+ streamMessage,
188
+ isCompleted,
189
+ }));
190
+ },
191
+ });
192
+ }
193
+ catch (err) {
194
+ set(makeResultsAppender({
195
+ resultId,
196
+ isCompleted: true,
197
+ errorMessage: {
198
+ error: err instanceof Error ? err.message : String(err),
199
+ },
200
+ }));
201
+ }
202
+ finally {
203
+ set((state) => produce(state, (draft) => {
204
+ draft.ai.isRunningAnalysis = false;
205
+ draft.ai.analysisPrompt = '';
206
+ }));
207
+ }
208
+ },
209
+ cancelAnalysis: () => {
163
210
  set((state) => produce(state, (draft) => {
164
211
  draft.ai.isRunningAnalysis = false;
165
- draft.ai.analysisPrompt = '';
166
212
  }));
167
- }
168
- },
169
- cancelAnalysis: () => {
170
- set((state) => produce(state, (draft) => {
171
- draft.ai.isRunningAnalysis = false;
172
- }));
173
- get().ai.analysisAbortController?.abort('Analysis cancelled');
213
+ get().ai.analysisAbortController?.abort('Analysis cancelled');
214
+ },
215
+ /**
216
+ * Delete an analysis result from a session
217
+ */
218
+ deleteAnalysisResult: (sessionId, resultId) => {
219
+ set((state) => produce(state, (draft) => {
220
+ const session = draft.config.ai.sessions.find((s) => s.id === sessionId);
221
+ if (session) {
222
+ session.analysisResults = session.analysisResults.filter((r) => r.id !== resultId);
223
+ }
224
+ }));
225
+ },
226
+ findToolComponent: (toolName) => {
227
+ return [
228
+ ...Object.entries(customTools),
229
+ ...Object.entries(TOOLS),
230
+ ].find(([name]) => name === toolName)?.[1]
231
+ ?.component;
232
+ },
174
233
  },
175
- },
176
- }));
234
+ };
235
+ });
236
+ }
237
+ /**
238
+ * Helper function to get the current session from state
239
+ */
240
+ function getCurrentSessionFromState(state) {
241
+ const { currentSessionId, sessions } = state.config.ai;
242
+ return sessions.find((session) => session.id === currentSessionId);
177
243
  }
178
244
  function findResultById(analysisResults, id) {
179
245
  return analysisResults.find((r) => r.id === id);
180
246
  }
181
247
  /**
182
- * Returns a function that will update the state by appending new results to the analysis results.
248
+ * Appends the tool results, tool calls, and analysis to the state
183
249
  *
184
- * @param resultId - The result id
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
250
+ * @param resultId - The id of the result to append to
251
+ * @param message - The message to append to the state. The structure of the message is defined as:
252
+ * - reasoning: string The reasoning of the assistant
253
+ * - toolCallMessages: ToolCallMessage[] The tool call messages
254
+ * - text: string The final text message
189
255
  * @param isCompleted - Whether the analysis is completed
190
256
  * @returns The new state
191
257
  */
192
- function makeResultsAppender({ resultId, toolResults, toolCalls, analysis, isCompleted, toolCallMessages, }) {
258
+ function makeResultsAppender({ resultId, streamMessage, errorMessage, isCompleted, }) {
193
259
  return (state) => produce(state, (draft) => {
194
- const result = findResultById(draft.project.config.ai.analysisResults, resultId);
260
+ const currentSession = getCurrentSessionFromState(draft);
261
+ if (!currentSession) {
262
+ console.error('No current session found');
263
+ return;
264
+ }
265
+ const result = findResultById(currentSession.analysisResults, resultId);
195
266
  if (result) {
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
- ];
267
+ if (streamMessage) {
268
+ result.streamMessage = {
269
+ toolCallMessages: (streamMessage.toolCallMessages || []).map((toolCall) => ({
270
+ args: { ...toolCall.args },
271
+ isCompleted: toolCall.isCompleted,
272
+ llmResult: toolCall.llmResult,
273
+ additionalData: toolCall.additionalData,
274
+ text: toolCall.text,
275
+ toolCallId: toolCall.toolCallId,
276
+ toolName: toolCall.toolName,
277
+ })),
278
+ reasoning: streamMessage.reasoning,
279
+ text: streamMessage.text,
280
+ analysis: streamMessage.analysis,
281
+ parts: streamMessage.parts?.map((part) => ({
282
+ ...part,
283
+ ...(part.type === 'text' && { text: part.text }),
284
+ ...(part.type === 'tool' && {
285
+ toolCallMessages: part.toolCallMessages?.map((toolCall) => ({
286
+ args: { ...toolCall.args },
287
+ isCompleted: toolCall.isCompleted,
288
+ llmResult: toolCall.llmResult,
289
+ additionalData: toolCall.additionalData,
290
+ text: toolCall.text,
291
+ toolCallId: toolCall.toolCallId,
292
+ toolName: toolCall.toolName,
293
+ })),
294
+ }),
295
+ })),
296
+ };
207
297
  }
208
- if (analysis) {
209
- result.analysis = analysis;
298
+ if (errorMessage) {
299
+ result.errorMessage = errorMessage;
210
300
  }
211
301
  if (isCompleted) {
212
302
  result.isCompleted = isCompleted;
@@ -1 +1 @@
1
- {"version":3,"file":"AiSlice.js","sourceRoot":"","sources":["../src/AiSlice.ts"],"names":[],"mappings":"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","sourcesContent":["import {createId} from '@paralleldrive/cuid2';\nimport {\n createSlice,\n ProjectState,\n useBaseProjectStore,\n type StateCreator,\n} from '@sqlrooms/project-builder';\nimport {BaseProjectConfig} from '@sqlrooms/project-config';\nimport {\n CoreAssistantMessage,\n CoreToolMessage,\n CoreUserMessage,\n StepResult,\n ToolSet,\n} from 'ai';\nimport {produce} from 'immer';\nimport {z} from 'zod';\nimport {runAnalysis} from './analysis';\nimport {\n AnalysisResultSchema,\n ToolCallSchema,\n ToolResultSchema,\n} from './schemas';\nimport {ToolCallMessage} from '@openassistant/core';\ntype AiMessage = (CoreToolMessage | CoreAssistantMessage | CoreUserMessage) & {\n id: string;\n};\n\nexport const AiSliceConfig = z.object({\n ai: z.object({\n modelProvider: z.string(),\n model: z.string(),\n analysisResults: z.array(AnalysisResultSchema),\n }),\n});\nexport type AiSliceConfig = z.infer<typeof AiSliceConfig>;\n\nexport function createDefaultAiConfig(): AiSliceConfig {\n return {\n ai: {\n modelProvider: 'openai',\n model: 'gpt-4o-mini',\n analysisResults: [],\n },\n };\n}\n\nexport type AiSliceState = {\n ai: {\n analysisPrompt: string;\n isRunningAnalysis: boolean;\n analysisAbortController?: AbortController;\n setAnalysisPrompt: (prompt: string) => void;\n startAnalysis: () => Promise<void>;\n cancelAnalysis: () => void;\n messagesById: Map<string, AiMessage>;\n addMessages: (messages: AiMessage[]) => void;\n getMessages: () => AiMessage[];\n setAiModel: (model: string) => void;\n };\n};\n\n/**\n * Execute the analysis. It will be used by the action `startAnalysis`.\n *\n * Each analysis contains an array of toolCalls and the results of the tool calls (toolResults).\n * After all the tool calls have been executed, the LLM will stream the results as text stored in `analysis`.\n *\n * @param resultId - The result id\n * @param prompt - The prompt\n * @param model - The model\n * @param apiKey - The api key\n * @param abortController - The abort controller\n * @param addMessages - The add messages function\n * @param set - The set function\n */\nasync function executeAnalysis({\n resultId,\n prompt,\n modelProvider,\n model,\n apiKey,\n abortController,\n addMessages,\n set,\n}: {\n resultId: string;\n prompt: string;\n modelProvider: string;\n model: string;\n apiKey: string;\n abortController: AbortController;\n addMessages: (messages: AiMessage[]) => void;\n set: <T>(fn: (state: T) => T) => void;\n}) {\n try {\n await runAnalysis({\n modelProvider,\n model,\n apiKey,\n prompt,\n abortController,\n onStepFinish: (\n event: StepResult<ToolSet>,\n toolCallMessages: ToolCallMessage[],\n ) => {\n addMessages(event.response.messages);\n set(\n makeResultsAppender({\n resultId,\n toolResults: event.toolResults,\n toolCalls: event.toolCalls,\n toolCallMessages,\n }),\n );\n },\n onStreamResult: (message, isCompleted) => {\n set(\n makeResultsAppender({\n resultId,\n analysis: message,\n isCompleted,\n }),\n );\n },\n });\n } catch (err) {\n set(\n makeResultsAppender({\n resultId,\n isCompleted: true,\n toolResults: [\n {\n toolName: 'error',\n toolCallId: createId(),\n args: {},\n result: {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n },\n },\n ],\n toolCalls: [],\n }),\n );\n }\n}\n\nexport function createAiSlice<PC extends BaseProjectConfig & AiSliceConfig>({\n getApiKey,\n initialAnalysisPrompt = 'Describe the data in the tables and make a chart providing an overview of the most important features.',\n}: {\n getApiKey: () => string;\n initialAnalysisPrompt?: string;\n}): StateCreator<AiSliceState> {\n return createSlice<PC, AiSliceState>((set, get) => ({\n ai: {\n analysisPrompt: initialAnalysisPrompt,\n isRunningAnalysis: false,\n messagesById: new Map(),\n\n setAnalysisPrompt: (prompt: string) => {\n set((state) =>\n produce(state, (draft) => {\n draft.ai.analysisPrompt = prompt;\n }),\n );\n },\n\n /**\n * Set the AI model\n * @param model - The model to set\n */\n setAiModel: (model: string) => {\n set((state) =>\n produce(state, (draft) => {\n draft.project.config.ai.model = model;\n }),\n );\n },\n\n /**\n * Add messages to the project store uniquely by id\n * @param messages - The messages to add.\n */\n addMessages: (messages: AiMessage[]) => {\n set((state) => {\n const newMessages = messages.filter(\n (m) => !state.ai.messagesById.has(m.id),\n );\n const newMessagesById = new Map(state.ai.messagesById);\n for (const m of newMessages) {\n if (!m.id) {\n console.warn('Message has no id', m);\n }\n newMessagesById.set(m.id, m);\n }\n return {\n ai: {\n ...state.ai,\n messagesById: newMessagesById,\n },\n };\n });\n },\n\n getMessages: () => {\n return Array.from(get().ai.messagesById.values());\n },\n\n startAnalysis: async () => {\n const resultId = createId();\n const abortController = new AbortController();\n set((state) =>\n produce(state, (draft) => {\n draft.ai.analysisAbortController = abortController;\n draft.ai.isRunningAnalysis = true;\n draft.project.config.ai.analysisResults.push({\n id: resultId,\n prompt: get().ai.analysisPrompt,\n toolResults: [],\n toolCalls: [],\n toolCallMessages: [],\n analysis: '',\n isCompleted: false,\n });\n }),\n );\n\n get().ai.addMessages([\n {\n id: createId(),\n role: 'user',\n content: get().ai.analysisPrompt,\n },\n ]);\n\n try {\n await executeAnalysis({\n resultId,\n prompt: get().ai.analysisPrompt,\n modelProvider: get().project.config.ai.modelProvider,\n model: get().project.config.ai.model,\n apiKey: getApiKey(),\n abortController,\n addMessages: get().ai.addMessages,\n set,\n });\n } finally {\n set((state) =>\n produce(state, (draft) => {\n draft.ai.isRunningAnalysis = false;\n draft.ai.analysisPrompt = '';\n }),\n );\n }\n },\n cancelAnalysis: () => {\n set((state) =>\n produce(state, (draft) => {\n draft.ai.isRunningAnalysis = false;\n }),\n );\n get().ai.analysisAbortController?.abort('Analysis cancelled');\n },\n },\n }));\n}\n\nfunction findResultById(analysisResults: AnalysisResultSchema[], id: string) {\n return analysisResults.find((r: AnalysisResultSchema) => r.id === id);\n}\n\n/**\n * Returns a function that will update the state by appending new results to the analysis results.\n *\n * @param resultId - The result id\n * @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.\n * @param toolResults - The results of the tool calls that were executed by the LLM. See {@link ToolResultSchema} for more details.\n * @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.\n * @param analysis - The analysis is the content generated after all the tool calls have been executed\n * @param isCompleted - Whether the analysis is completed\n * @returns The new state\n */\nfunction makeResultsAppender<PC extends BaseProjectConfig & AiSliceConfig>({\n resultId,\n toolResults,\n toolCalls,\n analysis,\n isCompleted,\n toolCallMessages,\n}: {\n resultId: string;\n toolResults?: ToolResultSchema[];\n toolCalls?: ToolCallSchema[];\n analysis?: string;\n isCompleted?: boolean;\n toolCallMessages?: ToolCallMessage[];\n}) {\n return (state: ProjectState<PC>) =>\n produce(state, (draft) => {\n const result = findResultById(\n draft.project.config.ai.analysisResults,\n resultId,\n );\n if (result) {\n if (toolResults) {\n result.toolResults = [...result.toolResults, ...toolResults];\n }\n if (toolCalls) {\n result.toolCalls = [...result.toolCalls, ...toolCalls];\n }\n if (toolCallMessages) {\n result.toolCallMessages = [\n ...result.toolCallMessages,\n ...toolCallMessages,\n ];\n }\n if (analysis) {\n result.analysis = analysis;\n }\n if (isCompleted) {\n result.isCompleted = isCompleted;\n }\n } else {\n console.error('Result not found', resultId);\n }\n });\n}\n\ntype ProjectConfigWithAi = BaseProjectConfig & AiSliceConfig;\ntype ProjectStateWithAi = ProjectState<ProjectConfigWithAi> & AiSliceState;\n\nexport function useStoreWithAi<T>(\n selector: (state: ProjectStateWithAi) => T,\n): T {\n return useBaseProjectStore<\n BaseProjectConfig & AiSliceConfig,\n ProjectState<ProjectConfigWithAi>,\n T\n >((state) => selector(state as unknown as ProjectStateWithAi));\n}\n"]}
1
+ {"version":3,"file":"AiSlice.js","sourceRoot":"","sources":["../src/AiSlice.ts"],"names":[],"mappings":"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","sourcesContent":["import {ExtendedTool, StreamMessage} from '@openassistant/core';\nimport {createId} from '@paralleldrive/cuid2';\nimport {\n createSlice,\n ProjectState,\n useBaseProjectStore,\n type StateCreator,\n} from '@sqlrooms/project-builder';\nimport {BaseProjectConfig} from '@sqlrooms/project-config';\nimport {produce, WritableDraft} from 'immer';\nimport {z} from 'zod';\nimport {getDefaultTools, runAnalysis, TOOLS} from './analysis';\nimport {\n AnalysisResultSchema,\n AnalysisSessionSchema,\n ErrorMessageSchema,\n} from './schemas';\nimport {DataTable} from '@sqlrooms/duckdb';\n\nexport const AiSliceConfig = z.object({\n ai: z.object({\n sessions: z.array(AnalysisSessionSchema),\n currentSessionId: z.string().optional(),\n }),\n});\nexport type AiSliceConfig = z.infer<typeof AiSliceConfig>;\n\nexport function createDefaultAiConfig(\n props: Partial<AiSliceConfig['ai']>,\n): AiSliceConfig {\n const defaultSessionId = createId();\n return {\n ai: {\n sessions: [\n {\n id: defaultSessionId,\n name: 'Default Session',\n modelProvider: 'openai',\n model: 'gpt-4o-mini',\n analysisResults: [],\n createdAt: new Date(),\n },\n ],\n currentSessionId: defaultSessionId,\n ...props,\n },\n };\n}\n\nexport type AiSliceTool = ExtendedTool<any>;\n\nexport type AiSliceState = {\n ai: {\n analysisPrompt: string;\n isRunningAnalysis: boolean;\n tools: Record<string, AiSliceTool>;\n analysisAbortController?: AbortController;\n setAnalysisPrompt: (prompt: string) => void;\n startAnalysis: () => Promise<void>;\n cancelAnalysis: () => void;\n setAiModel: (modelProvider: string, model: string) => void;\n createSession: (\n name?: string,\n modelProvider?: string,\n model?: string,\n ) => void;\n switchSession: (sessionId: string) => void;\n renameSession: (sessionId: string, name: string) => void;\n deleteSession: (sessionId: string) => void;\n getCurrentSession: () => AnalysisSessionSchema | undefined;\n deleteAnalysisResult: (sessionId: string, resultId: string) => void;\n findToolComponent: (toolName: string) => React.ComponentType | undefined;\n };\n};\n\nexport function createAiSlice<PC extends BaseProjectConfig & AiSliceConfig>({\n getApiKey,\n initialAnalysisPrompt = '',\n customTools = {},\n getInstructions,\n}: {\n getApiKey: (modelProvider: string) => string;\n initialAnalysisPrompt?: string;\n customTools?: Record<string, AiSliceTool>;\n /**\n * Function to get custom instructions for the AI assistant\n * @param tablesSchema - The schema of the tables in the database\n * @returns The instructions string to use\n */\n getInstructions?: (tablesSchema: DataTable[]) => string;\n}): StateCreator<AiSliceState> {\n return createSlice<PC, AiSliceState>((set, get) => {\n return {\n ai: {\n analysisPrompt: initialAnalysisPrompt,\n isRunningAnalysis: false,\n\n tools: {\n ...getDefaultTools(),\n ...customTools,\n },\n\n setAnalysisPrompt: (prompt: string) => {\n set((state) =>\n produce(state, (draft) => {\n draft.ai.analysisPrompt = prompt;\n }),\n );\n },\n\n /**\n * Set the AI model for the current session\n * @param model - The model to set\n */\n setAiModel: (modelProvider: string, model: string) => {\n set((state) =>\n produce(state, (draft) => {\n const currentSession = getCurrentSessionFromState(draft);\n if (currentSession) {\n currentSession.modelProvider = modelProvider;\n currentSession.model = model;\n }\n }),\n );\n },\n\n /**\n * Get the current active session\n */\n getCurrentSession: () => {\n const state = get();\n const {currentSessionId, sessions} = state.config.ai;\n return sessions.find((session) => session.id === currentSessionId);\n },\n\n /**\n * Create a new session with the given name and model settings\n */\n createSession: (\n name?: string,\n modelProvider?: string,\n model?: string,\n ) => {\n const currentSession = get().ai.getCurrentSession();\n const newSessionId = createId();\n\n // Generate a default name if none is provided\n let sessionName = name;\n if (!sessionName) {\n // Generate a human-readable date and time for the session name\n const now = new Date();\n const formattedDate = now.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n });\n const formattedTime = now.toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: 'numeric',\n hour12: true,\n });\n sessionName = `Session ${formattedDate} at ${formattedTime}`;\n }\n\n set((state) =>\n produce(state, (draft) => {\n draft.config.ai.sessions.unshift({\n id: newSessionId,\n name: sessionName,\n modelProvider:\n modelProvider || currentSession?.modelProvider || 'openai',\n model: model || currentSession?.model || 'gpt-4o-mini',\n analysisResults: [],\n createdAt: new Date(),\n });\n draft.config.ai.currentSessionId = newSessionId;\n }),\n );\n },\n\n /**\n * Switch to a different session\n */\n switchSession: (sessionId: string) => {\n set((state) =>\n produce(state, (draft) => {\n draft.config.ai.currentSessionId = sessionId;\n }),\n );\n },\n\n /**\n * Rename an existing session\n */\n renameSession: (sessionId: string, name: string) => {\n set((state) =>\n produce(state, (draft) => {\n const session = draft.config.ai.sessions.find(\n (s) => s.id === sessionId,\n );\n if (session) {\n session.name = name;\n }\n }),\n );\n },\n\n /**\n * Delete a session\n */\n deleteSession: (sessionId: string) => {\n set((state) =>\n produce(state, (draft) => {\n const sessionIndex = draft.config.ai.sessions.findIndex(\n (s) => s.id === sessionId,\n );\n if (sessionIndex !== -1) {\n // Don't delete the last session\n if (draft.config.ai.sessions.length > 1) {\n draft.config.ai.sessions.splice(sessionIndex, 1);\n // If we deleted the current session, switch to another one\n if (draft.config.ai.currentSessionId === sessionId) {\n // Make sure there's at least one session before accessing its id\n if (draft.config.ai.sessions.length > 0) {\n const firstSession = draft.config.ai.sessions[0];\n if (firstSession) {\n draft.config.ai.currentSessionId = firstSession.id;\n }\n }\n }\n }\n }\n }),\n );\n },\n\n /**\n * Start the analysis\n * TODO: how to pass the history analysisResults?\n */\n startAnalysis: async () => {\n const resultId = createId();\n const abortController = new AbortController();\n const currentSession = get().ai.getCurrentSession();\n\n if (!currentSession) {\n console.error('No current session found');\n return;\n }\n\n set((state) =>\n produce(state, (draft) => {\n draft.ai.analysisAbortController = abortController;\n draft.ai.isRunningAnalysis = true;\n\n const session = draft.config.ai.sessions.find(\n (s) => s.id === draft.config.ai.currentSessionId,\n );\n\n if (session) {\n session.analysisResults.push({\n id: resultId,\n prompt: get().ai.analysisPrompt,\n streamMessage: {\n toolCallMessages: [],\n reasoning: '',\n text: '',\n },\n isCompleted: false,\n });\n }\n }),\n );\n\n try {\n await runAnalysis({\n modelProvider: currentSession.modelProvider || 'openai',\n model: currentSession.model || 'gpt-4o-mini',\n apiKey: getApiKey(currentSession.modelProvider || 'openai'),\n prompt: get().ai.analysisPrompt,\n abortController,\n tools: get().ai.tools,\n getInstructions,\n onStreamResult: (isCompleted, streamMessage) => {\n set(\n makeResultsAppender({\n resultId,\n streamMessage,\n isCompleted,\n }),\n );\n },\n });\n } catch (err) {\n set(\n makeResultsAppender({\n resultId,\n isCompleted: true,\n errorMessage: {\n error: err instanceof Error ? err.message : String(err),\n },\n }),\n );\n } finally {\n set((state) =>\n produce(state, (draft) => {\n draft.ai.isRunningAnalysis = false;\n draft.ai.analysisPrompt = '';\n }),\n );\n }\n },\n\n cancelAnalysis: () => {\n set((state) =>\n produce(state, (draft) => {\n draft.ai.isRunningAnalysis = false;\n }),\n );\n get().ai.analysisAbortController?.abort('Analysis cancelled');\n },\n\n /**\n * Delete an analysis result from a session\n */\n deleteAnalysisResult: (sessionId: string, resultId: string) => {\n set((state) =>\n produce(state, (draft) => {\n const session = draft.config.ai.sessions.find(\n (s) => s.id === sessionId,\n );\n if (session) {\n session.analysisResults = session.analysisResults.filter(\n (r) => r.id !== resultId,\n );\n }\n }),\n );\n },\n\n findToolComponent: (toolName: string) => {\n return [\n ...Object.entries(customTools),\n ...Object.entries(TOOLS),\n ].find(([name]) => name === toolName)?.[1]\n ?.component as React.ComponentType;\n },\n },\n };\n });\n}\n\n/**\n * Helper function to get the current session from state\n */\nfunction getCurrentSessionFromState<\n PC extends BaseProjectConfig & AiSliceConfig,\n>(\n state: ProjectState<PC> | WritableDraft<ProjectState<PC>>,\n): AnalysisSessionSchema | undefined {\n const {currentSessionId, sessions} = state.config.ai;\n return sessions.find(\n (session: AnalysisSessionSchema) => session.id === currentSessionId,\n );\n}\n\nfunction findResultById(analysisResults: AnalysisResultSchema[], id: string) {\n return analysisResults.find((r: AnalysisResultSchema) => r.id === id);\n}\n\n/**\n * Appends the tool results, tool calls, and analysis to the state\n *\n * @param resultId - The id of the result to append to\n * @param message - The message to append to the state. The structure of the message is defined as:\n * - reasoning: string The reasoning of the assistant\n * - toolCallMessages: ToolCallMessage[] The tool call messages\n * - text: string The final text message\n * @param isCompleted - Whether the analysis is completed\n * @returns The new state\n */\nfunction makeResultsAppender<PC extends BaseProjectConfig & AiSliceConfig>({\n resultId,\n streamMessage,\n errorMessage,\n isCompleted,\n}: {\n resultId: string;\n streamMessage?: StreamMessage;\n errorMessage?: ErrorMessageSchema;\n isCompleted?: boolean;\n}) {\n return (state: ProjectState<PC>) =>\n produce(state, (draft) => {\n const currentSession = getCurrentSessionFromState(draft);\n if (!currentSession) {\n console.error('No current session found');\n return;\n }\n\n const result = findResultById(currentSession.analysisResults, resultId);\n if (result) {\n if (streamMessage) {\n result.streamMessage = {\n toolCallMessages: (streamMessage.toolCallMessages || []).map(\n (toolCall) => ({\n args: {...toolCall.args},\n isCompleted: toolCall.isCompleted,\n llmResult: toolCall.llmResult,\n additionalData: toolCall.additionalData,\n text: toolCall.text,\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n }),\n ),\n reasoning: streamMessage.reasoning,\n text: streamMessage.text,\n analysis: streamMessage.analysis,\n parts: streamMessage.parts?.map((part) => ({\n ...part,\n ...(part.type === 'text' && {text: part.text}),\n ...(part.type === 'tool' && {\n toolCallMessages: part.toolCallMessages?.map((toolCall) => ({\n args: {...toolCall.args},\n isCompleted: toolCall.isCompleted,\n llmResult: toolCall.llmResult,\n additionalData: toolCall.additionalData,\n text: toolCall.text,\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n })),\n }),\n })),\n };\n }\n if (errorMessage) {\n result.errorMessage = errorMessage;\n }\n if (isCompleted) {\n result.isCompleted = isCompleted;\n }\n } else {\n console.error('Result not found', resultId);\n }\n });\n}\n\ntype ProjectConfigWithAi = BaseProjectConfig & AiSliceConfig;\ntype ProjectStateWithAi = ProjectState<ProjectConfigWithAi> & AiSliceState;\n\nexport function useStoreWithAi<T>(\n selector: (state: ProjectStateWithAi) => T,\n): T {\n return useBaseProjectStore<\n BaseProjectConfig & AiSliceConfig,\n ProjectState<ProjectConfigWithAi>,\n T\n >((state) => selector(state as unknown as ProjectStateWithAi));\n}\n"]}