@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.
- package/README.md +377 -25
- package/dist/AiSlice.d.ts +489 -307
- package/dist/AiSlice.d.ts.map +1 -1
- package/dist/AiSlice.js +267 -177
- package/dist/AiSlice.js.map +1 -1
- package/dist/analysis.d.ts +25 -19
- package/dist/analysis.d.ts.map +1 -1
- package/dist/analysis.js +86 -145
- package/dist/analysis.js.map +1 -1
- package/dist/components/AnalysisAnswer.d.ts +14 -0
- package/dist/components/AnalysisAnswer.d.ts.map +1 -0
- package/dist/components/AnalysisAnswer.js +14 -0
- package/dist/components/AnalysisAnswer.js.map +1 -0
- package/dist/{AnalysisResult.d.ts → components/AnalysisResult.d.ts} +2 -1
- package/dist/components/AnalysisResult.d.ts.map +1 -0
- package/dist/components/AnalysisResult.js +46 -0
- package/dist/components/AnalysisResult.js.map +1 -0
- package/dist/components/AnalysisResultsContainer.d.ts +5 -0
- package/dist/components/AnalysisResultsContainer.d.ts.map +1 -0
- package/dist/components/AnalysisResultsContainer.js +27 -0
- package/dist/components/AnalysisResultsContainer.js.map +1 -0
- package/dist/components/ErrorMessage.d.ts +4 -0
- package/dist/components/ErrorMessage.d.ts.map +1 -0
- package/dist/components/ErrorMessage.js +7 -0
- package/dist/components/ErrorMessage.js.map +1 -0
- package/dist/components/MessageContainer.d.ts +10 -0
- package/dist/components/MessageContainer.d.ts.map +1 -0
- package/dist/components/MessageContainer.js +17 -0
- package/dist/components/MessageContainer.js.map +1 -0
- package/dist/components/ModelSelector.d.ts +13 -0
- package/dist/components/ModelSelector.d.ts.map +1 -0
- package/dist/components/ModelSelector.js +29 -0
- package/dist/components/ModelSelector.js.map +1 -0
- package/dist/components/QueryControls.d.ts +8 -0
- package/dist/components/QueryControls.d.ts.map +1 -0
- package/dist/components/QueryControls.js +45 -0
- package/dist/components/QueryControls.js.map +1 -0
- package/dist/components/SessionControls.d.ts +17 -0
- package/dist/components/SessionControls.d.ts.map +1 -0
- package/dist/components/SessionControls.js +20 -0
- package/dist/components/SessionControls.js.map +1 -0
- package/dist/components/session/DeleteSessionButton.d.ts +19 -0
- package/dist/components/session/DeleteSessionButton.d.ts.map +1 -0
- package/dist/components/session/DeleteSessionButton.js +54 -0
- package/dist/components/session/DeleteSessionButton.js.map +1 -0
- package/dist/components/session/DeleteSessionDialog.d.ts +27 -0
- package/dist/components/session/DeleteSessionDialog.d.ts.map +1 -0
- package/dist/components/session/DeleteSessionDialog.js +19 -0
- package/dist/components/session/DeleteSessionDialog.js.map +1 -0
- package/dist/components/session/SessionActions.d.ts +18 -0
- package/dist/components/session/SessionActions.d.ts.map +1 -0
- package/dist/components/session/SessionActions.js +19 -0
- package/dist/components/session/SessionActions.js.map +1 -0
- package/dist/components/session/SessionDropdown.d.ts +18 -0
- package/dist/components/session/SessionDropdown.d.ts.map +1 -0
- package/dist/components/session/SessionDropdown.js +21 -0
- package/dist/components/session/SessionDropdown.js.map +1 -0
- package/dist/components/session/SessionTitle.d.ts +18 -0
- package/dist/components/session/SessionTitle.d.ts.map +1 -0
- package/dist/components/session/SessionTitle.js +22 -0
- package/dist/components/session/SessionTitle.js.map +1 -0
- package/dist/components/session/SessionType.d.ts +24 -0
- package/dist/components/session/SessionType.d.ts.map +1 -0
- package/dist/components/session/SessionType.js +2 -0
- package/dist/components/session/SessionType.js.map +1 -0
- package/dist/components/session/index.d.ts +7 -0
- package/dist/components/session/index.d.ts.map +1 -0
- package/dist/components/session/index.js +7 -0
- package/dist/components/session/index.js.map +1 -0
- package/dist/components/tools/QueryToolResult.d.ts +7 -0
- package/dist/components/tools/QueryToolResult.d.ts.map +1 -0
- package/dist/components/tools/QueryToolResult.js +9 -0
- package/dist/components/tools/QueryToolResult.js.map +1 -0
- package/dist/components/tools/ToolResult.d.ts +9 -0
- package/dist/components/tools/ToolResult.d.ts.map +1 -0
- package/dist/components/tools/ToolResult.js +32 -0
- package/dist/components/tools/ToolResult.js.map +1 -0
- package/dist/components/tools/ToolResultErrorBoundary.d.ts +19 -0
- package/dist/components/tools/ToolResultErrorBoundary.d.ts.map +1 -0
- package/dist/components/tools/ToolResultErrorBoundary.js +23 -0
- package/dist/components/tools/ToolResultErrorBoundary.js.map +1 -0
- package/dist/hooks/useScrollToBottom.d.ts +82 -0
- package/dist/hooks/useScrollToBottom.d.ts.map +1 -0
- package/dist/hooks/useScrollToBottom.js +140 -0
- package/dist/hooks/useScrollToBottom.js.map +1 -0
- package/dist/index.d.ts +16 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -5
- package/dist/index.js.map +1 -1
- package/dist/schemas.d.ts +592 -201
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +36 -11
- package/dist/schemas.js.map +1 -1
- package/package.json +11 -10
- package/dist/AnalysisResult.d.ts.map +0 -1
- package/dist/AnalysisResult.js +0 -56
- package/dist/AnalysisResult.js.map +0 -1
- package/dist/AnalysisResultsContainer.d.ts +0 -2
- package/dist/AnalysisResultsContainer.d.ts.map +0 -1
- package/dist/AnalysisResultsContainer.js +0 -15
- package/dist/AnalysisResultsContainer.js.map +0 -1
- package/dist/QueryControls.d.ts +0 -6
- package/dist/QueryControls.d.ts.map +0 -1
- package/dist/QueryControls.js +0 -28
- package/dist/QueryControls.js.map +0 -1
- package/dist/QueryResult.d.ts +0 -9
- package/dist/QueryResult.d.ts.map +0 -1
- package/dist/QueryResult.js +0 -46
- package/dist/QueryResult.js.map +0 -1
- package/dist/ToolCall.d.ts +0 -66
- package/dist/ToolCall.d.ts.map +0 -1
- package/dist/ToolCall.js +0 -59
- package/dist/ToolCall.js.map +0 -1
- package/dist/ToolResult.d.ts +0 -10
- package/dist/ToolResult.d.ts.map +0 -1
- package/dist/ToolResult.js +0 -39
- package/dist/ToolResult.js.map +0 -1
- package/dist/hooks/use-scroll-to-bottom.d.ts +0 -7
- package/dist/hooks/use-scroll-to-bottom.d.ts.map +0 -1
- package/dist/hooks/use-scroll-to-bottom.js +0 -51
- package/dist/hooks/use-scroll-to-bottom.js.map +0 -1
package/dist/AiSlice.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiSlice.d.ts","sourceRoot":"","sources":["../src/AiSlice.ts"],"names":[],"mappings":"
|
|
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 {
|
|
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
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
27
|
+
currentSessionId: defaultSessionId,
|
|
28
|
+
...props,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
81
31
|
}
|
|
82
|
-
export function createAiSlice({ getApiKey, initialAnalysisPrompt = '
|
|
83
|
-
return createSlice((set, get) =>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
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
|
-
|
|
117
|
-
ai
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
draft
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
*
|
|
248
|
+
* Appends the tool results, tool calls, and analysis to the state
|
|
183
249
|
*
|
|
184
|
-
* @param resultId - The result
|
|
185
|
-
* @param
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
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,
|
|
258
|
+
function makeResultsAppender({ resultId, streamMessage, errorMessage, isCompleted, }) {
|
|
193
259
|
return (state) => produce(state, (draft) => {
|
|
194
|
-
const
|
|
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 (
|
|
197
|
-
result.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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 (
|
|
209
|
-
result.
|
|
298
|
+
if (errorMessage) {
|
|
299
|
+
result.errorMessage = errorMessage;
|
|
210
300
|
}
|
|
211
301
|
if (isCompleted) {
|
|
212
302
|
result.isCompleted = isCompleted;
|
package/dist/AiSlice.js.map
CHANGED
|
@@ -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"]}
|