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