@messenger-box/tailwind-ui-inbox 10.0.3-alpha.72 → 10.0.3-alpha.74
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/CHANGELOG.md +8 -0
- package/lib/components/AIAgent/AIAgent.d.ts +7 -0
- package/lib/components/AIAgent/AIAgent.d.ts.map +1 -1
- package/lib/components/AIAgent/AIAgent.js +362 -615
- package/lib/components/AIAgent/AIAgent.js.map +1 -1
- package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -1
- package/lib/components/InboxMessage/InputComponent.js +143 -140
- package/lib/components/InboxMessage/InputComponent.js.map +1 -1
- package/lib/components/InboxMessage/RightSidebarAi.d.ts +23 -0
- package/lib/components/InboxMessage/RightSidebarAi.d.ts.map +1 -0
- package/lib/components/InboxMessage/RightSidebarAi.js +9 -0
- package/lib/components/InboxMessage/RightSidebarAi.js.map +1 -0
- package/lib/components/InboxMessage/index.d.ts +1 -0
- package/lib/components/InboxMessage/index.d.ts.map +1 -1
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.d.ts +11 -0
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.d.ts.map +1 -0
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.js +194 -0
- package/lib/components/InboxMessage/message-widgets/ErrorFixCard.js.map +1 -0
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +5 -1
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -1
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +308 -857
- package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -1
- package/lib/components/ModelConfigPanel.d.ts +12 -0
- package/lib/components/ModelConfigPanel.d.ts.map +1 -0
- package/lib/components/ModelConfigPanel.js +304 -0
- package/lib/components/ModelConfigPanel.js.map +1 -0
- package/lib/components/filler-components/RightSiderBar.d.ts +24 -0
- package/lib/components/filler-components/RightSiderBar.d.ts.map +1 -0
- package/lib/components/filler-components/RightSiderBar.js +335 -0
- package/lib/components/filler-components/RightSiderBar.js.map +1 -0
- package/lib/components/index.d.ts +4 -2
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/live-code-editor/hybrid-live-editor.d.ts +20 -0
- package/lib/components/live-code-editor/hybrid-live-editor.d.ts.map +1 -0
- package/lib/components/live-code-editor/hybrid-live-editor.js +68 -0
- package/lib/components/live-code-editor/hybrid-live-editor.js.map +1 -0
- package/lib/components/live-code-editor/index.d.ts +4 -0
- package/lib/components/live-code-editor/index.d.ts.map +1 -0
- package/lib/components/live-code-editor/live-code-editor.d.ts +14 -0
- package/lib/components/live-code-editor/live-code-editor.d.ts.map +1 -0
- package/lib/components/live-code-editor/live-code-editor.js +207 -0
- package/lib/components/live-code-editor/live-code-editor.js.map +1 -0
- package/lib/components/slot-fill/chat-message-filler.js +1 -1
- package/lib/components/slot-fill/chat-message-filler.js.map +1 -1
- package/lib/components/slot-fill/index.d.ts +1 -0
- package/lib/components/slot-fill/index.d.ts.map +1 -1
- package/lib/components/slot-fill/right-sidebar-filler.d.ts +4 -0
- package/lib/components/slot-fill/right-sidebar-filler.d.ts.map +1 -0
- package/lib/components/slot-fill/right-sidebar-filler.js +13 -0
- package/lib/components/slot-fill/right-sidebar-filler.js.map +1 -0
- package/lib/components/ui/button.d.ts +9 -0
- package/lib/components/ui/button.d.ts.map +1 -0
- package/lib/compute.js +1 -2
- package/lib/container/AiInbox.d.ts.map +1 -1
- package/lib/container/AiLandingInput.d.ts.map +1 -1
- package/lib/container/AiLandingInput.js +46 -119
- package/lib/container/AiLandingInput.js.map +1 -1
- package/lib/container/Inbox.js +1 -1
- package/lib/container/Inbox.js.map +1 -1
- package/lib/container/InboxAiMessagesLoader.d.ts +0 -21
- package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -1
- package/lib/container/InboxAiMessagesLoader.js +18 -35
- package/lib/container/InboxAiMessagesLoader.js.map +1 -1
- package/lib/container/ServiceInbox.js +1 -1
- package/lib/container/ServiceInbox.js.map +1 -1
- package/lib/container/ThreadMessages.js +1 -1
- package/lib/container/ThreadMessages.js.map +1 -1
- package/lib/container/ThreadMessagesInbox.js +1 -1
- package/lib/container/ThreadMessagesInbox.js.map +1 -1
- package/lib/container/Threads.js +1 -1
- package/lib/container/Threads.js.map +1 -1
- package/lib/container/index.d.ts +5 -4
- package/lib/container/index.d.ts.map +1 -1
- package/lib/enums/messenger-slot-fill-name-enum.d.ts +2 -1
- package/lib/enums/messenger-slot-fill-name-enum.d.ts.map +1 -1
- package/lib/enums/messenger-slot-fill-name-enum.js +1 -0
- package/lib/enums/messenger-slot-fill-name-enum.js.map +1 -1
- package/lib/hooks/index.d.ts +3 -0
- package/lib/hooks/index.d.ts.map +1 -0
- package/lib/hooks/use-file-sync.d.ts +16 -0
- package/lib/hooks/use-file-sync.d.ts.map +1 -0
- package/lib/hooks/use-file-sync.js +63 -0
- package/lib/hooks/use-file-sync.js.map +1 -0
- package/lib/hooks/usePersistentModelConfig.d.ts +15 -0
- package/lib/hooks/usePersistentModelConfig.d.ts.map +1 -0
- package/lib/hooks/usePersistentModelConfig.js +46 -0
- package/lib/hooks/usePersistentModelConfig.js.map +1 -0
- package/lib/index.d.ts +5 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/machines/aiAgentMachine.d.ts.map +1 -1
- package/lib/machines/aiAgentMachine.js +64 -21
- package/lib/machines/aiAgentMachine.js.map +1 -1
- package/lib/machines/aiAgentMachine.simple.d.ts +3 -0
- package/lib/machines/aiAgentMachine.simple.d.ts.map +1 -0
- package/lib/machines/aiAgentMachine.simple.js +108 -0
- package/lib/machines/aiAgentMachine.simple.js.map +1 -0
- package/lib/machines/index.d.ts +3 -0
- package/lib/machines/index.d.ts.map +1 -0
- package/lib/module.d.ts +2 -1
- package/lib/module.d.ts.map +1 -1
- package/lib/module.js +11 -3
- package/lib/module.js.map +1 -1
- package/lib/routes.json +1 -2
- package/lib/templates/InboxWithAi.d.ts.map +1 -1
- package/lib/templates/InboxWithAi.js +129 -70
- package/lib/templates/InboxWithAi.js.map +1 -1
- package/lib/templates/InboxWithAi.tsx +151 -90
- package/lib/templates/index.d.ts +2 -0
- package/lib/templates/index.d.ts.map +1 -0
- package/lib/templates/index.ts +1 -0
- package/lib/utils/utils.d.ts +2 -0
- package/lib/utils/utils.d.ts.map +1 -0
- package/lib/utils/utils.js +3 -0
- package/lib/utils/utils.js.map +1 -0
- package/package.json +8 -5
- package/src/components/AIAgent/AIAgent.tsx +469 -731
- package/src/components/AIAgent/AIAgent.tsx.bk +1365 -0
- package/src/components/InboxMessage/InputComponent.tsx +2 -1
- package/src/components/InboxMessage/RightSidebarAi.tsx +37 -0
- package/src/components/InboxMessage/index.ts +1 -0
- package/src/components/InboxMessage/message-widgets/ErrorFixCard.tsx +240 -0
- package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +337 -1116
- package/src/components/ModelConfigPanel.tsx +334 -0
- package/src/components/filler-components/RightSiderBar.tsx +408 -0
- package/src/components/index.ts +4 -1
- package/src/components/live-code-editor/hybrid-live-editor.tsx +105 -0
- package/src/components/live-code-editor/index.ts +3 -0
- package/src/components/live-code-editor/live-code-editor.tsx +257 -0
- package/src/components/slot-fill/index.ts +1 -0
- package/src/components/slot-fill/right-sidebar-filler.tsx +39 -0
- package/src/components/ui/button.tsx +32 -0
- package/src/container/AiInbox.tsx +26 -3
- package/src/container/AiLandingInput.tsx +48 -22
- package/src/container/InboxAiMessagesLoader.tsx +17 -41
- package/src/container/index.ts +14 -6
- package/src/enums/messenger-slot-fill-name-enum.ts +1 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/use-file-sync.ts +91 -0
- package/src/hooks/usePersistentModelConfig.ts +63 -0
- package/src/index.ts +19 -1
- package/src/machines/aiAgentMachine.simple.ts +89 -0
- package/src/machines/aiAgentMachine.ts +67 -19
- package/src/machines/aiAgentMachine.ts.bk +1296 -0
- package/src/machines/index.ts +2 -0
- package/src/module.tsx +10 -1
- package/src/templates/InboxWithAi.tsx +151 -90
- package/src/templates/index.ts +1 -0
- package/src/utils/utils.ts +3 -0
- package/lib/components/InboxMessage/MessageInputComponent.js +0 -173
- package/lib/components/InboxMessage/MessageInputComponent.js.map +0 -1
- package/lib/components/InboxMessage/MessagesBuilderUi.js +0 -162
- package/lib/components/InboxMessage/MessagesBuilderUi.js.map +0 -1
- package/lib/container/AiInbox.js +0 -1520
- package/lib/container/AiInbox.js.map +0 -1
- package/lib/container/AiInboxWithLoader.js +0 -300
- package/lib/container/AiInboxWithLoader.js.map +0 -1
- package/lib/container/InboxTemplate1.js +0 -1375
- package/lib/container/InboxTemplate1.js.map +0 -1
- package/lib/container/InboxTemplate2.js +0 -1426
- package/lib/container/InboxTemplate2.js.map +0 -1
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import React, { useCallback, useMemo, useRef, useState, useEffect } from 'react';
|
|
2
2
|
import { useActor, useMachine } from '@xstate/react';
|
|
3
|
-
import { aiAgentMachine } from '../../machines/aiAgentMachine';
|
|
4
|
-
import { Message } from '../../machines/types';
|
|
3
|
+
import { aiAgentMachine } from '../../machines/aiAgentMachine.simple';
|
|
5
4
|
import { InputComponent } from '../InboxMessage/InputComponent';
|
|
6
5
|
import { format, isToday, isYesterday, formatDistanceToNow } from 'date-fns';
|
|
7
6
|
import { useTranslation } from 'react-i18next';
|
|
8
7
|
import { ModernMessageGroupComponent } from '../InboxMessage/message-widgets/ModernMessageGroup';
|
|
9
8
|
import { useUploadFiles } from '@messenger-box/platform-client';
|
|
10
|
-
import { IFileInfo, PostTypeEnum } from 'common';
|
|
9
|
+
import { IFileInfo, PostTypeEnum, ISandboxError } from 'common';
|
|
11
10
|
import { useSelector, shallowEqual } from 'react-redux';
|
|
12
11
|
import { Store, userSelector } from '@adminide-stack/user-auth0-client';
|
|
13
12
|
import { IUserState } from '@adminide-stack/core';
|
|
@@ -18,12 +17,17 @@ import {
|
|
|
18
17
|
MessagesDocument,
|
|
19
18
|
useMessagesQuery,
|
|
20
19
|
OnChatMessageAddedDocument as CHAT_MESSAGE_ADDED,
|
|
20
|
+
useGenerateAiCodeMutation,
|
|
21
|
+
useOnChatMessageAddedSubscription,
|
|
22
|
+
useSandboxErrorSubscription,
|
|
23
|
+
useRecreateSandboxMutation,
|
|
21
24
|
} from 'common/graphql';
|
|
22
25
|
import { config } from '../../config';
|
|
23
26
|
import { orderBy, uniqBy } from 'lodash-es';
|
|
24
|
-
import { useParams } from '@remix-run/react';
|
|
27
|
+
import { useParams, useNavigate } from '@remix-run/react';
|
|
25
28
|
import { RoomType } from 'common';
|
|
26
29
|
import { SubscriptionHandler } from '../InboxMessage/SubscriptionHandler';
|
|
30
|
+
import { usePersistentModelConfig } from '../../hooks/usePersistentModelConfig';
|
|
27
31
|
|
|
28
32
|
const { MESSAGES_PER_PAGE } = config;
|
|
29
33
|
|
|
@@ -36,6 +40,13 @@ interface AIAgentProps {
|
|
|
36
40
|
channelName?: string;
|
|
37
41
|
isDesktopView?: boolean;
|
|
38
42
|
isSmallScreen?: boolean;
|
|
43
|
+
messages?: any[];
|
|
44
|
+
setMessages?: (messages: any[]) => void;
|
|
45
|
+
selectedPost?: any;
|
|
46
|
+
setSelectedPost?: (selectedPost: any) => void;
|
|
47
|
+
setIsLoading?: (isLoading: boolean) => void;
|
|
48
|
+
isLoading?: boolean;
|
|
49
|
+
[key: string]: any; // Allow other props to be passed through to Inbox
|
|
39
50
|
}
|
|
40
51
|
|
|
41
52
|
export const AIAgent: React.FC<AIAgentProps> = ({
|
|
@@ -46,6 +57,12 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
46
57
|
currentUser,
|
|
47
58
|
isDesktopView = false,
|
|
48
59
|
isSmallScreen = false,
|
|
60
|
+
setMessages,
|
|
61
|
+
setSelectedPost,
|
|
62
|
+
messages,
|
|
63
|
+
selectedPost,
|
|
64
|
+
setIsLoading,
|
|
65
|
+
isLoading,
|
|
49
66
|
}) => {
|
|
50
67
|
const [state, send] = useMachine(aiAgentMachine);
|
|
51
68
|
const apolloClient = useApolloClient();
|
|
@@ -53,14 +70,31 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
53
70
|
const [sendMsg] = useSendMessagesMutation();
|
|
54
71
|
const auth: any = useSelector<Store.Auth, IUserState>(userSelector, shallowEqual);
|
|
55
72
|
const { id: pathChannelId } = useParams();
|
|
56
|
-
|
|
73
|
+
const navigate = useNavigate();
|
|
74
|
+
const { modelConfig, getValidatedConfig, hasApiKey } = usePersistentModelConfig();
|
|
75
|
+
// const [isLoading, setIsLoading] = useState(false);
|
|
76
|
+
const [errorData, setError] = useState<string | null>(null);
|
|
57
77
|
// Get channelId from props or path params
|
|
58
78
|
const actualChannelId = channelId || pathChannelId;
|
|
79
|
+
const [generateAiCode] = useGenerateAiCodeMutation();
|
|
80
|
+
const [recreateSandbox] = useRecreateSandboxMutation();
|
|
81
|
+
const { data: chatMessageAddedData } = useOnChatMessageAddedSubscription({
|
|
82
|
+
variables: { channelId: actualChannelId?.toString() || '' },
|
|
83
|
+
skip: !actualChannelId,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Subscribe to sandbox errors if projectId is provided
|
|
87
|
+
const { data: sandboxErrorData } = useSandboxErrorSubscription({
|
|
88
|
+
variables: { projectId: actualChannelId?.toString() || '' },
|
|
89
|
+
skip: !actualChannelId,
|
|
90
|
+
});
|
|
59
91
|
|
|
60
92
|
// Direct message query from InboxWithAiLoader.tsx
|
|
61
93
|
const messagesQuery = useMessagesQuery({
|
|
62
94
|
variables: {
|
|
63
|
-
|
|
95
|
+
props: {
|
|
96
|
+
projectId: actualChannelId?.toString(),
|
|
97
|
+
},
|
|
64
98
|
parentId: null,
|
|
65
99
|
limit: MESSAGES_PER_PAGE,
|
|
66
100
|
},
|
|
@@ -80,28 +114,147 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
80
114
|
|
|
81
115
|
const [isOpen, setIsOpen] = useState(false);
|
|
82
116
|
const [selectedElement, setSelectedElement] = useState<any>(null);
|
|
83
|
-
const [currentProcessingMessage, setCurrentProcessingMessage] = useState<number | null>(null);
|
|
84
|
-
const [processedMessageIds, setProcessedMessageIds] = useState<Set<string>>(new Set());
|
|
85
117
|
const [activeTab, setActiveTab] = useState<'chat' | 'history'>('chat');
|
|
86
118
|
const bottomRef = useRef<HTMLDivElement | null>(null);
|
|
87
|
-
|
|
119
|
+
const [sandboxErrors, setSandboxErrors] = useState<ISandboxError[]>([]);
|
|
120
|
+
const [currentFiles, setCurrentFiles] = useState<Record<string, string>>({});
|
|
121
|
+
const [canvasLayers, setCanvasLayers] = useState<any[]>([]);
|
|
88
122
|
// New state variables for message display control
|
|
89
|
-
const [
|
|
90
|
-
const
|
|
123
|
+
const [isSuccessThinking, setIsSuccessThinking] = useState(false);
|
|
124
|
+
const successThinkingTimeoutRef = useRef<any>(null);
|
|
91
125
|
|
|
92
126
|
// Get regular messages from direct query
|
|
93
127
|
const {
|
|
94
128
|
data: messagesData,
|
|
95
129
|
loading: messageLoading,
|
|
130
|
+
refetch: refetchMessages,
|
|
96
131
|
fetchMore: fetchMoreMessages,
|
|
97
132
|
subscribeToMore,
|
|
98
133
|
} = messagesQuery;
|
|
99
134
|
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (actualChannelId) {
|
|
137
|
+
refetchMessages({
|
|
138
|
+
limit: MESSAGES_PER_PAGE,
|
|
139
|
+
props: {
|
|
140
|
+
projectId: actualChannelId?.toString(),
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}, [actualChannelId, refetchMessages]);
|
|
145
|
+
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
if (chatMessageAddedData?.chatMessageAdded) {
|
|
148
|
+
console.log(
|
|
149
|
+
'chatMessageAddedData?.chatMessageAdded',
|
|
150
|
+
JSON.stringify(chatMessageAddedData?.chatMessageAdded, null, 2),
|
|
151
|
+
);
|
|
152
|
+
// handleGenerateAiCode(chatMessageAddedData.chatMessageAdded.id);
|
|
153
|
+
// Stop the success thinking loader once a new message arrives
|
|
154
|
+
if (isSuccessThinking) {
|
|
155
|
+
setIsSuccessThinking(false);
|
|
156
|
+
if (successThinkingTimeoutRef.current) {
|
|
157
|
+
clearTimeout(successThinkingTimeoutRef.current);
|
|
158
|
+
successThinkingTimeoutRef.current = null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}, [chatMessageAddedData?.chatMessageAdded]);
|
|
163
|
+
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
if (messagesData?.messages?.data?.length == 1) {
|
|
166
|
+
handleGenerateAiCode(messagesData.messages.data[0].id);
|
|
167
|
+
}
|
|
168
|
+
// console.log('messagesData?.messages?.data',JSON.stringify(messagesData?.messages?.data,null,2))
|
|
169
|
+
}, [messagesData?.messages?.data]);
|
|
170
|
+
|
|
171
|
+
// Handle sandbox error subscription updates
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
if (sandboxErrorData?.sandboxError) {
|
|
174
|
+
const errorData = sandboxErrorData.sandboxError;
|
|
175
|
+
console.log('Sandbox error received:', errorData);
|
|
176
|
+
setSandboxErrors((prev) => [...prev, errorData.error]);
|
|
177
|
+
}
|
|
178
|
+
}, [sandboxErrorData]);
|
|
179
|
+
|
|
100
180
|
const regularMessages = useMemo(() => {
|
|
101
181
|
if (!messagesData?.messages?.data) return [];
|
|
102
182
|
return orderBy(uniqBy(messagesData.messages.data || [], 'id'), ['createdAt'], ['asc']);
|
|
103
183
|
}, [messagesData?.messages?.data]);
|
|
104
184
|
|
|
185
|
+
// Send regular messages to AI agent machine for context
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
if (regularMessages && regularMessages.length > 0) {
|
|
188
|
+
send({ type: 'UPDATE_REGULAR_MESSAGES', messages: regularMessages });
|
|
189
|
+
setMessages(regularMessages);
|
|
190
|
+
const currentMessage = regularMessages?.[regularMessages.length - 1];
|
|
191
|
+
setSelectedPost(regularMessages[regularMessages.length - 1]);
|
|
192
|
+
setCurrentFiles(currentMessage?.propsConfiguration?.contents?.fragment?.files ?? {});
|
|
193
|
+
let canvasLayers = currentMessage?.propsConfiguration?.contents?.fragment?.canvasLayers ?? [];
|
|
194
|
+
const summary = currentMessage?.propsConfiguration?.contents?.fragment?.summary ?? null;
|
|
195
|
+
// If not in direct field, try to extract from summary
|
|
196
|
+
if (!canvasLayers && summary) {
|
|
197
|
+
const canvasLayersMatch = summary?.match(/<canvas_layers>([\s\S]*?)<\/canvas_layers>/);
|
|
198
|
+
if (canvasLayersMatch) {
|
|
199
|
+
try {
|
|
200
|
+
canvasLayers = JSON.parse(canvasLayersMatch[1]);
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error('Failed to parse canvas layers from summary:', error);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Update canvas layers if available
|
|
207
|
+
if (canvasLayers && Array.isArray(canvasLayers)) {
|
|
208
|
+
setCanvasLayers(canvasLayers);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
console.log('currenmessage', currentMessage);
|
|
212
|
+
if (currentMessage?.propsConfiguration?.contents?.role === 'ASSISTANT') {
|
|
213
|
+
//setIsLoading(false);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
scrollToBottom('smooth', 0);
|
|
217
|
+
}
|
|
218
|
+
}, [regularMessages, send]);
|
|
219
|
+
|
|
220
|
+
const handleGenerateAiCode = useCallback(
|
|
221
|
+
(messageId: string) => {
|
|
222
|
+
generateAiCode({
|
|
223
|
+
variables: {
|
|
224
|
+
messageId: messageId,
|
|
225
|
+
modelConfig: modelConfig,
|
|
226
|
+
},
|
|
227
|
+
onCompleted: (res) => {
|
|
228
|
+
if (res.generateAiCode.success) {
|
|
229
|
+
console.log('generated_result', res);
|
|
230
|
+
// Show AI is thinking loader on success
|
|
231
|
+
if (successThinkingTimeoutRef.current) {
|
|
232
|
+
clearTimeout(successThinkingTimeoutRef.current);
|
|
233
|
+
successThinkingTimeoutRef.current = null;
|
|
234
|
+
}
|
|
235
|
+
setIsSuccessThinking(true);
|
|
236
|
+
// Fallback auto-hide after 15s in case no subsequent event arrives
|
|
237
|
+
successThinkingTimeoutRef.current = setTimeout(() => {
|
|
238
|
+
setIsSuccessThinking(false);
|
|
239
|
+
// setIsLoading(false);
|
|
240
|
+
successThinkingTimeoutRef.current = null;
|
|
241
|
+
}, 15000);
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
onError: (err) => {
|
|
245
|
+
console.log('err', JSON.stringify(err, null, 2));
|
|
246
|
+
// Also ensure loader is hidden on error
|
|
247
|
+
if (successThinkingTimeoutRef.current) {
|
|
248
|
+
clearTimeout(successThinkingTimeoutRef.current);
|
|
249
|
+
successThinkingTimeoutRef.current = null;
|
|
250
|
+
}
|
|
251
|
+
setIsSuccessThinking(false);
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
},
|
|
255
|
+
[generateAiCode, modelConfig],
|
|
256
|
+
);
|
|
257
|
+
|
|
105
258
|
const onOpen = (element?: any) => {
|
|
106
259
|
setSelectedElement(element);
|
|
107
260
|
setIsOpen(true);
|
|
@@ -125,403 +278,205 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
125
278
|
}, delay);
|
|
126
279
|
}, []);
|
|
127
280
|
|
|
281
|
+
const recreateSandboxForFragment = useCallback(
|
|
282
|
+
async (messageId: string) => {
|
|
283
|
+
if (!actualChannelId) {
|
|
284
|
+
console.error('No project ID available for sandbox recreation');
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
try {
|
|
289
|
+
setIsLoading(true);
|
|
290
|
+
setError(null);
|
|
291
|
+
|
|
292
|
+
const response = await recreateSandbox({
|
|
293
|
+
variables: {
|
|
294
|
+
projectId: actualChannelId,
|
|
295
|
+
messageId,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
if (response.data?.recreateSandbox?.success) {
|
|
300
|
+
console.log('Sandbox recreation initiated successfully');
|
|
301
|
+
// The subscription will handle updating the UI with the new sandbox URL
|
|
302
|
+
} else {
|
|
303
|
+
const errorMsg = response.data?.recreateSandbox?.message || 'Failed to recreate sandbox';
|
|
304
|
+
throw new Error(errorMsg);
|
|
305
|
+
}
|
|
306
|
+
} catch (err) {
|
|
307
|
+
console.error('Error recreating sandbox:', err);
|
|
308
|
+
setError(err instanceof Error ? err.message : 'Failed to recreate sandbox');
|
|
309
|
+
setIsLoading(false);
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
[recreateSandbox, actualChannelId],
|
|
313
|
+
);
|
|
314
|
+
|
|
128
315
|
// Updated handleSend function from InboxWithAi.tsx
|
|
129
316
|
const handleSend = useCallback(
|
|
130
317
|
async (message: string, files: any[] = []) => {
|
|
131
318
|
// Allow sending if there's either a message or files
|
|
132
319
|
if ((!message || !message.trim()) && (!files || files.length === 0)) return;
|
|
133
|
-
if (!actualChannelId) return;
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
const postId = objectId();
|
|
137
|
-
const currentDate = new Date();
|
|
138
|
-
|
|
139
|
-
const createOptimisticMessage = (files?: any[]) => ({
|
|
140
|
-
__typename: 'Post' as const,
|
|
141
|
-
id: postId,
|
|
142
|
-
message,
|
|
143
|
-
createdAt: currentDate.toISOString(),
|
|
144
|
-
updatedAt: currentDate.toISOString(),
|
|
145
|
-
author: {
|
|
146
|
-
__typename: 'UserAccount' as const,
|
|
147
|
-
id: currentUser?.id,
|
|
148
|
-
givenName: currentUser?.profile?.given_name || '',
|
|
149
|
-
familyName: currentUser?.profile?.family_name || '',
|
|
150
|
-
email: currentUser?.profile?.email || '',
|
|
151
|
-
username: currentUser?.profile?.nickname || '',
|
|
152
|
-
fullName: currentUser?.profile?.name || '',
|
|
153
|
-
picture: currentUser?.profile?.picture || '',
|
|
154
|
-
alias: [currentUser?.authUserId ?? ''],
|
|
155
|
-
tokens: [],
|
|
156
|
-
},
|
|
157
|
-
isDelivered: false, // Will be true once confirmed by server
|
|
158
|
-
isRead: false,
|
|
159
|
-
type: 'Simple' as any,
|
|
160
|
-
parentId: null,
|
|
161
|
-
fromServer: false,
|
|
162
|
-
channel: {
|
|
163
|
-
__typename: 'Channel' as const,
|
|
164
|
-
id: actualChannelId,
|
|
165
|
-
},
|
|
166
|
-
propsConfiguration: {
|
|
167
|
-
__typename: 'MachineConfiguration' as const,
|
|
168
|
-
id: null,
|
|
169
|
-
resource: '' as any,
|
|
170
|
-
contents: null,
|
|
171
|
-
keys: null,
|
|
172
|
-
target: null,
|
|
173
|
-
overrides: null,
|
|
174
|
-
},
|
|
175
|
-
props: {},
|
|
176
|
-
files: {
|
|
177
|
-
__typename: 'FilesInfo' as const,
|
|
178
|
-
data: files || [],
|
|
179
|
-
totalCount: files?.length || 0,
|
|
180
|
-
},
|
|
181
|
-
replies: {
|
|
182
|
-
__typename: 'Messages' as const,
|
|
183
|
-
data: [],
|
|
184
|
-
totalCount: 0,
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
320
|
|
|
188
|
-
|
|
321
|
+
const validated = getValidatedConfig();
|
|
322
|
+
if (!validated && !hasApiKey) {
|
|
323
|
+
// No API key/config; do nothing (AiLandingInput would prompt config UI)
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
189
326
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
327
|
+
// Start the AI thinking loader immediately on send
|
|
328
|
+
if (successThinkingTimeoutRef.current) {
|
|
329
|
+
clearTimeout(successThinkingTimeoutRef.current);
|
|
330
|
+
successThinkingTimeoutRef.current = null;
|
|
331
|
+
}
|
|
332
|
+
setIsSuccessThinking(true);
|
|
333
|
+
setIsLoading(true);
|
|
334
|
+
// Safety auto-stop in case no event arrives
|
|
335
|
+
successThinkingTimeoutRef.current = setTimeout(() => {
|
|
336
|
+
setIsSuccessThinking(false);
|
|
337
|
+
successThinkingTimeoutRef.current = null;
|
|
338
|
+
}, 15000);
|
|
339
|
+
|
|
340
|
+
// If we already have a channel, send message (with optional file upload) similar to Inbox
|
|
341
|
+
if (actualChannelId) {
|
|
342
|
+
try {
|
|
343
|
+
const postId = objectId();
|
|
344
|
+
const channelId = objectId();
|
|
345
|
+
const currentDate = new Date();
|
|
346
|
+
|
|
347
|
+
const createOptimisticMessage = (uploadedFiles?: any[]) => ({
|
|
348
|
+
__typename: 'Post' as const,
|
|
349
|
+
id: postId,
|
|
350
|
+
message,
|
|
351
|
+
createdAt: currentDate.toISOString(),
|
|
352
|
+
updatedAt: currentDate.toISOString(),
|
|
353
|
+
author: {
|
|
354
|
+
__typename: 'UserAccount' as const,
|
|
355
|
+
id: auth?.id,
|
|
356
|
+
givenName: auth?.profile?.given_name || '',
|
|
357
|
+
familyName: auth?.profile?.family_name || '',
|
|
358
|
+
email: auth?.profile?.email || '',
|
|
359
|
+
username: auth?.profile?.nickname || '',
|
|
360
|
+
fullName: auth?.profile?.name || '',
|
|
361
|
+
picture: auth?.profile?.picture || '',
|
|
362
|
+
alias: [auth?.authUserId ?? ''],
|
|
363
|
+
tokens: [],
|
|
364
|
+
},
|
|
365
|
+
isDelivered: false,
|
|
366
|
+
isRead: false,
|
|
367
|
+
type: 'TEXT' as PostTypeEnum,
|
|
368
|
+
parentId: null,
|
|
369
|
+
fromServer: false,
|
|
370
|
+
channel: {
|
|
371
|
+
__typename: 'Channel' as const,
|
|
372
|
+
id: actualChannelId,
|
|
373
|
+
},
|
|
374
|
+
propsConfiguration: {
|
|
375
|
+
__typename: 'MachineConfiguration' as const,
|
|
376
|
+
id: null,
|
|
377
|
+
resource: '' as any,
|
|
378
|
+
contents: null,
|
|
379
|
+
keys: null,
|
|
380
|
+
target: null,
|
|
381
|
+
overrides: null,
|
|
382
|
+
},
|
|
383
|
+
props: {},
|
|
384
|
+
files: {
|
|
385
|
+
__typename: 'FilesInfo' as const,
|
|
386
|
+
data: uploadedFiles || [],
|
|
387
|
+
totalCount: uploadedFiles?.length || 0,
|
|
388
|
+
},
|
|
389
|
+
replies: {
|
|
390
|
+
__typename: 'Messages' as const,
|
|
391
|
+
data: [],
|
|
392
|
+
totalCount: 0,
|
|
393
|
+
},
|
|
195
394
|
});
|
|
196
395
|
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
396
|
+
const cacheMessagesQuery = {
|
|
397
|
+
query: MessagesDocument,
|
|
398
|
+
variables: {
|
|
399
|
+
// Match variables used in useMessagesQuery above
|
|
400
|
+
props: { projectId: actualChannelId.toString() },
|
|
401
|
+
parentId: null,
|
|
402
|
+
limit: MESSAGES_PER_PAGE,
|
|
403
|
+
},
|
|
404
|
+
} as const;
|
|
405
|
+
|
|
406
|
+
const extraProps = {
|
|
407
|
+
projectId: actualChannelId,
|
|
408
|
+
template: modelConfig?.template || 'vite-react',
|
|
409
|
+
role: 'USER',
|
|
410
|
+
sendNotificationWithProjectId: true,
|
|
411
|
+
} as any;
|
|
412
|
+
|
|
413
|
+
if (files?.length > 0) {
|
|
414
|
+
const uploadResponse = await startUpload({
|
|
415
|
+
file: files,
|
|
416
|
+
saveUploadedFile: { variables: { postId } },
|
|
417
|
+
createUploadLink: { variables: { postId } },
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
const uploadedFiles = uploadResponse.data as unknown as IFileInfo[];
|
|
421
|
+
const fileIds = (uploadedFiles || []).map((f: any) => f.id);
|
|
422
|
+
|
|
200
423
|
await sendMsg({
|
|
201
|
-
variables: {
|
|
424
|
+
variables: {
|
|
425
|
+
postId,
|
|
426
|
+
channelId: actualChannelId,
|
|
427
|
+
content: message,
|
|
428
|
+
files: fileIds,
|
|
429
|
+
extraProps,
|
|
430
|
+
},
|
|
202
431
|
optimisticResponse: {
|
|
203
432
|
__typename: 'Mutation',
|
|
204
433
|
sendMessage: createOptimisticMessage(uploadedFiles),
|
|
205
434
|
},
|
|
206
435
|
update: (cache, { data: mutationData }) => {
|
|
207
436
|
if (!mutationData?.sendMessage) return;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
messages: {
|
|
226
|
-
...existingData.messages,
|
|
227
|
-
data: [
|
|
228
|
-
...(existingData.messages.data || []),
|
|
229
|
-
mutationData.sendMessage,
|
|
230
|
-
],
|
|
231
|
-
totalCount: (existingData.messages.totalCount || 0) + 1,
|
|
232
|
-
},
|
|
233
|
-
},
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
} catch (error) {
|
|
237
|
-
console.debug('Cache update failed (expected on first message):', error);
|
|
437
|
+
if (mutationData?.sendMessage?.id) {
|
|
438
|
+
handleGenerateAiCode(mutationData.sendMessage.id);
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
} else {
|
|
443
|
+
await sendMsg({
|
|
444
|
+
variables: { channelId: actualChannelId, content: message, extraProps },
|
|
445
|
+
optimisticResponse: {
|
|
446
|
+
__typename: 'Mutation',
|
|
447
|
+
sendMessage: createOptimisticMessage(),
|
|
448
|
+
},
|
|
449
|
+
update: (cache, { data: mutationData }) => {
|
|
450
|
+
if (!mutationData?.sendMessage) return;
|
|
451
|
+
console.log('mutationData', JSON.stringify(mutationData, null, 2));
|
|
452
|
+
if (mutationData?.sendMessage?.id) {
|
|
453
|
+
handleGenerateAiCode(mutationData.sendMessage.id);
|
|
238
454
|
}
|
|
239
455
|
},
|
|
240
456
|
});
|
|
241
457
|
}
|
|
242
|
-
} else {
|
|
243
|
-
await sendMsg({
|
|
244
|
-
variables: { channelId: actualChannelId, content: message },
|
|
245
|
-
optimisticResponse: {
|
|
246
|
-
__typename: 'Mutation',
|
|
247
|
-
sendMessage: optimisticMessage,
|
|
248
|
-
},
|
|
249
|
-
update: (cache, { data: mutationData }) => {
|
|
250
|
-
if (!mutationData?.sendMessage) return;
|
|
251
|
-
|
|
252
|
-
// Update messages cache optimistically
|
|
253
|
-
const messagesQuery = {
|
|
254
|
-
query: MessagesDocument,
|
|
255
|
-
variables: {
|
|
256
|
-
channelId: actualChannelId.toString(),
|
|
257
|
-
parentId: null,
|
|
258
|
-
limit: MESSAGES_PER_PAGE,
|
|
259
|
-
},
|
|
260
|
-
};
|
|
261
458
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
data: {
|
|
268
|
-
messages: {
|
|
269
|
-
...existingData.messages,
|
|
270
|
-
data: [...(existingData.messages.data || []), mutationData.sendMessage],
|
|
271
|
-
totalCount: (existingData.messages.totalCount || 0) + 1,
|
|
272
|
-
},
|
|
273
|
-
},
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
} catch (error) {
|
|
277
|
-
console.debug('Cache update failed (expected on first message):', error);
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
});
|
|
459
|
+
// Scroll to bottom after send
|
|
460
|
+
scrollToBottom('smooth', 0);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
console.error('Error sending message from AIAgent:', error);
|
|
463
|
+
setIsLoading(false);
|
|
281
464
|
}
|
|
282
465
|
|
|
283
|
-
|
|
284
|
-
send({ type: 'SEND_MESSAGE', message: message.trim() });
|
|
285
|
-
|
|
286
|
-
// Ensure we scroll to the newest message immediately
|
|
287
|
-
scrollToBottom('smooth', 0);
|
|
288
|
-
|
|
289
|
-
// When sending new messages, increment the displayed count to show the new message
|
|
290
|
-
// This ensures we show both the existing last message and the new message
|
|
291
|
-
setDisplayedMessageCount((prev) => {
|
|
292
|
-
const newCount = Math.max(prev + 1, 2);
|
|
293
|
-
console.log('🔄 Message sent: Updating displayedMessageCount', {
|
|
294
|
-
previous: prev,
|
|
295
|
-
new: newCount,
|
|
296
|
-
reason: 'New message sent',
|
|
297
|
-
});
|
|
298
|
-
return newCount;
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// Call the optional onSendMessage prop if provided
|
|
302
|
-
if (onSendMessage) {
|
|
303
|
-
await onSendMessage(message, files);
|
|
304
|
-
}
|
|
305
|
-
} catch (error) {
|
|
306
|
-
console.error('Error sending message:', error);
|
|
466
|
+
return;
|
|
307
467
|
}
|
|
468
|
+
// If no channelId, we skip sending here.
|
|
308
469
|
},
|
|
309
|
-
[actualChannelId,
|
|
470
|
+
[actualChannelId, auth, startUpload, sendMsg, scrollToBottom, getValidatedConfig, hasApiKey, modelConfig],
|
|
310
471
|
);
|
|
311
472
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (currentProcessingMessage !== null) {
|
|
320
|
-
console.log('🤖 AI response received, clearing processing message');
|
|
321
|
-
setCurrentProcessingMessage(null);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Auto-scroll to bottom when new AI response appears
|
|
325
|
-
scrollToBottom('smooth', 200);
|
|
326
|
-
} else {
|
|
327
|
-
console.log('🤖 No AI messages in state - this might indicate an issue');
|
|
328
|
-
}
|
|
329
|
-
}, [aiMessages, currentProcessingMessage]);
|
|
330
|
-
|
|
331
|
-
// Debug effect to track machine state changes
|
|
332
|
-
useEffect(() => {
|
|
333
|
-
console.log('🤖 Machine state changed:', state.value);
|
|
334
|
-
console.log('🤖 Machine context:', {
|
|
335
|
-
messagesCount: state.context.messages.length,
|
|
336
|
-
hasMessageToRespondTo: !!state.context.messageToRespondTo,
|
|
337
|
-
messageToRespondTo: state.context.messageToRespondTo,
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
// Check if we're in processing state but no AI response is being generated
|
|
341
|
-
if (state.value === 'processing' && !state.context.messageToRespondTo) {
|
|
342
|
-
console.log('🤖 ⚠️ WARNING: In processing state but no messageToRespondTo!');
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Auto-scroll when AI starts processing
|
|
346
|
-
if (state.value === 'processing') {
|
|
347
|
-
scrollToBottom('smooth', 100);
|
|
348
|
-
}
|
|
349
|
-
}, [state.value, state.context, scrollToBottom]);
|
|
350
|
-
|
|
351
|
-
// Send regular messages to AI agent machine for context
|
|
352
|
-
useEffect(() => {
|
|
353
|
-
if (regularMessages && regularMessages.length > 0) {
|
|
354
|
-
send({ type: 'UPDATE_REGULAR_MESSAGES', messages: regularMessages });
|
|
355
|
-
}
|
|
356
|
-
}, [regularMessages, send]);
|
|
357
|
-
|
|
358
|
-
// Reset processed messages when regular messages change completely
|
|
359
|
-
useEffect(() => {
|
|
360
|
-
if (regularMessages && regularMessages.length > 0) {
|
|
361
|
-
// Check if we have completely new messages (different IDs)
|
|
362
|
-
const currentMessageIds = new Set(regularMessages.map((msg: any) => msg.id));
|
|
363
|
-
const hasNewMessages = !regularMessages.every((msg: any) => processedMessageIds.has(msg.id));
|
|
364
|
-
|
|
365
|
-
if (hasNewMessages) {
|
|
366
|
-
console.log('🤖 New messages detected, resetting processed state');
|
|
367
|
-
setProcessedMessageIds(new Set());
|
|
368
|
-
setCurrentProcessingMessage(null);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}, [regularMessages]);
|
|
372
|
-
|
|
373
|
-
// Sequential auto-response logic - respond to each message one at a time
|
|
374
|
-
useEffect(() => {
|
|
375
|
-
if (regularMessages && regularMessages.length > 0) {
|
|
376
|
-
console.log('🤖 Regular messages detected:', regularMessages.length);
|
|
377
|
-
console.log('🤖 Current AI messages:', aiMessages.length);
|
|
378
|
-
console.log('🤖 Already processed message IDs:', Array.from(processedMessageIds));
|
|
379
|
-
|
|
380
|
-
// Find messages that don't have AI responses yet and haven't been processed
|
|
381
|
-
const messagesWithoutAIResponses = regularMessages.filter((msg: any, index: number) => {
|
|
382
|
-
// Check if this message already has an AI response
|
|
383
|
-
const hasAIResponse = aiMessages.length > index;
|
|
384
|
-
// Check if this message has already been processed
|
|
385
|
-
const alreadyProcessed = processedMessageIds.has(msg.id);
|
|
386
|
-
return !hasAIResponse && !alreadyProcessed;
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
if (messagesWithoutAIResponses.length > 0) {
|
|
390
|
-
console.log(`🤖 Found ${messagesWithoutAIResponses.length} messages to process`);
|
|
391
|
-
|
|
392
|
-
// Simplified: Just process the first message and let the machine handle the rest
|
|
393
|
-
const firstMsg = messagesWithoutAIResponses[0];
|
|
394
|
-
console.log(`🤖 Starting with first message: ${firstMsg.message?.substring(0, 50)}...`);
|
|
395
|
-
|
|
396
|
-
// Mark this message as being processed
|
|
397
|
-
setProcessedMessageIds((prev) => new Set([...prev, firstMsg.id]));
|
|
398
|
-
setCurrentProcessingMessage(0);
|
|
399
|
-
|
|
400
|
-
// Send the first message to AI
|
|
401
|
-
send({ type: 'AUTO_RESPOND_TO_MESSAGE', message: firstMsg.message, isAutoResponse: true });
|
|
402
|
-
} else {
|
|
403
|
-
console.log('🤖 All messages already have AI responses or are being processed');
|
|
404
|
-
setCurrentProcessingMessage(null);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}, [regularMessages.length, aiMessages.length, processedMessageIds.size]); // Only depend on lengths and processed count
|
|
408
|
-
|
|
409
|
-
// Process next message when machine becomes idle (after completing AI response)
|
|
410
|
-
useEffect(() => {
|
|
411
|
-
// Only run when machine is idle and we have messages to process
|
|
412
|
-
if (state.matches('idle') && regularMessages && regularMessages.length > 0) {
|
|
413
|
-
console.log('🤖 Machine idle, checking for next message to process...');
|
|
414
|
-
console.log(
|
|
415
|
-
'🤖 Current state - AI messages:',
|
|
416
|
-
aiMessages.length,
|
|
417
|
-
'Processed IDs:',
|
|
418
|
-
processedMessageIds.size,
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
// Find the next message that needs an AI response
|
|
422
|
-
const nextMessageIndex = regularMessages.findIndex((msg: any, index: number) => {
|
|
423
|
-
const hasAIResponse = aiMessages.length > index;
|
|
424
|
-
const alreadyProcessed = processedMessageIds.has(msg.id);
|
|
425
|
-
const needsResponse = !hasAIResponse && !alreadyProcessed;
|
|
426
|
-
|
|
427
|
-
console.log(
|
|
428
|
-
`🤖 Message ${index + 1} "${msg.message?.substring(
|
|
429
|
-
0,
|
|
430
|
-
30,
|
|
431
|
-
)}..." - hasAIResponse: ${hasAIResponse}, alreadyProcessed: ${alreadyProcessed}, needsResponse: ${needsResponse}`,
|
|
432
|
-
);
|
|
433
|
-
|
|
434
|
-
return needsResponse;
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
if (nextMessageIndex !== -1) {
|
|
438
|
-
console.log(
|
|
439
|
-
`🤖 Found next message to process: ${nextMessageIndex + 1}: ${regularMessages[
|
|
440
|
-
nextMessageIndex
|
|
441
|
-
].message?.substring(0, 50)}...`,
|
|
442
|
-
);
|
|
443
|
-
|
|
444
|
-
// Check if this message is a duplicate of a previous one
|
|
445
|
-
const currentMessage = regularMessages[nextMessageIndex];
|
|
446
|
-
const previousMessageIndex = regularMessages.findIndex(
|
|
447
|
-
(prevMsg: any, prevIndex: number) =>
|
|
448
|
-
prevIndex < nextMessageIndex && prevMsg.message === currentMessage.message,
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
if (previousMessageIndex !== -1 && aiMessages.length > previousMessageIndex) {
|
|
452
|
-
// This is a duplicate message, mark it as processed without sending to AI
|
|
453
|
-
console.log(
|
|
454
|
-
`🤖 Duplicate message detected: "${
|
|
455
|
-
currentMessage.message
|
|
456
|
-
}" - reusing AI response from message ${previousMessageIndex + 1}`,
|
|
457
|
-
);
|
|
458
|
-
setProcessedMessageIds((prev) => new Set([...prev, currentMessage.id]));
|
|
459
|
-
setCurrentProcessingMessage(null);
|
|
460
|
-
|
|
461
|
-
// Continue with next message immediately
|
|
462
|
-
setTimeout(() => {
|
|
463
|
-
send({ type: 'CONTINUE_PROCESSING' });
|
|
464
|
-
}, 100);
|
|
465
|
-
} else {
|
|
466
|
-
// Mark this message as being processed
|
|
467
|
-
setProcessedMessageIds((prev) => new Set([...prev, currentMessage.id]));
|
|
468
|
-
setCurrentProcessingMessage(nextMessageIndex);
|
|
469
|
-
|
|
470
|
-
// Send to AI
|
|
471
|
-
console.log(`🤖 Sending message to AI: "${currentMessage.message}"`);
|
|
472
|
-
send({ type: 'AUTO_RESPOND_TO_MESSAGE', message: currentMessage.message, isAutoResponse: true });
|
|
473
|
-
}
|
|
474
|
-
} else {
|
|
475
|
-
// Check if we actually have all responses
|
|
476
|
-
const totalMessagesNeedingResponses = regularMessages.length;
|
|
477
|
-
const messagesWithResponses = aiMessages.length;
|
|
478
|
-
const messagesProcessed = processedMessageIds.size;
|
|
479
|
-
|
|
480
|
-
console.log(`🤖 No more messages to process. Summary:`, {
|
|
481
|
-
totalMessages: totalMessagesNeedingResponses,
|
|
482
|
-
messagesWithResponses,
|
|
483
|
-
messagesProcessed,
|
|
484
|
-
allHaveResponses: messagesWithResponses >= totalMessagesNeedingResponses,
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
if (messagesWithResponses >= totalMessagesNeedingResponses) {
|
|
488
|
-
console.log('🤖 All messages have been processed successfully');
|
|
489
|
-
setCurrentProcessingMessage(null);
|
|
490
|
-
} else {
|
|
491
|
-
console.log('🤖 ⚠️ Discrepancy detected: Some messages may not have proper AI responses');
|
|
492
|
-
// Force a reset to try again
|
|
493
|
-
setProcessedMessageIds(new Set());
|
|
494
|
-
setCurrentProcessingMessage(null);
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}, [state.value, regularMessages, aiMessages.length, processedMessageIds.size, send]);
|
|
499
|
-
|
|
500
|
-
// Reset processing state when regularMessages change significantly
|
|
501
|
-
useEffect(() => {
|
|
502
|
-
if (regularMessages && regularMessages.length > 0) {
|
|
503
|
-
// Reset processing state when we get new messages
|
|
504
|
-
setProcessedMessageIds(new Set());
|
|
505
|
-
setCurrentProcessingMessage(null);
|
|
506
|
-
console.log('🤖 Reset processing state for new messages');
|
|
507
|
-
}
|
|
508
|
-
}, [regularMessages.length]); // Only depend on length to avoid unnecessary resets
|
|
509
|
-
|
|
510
|
-
// Only reset displayed message count on initial load, not when new messages arrive
|
|
511
|
-
useEffect(() => {
|
|
512
|
-
if (regularMessages && regularMessages.length > 0) {
|
|
513
|
-
// Only reset to show last message if this is the first time we're getting messages
|
|
514
|
-
// or if we're currently showing more messages than we have
|
|
515
|
-
if (displayedMessageCount === 1 || displayedMessageCount > regularMessages.length) {
|
|
516
|
-
console.log('🔄 Resetting displayedMessageCount to 1:', {
|
|
517
|
-
reason: 'Initial load or count mismatch',
|
|
518
|
-
currentDisplayed: displayedMessageCount,
|
|
519
|
-
regularMessagesLength: regularMessages.length,
|
|
520
|
-
});
|
|
521
|
-
setDisplayedMessageCount(1);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}, [regularMessages.length, displayedMessageCount]);
|
|
473
|
+
const fixError = useCallback(
|
|
474
|
+
(errorMessage: string) => {
|
|
475
|
+
// Use sendMessage to fix the error, which will use createProject flow
|
|
476
|
+
return handleSend(errorMessage);
|
|
477
|
+
},
|
|
478
|
+
[handleSend],
|
|
479
|
+
);
|
|
525
480
|
|
|
526
481
|
const handleRetry = useCallback(() => {
|
|
527
482
|
send({ type: 'RETRY' });
|
|
@@ -531,200 +486,24 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
531
486
|
send({ type: 'CLEAR_ERROR' });
|
|
532
487
|
}, [send]);
|
|
533
488
|
|
|
534
|
-
//
|
|
489
|
+
// Use only default/regular messages and ignore AI messages
|
|
535
490
|
const allMessages = useMemo(() => {
|
|
536
491
|
if (!regularMessages) return [] as any[];
|
|
537
492
|
|
|
538
|
-
console.log(
|
|
539
|
-
'🔄 Merging messages - AI messages:',
|
|
540
|
-
aiMessages.length,
|
|
541
|
-
'Regular messages:',
|
|
542
|
-
regularMessages.length,
|
|
543
|
-
);
|
|
544
|
-
console.log(
|
|
545
|
-
'🔄 AI messages content:',
|
|
546
|
-
aiMessages.map((m) => ({ id: m.id, content: m.content.substring(0, 50) + '...', sender: m.sender })),
|
|
547
|
-
);
|
|
548
|
-
|
|
549
493
|
const regularMessagesFormatted = (regularMessages || []).map((m, idx) => ({
|
|
550
494
|
id: m.id || `regular-${idx}`,
|
|
551
495
|
message: (m as any).message || (m as any).content || '',
|
|
552
496
|
createdAt: new Date((m as any).createdAt || Date.now()),
|
|
497
|
+
propsConfiguration: (m as any).propsConfiguration,
|
|
498
|
+
props: (m as any).props,
|
|
499
|
+
files: (m as any).files,
|
|
553
500
|
sender: 'user',
|
|
554
501
|
author: (m as any).author,
|
|
555
|
-
isUserMessage: true,
|
|
556
|
-
}));
|
|
557
|
-
|
|
558
|
-
const aiMessagesFormatted = (aiMessages || []).map((m) => ({
|
|
559
|
-
id: m.id,
|
|
560
|
-
message: m.content,
|
|
561
|
-
createdAt: new Date(m.timestamp || Date.now()),
|
|
562
|
-
sender: 'ai',
|
|
563
|
-
isUserMessage: false, // Explicitly mark as AI message
|
|
502
|
+
isUserMessage: true,
|
|
564
503
|
}));
|
|
565
504
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
console.log('🔄 Starting message interleaving...');
|
|
570
|
-
console.log('🔄 Regular messages count:', regularMessagesFormatted.length);
|
|
571
|
-
console.log('🔄 AI messages count:', aiMessagesFormatted.length);
|
|
572
|
-
|
|
573
|
-
for (let i = 0; i < regularMessagesFormatted.length; i++) {
|
|
574
|
-
const userMsg = regularMessagesFormatted[i];
|
|
575
|
-
console.log(`🔄 Processing user message ${i + 1}:`, {
|
|
576
|
-
id: userMsg.id,
|
|
577
|
-
message: userMsg.message.substring(0, 50),
|
|
578
|
-
sender: userMsg.sender,
|
|
579
|
-
isUserMessage: userMsg.isUserMessage,
|
|
580
|
-
author: userMsg.author,
|
|
581
|
-
});
|
|
582
|
-
|
|
583
|
-
interleavedMessages.push(userMsg);
|
|
584
|
-
console.log(`🔄 Added user message ${i + 1}: ${userMsg.message.substring(0, 50)}...`);
|
|
585
|
-
|
|
586
|
-
// Check if this message is a duplicate of a previous one
|
|
587
|
-
const isDuplicate =
|
|
588
|
-
i > 0 && regularMessagesFormatted.slice(0, i).some((prevMsg) => prevMsg.message === userMsg.message);
|
|
589
|
-
|
|
590
|
-
if (isDuplicate) {
|
|
591
|
-
// Find the first occurrence of this message to get its AI response
|
|
592
|
-
const firstOccurrenceIndex = regularMessagesFormatted.findIndex(
|
|
593
|
-
(msg) => msg.message === userMsg.message,
|
|
594
|
-
);
|
|
595
|
-
const hasAIResponseForFirst = firstOccurrenceIndex < aiMessagesFormatted.length;
|
|
596
|
-
|
|
597
|
-
if (hasAIResponseForFirst) {
|
|
598
|
-
// Reuse the AI response from the first occurrence
|
|
599
|
-
const aiResponse = aiMessagesFormatted[firstOccurrenceIndex];
|
|
600
|
-
const adjustedCreatedAt = new Date(userMsg.createdAt.getTime() + 1);
|
|
601
|
-
const finalAiResponse = {
|
|
602
|
-
...aiResponse,
|
|
603
|
-
createdAt: adjustedCreatedAt,
|
|
604
|
-
id: `duplicate-${aiResponse.id}-${i}`,
|
|
605
|
-
isDuplicate: true,
|
|
606
|
-
};
|
|
607
|
-
interleavedMessages.push(finalAiResponse);
|
|
608
|
-
console.log(
|
|
609
|
-
`🔄 Added duplicate AI response for message ${i + 1} (reusing from message ${
|
|
610
|
-
firstOccurrenceIndex + 1
|
|
611
|
-
}):`,
|
|
612
|
-
{
|
|
613
|
-
id: finalAiResponse.id,
|
|
614
|
-
message: finalAiResponse.message.substring(0, 50),
|
|
615
|
-
sender: finalAiResponse.sender,
|
|
616
|
-
isUserMessage: finalAiResponse.isUserMessage,
|
|
617
|
-
isDuplicate: finalAiResponse.isDuplicate,
|
|
618
|
-
},
|
|
619
|
-
);
|
|
620
|
-
} else {
|
|
621
|
-
// First occurrence doesn't have AI response yet, show loading
|
|
622
|
-
const loadingMessage = {
|
|
623
|
-
id: `loading-duplicate-${i}`,
|
|
624
|
-
message: 'Loading...', // Shorter text since we show visual loader
|
|
625
|
-
createdAt: new Date(userMsg.createdAt.getTime() + 1),
|
|
626
|
-
sender: 'ai',
|
|
627
|
-
isLoading: true,
|
|
628
|
-
isProcessing: false,
|
|
629
|
-
isUserMessage: false,
|
|
630
|
-
isDuplicate: true,
|
|
631
|
-
};
|
|
632
|
-
interleavedMessages.push(loadingMessage);
|
|
633
|
-
console.log(`🔄 Added loading indicator for duplicate message ${i + 1}:`, {
|
|
634
|
-
id: loadingMessage.id,
|
|
635
|
-
message: loadingMessage.message,
|
|
636
|
-
isDuplicate: loadingMessage.isDuplicate,
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
} else {
|
|
640
|
-
// This is not a duplicate, handle normally
|
|
641
|
-
if (i < aiMessagesFormatted.length) {
|
|
642
|
-
const aiResponse = aiMessagesFormatted[i];
|
|
643
|
-
// Ensure AI response sorts after corresponding user message
|
|
644
|
-
const adjustedCreatedAt = new Date(userMsg.createdAt.getTime() + 1);
|
|
645
|
-
const finalAiResponse = { ...aiResponse, createdAt: adjustedCreatedAt };
|
|
646
|
-
interleavedMessages.push(finalAiResponse);
|
|
647
|
-
console.log(`🔄 Added AI response for message ${i + 1}:`, {
|
|
648
|
-
id: finalAiResponse.id,
|
|
649
|
-
message: finalAiResponse.message.substring(0, 50),
|
|
650
|
-
sender: finalAiResponse.sender,
|
|
651
|
-
isUserMessage: finalAiResponse.isUserMessage,
|
|
652
|
-
});
|
|
653
|
-
} else {
|
|
654
|
-
// Add a loading indicator for messages waiting for AI responses
|
|
655
|
-
const loadingMessage = {
|
|
656
|
-
id: `loading-${i}`,
|
|
657
|
-
message: 'Loading...', // Shorter text since we show visual loader
|
|
658
|
-
createdAt: new Date(userMsg.createdAt.getTime() + 1),
|
|
659
|
-
sender: 'ai',
|
|
660
|
-
isLoading: true,
|
|
661
|
-
isProcessing: currentProcessingMessage === i,
|
|
662
|
-
isUserMessage: false, // Explicitly mark as not a user message
|
|
663
|
-
};
|
|
664
|
-
interleavedMessages.push(loadingMessage);
|
|
665
|
-
console.log(`🔄 Added loading indicator for message ${i + 1}:`, {
|
|
666
|
-
id: loadingMessage.id,
|
|
667
|
-
message: loadingMessage.message,
|
|
668
|
-
sender: loadingMessage.sender,
|
|
669
|
-
isUserMessage: loadingMessage.isUserMessage,
|
|
670
|
-
isProcessing: loadingMessage.isProcessing,
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
console.log('🔄 Final interleaved messages:', interleavedMessages.length);
|
|
677
|
-
console.log(
|
|
678
|
-
'🔄 Message structure:',
|
|
679
|
-
interleavedMessages.map((m) => ({
|
|
680
|
-
sender: m.sender,
|
|
681
|
-
isUserMessage: m.isUserMessage,
|
|
682
|
-
message: m.message.substring(0, 30) + '...',
|
|
683
|
-
})),
|
|
684
|
-
);
|
|
685
|
-
|
|
686
|
-
return interleavedMessages;
|
|
687
|
-
}, [aiMessages, regularMessages, currentUser, currentProcessingMessage]);
|
|
688
|
-
|
|
689
|
-
// Update hasMoreMessages when allMessages changes
|
|
690
|
-
useEffect(() => {
|
|
691
|
-
if (allMessages && allMessages.length > 0) {
|
|
692
|
-
// Count complete conversation pairs instead of individual messages
|
|
693
|
-
const conversationPairs = Math.ceil(allMessages.length / 2);
|
|
694
|
-
console.log('🔄 Conversation pairs calculation:', {
|
|
695
|
-
totalMessages: allMessages.length,
|
|
696
|
-
conversationPairs,
|
|
697
|
-
displayedMessageCount,
|
|
698
|
-
hasMore: conversationPairs > displayedMessageCount,
|
|
699
|
-
});
|
|
700
|
-
|
|
701
|
-
// Show "Load Past Messages" whenever there are more conversation pairs
|
|
702
|
-
// than currently displayed (including initial view)
|
|
703
|
-
const hasMore = conversationPairs > displayedMessageCount;
|
|
704
|
-
setHasMoreMessages(hasMore);
|
|
705
|
-
|
|
706
|
-
// Ensure we always show at least the last conversation
|
|
707
|
-
if (displayedMessageCount === 0) {
|
|
708
|
-
setDisplayedMessageCount(1);
|
|
709
|
-
}
|
|
710
|
-
} else {
|
|
711
|
-
setHasMoreMessages(false);
|
|
712
|
-
}
|
|
713
|
-
}, [allMessages, displayedMessageCount]);
|
|
714
|
-
|
|
715
|
-
// Function to load more past messages
|
|
716
|
-
const loadMoreMessages = useCallback(() => {
|
|
717
|
-
if (allMessages && allMessages.length > 0) {
|
|
718
|
-
// Load more conversation pairs (5 pairs = 10 messages)
|
|
719
|
-
const conversationPairs = Math.ceil(allMessages.length / 2);
|
|
720
|
-
setDisplayedMessageCount((prev) => Math.min(prev + 5, conversationPairs));
|
|
721
|
-
}
|
|
722
|
-
}, [allMessages]);
|
|
723
|
-
|
|
724
|
-
// Function to reset to showing only last message
|
|
725
|
-
const resetToLastMessage = useCallback(() => {
|
|
726
|
-
setDisplayedMessageCount(1);
|
|
727
|
-
}, []);
|
|
505
|
+
return regularMessagesFormatted;
|
|
506
|
+
}, [regularMessages, currentUser]);
|
|
728
507
|
|
|
729
508
|
// Build list with date separators similar to MessagesBuilderUi
|
|
730
509
|
const messageListWithDates = useMemo(() => {
|
|
@@ -778,59 +557,11 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
778
557
|
return sections;
|
|
779
558
|
}, [messageListWithDates]);
|
|
780
559
|
|
|
781
|
-
//
|
|
560
|
+
// Show all messages without limiting
|
|
782
561
|
const limitedMessagesByDate = useMemo(() => {
|
|
783
562
|
if (!messagesByDate || messagesByDate.length === 0) return [];
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
let conversationPairs = 0;
|
|
787
|
-
const limitedSections: { date: string | null; messages: any[] }[] = [];
|
|
788
|
-
|
|
789
|
-
// Start from the end (most recent messages) and work backwards
|
|
790
|
-
for (let i = messagesByDate.length - 1; i >= 0; i--) {
|
|
791
|
-
const section = messagesByDate[i];
|
|
792
|
-
const sectionMessages = [...section.messages];
|
|
793
|
-
|
|
794
|
-
// Count conversation pairs in this section
|
|
795
|
-
let sectionPairs = 0;
|
|
796
|
-
for (let j = 0; j < sectionMessages.length; j++) {
|
|
797
|
-
const currentMsg = sectionMessages[j];
|
|
798
|
-
if (currentMsg.sender === 'user' || currentMsg.isUserMessage) {
|
|
799
|
-
// Check if there's an AI response following this user message
|
|
800
|
-
if (j + 1 < sectionMessages.length) {
|
|
801
|
-
const nextMsg = sectionMessages[j + 1];
|
|
802
|
-
if (nextMsg.sender === 'ai' || !nextMsg.isUserMessage) {
|
|
803
|
-
sectionPairs++;
|
|
804
|
-
j++; // Skip the AI response since we counted it as a pair
|
|
805
|
-
}
|
|
806
|
-
} else {
|
|
807
|
-
sectionPairs++; // User message without AI response still counts
|
|
808
|
-
}
|
|
809
|
-
} else if (currentMsg.sender === 'ai' || !currentMsg.isUserMessage) {
|
|
810
|
-
// AI message without preceding user message counts as half a pair
|
|
811
|
-
sectionPairs += 0.5;
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// If this section would exceed our limit, only take what we can fit
|
|
816
|
-
if (conversationPairs + sectionPairs > displayedMessageCount) {
|
|
817
|
-
const remainingPairs = displayedMessageCount - conversationPairs;
|
|
818
|
-
if (remainingPairs > 0) {
|
|
819
|
-
// Take only the last N conversation pairs from this section
|
|
820
|
-
const limitedMessages = sectionMessages.slice(-Math.floor(remainingPairs * 2));
|
|
821
|
-
limitedSections.unshift({ ...section, messages: limitedMessages });
|
|
822
|
-
conversationPairs += remainingPairs;
|
|
823
|
-
}
|
|
824
|
-
break;
|
|
825
|
-
} else {
|
|
826
|
-
// We can fit this entire section
|
|
827
|
-
limitedSections.unshift(section);
|
|
828
|
-
conversationPairs += sectionPairs;
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
return limitedSections;
|
|
833
|
-
}, [messagesByDate, displayedMessageCount]);
|
|
563
|
+
return messagesByDate;
|
|
564
|
+
}, [messagesByDate]);
|
|
834
565
|
|
|
835
566
|
// Ensure we show complete conversation pairs (user message + AI response)
|
|
836
567
|
const completeConversationMessages = useMemo(() => {
|
|
@@ -893,15 +624,31 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
893
624
|
|
|
894
625
|
// Auto scroll to bottom when messages, typing status, or AI responses change
|
|
895
626
|
useEffect(() => {
|
|
896
|
-
scrollToBottom('smooth', 100);
|
|
627
|
+
// scrollToBottom('smooth', 100);
|
|
897
628
|
}, [completeConversationMessages?.length, isTyping, aiMessages.length, scrollToBottom]);
|
|
898
629
|
|
|
899
|
-
//
|
|
630
|
+
// Cleanup any pending timeout on unmount
|
|
900
631
|
useEffect(() => {
|
|
901
|
-
|
|
902
|
-
|
|
632
|
+
return () => {
|
|
633
|
+
if (successThinkingTimeoutRef.current) {
|
|
634
|
+
clearTimeout(successThinkingTimeoutRef.current);
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
}, []);
|
|
638
|
+
|
|
639
|
+
const extractCleanContent = useCallback((summary: string): string => {
|
|
640
|
+
if (!summary) return 'Project generated successfully!';
|
|
641
|
+
|
|
642
|
+
// Extract content from <task_summary> tags
|
|
643
|
+
const taskSummaryMatch = summary.match(/<task_summary>([\s\S]*?)<\/task_summary>/);
|
|
644
|
+
if (taskSummaryMatch) {
|
|
645
|
+
return taskSummaryMatch[1].trim();
|
|
903
646
|
}
|
|
904
|
-
|
|
647
|
+
|
|
648
|
+
// If no task_summary tags, remove canvas_layers and return the rest
|
|
649
|
+
const withoutCanvasLayers = summary.replace(/<canvas_layers>[\s\S]*?<\/canvas_layers>/g, '').trim();
|
|
650
|
+
return withoutCanvasLayers || 'Project generated successfully!';
|
|
651
|
+
}, []);
|
|
905
652
|
|
|
906
653
|
return (
|
|
907
654
|
<div className={`flex flex-col h-full ${className}`}>
|
|
@@ -937,14 +684,8 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
937
684
|
</div>
|
|
938
685
|
|
|
939
686
|
{/* New Chat Button */}
|
|
940
|
-
<button
|
|
687
|
+
{/* <button
|
|
941
688
|
onClick={() => {
|
|
942
|
-
// Reset to show only the last message for new chat
|
|
943
|
-
setDisplayedMessageCount(1);
|
|
944
|
-
setHasMoreMessages(false);
|
|
945
|
-
// Clear processing state
|
|
946
|
-
setProcessedMessageIds(new Set());
|
|
947
|
-
setCurrentProcessingMessage(null);
|
|
948
689
|
// Clear AI messages by sending update event to the machine
|
|
949
690
|
send({ type: 'UPDATE', value: { messages: [] } });
|
|
950
691
|
}}
|
|
@@ -952,7 +693,7 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
952
693
|
style={{ borderRadius: '10px' }}
|
|
953
694
|
>
|
|
954
695
|
New Chat
|
|
955
|
-
</button>
|
|
696
|
+
</button> */}
|
|
956
697
|
</div>
|
|
957
698
|
</div>
|
|
958
699
|
|
|
@@ -1001,72 +742,84 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
1001
742
|
{/* Message History List */}
|
|
1002
743
|
<div className="px-4 py-2">
|
|
1003
744
|
{regularMessages && regularMessages.length > 0 ? (
|
|
1004
|
-
regularMessages
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
<div
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
745
|
+
regularMessages
|
|
746
|
+
.filter((msg: any) => (msg as any)?.propsConfiguration?.contents?.role === 'USER')
|
|
747
|
+
.map((msg: any, index: number) => {
|
|
748
|
+
const messageTime = new Date(msg.createdAt);
|
|
749
|
+
|
|
750
|
+
return (
|
|
751
|
+
<div key={msg.id || index} className="mb-4">
|
|
752
|
+
{/* Restore to this point button */}
|
|
753
|
+
<div className="flex items-center justify-end mb-2">
|
|
754
|
+
<button className="text-blue-600 text-sm underline hover:text-blue-800 flex items-center">
|
|
755
|
+
<svg
|
|
756
|
+
className="w-4 h-4 mr-1"
|
|
757
|
+
fill="none"
|
|
758
|
+
viewBox="0 0 24 24"
|
|
759
|
+
stroke="currentColor"
|
|
760
|
+
>
|
|
761
|
+
<path
|
|
762
|
+
strokeLinecap="round"
|
|
763
|
+
strokeLinejoin="round"
|
|
764
|
+
strokeWidth={2}
|
|
765
|
+
d="M15 19l-7-7 7-7"
|
|
766
|
+
/>
|
|
767
|
+
</svg>
|
|
768
|
+
Restore to this point
|
|
769
|
+
</button>
|
|
770
|
+
</div>
|
|
771
|
+
|
|
772
|
+
{/* Message using same container as Chat tab */}
|
|
773
|
+
<ModernMessageGroupComponent
|
|
774
|
+
messages={[
|
|
775
|
+
{
|
|
776
|
+
id: msg.id,
|
|
777
|
+
//message: msg.message || msg.content || 'No message content',
|
|
778
|
+
message:
|
|
779
|
+
(msg as any)?.propsConfiguration?.contents?.role ===
|
|
780
|
+
'ASSISTANT'
|
|
781
|
+
? msg.propsConfiguration?.contents?.fragment?.summary
|
|
782
|
+
? extractCleanContent(
|
|
783
|
+
msg.propsConfiguration?.contents?.fragment
|
|
784
|
+
?.summary,
|
|
785
|
+
)
|
|
786
|
+
: msg.message
|
|
787
|
+
: msg.message,
|
|
788
|
+
author: msg.author || {
|
|
789
|
+
id: 'user',
|
|
790
|
+
givenName: 'User',
|
|
791
|
+
familyName: '',
|
|
792
|
+
fullName: 'User',
|
|
793
|
+
username: 'user',
|
|
794
|
+
email: '',
|
|
795
|
+
picture: null,
|
|
796
|
+
alias: [],
|
|
797
|
+
tokens: [],
|
|
798
|
+
},
|
|
799
|
+
createdAt: msg.createdAt,
|
|
800
|
+
type: 'Simple' as any,
|
|
801
|
+
isDelivered: false,
|
|
802
|
+
isRead: false,
|
|
803
|
+
parentId: null,
|
|
804
|
+
fromServer: null,
|
|
805
|
+
updatedAt: msg.createdAt,
|
|
806
|
+
propsConfiguration: msg.propsConfiguration,
|
|
807
|
+
props: msg.props,
|
|
808
|
+
files: msg.files,
|
|
809
|
+
replies: null,
|
|
810
|
+
channel: null,
|
|
811
|
+
isPinned: false,
|
|
1045
812
|
},
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
replies: null,
|
|
1057
|
-
channel: null,
|
|
1058
|
-
isPinned: false,
|
|
1059
|
-
},
|
|
1060
|
-
]}
|
|
1061
|
-
currentUser={currentUser as any}
|
|
1062
|
-
onOpen={onOpen}
|
|
1063
|
-
onMessageClick={() => {}}
|
|
1064
|
-
isDesktopView={isDesktopView}
|
|
1065
|
-
isSmallScreen={isSmallScreen}
|
|
1066
|
-
/>
|
|
1067
|
-
</div>
|
|
1068
|
-
);
|
|
1069
|
-
})
|
|
813
|
+
]}
|
|
814
|
+
currentUser={currentUser as any}
|
|
815
|
+
onOpen={onOpen}
|
|
816
|
+
onMessageClick={(msg) => setSelectedPost(msg)}
|
|
817
|
+
isDesktopView={isDesktopView}
|
|
818
|
+
isSmallScreen={isSmallScreen}
|
|
819
|
+
/>
|
|
820
|
+
</div>
|
|
821
|
+
);
|
|
822
|
+
})
|
|
1070
823
|
) : (
|
|
1071
824
|
// Fallback entries when no messages
|
|
1072
825
|
<>
|
|
@@ -1108,16 +861,7 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
1108
861
|
}`}
|
|
1109
862
|
>
|
|
1110
863
|
{/* Load Past Messages Button */}
|
|
1111
|
-
{
|
|
1112
|
-
<div className="px-4 py-3 text-center">
|
|
1113
|
-
<button
|
|
1114
|
-
onClick={loadMoreMessages}
|
|
1115
|
-
className="px-4 py-2 text-sm text-gray-600 bg-gray-100 border border-gray-300 rounded-lg hover:bg-gray-200 transition-colors"
|
|
1116
|
-
>
|
|
1117
|
-
Load Past Messages
|
|
1118
|
-
</button>
|
|
1119
|
-
</div>
|
|
1120
|
-
)}
|
|
864
|
+
{/* Load Past Messages disabled to show all messages */}
|
|
1121
865
|
|
|
1122
866
|
{/* Show placeholder when no messages */}
|
|
1123
867
|
{(!completeConversationMessages || completeConversationMessages.length === 0) && (
|
|
@@ -1170,7 +914,18 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
1170
914
|
messages={[
|
|
1171
915
|
{
|
|
1172
916
|
id: msg.id,
|
|
1173
|
-
message: msg.message,
|
|
917
|
+
// message: msg.message,
|
|
918
|
+
message:
|
|
919
|
+
(msg as any)?.propsConfiguration?.contents?.role ===
|
|
920
|
+
'ASSISTANT'
|
|
921
|
+
? msg.propsConfiguration?.contents?.fragment
|
|
922
|
+
?.summary
|
|
923
|
+
? extractCleanContent(
|
|
924
|
+
msg.propsConfiguration?.contents?.fragment
|
|
925
|
+
?.summary,
|
|
926
|
+
)
|
|
927
|
+
: msg.message
|
|
928
|
+
: msg.message,
|
|
1174
929
|
author:
|
|
1175
930
|
msg.sender === 'user'
|
|
1176
931
|
? msg.author
|
|
@@ -1192,9 +947,9 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
1192
947
|
parentId: null,
|
|
1193
948
|
fromServer: null,
|
|
1194
949
|
updatedAt: msg.createdAt,
|
|
1195
|
-
propsConfiguration:
|
|
1196
|
-
props:
|
|
1197
|
-
files:
|
|
950
|
+
propsConfiguration: msg.propsConfiguration,
|
|
951
|
+
props: msg.props,
|
|
952
|
+
files: msg.files,
|
|
1198
953
|
replies: null,
|
|
1199
954
|
channel: null,
|
|
1200
955
|
isPinned: false,
|
|
@@ -1202,9 +957,13 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
1202
957
|
]}
|
|
1203
958
|
currentUser={currentUser as any}
|
|
1204
959
|
onOpen={onOpen}
|
|
1205
|
-
onMessageClick={() =>
|
|
960
|
+
onMessageClick={(msg) => setSelectedPost(msg)}
|
|
1206
961
|
isDesktopView={isDesktopView}
|
|
1207
962
|
isSmallScreen={isSmallScreen}
|
|
963
|
+
sandboxErrors={sandboxErrors}
|
|
964
|
+
currentFiles={currentFiles}
|
|
965
|
+
onFixError={fixError}
|
|
966
|
+
onRecreateSandbox={recreateSandboxForFragment}
|
|
1208
967
|
/>
|
|
1209
968
|
)}
|
|
1210
969
|
</div>
|
|
@@ -1214,7 +973,7 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
1214
973
|
))}
|
|
1215
974
|
|
|
1216
975
|
{/* Typing indicator */}
|
|
1217
|
-
{isTyping && (
|
|
976
|
+
{(isTyping || isSuccessThinking || isLoading) && (
|
|
1218
977
|
<div className="px-4">
|
|
1219
978
|
<div className="flex justify-start">
|
|
1220
979
|
<div className="bg-gray-50 border border-gray-200 px-4 py-3 rounded-lg">
|
|
@@ -1243,6 +1002,7 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
1243
1002
|
return prev;
|
|
1244
1003
|
}
|
|
1245
1004
|
const newMessage = subscriptionData.data.chatMessageAdded;
|
|
1005
|
+
|
|
1246
1006
|
console.log('New message received via subscription:', newMessage);
|
|
1247
1007
|
|
|
1248
1008
|
return {
|
|
@@ -1287,28 +1047,6 @@ export const AIAgent: React.FC<AIAgentProps> = ({
|
|
|
1287
1047
|
{/* Input Area - Only show for Chat tab */}
|
|
1288
1048
|
{activeTab === 'chat' && (
|
|
1289
1049
|
<div className="border-t border-gray-200 bg-white">
|
|
1290
|
-
{/* Processing Status Indicator */}
|
|
1291
|
-
{currentProcessingMessage !== null && (
|
|
1292
|
-
<div className="px-4 py-2 border-b border-blue-100 bg-blue-50">
|
|
1293
|
-
<div className="flex items-center space-x-2 text-sm text-blue-700">
|
|
1294
|
-
<div className="flex space-x-1">
|
|
1295
|
-
<div className="w-2 h-2 bg-blue-500 rounded-full animate-bounce"></div>
|
|
1296
|
-
<div
|
|
1297
|
-
className="w-2 h-2 bg-blue-500 rounded-full animate-bounce"
|
|
1298
|
-
style={{ animationDelay: '0.1s' }}
|
|
1299
|
-
></div>
|
|
1300
|
-
<div
|
|
1301
|
-
className="w-2 h-2 bg-blue-500 rounded-full animate-bounce"
|
|
1302
|
-
style={{ animationDelay: '0.2s' }}
|
|
1303
|
-
></div>
|
|
1304
|
-
</div>
|
|
1305
|
-
<span>
|
|
1306
|
-
AI is processing message {currentProcessingMessage + 1} of {regularMessages.length}
|
|
1307
|
-
</span>
|
|
1308
|
-
</div>
|
|
1309
|
-
</div>
|
|
1310
|
-
)}
|
|
1311
|
-
|
|
1312
1050
|
{/* Removed temporary test button */}
|
|
1313
1051
|
<InputComponent channelId={actualChannelId} handleSend={handleSend} placeholder={placeholder} />
|
|
1314
1052
|
</div>
|