@sqlrooms/ai-core 0.27.0-rc.0 → 0.27.0-rc.2
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 +2 -2
- package/dist/AiSlice.d.ts +33 -46
- package/dist/AiSlice.d.ts.map +1 -1
- package/dist/AiSlice.js +183 -91
- package/dist/AiSlice.js.map +1 -1
- package/dist/agents/AgentUtils.d.ts +19 -11
- package/dist/agents/AgentUtils.d.ts.map +1 -1
- package/dist/agents/AgentUtils.js +95 -57
- package/dist/agents/AgentUtils.js.map +1 -1
- package/dist/chatTransport.d.ts +13 -18
- package/dist/chatTransport.d.ts.map +1 -1
- package/dist/chatTransport.js +139 -203
- package/dist/chatTransport.js.map +1 -1
- package/dist/components/AnalysisResult.d.ts +1 -1
- package/dist/components/AnalysisResult.d.ts.map +1 -1
- package/dist/components/AnalysisResult.js +8 -27
- package/dist/components/AnalysisResult.js.map +1 -1
- package/dist/components/AnalysisResultsContainer.d.ts +1 -1
- package/dist/components/AnalysisResultsContainer.d.ts.map +1 -1
- package/dist/components/AnalysisResultsContainer.js +7 -5
- package/dist/components/AnalysisResultsContainer.js.map +1 -1
- package/dist/components/Chat.d.ts +13 -0
- package/dist/components/Chat.d.ts.map +1 -0
- package/dist/components/Chat.js +17 -0
- package/dist/components/Chat.js.map +1 -0
- package/dist/components/GroupedMessageParts.d.ts +2 -0
- package/dist/components/GroupedMessageParts.d.ts.map +1 -1
- package/dist/components/GroupedMessageParts.js +9 -3
- package/dist/components/GroupedMessageParts.js.map +1 -1
- package/dist/components/MessagePartsList.d.ts +2 -0
- package/dist/components/MessagePartsList.d.ts.map +1 -1
- package/dist/components/MessagePartsList.js +4 -4
- package/dist/components/MessagePartsList.js.map +1 -1
- package/dist/components/PromptSuggestions.d.ts.map +1 -1
- package/dist/components/PromptSuggestions.js +8 -5
- package/dist/components/PromptSuggestions.js.map +1 -1
- package/dist/components/QueryControls.d.ts.map +1 -1
- package/dist/components/QueryControls.js +26 -19
- package/dist/components/QueryControls.js.map +1 -1
- package/dist/components/SessionChatManager.d.ts +9 -0
- package/dist/components/SessionChatManager.d.ts.map +1 -0
- package/dist/components/SessionChatManager.js +27 -0
- package/dist/components/SessionChatManager.js.map +1 -0
- package/dist/components/SessionChatProvider.d.ts +13 -0
- package/dist/components/SessionChatProvider.d.ts.map +1 -0
- package/dist/components/SessionChatProvider.js +32 -0
- package/dist/components/SessionChatProvider.js.map +1 -0
- package/dist/components/SessionControls.d.ts +0 -1
- package/dist/components/SessionControls.d.ts.map +1 -1
- package/dist/components/SessionControls.js +4 -2
- package/dist/components/SessionControls.js.map +1 -1
- package/dist/components/ToolPartRenderer.d.ts +3 -1
- package/dist/components/ToolPartRenderer.d.ts.map +1 -1
- package/dist/components/ToolPartRenderer.js +2 -3
- package/dist/components/ToolPartRenderer.js.map +1 -1
- package/dist/components/tools/ToolErrorMessage.d.ts +1 -30
- package/dist/components/tools/ToolErrorMessage.d.ts.map +1 -1
- package/dist/components/tools/ToolErrorMessage.js +18 -14
- package/dist/components/tools/ToolErrorMessage.js.map +1 -1
- package/dist/components/tools/ToolResult.d.ts.map +1 -1
- package/dist/components/tools/ToolResult.js +5 -1
- package/dist/components/tools/ToolResult.js.map +1 -1
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +8 -0
- package/dist/constants.js.map +1 -1
- package/dist/hooks/useScrollToBottom.d.ts +1 -1
- package/dist/hooks/useScrollToBottom.js +1 -1
- package/dist/hooks/useScrollToBottom.js.map +1 -1
- package/dist/hooks/useSessionChat.d.ts +38 -0
- package/dist/hooks/useSessionChat.d.ts.map +1 -0
- package/dist/hooks/{useAiChat.js → useSessionChat.js} +50 -46
- package/dist/hooks/useSessionChat.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +21 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +28 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +113 -1
- package/dist/utils.js.map +1 -1
- package/package.json +7 -7
- package/dist/components/DeleteConfirmationDialog.d.ts +0 -14
- package/dist/components/DeleteConfirmationDialog.d.ts.map +0 -1
- package/dist/components/DeleteConfirmationDialog.js +0 -6
- package/dist/components/DeleteConfirmationDialog.js.map +0 -1
- package/dist/hooks/useAiChat.d.ts +0 -39
- package/dist/hooks/useAiChat.d.ts.map +0 -1
- package/dist/hooks/useAiChat.js.map +0 -1
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ const {roomStore, useRoomStore} = createRoomStore({
|
|
|
43
43
|
getInstructions: () => {
|
|
44
44
|
return `You are an AI assistant that can answer questions and help with tasks.`;
|
|
45
45
|
},
|
|
46
|
-
|
|
46
|
+
initialPrompt: 'What insights can you provide from my data?',
|
|
47
47
|
tools: {
|
|
48
48
|
// Your tools
|
|
49
49
|
},
|
|
@@ -464,7 +464,7 @@ createAiSlice({
|
|
|
464
464
|
The `processAgentStream` function handles the complexity of integrating agent execution into the main conversation:
|
|
465
465
|
|
|
466
466
|
```typescript
|
|
467
|
-
await processAgentStream(agentResult, store, parentToolCallId)
|
|
467
|
+
await processAgentStream(agentResult, store, parentToolCallId, abortSignal)
|
|
468
468
|
```
|
|
469
469
|
|
|
470
470
|
**What it handles:**
|
package/dist/AiSlice.d.ts
CHANGED
|
@@ -1,42 +1,33 @@
|
|
|
1
1
|
import { AiSliceConfig, AnalysisResultSchema, AnalysisSessionSchema } from '@sqlrooms/ai-config';
|
|
2
2
|
import { type StateCreator } from '@sqlrooms/room-store';
|
|
3
|
-
import { UIMessage, DefaultChatTransport, LanguageModel,
|
|
3
|
+
import { UIMessage, DefaultChatTransport, LanguageModel, ChatOnDataCallback } from 'ai';
|
|
4
4
|
import { ToolCall } from './chatTransport';
|
|
5
5
|
import { OpenAssistantToolSet } from '@openassistant/utils';
|
|
6
|
-
import { AddToolResult } from './types';
|
|
7
|
-
type ExtendedChatOnToolCallCallback = (args: {
|
|
8
|
-
toolCall: ToolCall;
|
|
9
|
-
addToolResult?: AddToolResult;
|
|
10
|
-
}) => Promise<void> | void;
|
|
6
|
+
import type { AddToolResult, AiChatSendMessage, GetProviderOptions } from './types';
|
|
11
7
|
export type AiSliceState = {
|
|
12
8
|
ai: {
|
|
13
9
|
config: AiSliceConfig;
|
|
14
|
-
analysisPrompt: string;
|
|
15
|
-
isRunningAnalysis: boolean;
|
|
16
10
|
promptSuggestionsVisible: boolean;
|
|
17
11
|
tools: OpenAssistantToolSet;
|
|
18
|
-
|
|
12
|
+
getProviderOptions?: GetProviderOptions;
|
|
19
13
|
setConfig: (config: AiSliceConfig) => void;
|
|
20
14
|
setPromptSuggestionsVisible: (visible: boolean) => void;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
/** Wait for a tool result to be added by UI component */
|
|
38
|
-
waitForToolResult: (toolCallId: string, abortSignal?: AbortSignal) => Promise<void>;
|
|
39
|
-
setAnalysisPrompt: (prompt: string) => void;
|
|
15
|
+
getAbortController: (sessionId: string) => AbortController | undefined;
|
|
16
|
+
setAbortController: (sessionId: string, controller: AbortController | undefined) => void;
|
|
17
|
+
setChatStop: (sessionId: string, stop: (() => void) | undefined) => void;
|
|
18
|
+
getChatStop: (sessionId: string) => (() => void) | undefined;
|
|
19
|
+
setChatSendMessage: (sessionId: string, sendMessage: AiChatSendMessage | undefined) => void;
|
|
20
|
+
getChatSendMessage: (sessionId: string) => AiChatSendMessage | undefined;
|
|
21
|
+
setAddToolResult: (sessionId: string, addToolResult: AddToolResult | undefined) => void;
|
|
22
|
+
getAddToolResult: (sessionId: string) => AddToolResult | undefined;
|
|
23
|
+
waitForToolResult: (sessionId: string, toolCallId: string, abortSignal?: AbortSignal) => Promise<void>;
|
|
24
|
+
/** Map toolCallId -> sessionId for long-running tool streams (e.g. agent tools) */
|
|
25
|
+
setToolCallSession: (toolCallId: string, sessionId: string | undefined) => void;
|
|
26
|
+
getToolCallSession: (toolCallId: string) => string | undefined;
|
|
27
|
+
setPrompt: (sessionId: string, prompt: string) => void;
|
|
28
|
+
getPrompt: (sessionId: string) => string;
|
|
29
|
+
setIsRunning: (sessionId: string, isRunning: boolean) => void;
|
|
30
|
+
getIsRunning: (sessionId: string) => boolean;
|
|
40
31
|
addAnalysisResult: (message: UIMessage) => void;
|
|
41
32
|
sendPrompt: (prompt: string, options?: {
|
|
42
33
|
systemInstructions?: string;
|
|
@@ -46,10 +37,8 @@ export type AiSliceState = {
|
|
|
46
37
|
abortSignal?: AbortSignal;
|
|
47
38
|
useTools?: boolean;
|
|
48
39
|
}) => Promise<string>;
|
|
49
|
-
startAnalysis: (
|
|
50
|
-
|
|
51
|
-
}) => void) => Promise<void>;
|
|
52
|
-
cancelAnalysis: () => void;
|
|
40
|
+
startAnalysis: (sessionId: string) => Promise<void>;
|
|
41
|
+
cancelAnalysis: (sessionId: string) => void;
|
|
53
42
|
setAiModel: (modelProvider: string, model: string) => void;
|
|
54
43
|
createSession: (name?: string, modelProvider?: string, model?: string) => void;
|
|
55
44
|
switchSession: (sessionId: string) => void;
|
|
@@ -66,19 +55,23 @@ export type AiSliceState = {
|
|
|
66
55
|
getBaseUrlFromSettings: () => string | undefined;
|
|
67
56
|
getMaxStepsFromSettings: () => number;
|
|
68
57
|
getFullInstructions: () => string;
|
|
69
|
-
getLocalChatTransport: () => DefaultChatTransport<UIMessage>;
|
|
58
|
+
getLocalChatTransport: (sessionId: string) => DefaultChatTransport<UIMessage>;
|
|
70
59
|
/** Optional remote endpoint to use for chat; if empty, local transport is used */
|
|
71
60
|
chatEndPoint: string;
|
|
72
61
|
chatHeaders: Record<string, string>;
|
|
73
|
-
getRemoteChatTransport: (endpoint: string, headers?: Record<string, string>) => DefaultChatTransport<UIMessage>;
|
|
74
|
-
onChatToolCall: ExtendedChatOnToolCallCallback;
|
|
75
|
-
onChatData: ChatOnDataCallback<UIMessage<unknown, UIDataTypes, UITools>>;
|
|
62
|
+
getRemoteChatTransport: (sessionId: string, endpoint: string, headers?: Record<string, string>) => DefaultChatTransport<UIMessage>;
|
|
76
63
|
onChatFinish: (args: {
|
|
77
|
-
|
|
64
|
+
sessionId: string;
|
|
78
65
|
messages: UIMessage[];
|
|
79
66
|
isError?: boolean;
|
|
80
67
|
}) => void;
|
|
81
|
-
|
|
68
|
+
onChatToolCall: (args: {
|
|
69
|
+
sessionId: string;
|
|
70
|
+
toolCall: ToolCall;
|
|
71
|
+
addToolResult?: AddToolResult;
|
|
72
|
+
}) => Promise<void> | void;
|
|
73
|
+
onChatData: (sessionId: string, dataPart: Parameters<ChatOnDataCallback<UIMessage>>[0]) => void;
|
|
74
|
+
onChatError: (sessionId: string, error: unknown) => void;
|
|
82
75
|
};
|
|
83
76
|
};
|
|
84
77
|
/**
|
|
@@ -86,19 +79,14 @@ export type AiSliceState = {
|
|
|
86
79
|
*/
|
|
87
80
|
export interface AiSliceOptions {
|
|
88
81
|
config?: Partial<AiSliceConfig>;
|
|
89
|
-
|
|
90
|
-
initialAnalysisPrompt?: string;
|
|
91
|
-
/** Tools to add to the AI assistant */
|
|
82
|
+
initialPrompt?: string;
|
|
92
83
|
tools: OpenAssistantToolSet;
|
|
93
|
-
/**
|
|
94
|
-
* Function to get custom instructions for the AI assistant
|
|
95
|
-
* @returns The instructions string to use
|
|
96
|
-
*/
|
|
97
84
|
getInstructions: () => string;
|
|
98
85
|
defaultProvider?: string;
|
|
99
86
|
defaultModel?: string;
|
|
100
87
|
/** Provide a pre-configured model client for a provider (e.g., Azure). */
|
|
101
88
|
getCustomModel?: () => LanguageModel | undefined;
|
|
89
|
+
getProviderOptions?: GetProviderOptions;
|
|
102
90
|
maxSteps?: number;
|
|
103
91
|
getApiKey?: (modelProvider: string) => string;
|
|
104
92
|
getBaseUrl?: () => string;
|
|
@@ -109,5 +97,4 @@ export interface AiSliceOptions {
|
|
|
109
97
|
}
|
|
110
98
|
export declare function createAiSlice(params: AiSliceOptions): StateCreator<AiSliceState>;
|
|
111
99
|
export declare function useStoreWithAi<T>(selector: (state: AiSliceState) => T): T;
|
|
112
|
-
export {};
|
|
113
100
|
//# sourceMappingURL=AiSlice.d.ts.map
|
package/dist/AiSlice.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiSlice.d.ts","sourceRoot":"","sources":["../src/AiSlice.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EAEtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,SAAS,EACT,oBAAoB,EACpB,aAAa,EACb,
|
|
1
|
+
{"version":3,"file":"AiSlice.d.ts","sourceRoot":"","sources":["../src/AiSlice.ts"],"names":[],"mappings":"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"}
|
package/dist/AiSlice.js
CHANGED
|
@@ -3,13 +3,13 @@ import { createDefaultAiConfig, } from '@sqlrooms/ai-config';
|
|
|
3
3
|
import { createSlice, useBaseRoomStore, } from '@sqlrooms/room-store';
|
|
4
4
|
import { produce } from 'immer';
|
|
5
5
|
import { generateText, } from 'ai';
|
|
6
|
-
import { createChatHandlers, createLocalChatTransportFactory, createRemoteChatTransportFactory, convertToAiSDKTools,
|
|
7
|
-
import { AI_DEFAULT_TEMPERATURE } from './constants';
|
|
6
|
+
import { createChatHandlers, createLocalChatTransportFactory, createRemoteChatTransportFactory, convertToAiSDKTools, } from './chatTransport';
|
|
7
|
+
import { ABORT_EVENT, AI_DEFAULT_TEMPERATURE, ANALYSIS_CANCELLED, ANALYSIS_PENDING_ID, SESSION_DELETED, TOOL_CALL_CANCELLED, } from './constants';
|
|
8
8
|
import { hasAiSettingsConfig } from './hasAiSettingsConfig';
|
|
9
|
-
import { cleanupPendingAnalysisResults } from './utils';
|
|
9
|
+
import { cleanupPendingAnalysisResults, ToolAbortError, fixIncompleteToolCalls, } from './utils';
|
|
10
10
|
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
|
11
11
|
export function createAiSlice(params) {
|
|
12
|
-
const {
|
|
12
|
+
const { initialPrompt = '', tools, getApiKey, getBaseUrl, maxSteps = 50, getInstructions, defaultProvider = 'openai', defaultModel = 'gpt-4.1', getCustomModel, getProviderOptions, chatEndPoint = '', chatHeaders = {}, } = params;
|
|
13
13
|
return createSlice((set, get, store) => {
|
|
14
14
|
// Clean up pending analysis results from persisted config
|
|
15
15
|
const cleanedConfig = params.config?.sessions
|
|
@@ -18,7 +18,7 @@ export function createAiSlice(params) {
|
|
|
18
18
|
sessions: params.config.sessions.map((session) => {
|
|
19
19
|
const cleaned = cleanupPendingAnalysisResults(session);
|
|
20
20
|
const completedUiMessages = Array.isArray(cleaned.uiMessages)
|
|
21
|
-
?
|
|
21
|
+
? fixIncompleteToolCalls(cleaned.uiMessages || [])
|
|
22
22
|
: [];
|
|
23
23
|
return {
|
|
24
24
|
...cleaned,
|
|
@@ -27,8 +27,13 @@ export function createAiSlice(params) {
|
|
|
27
27
|
}),
|
|
28
28
|
}
|
|
29
29
|
: params.config;
|
|
30
|
-
// Create
|
|
30
|
+
// Create persistent Maps (outside of immer draft)
|
|
31
31
|
const pendingToolCallResolvers = new Map();
|
|
32
|
+
const toolCallToSessionId = new Map();
|
|
33
|
+
const sessionAbortControllers = new Map();
|
|
34
|
+
const sessionChatStops = new Map();
|
|
35
|
+
const sessionChatSendMessages = new Map();
|
|
36
|
+
const sessionAddToolResults = new Map();
|
|
32
37
|
// Initialize base config and ensure the initial session respects default provider/model
|
|
33
38
|
const baseConfig = createDefaultAiConfig(cleanedConfig);
|
|
34
39
|
if (!cleanedConfig?.sessions || cleanedConfig.sessions.length === 0) {
|
|
@@ -36,55 +41,124 @@ export function createAiSlice(params) {
|
|
|
36
41
|
if (firstSession) {
|
|
37
42
|
firstSession.modelProvider = defaultProvider;
|
|
38
43
|
firstSession.model = defaultModel;
|
|
44
|
+
firstSession.prompt = initialPrompt;
|
|
45
|
+
firstSession.isRunning = false;
|
|
39
46
|
}
|
|
40
47
|
}
|
|
41
48
|
return {
|
|
42
49
|
ai: {
|
|
43
50
|
config: baseConfig,
|
|
44
|
-
analysisPrompt: initialAnalysisPrompt,
|
|
45
|
-
isRunningAnalysis: false,
|
|
46
51
|
promptSuggestionsVisible: true,
|
|
47
52
|
tools,
|
|
48
|
-
|
|
53
|
+
getProviderOptions,
|
|
54
|
+
waitForToolResult: (sessionId, toolCallId, abortSignal) => {
|
|
55
|
+
const key = `${sessionId}:${toolCallId}`;
|
|
49
56
|
return new Promise((resolve, reject) => {
|
|
50
57
|
// Set up abort handler
|
|
51
58
|
const abortHandler = () => {
|
|
52
|
-
const resolver = pendingToolCallResolvers.get(
|
|
59
|
+
const resolver = pendingToolCallResolvers.get(key);
|
|
53
60
|
if (resolver) {
|
|
54
|
-
pendingToolCallResolvers.delete(
|
|
55
|
-
resolver.reject(new Error(
|
|
61
|
+
pendingToolCallResolvers.delete(key);
|
|
62
|
+
resolver.reject(new Error(TOOL_CALL_CANCELLED));
|
|
56
63
|
}
|
|
57
64
|
};
|
|
58
65
|
if (abortSignal) {
|
|
59
66
|
if (abortSignal.aborted) {
|
|
60
|
-
reject(new Error(
|
|
67
|
+
reject(new Error(TOOL_CALL_CANCELLED));
|
|
61
68
|
return;
|
|
62
69
|
}
|
|
63
|
-
abortSignal.addEventListener(
|
|
70
|
+
abortSignal.addEventListener(ABORT_EVENT, abortHandler, {
|
|
71
|
+
once: true,
|
|
72
|
+
});
|
|
64
73
|
}
|
|
65
74
|
// Store resolver (overwrites any existing one, which is fine for our use case)
|
|
66
|
-
pendingToolCallResolvers.set(
|
|
75
|
+
pendingToolCallResolvers.set(key, {
|
|
67
76
|
resolve: () => {
|
|
68
77
|
if (abortSignal) {
|
|
69
|
-
abortSignal.removeEventListener(
|
|
78
|
+
abortSignal.removeEventListener(ABORT_EVENT, abortHandler);
|
|
70
79
|
}
|
|
71
|
-
pendingToolCallResolvers.delete(
|
|
80
|
+
pendingToolCallResolvers.delete(key);
|
|
72
81
|
resolve();
|
|
73
82
|
},
|
|
74
83
|
reject: (error) => {
|
|
75
84
|
if (abortSignal) {
|
|
76
|
-
abortSignal.removeEventListener(
|
|
85
|
+
abortSignal.removeEventListener(ABORT_EVENT, abortHandler);
|
|
77
86
|
}
|
|
78
|
-
pendingToolCallResolvers.delete(
|
|
87
|
+
pendingToolCallResolvers.delete(key);
|
|
79
88
|
reject(error);
|
|
80
89
|
},
|
|
81
90
|
});
|
|
82
91
|
});
|
|
83
92
|
},
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
setToolCallSession: (toolCallId, sessionId) => {
|
|
94
|
+
if (!toolCallId)
|
|
95
|
+
return;
|
|
96
|
+
if (sessionId) {
|
|
97
|
+
toolCallToSessionId.set(toolCallId, sessionId);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
toolCallToSessionId.delete(toolCallId);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
getToolCallSession: (toolCallId) => {
|
|
104
|
+
if (!toolCallId)
|
|
105
|
+
return undefined;
|
|
106
|
+
return toolCallToSessionId.get(toolCallId);
|
|
107
|
+
},
|
|
108
|
+
getAbortController: (sessionId) => {
|
|
109
|
+
return sessionAbortControllers.get(sessionId);
|
|
110
|
+
},
|
|
111
|
+
setAbortController: (sessionId, controller) => {
|
|
112
|
+
if (controller) {
|
|
113
|
+
sessionAbortControllers.set(sessionId, controller);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
sessionAbortControllers.delete(sessionId);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
setChatStop: (sessionId, stopFn) => {
|
|
120
|
+
if (stopFn) {
|
|
121
|
+
sessionChatStops.set(sessionId, stopFn);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
sessionChatStops.delete(sessionId);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
getChatStop: (sessionId) => {
|
|
128
|
+
return sessionChatStops.get(sessionId);
|
|
129
|
+
},
|
|
130
|
+
setChatSendMessage: (sessionId, sendMessageFn) => {
|
|
131
|
+
if (sendMessageFn) {
|
|
132
|
+
sessionChatSendMessages.set(sessionId, sendMessageFn);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
sessionChatSendMessages.delete(sessionId);
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
getChatSendMessage: (sessionId) => {
|
|
139
|
+
return sessionChatSendMessages.get(sessionId);
|
|
140
|
+
},
|
|
141
|
+
setAddToolResult: (sessionId, addToolResultFn) => {
|
|
142
|
+
if (addToolResultFn) {
|
|
143
|
+
// Wrap addToolResult to intercept calls and resolve pending promises
|
|
144
|
+
const wrappedAddToolResult = (options) => {
|
|
145
|
+
addToolResultFn(options);
|
|
146
|
+
const key = `${sessionId}:${options.toolCallId}`;
|
|
147
|
+
const resolver = pendingToolCallResolvers.get(key);
|
|
148
|
+
if (resolver) {
|
|
149
|
+
resolver.resolve();
|
|
150
|
+
}
|
|
151
|
+
// Tool is complete (success or error), we can drop toolCall->session mapping.
|
|
152
|
+
toolCallToSessionId.delete(options.toolCallId);
|
|
153
|
+
};
|
|
154
|
+
sessionAddToolResults.set(sessionId, wrappedAddToolResult);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
sessionAddToolResults.delete(sessionId);
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
getAddToolResult: (sessionId) => {
|
|
161
|
+
return sessionAddToolResults.get(sessionId);
|
|
88
162
|
},
|
|
89
163
|
setConfig: (config) => {
|
|
90
164
|
set((state) => produce(state, (draft) => {
|
|
@@ -96,33 +170,32 @@ export function createAiSlice(params) {
|
|
|
96
170
|
draft.ai.promptSuggestionsVisible = visible;
|
|
97
171
|
}));
|
|
98
172
|
},
|
|
99
|
-
|
|
173
|
+
setPrompt: (sessionId, prompt) => {
|
|
100
174
|
set((state) => produce(state, (draft) => {
|
|
101
|
-
draft.ai.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
setAddToolResult: (addToolResultFn) => {
|
|
105
|
-
// Wrap addToolResult to intercept calls and resolve pending promises
|
|
106
|
-
const wrappedAddToolResult = addToolResultFn
|
|
107
|
-
? (options) => {
|
|
108
|
-
// Call the original addToolResult
|
|
109
|
-
addToolResultFn(options);
|
|
110
|
-
// Resolve the promise if there's a pending waiter for this toolCallId
|
|
111
|
-
const resolver = pendingToolCallResolvers.get(options.toolCallId);
|
|
112
|
-
if (resolver) {
|
|
113
|
-
resolver.resolve();
|
|
114
|
-
}
|
|
175
|
+
const session = draft.ai.config.sessions.find((s) => s.id === sessionId);
|
|
176
|
+
if (session) {
|
|
177
|
+
session.prompt = prompt;
|
|
115
178
|
}
|
|
116
|
-
: undefined;
|
|
117
|
-
set((state) => produce(state, (draft) => {
|
|
118
|
-
draft.ai.addToolResult = wrappedAddToolResult;
|
|
119
179
|
}));
|
|
120
180
|
},
|
|
121
|
-
|
|
181
|
+
getPrompt: (sessionId) => {
|
|
182
|
+
const state = get();
|
|
183
|
+
const session = state.ai.config.sessions.find((s) => s.id === sessionId);
|
|
184
|
+
return session?.prompt || '';
|
|
185
|
+
},
|
|
186
|
+
setIsRunning: (sessionId, isRunning) => {
|
|
122
187
|
set((state) => produce(state, (draft) => {
|
|
123
|
-
draft.ai.
|
|
188
|
+
const session = draft.ai.config.sessions.find((s) => s.id === sessionId);
|
|
189
|
+
if (session) {
|
|
190
|
+
session.isRunning = isRunning;
|
|
191
|
+
}
|
|
124
192
|
}));
|
|
125
193
|
},
|
|
194
|
+
getIsRunning: (sessionId) => {
|
|
195
|
+
const state = get();
|
|
196
|
+
const session = state.ai.config.sessions.find((s) => s.id === sessionId);
|
|
197
|
+
return session?.isRunning || false;
|
|
198
|
+
},
|
|
126
199
|
/**
|
|
127
200
|
* Set the AI model for the current session
|
|
128
201
|
* @param model - The model to set
|
|
@@ -168,7 +241,7 @@ export function createAiSlice(params) {
|
|
|
168
241
|
sessionName = `Session ${formattedDate} at ${formattedTime}`;
|
|
169
242
|
}
|
|
170
243
|
set((state) => produce(state, (draft) => {
|
|
171
|
-
// Add to AI sessions
|
|
244
|
+
// Add to AI sessions with per-session state
|
|
172
245
|
draft.ai.config.sessions.unshift({
|
|
173
246
|
id: newSessionId,
|
|
174
247
|
name: sessionName,
|
|
@@ -181,6 +254,8 @@ export function createAiSlice(params) {
|
|
|
181
254
|
uiMessages: [],
|
|
182
255
|
toolAdditionalData: {},
|
|
183
256
|
messagesRevision: 0,
|
|
257
|
+
prompt: '',
|
|
258
|
+
isRunning: false,
|
|
184
259
|
});
|
|
185
260
|
draft.ai.config.currentSessionId = newSessionId;
|
|
186
261
|
}));
|
|
@@ -205,9 +280,18 @@ export function createAiSlice(params) {
|
|
|
205
280
|
}));
|
|
206
281
|
},
|
|
207
282
|
/**
|
|
208
|
-
* Delete a session
|
|
283
|
+
* Delete a session and clean up its resources
|
|
209
284
|
*/
|
|
210
285
|
deleteSession: (sessionId) => {
|
|
286
|
+
// Clean up per-session state
|
|
287
|
+
const abortController = sessionAbortControllers.get(sessionId);
|
|
288
|
+
if (abortController) {
|
|
289
|
+
abortController.abort(SESSION_DELETED);
|
|
290
|
+
}
|
|
291
|
+
sessionAbortControllers.delete(sessionId);
|
|
292
|
+
sessionChatStops.delete(sessionId);
|
|
293
|
+
sessionChatSendMessages.delete(sessionId);
|
|
294
|
+
sessionAddToolResults.delete(sessionId);
|
|
211
295
|
set((state) => produce(state, (draft) => {
|
|
212
296
|
const sessionIndex = draft.ai.config.sessions.findIndex((s) => s.id === sessionId);
|
|
213
297
|
if (sessionIndex !== -1) {
|
|
@@ -333,15 +417,15 @@ export function createAiSlice(params) {
|
|
|
333
417
|
sendPrompt: async (prompt, options = {}) => {
|
|
334
418
|
// One-shot generateText path with explicit abort lifecycle management
|
|
335
419
|
const state = get();
|
|
336
|
-
const currentSession = state.ai.getCurrentSession();
|
|
420
|
+
const currentSession = state.ai.getCurrentSession(); // only used when no model provider is provided
|
|
337
421
|
const { systemInstructions, modelProvider, modelName, baseUrl, abortSignal, useTools = false, } = options;
|
|
422
|
+
if (abortSignal?.aborted) {
|
|
423
|
+
throw new ToolAbortError(TOOL_CALL_CANCELLED);
|
|
424
|
+
}
|
|
338
425
|
const provider = modelProvider || currentSession?.modelProvider || defaultProvider;
|
|
339
426
|
const modelId = modelName || currentSession?.model || defaultModel;
|
|
340
|
-
const baseURL = baseUrl
|
|
341
|
-
state.ai.getBaseUrlFromSettings() ||
|
|
342
|
-
'https://api.openai.com/v1';
|
|
427
|
+
const baseURL = baseUrl ?? state.ai.getBaseUrlFromSettings() ?? '';
|
|
343
428
|
const tools = state.ai.tools;
|
|
344
|
-
// remove execute from tools
|
|
345
429
|
const toolsWithoutExecute = Object.fromEntries(Object.entries(tools).filter(([, tool]) => !tool.execute));
|
|
346
430
|
const model = createOpenAICompatible({
|
|
347
431
|
apiKey: state.ai.getApiKeyFromSettings(),
|
|
@@ -362,63 +446,69 @@ export function createAiSlice(params) {
|
|
|
362
446
|
return response.text;
|
|
363
447
|
}
|
|
364
448
|
catch (error) {
|
|
449
|
+
const errorName = typeof error === 'object' && error && 'name' in error
|
|
450
|
+
? String(error.name)
|
|
451
|
+
: '';
|
|
452
|
+
if (abortSignal?.aborted || errorName === 'AbortError') {
|
|
453
|
+
throw new ToolAbortError(TOOL_CALL_CANCELLED);
|
|
454
|
+
}
|
|
365
455
|
console.error('Error generating text:', error);
|
|
366
456
|
return 'error: can not generate response';
|
|
367
457
|
}
|
|
368
458
|
},
|
|
369
459
|
/**
|
|
370
|
-
* Start the analysis
|
|
460
|
+
* Start the analysis for a specific session
|
|
371
461
|
*/
|
|
372
|
-
startAnalysis: async (
|
|
373
|
-
const
|
|
374
|
-
const
|
|
375
|
-
if (!
|
|
376
|
-
console.error('
|
|
462
|
+
startAnalysis: async (sessionId) => {
|
|
463
|
+
const state = get();
|
|
464
|
+
const session = state.ai.config.sessions.find((s) => s.id === sessionId);
|
|
465
|
+
if (!session) {
|
|
466
|
+
console.error('Session not found:', sessionId);
|
|
377
467
|
return;
|
|
378
468
|
}
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
469
|
+
const sendMessage = state.ai.getChatSendMessage(sessionId);
|
|
470
|
+
if (!sendMessage) {
|
|
471
|
+
console.error('No sendMessage function found for session:', sessionId);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const abortController = new AbortController();
|
|
475
|
+
const promptText = session.prompt || '';
|
|
476
|
+
// Store abort controller for this session
|
|
477
|
+
state.ai.setAbortController(sessionId, abortController);
|
|
478
|
+
set((stateToUpdate) => produce(stateToUpdate, (draft) => {
|
|
479
|
+
const draftSession = draft.ai.config.sessions.find((s) => s.id === sessionId);
|
|
480
|
+
if (draftSession) {
|
|
481
|
+
draftSession.isRunning = true;
|
|
482
|
+
draftSession.prompt = '';
|
|
483
|
+
draft.ai.promptSuggestionsVisible = false;
|
|
484
|
+
// Remove any existing pending results
|
|
485
|
+
draftSession.analysisResults =
|
|
486
|
+
draftSession.analysisResults.filter((result) => result.id !== ANALYSIS_PENDING_ID);
|
|
390
487
|
// Add incomplete analysis result with a temporary ID
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
id: '__pending__',
|
|
488
|
+
draftSession.analysisResults.push({
|
|
489
|
+
id: ANALYSIS_PENDING_ID,
|
|
394
490
|
prompt: promptText,
|
|
395
491
|
isCompleted: false,
|
|
396
492
|
});
|
|
397
493
|
}
|
|
398
494
|
}));
|
|
399
|
-
//
|
|
495
|
+
// Send the message through the session's chat instance
|
|
400
496
|
sendMessage({ text: promptText });
|
|
401
497
|
},
|
|
402
|
-
cancelAnalysis: () => {
|
|
403
|
-
const
|
|
498
|
+
cancelAnalysis: (sessionId) => {
|
|
499
|
+
const state = get();
|
|
500
|
+
const abortController = state.ai.getAbortController(sessionId);
|
|
501
|
+
const stopFn = state.ai.getChatStop(sessionId);
|
|
404
502
|
// Stop local chat streaming immediately if available
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
// can check if it was aborted. The onChatFinish handler will clean it up.
|
|
414
|
-
abortController?.abort('Analysis cancelled');
|
|
415
|
-
set((state) => produce(state, (draft) => {
|
|
416
|
-
// Set isRunningAnalysis to false to update UI
|
|
417
|
-
draft.ai.isRunningAnalysis = false;
|
|
418
|
-
// Keep analysisAbortController so handlers can check signal.aborted
|
|
503
|
+
stopFn?.();
|
|
504
|
+
abortController?.abort(ANALYSIS_CANCELLED);
|
|
505
|
+
set((stateToUpdate) => produce(stateToUpdate, (draft) => {
|
|
506
|
+
const session = draft.ai.config.sessions.find((s) => s.id === sessionId);
|
|
507
|
+
if (session) {
|
|
508
|
+
session.isRunning = false;
|
|
509
|
+
}
|
|
510
|
+
// Keep abort controller so handlers can check signal.aborted
|
|
419
511
|
// It will be cleared by onChatFinish
|
|
420
|
-
// Intentionally preserve any pending analysis result so the
|
|
421
|
-
// conversation row remains visible until onChatFinish runs.
|
|
422
512
|
}));
|
|
423
513
|
},
|
|
424
514
|
/**
|
|
@@ -539,7 +629,7 @@ export function createAiSlice(params) {
|
|
|
539
629
|
// Chat transport configuration
|
|
540
630
|
chatEndPoint,
|
|
541
631
|
chatHeaders,
|
|
542
|
-
getLocalChatTransport: () => {
|
|
632
|
+
getLocalChatTransport: (sessionId) => {
|
|
543
633
|
const state = get();
|
|
544
634
|
return createLocalChatTransportFactory({
|
|
545
635
|
store,
|
|
@@ -549,12 +639,14 @@ export function createAiSlice(params) {
|
|
|
549
639
|
baseUrl: state.ai.getBaseUrlFromSettings(),
|
|
550
640
|
getInstructions: () => store.getState().ai.getFullInstructions(),
|
|
551
641
|
getCustomModel,
|
|
642
|
+
sessionId,
|
|
552
643
|
})();
|
|
553
644
|
},
|
|
554
|
-
getRemoteChatTransport: (endpoint, headers) => createRemoteChatTransportFactory({
|
|
645
|
+
getRemoteChatTransport: (sessionId, endpoint, headers) => createRemoteChatTransportFactory({
|
|
555
646
|
store,
|
|
556
647
|
defaultProvider,
|
|
557
648
|
defaultModel,
|
|
649
|
+
sessionId,
|
|
558
650
|
})(endpoint, headers),
|
|
559
651
|
...createChatHandlers({ store }),
|
|
560
652
|
},
|