@messenger-box/tailwind-ui-inbox 10.0.3-alpha.0

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 (415) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/LICENSE +21 -0
  3. package/jest.config.js +9 -0
  4. package/lib/cdm-locales/en/translations.json +31 -0
  5. package/lib/cdm-locales/es/translations.json +31 -0
  6. package/lib/components/AIAgent/AIAgent.d.ts +32 -0
  7. package/lib/components/AIAgent/AIAgent.d.ts.map +1 -0
  8. package/lib/components/AIAgent/AIAgent.js +1135 -0
  9. package/lib/components/AIAgent/AIAgent.js.map +1 -0
  10. package/lib/components/AIAgent/InputComponent.d.ts +84 -0
  11. package/lib/components/AIAgent/InputComponent.d.ts.map +1 -0
  12. package/lib/components/AIAgent/InputComponent.js +417 -0
  13. package/lib/components/AIAgent/InputComponent.js.map +1 -0
  14. package/lib/components/AIAgent/index.d.ts +2 -0
  15. package/lib/components/AIAgent/index.d.ts.map +1 -0
  16. package/lib/components/InboxMessage/CommonMessage.d.ts +8 -0
  17. package/lib/components/InboxMessage/CommonMessage.d.ts.map +1 -0
  18. package/lib/components/InboxMessage/CommonMessage.js +35 -0
  19. package/lib/components/InboxMessage/CommonMessage.js.map +1 -0
  20. package/lib/components/InboxMessage/ConversationItem.d.ts +14 -0
  21. package/lib/components/InboxMessage/ConversationItem.d.ts.map +1 -0
  22. package/lib/components/InboxMessage/ConversationItem.js +200 -0
  23. package/lib/components/InboxMessage/ConversationItem.js.map +1 -0
  24. package/lib/components/InboxMessage/InputComponent.d.ts +20 -0
  25. package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -0
  26. package/lib/components/InboxMessage/InputComponent.js +148 -0
  27. package/lib/components/InboxMessage/InputComponent.js.map +1 -0
  28. package/lib/components/InboxMessage/LeftSidebar.d.ts +20 -0
  29. package/lib/components/InboxMessage/LeftSidebar.d.ts.map +1 -0
  30. package/lib/components/InboxMessage/LeftSidebar.js +102 -0
  31. package/lib/components/InboxMessage/LeftSidebar.js.map +1 -0
  32. package/lib/components/InboxMessage/MessageInput.d.ts +9 -0
  33. package/lib/components/InboxMessage/MessageInput.d.ts.map +1 -0
  34. package/lib/components/InboxMessage/MessageInput.js +154 -0
  35. package/lib/components/InboxMessage/MessageInput.js.map +1 -0
  36. package/lib/components/InboxMessage/MessageInputComponent.d.ts +9 -0
  37. package/lib/components/InboxMessage/MessageInputComponent.d.ts.map +1 -0
  38. package/lib/components/InboxMessage/Messages.d.ts +17 -0
  39. package/lib/components/InboxMessage/Messages.d.ts.map +1 -0
  40. package/lib/components/InboxMessage/Messages.js +99 -0
  41. package/lib/components/InboxMessage/Messages.js.map +1 -0
  42. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts +17 -0
  43. package/lib/components/InboxMessage/MessagesBuilderUi.d.ts.map +1 -0
  44. package/lib/components/InboxMessage/Popover.d.ts +3 -0
  45. package/lib/components/InboxMessage/Popover.d.ts.map +1 -0
  46. package/lib/components/InboxMessage/Popover.js +31 -0
  47. package/lib/components/InboxMessage/Popover.js.map +1 -0
  48. package/lib/components/InboxMessage/RightSidebar.d.ts +9 -0
  49. package/lib/components/InboxMessage/RightSidebar.d.ts.map +1 -0
  50. package/lib/components/InboxMessage/RightSidebar.js +9 -0
  51. package/lib/components/InboxMessage/RightSidebar.js.map +1 -0
  52. package/lib/components/InboxMessage/RightSidebarAi.d.ts +37 -0
  53. package/lib/components/InboxMessage/RightSidebarAi.d.ts.map +1 -0
  54. package/lib/components/InboxMessage/RightSidebarAi.js +9 -0
  55. package/lib/components/InboxMessage/RightSidebarAi.js.map +1 -0
  56. package/lib/components/InboxMessage/ServiceConversationItem.d.ts +12 -0
  57. package/lib/components/InboxMessage/ServiceConversationItem.d.ts.map +1 -0
  58. package/lib/components/InboxMessage/ServiceConversationItem.js +185 -0
  59. package/lib/components/InboxMessage/ServiceConversationItem.js.map +1 -0
  60. package/lib/components/InboxMessage/ServiceInboxItem.d.ts +12 -0
  61. package/lib/components/InboxMessage/ServiceInboxItem.d.ts.map +1 -0
  62. package/lib/components/InboxMessage/ServiceInboxItem.js +182 -0
  63. package/lib/components/InboxMessage/ServiceInboxItem.js.map +1 -0
  64. package/lib/components/InboxMessage/StreamingMessageBubble.d.ts +18 -0
  65. package/lib/components/InboxMessage/StreamingMessageBubble.d.ts.map +1 -0
  66. package/lib/components/InboxMessage/SubscriptionHandler.d.ts +19 -0
  67. package/lib/components/InboxMessage/SubscriptionHandler.d.ts.map +1 -0
  68. package/lib/components/InboxMessage/SubscriptionHandler.js +41 -0
  69. package/lib/components/InboxMessage/SubscriptionHandler.js.map +1 -0
  70. package/lib/components/InboxMessage/TypingIndicator.d.ts +11 -0
  71. package/lib/components/InboxMessage/TypingIndicator.d.ts.map +1 -0
  72. package/lib/components/InboxMessage/UploadImageButton.d.ts +7 -0
  73. package/lib/components/InboxMessage/UploadImageButton.d.ts.map +1 -0
  74. package/lib/components/InboxMessage/UploadImageButton.js +30 -0
  75. package/lib/components/InboxMessage/UploadImageButton.js.map +1 -0
  76. package/lib/components/InboxMessage/UserModalContent.d.ts +3 -0
  77. package/lib/components/InboxMessage/UserModalContent.d.ts.map +1 -0
  78. package/lib/components/InboxMessage/UserModalContent.js +60 -0
  79. package/lib/components/InboxMessage/UserModalContent.js.map +1 -0
  80. package/lib/components/InboxMessage/index.d.ts +19 -0
  81. package/lib/components/InboxMessage/index.d.ts.map +1 -0
  82. package/lib/components/InboxMessage/message-widgets/CommonMessage.d.ts +11 -0
  83. package/lib/components/InboxMessage/message-widgets/CommonMessage.d.ts.map +1 -0
  84. package/lib/components/InboxMessage/message-widgets/CommonMessage.js +44 -0
  85. package/lib/components/InboxMessage/message-widgets/CommonMessage.js.map +1 -0
  86. package/lib/components/InboxMessage/message-widgets/ErrorFixCard.d.ts +10 -0
  87. package/lib/components/InboxMessage/message-widgets/ErrorFixCard.d.ts.map +1 -0
  88. package/lib/components/InboxMessage/message-widgets/ErrorFixCard.js +194 -0
  89. package/lib/components/InboxMessage/message-widgets/ErrorFixCard.js.map +1 -0
  90. package/lib/components/InboxMessage/message-widgets/MessageCard.d.ts +8 -0
  91. package/lib/components/InboxMessage/message-widgets/MessageCard.d.ts.map +1 -0
  92. package/lib/components/InboxMessage/message-widgets/MessageSliceRenderer.d.ts +12 -0
  93. package/lib/components/InboxMessage/message-widgets/MessageSliceRenderer.d.ts.map +1 -0
  94. package/lib/components/InboxMessage/message-widgets/MessageSliceRenderer.js +37 -0
  95. package/lib/components/InboxMessage/message-widgets/MessageSliceRenderer.js.map +1 -0
  96. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts +42 -0
  97. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.d.ts.map +1 -0
  98. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js +1339 -0
  99. package/lib/components/InboxMessage/message-widgets/ModernMessageGroup.js.map +1 -0
  100. package/lib/components/InboxMessage/message-widgets/PlainMessage.d.ts +8 -0
  101. package/lib/components/InboxMessage/message-widgets/PlainMessage.d.ts.map +1 -0
  102. package/lib/components/InboxMessage/message-widgets/PlainMessage.js +14 -0
  103. package/lib/components/InboxMessage/message-widgets/PlainMessage.js.map +1 -0
  104. package/lib/components/InboxMessage/message-widgets/PropertyMessageWidget.d.ts +9 -0
  105. package/lib/components/InboxMessage/message-widgets/PropertyMessageWidget.d.ts.map +1 -0
  106. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.d.ts +14 -0
  107. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.d.ts.map +1 -0
  108. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js +333 -0
  109. package/lib/components/InboxMessage/message-widgets/SlackLikeMessageGroup.js.map +1 -0
  110. package/lib/components/InboxMessage/message-widgets/index.d.ts +4 -0
  111. package/lib/components/InboxMessage/message-widgets/index.d.ts.map +1 -0
  112. package/lib/components/ModelConfigPanel.d.ts +74 -0
  113. package/lib/components/ModelConfigPanel.d.ts.map +1 -0
  114. package/lib/components/ModelConfigPanel.js +1152 -0
  115. package/lib/components/ModelConfigPanel.js.map +1 -0
  116. package/lib/components/filler-components/RightSiderBar.d.ts +3 -0
  117. package/lib/components/filler-components/RightSiderBar.d.ts.map +1 -0
  118. package/lib/components/filler-components/RightSiderBar.js +532 -0
  119. package/lib/components/filler-components/RightSiderBar.js.map +1 -0
  120. package/lib/components/inbox/FilesList.d.ts +20 -0
  121. package/lib/components/inbox/FilesList.d.ts.map +1 -0
  122. package/lib/components/inbox/FilesList.js +68 -0
  123. package/lib/components/inbox/FilesList.js.map +1 -0
  124. package/lib/components/inbox/MessageItem.d.ts +17 -0
  125. package/lib/components/inbox/MessageItem.d.ts.map +1 -0
  126. package/lib/components/inbox/MessageItem.js +50 -0
  127. package/lib/components/inbox/MessageItem.js.map +1 -0
  128. package/lib/components/inbox/ThreadItem.d.ts +11 -0
  129. package/lib/components/inbox/ThreadItem.d.ts.map +1 -0
  130. package/lib/components/inbox/ThreadItem.js +147 -0
  131. package/lib/components/inbox/ThreadItem.js.map +1 -0
  132. package/lib/components/inbox/index.d.ts +4 -0
  133. package/lib/components/inbox/index.d.ts.map +1 -0
  134. package/lib/components/index.d.ts +10 -0
  135. package/lib/components/index.d.ts.map +1 -0
  136. package/lib/components/live-code-editor/hybrid-live-editor.d.ts +20 -0
  137. package/lib/components/live-code-editor/hybrid-live-editor.d.ts.map +1 -0
  138. package/lib/components/live-code-editor/index.d.ts +4 -0
  139. package/lib/components/live-code-editor/index.d.ts.map +1 -0
  140. package/lib/components/live-code-editor/live-code-editor.d.ts +14 -0
  141. package/lib/components/live-code-editor/live-code-editor.d.ts.map +1 -0
  142. package/lib/components/messages-container-ui/MessagesContainerUI.d.ts +81 -0
  143. package/lib/components/messages-container-ui/MessagesContainerUI.d.ts.map +1 -0
  144. package/lib/components/messages-container-ui/MessagesContainerUI.js +77 -0
  145. package/lib/components/messages-container-ui/MessagesContainerUI.js.map +1 -0
  146. package/lib/components/messages-container-ui/PlanModeView.d.ts +82 -0
  147. package/lib/components/messages-container-ui/PlanModeView.d.ts.map +1 -0
  148. package/lib/components/messages-container-ui/PlanModeView.js +267 -0
  149. package/lib/components/messages-container-ui/PlanModeView.js.map +1 -0
  150. package/lib/components/messages-container-ui/index.d.ts +6 -0
  151. package/lib/components/messages-container-ui/index.d.ts.map +1 -0
  152. package/lib/components/messages-container-ui/types.d.ts +38 -0
  153. package/lib/components/messages-container-ui/types.d.ts.map +1 -0
  154. package/lib/components/slot-fill/chat-message-filler.d.ts +4 -0
  155. package/lib/components/slot-fill/chat-message-filler.d.ts.map +1 -0
  156. package/lib/components/slot-fill/chat-message-filler.js +5 -0
  157. package/lib/components/slot-fill/chat-message-filler.js.map +1 -0
  158. package/lib/components/slot-fill/chat-message-slot.d.ts +11 -0
  159. package/lib/components/slot-fill/chat-message-slot.d.ts.map +1 -0
  160. package/lib/components/slot-fill/chat-message-slot.js +6 -0
  161. package/lib/components/slot-fill/chat-message-slot.js.map +1 -0
  162. package/lib/components/slot-fill/index.d.ts +4 -0
  163. package/lib/components/slot-fill/index.d.ts.map +1 -0
  164. package/lib/components/slot-fill/right-sidebar-filler.d.ts +4 -0
  165. package/lib/components/slot-fill/right-sidebar-filler.d.ts.map +1 -0
  166. package/lib/components/slot-fill/right-sidebar-filler.js +13 -0
  167. package/lib/components/slot-fill/right-sidebar-filler.js.map +1 -0
  168. package/lib/components/ui/button.d.ts +9 -0
  169. package/lib/components/ui/button.d.ts.map +1 -0
  170. package/lib/compute.d.ts +8 -0
  171. package/lib/compute.d.ts.map +1 -0
  172. package/lib/compute.js +264 -0
  173. package/lib/compute.js.map +1 -0
  174. package/lib/config/env-config.d.ts +20 -0
  175. package/lib/config/env-config.d.ts.map +1 -0
  176. package/lib/config/env-config.js +55 -0
  177. package/lib/config/env-config.js.map +1 -0
  178. package/lib/config/index.d.ts +2 -0
  179. package/lib/config/index.d.ts.map +1 -0
  180. package/lib/constants/breakpoints.d.ts +8 -0
  181. package/lib/constants/breakpoints.d.ts.map +1 -0
  182. package/lib/constants/index.d.ts +3 -0
  183. package/lib/constants/index.d.ts.map +1 -0
  184. package/lib/container/AiInbox.d.ts +15 -0
  185. package/lib/container/AiInbox.d.ts.map +1 -0
  186. package/lib/container/AiInboxWithLoader.d.ts +36 -0
  187. package/lib/container/AiInboxWithLoader.d.ts.map +1 -0
  188. package/lib/container/AiLandingInput.d.ts +27 -0
  189. package/lib/container/AiLandingInput.d.ts.map +1 -0
  190. package/lib/container/AiLandingInput.js +149 -0
  191. package/lib/container/AiLandingInput.js.map +1 -0
  192. package/lib/container/Inbox.d.ts +15 -0
  193. package/lib/container/Inbox.d.ts.map +1 -0
  194. package/lib/container/Inbox.js +964 -0
  195. package/lib/container/Inbox.js.map +1 -0
  196. package/lib/container/InboxAiMessagesLoader.d.ts +45 -0
  197. package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -0
  198. package/lib/container/InboxAiMessagesLoader.js +80 -0
  199. package/lib/container/InboxAiMessagesLoader.js.map +1 -0
  200. package/lib/container/InboxContainer.d.ts +41 -0
  201. package/lib/container/InboxContainer.d.ts.map +1 -0
  202. package/lib/container/InboxContainer.js +27 -0
  203. package/lib/container/InboxContainer.js.map +1 -0
  204. package/lib/container/InboxTemplate1.d.ts +15 -0
  205. package/lib/container/InboxTemplate1.d.ts.map +1 -0
  206. package/lib/container/InboxTemplate1WithLoader.d.ts +36 -0
  207. package/lib/container/InboxTemplate1WithLoader.d.ts.map +1 -0
  208. package/lib/container/InboxTemplate2.d.ts +15 -0
  209. package/lib/container/InboxTemplate2.d.ts.map +1 -0
  210. package/lib/container/InboxWithAiLoader.d.ts +47 -0
  211. package/lib/container/InboxWithAiLoader.d.ts.map +1 -0
  212. package/lib/container/InboxWithAiLoader.js +118 -0
  213. package/lib/container/InboxWithAiLoader.js.map +1 -0
  214. package/lib/container/InboxWithLoader.d.ts +36 -0
  215. package/lib/container/InboxWithLoader.d.ts.map +1 -0
  216. package/lib/container/InboxWithLoader.js +277 -0
  217. package/lib/container/InboxWithLoader.js.map +1 -0
  218. package/lib/container/ServiceInbox.d.ts +9 -0
  219. package/lib/container/ServiceInbox.d.ts.map +1 -0
  220. package/lib/container/ServiceInbox.js +141 -0
  221. package/lib/container/ServiceInbox.js.map +1 -0
  222. package/lib/container/TestInboxWithAiLoader.d.ts +7 -0
  223. package/lib/container/TestInboxWithAiLoader.d.ts.map +1 -0
  224. package/lib/container/TestInboxWithAiLoader.js +135 -0
  225. package/lib/container/TestInboxWithAiLoader.js.map +1 -0
  226. package/lib/container/ThreadMessages.d.ts +13 -0
  227. package/lib/container/ThreadMessages.d.ts.map +1 -0
  228. package/lib/container/ThreadMessages.js +320 -0
  229. package/lib/container/ThreadMessages.js.map +1 -0
  230. package/lib/container/ThreadMessagesInbox.d.ts +14 -0
  231. package/lib/container/ThreadMessagesInbox.d.ts.map +1 -0
  232. package/lib/container/ThreadMessagesInbox.js +347 -0
  233. package/lib/container/ThreadMessagesInbox.js.map +1 -0
  234. package/lib/container/Threads.d.ts +8 -0
  235. package/lib/container/Threads.d.ts.map +1 -0
  236. package/lib/container/Threads.js +231 -0
  237. package/lib/container/Threads.js.map +1 -0
  238. package/lib/container/ThreadsInbox.d.ts +21 -0
  239. package/lib/container/ThreadsInbox.d.ts.map +1 -0
  240. package/lib/container/ThreadsInbox.js +243 -0
  241. package/lib/container/ThreadsInbox.js.map +1 -0
  242. package/lib/container/apply-footer-styles.d.ts +2 -0
  243. package/lib/container/apply-footer-styles.d.ts.map +1 -0
  244. package/lib/container/apply-footer-styles.js +16 -0
  245. package/lib/container/apply-footer-styles.js.map +1 -0
  246. package/lib/container/index.d.ts +13 -0
  247. package/lib/container/index.d.ts.map +1 -0
  248. package/lib/enums/index.d.ts +2 -0
  249. package/lib/enums/index.d.ts.map +1 -0
  250. package/lib/enums/messenger-slot-fill-name-enum.d.ts +11 -0
  251. package/lib/enums/messenger-slot-fill-name-enum.d.ts.map +1 -0
  252. package/lib/enums/messenger-slot-fill-name-enum.js +11 -0
  253. package/lib/enums/messenger-slot-fill-name-enum.js.map +1 -0
  254. package/lib/hooks/index.d.ts +4 -0
  255. package/lib/hooks/index.d.ts.map +1 -0
  256. package/lib/hooks/usePersistentModelConfig.d.ts +33 -0
  257. package/lib/hooks/usePersistentModelConfig.d.ts.map +1 -0
  258. package/lib/hooks/usePersistentModelConfig.js +123 -0
  259. package/lib/hooks/usePersistentModelConfig.js.map +1 -0
  260. package/lib/hooks/useStreamAssembler.d.ts +8 -0
  261. package/lib/hooks/useStreamAssembler.d.ts.map +1 -0
  262. package/lib/hooks/useTemplates.d.ts +14 -0
  263. package/lib/hooks/useTemplates.d.ts.map +1 -0
  264. package/lib/hooks/useTemplates.js +59 -0
  265. package/lib/hooks/useTemplates.js.map +1 -0
  266. package/lib/index.d.ts +14 -0
  267. package/lib/index.d.ts.map +1 -0
  268. package/lib/index.js +1 -0
  269. package/lib/index.js.map +1 -0
  270. package/lib/interfaces/index.d.ts +2 -0
  271. package/lib/interfaces/index.d.ts.map +1 -0
  272. package/lib/interfaces/message-widgets.interface.d.ts +21 -0
  273. package/lib/interfaces/message-widgets.interface.d.ts.map +1 -0
  274. package/lib/machines/aiAgentMachine.d.ts +3 -0
  275. package/lib/machines/aiAgentMachine.d.ts.map +1 -0
  276. package/lib/machines/aiAgentMachine.js +1083 -0
  277. package/lib/machines/aiAgentMachine.js.map +1 -0
  278. package/lib/machines/aiAgentMachine.simple.d.ts +3 -0
  279. package/lib/machines/aiAgentMachine.simple.d.ts.map +1 -0
  280. package/lib/machines/aiAgentMachine.simple.js +108 -0
  281. package/lib/machines/aiAgentMachine.simple.js.map +1 -0
  282. package/lib/machines/index.d.ts +3 -0
  283. package/lib/machines/index.d.ts.map +1 -0
  284. package/lib/machines/types.d.ts +77 -0
  285. package/lib/machines/types.d.ts.map +1 -0
  286. package/lib/module.d.ts +7 -0
  287. package/lib/module.d.ts.map +1 -0
  288. package/lib/module.js +26 -0
  289. package/lib/module.js.map +1 -0
  290. package/lib/routes.json +251 -0
  291. package/lib/styles/responsive.css +76 -0
  292. package/lib/templates/InboxWithAi.d.ts +44 -0
  293. package/lib/templates/InboxWithAi.d.ts.map +1 -0
  294. package/lib/templates/InboxWithAi.js +651 -0
  295. package/lib/templates/InboxWithAi.js.map +1 -0
  296. package/lib/templates/InboxWithAi.tsx +844 -0
  297. package/lib/templates/index.d.ts +2 -0
  298. package/lib/templates/index.d.ts.map +1 -0
  299. package/lib/templates/index.ts +1 -0
  300. package/lib/types/templates.d.ts +35 -0
  301. package/lib/types/templates.d.ts.map +1 -0
  302. package/lib/utils/utils.d.ts +2 -0
  303. package/lib/utils/utils.d.ts.map +1 -0
  304. package/lib/xstate/index.d.ts +3 -0
  305. package/lib/xstate/index.d.ts.map +1 -0
  306. package/lib/xstate/rightSidebar.machine.d.ts +4 -0
  307. package/lib/xstate/rightSidebar.machine.d.ts.map +1 -0
  308. package/lib/xstate/rightSidebar.types.d.ts +57 -0
  309. package/lib/xstate/rightSidebar.types.d.ts.map +1 -0
  310. package/package.json +69 -0
  311. package/rollup.config.mjs +47 -0
  312. package/src/cdm-locales/en/translations.json +31 -0
  313. package/src/cdm-locales/es/translations.json +31 -0
  314. package/src/components/AIAgent/AIAgent.tsx +1468 -0
  315. package/src/components/AIAgent/AIAgent.tsx.bk +1365 -0
  316. package/src/components/AIAgent/InputComponent.tsx +608 -0
  317. package/src/components/AIAgent/README.md +174 -0
  318. package/src/components/AIAgent/index.ts +1 -0
  319. package/src/components/InboxMessage/CommonMessage.tsx +40 -0
  320. package/src/components/InboxMessage/ConversationItem.tsx +255 -0
  321. package/src/components/InboxMessage/InputComponent.tsx +198 -0
  322. package/src/components/InboxMessage/LeftSidebar.tsx +140 -0
  323. package/src/components/InboxMessage/MessageInput.tsx +209 -0
  324. package/src/components/InboxMessage/MessageInputComponent.tsx +245 -0
  325. package/src/components/InboxMessage/Messages.tsx +137 -0
  326. package/src/components/InboxMessage/MessagesBuilderUi.tsx +205 -0
  327. package/src/components/InboxMessage/Popover.tsx +42 -0
  328. package/src/components/InboxMessage/RightSidebar.tsx +22 -0
  329. package/src/components/InboxMessage/RightSidebarAi.tsx +47 -0
  330. package/src/components/InboxMessage/ServiceConversationItem.tsx +234 -0
  331. package/src/components/InboxMessage/ServiceInboxItem.tsx +223 -0
  332. package/src/components/InboxMessage/StreamingMessageBubble.tsx +270 -0
  333. package/src/components/InboxMessage/SubscriptionHandler.tsx +55 -0
  334. package/src/components/InboxMessage/TypingIndicator.tsx +38 -0
  335. package/src/components/InboxMessage/UploadImageButton.tsx +46 -0
  336. package/src/components/InboxMessage/UserModalContent.tsx +60 -0
  337. package/src/components/InboxMessage/index.ts +18 -0
  338. package/src/components/InboxMessage/message-widgets/CommonMessage.tsx +69 -0
  339. package/src/components/InboxMessage/message-widgets/ErrorFixCard.tsx +239 -0
  340. package/src/components/InboxMessage/message-widgets/MessageCard.tsx +127 -0
  341. package/src/components/InboxMessage/message-widgets/MessageSliceRenderer.tsx +40 -0
  342. package/src/components/InboxMessage/message-widgets/ModernMessageGroup.tsx +1733 -0
  343. package/src/components/InboxMessage/message-widgets/PlainMessage.tsx +18 -0
  344. package/src/components/InboxMessage/message-widgets/PropertyMessageWidget.tsx +29 -0
  345. package/src/components/InboxMessage/message-widgets/SlackLikeMessageGroup.tsx +492 -0
  346. package/src/components/InboxMessage/message-widgets/index.ts +8 -0
  347. package/src/components/ModelConfigPanel.tsx +1357 -0
  348. package/src/components/filler-components/RightSiderBar.tsx +572 -0
  349. package/src/components/inbox/FilesList.tsx +89 -0
  350. package/src/components/inbox/MessageItem.tsx +50 -0
  351. package/src/components/inbox/ThreadItem.tsx +295 -0
  352. package/src/components/inbox/index.ts +3 -0
  353. package/src/components/index.ts +29 -0
  354. package/src/components/live-code-editor/hybrid-live-editor.tsx +105 -0
  355. package/src/components/live-code-editor/index.ts +3 -0
  356. package/src/components/live-code-editor/live-code-editor.tsx +257 -0
  357. package/src/components/messages-container-ui/MessagesContainerUI.tsx +151 -0
  358. package/src/components/messages-container-ui/PlanModeView.tsx +426 -0
  359. package/src/components/messages-container-ui/README.md +91 -0
  360. package/src/components/messages-container-ui/index.ts +5 -0
  361. package/src/components/messages-container-ui/types.ts +40 -0
  362. package/src/components/slot-fill/chat-message-filler.tsx +18 -0
  363. package/src/components/slot-fill/chat-message-slot.tsx +18 -0
  364. package/src/components/slot-fill/index.ts +3 -0
  365. package/src/components/slot-fill/right-sidebar-filler.tsx +48 -0
  366. package/src/components/ui/button.tsx +32 -0
  367. package/src/compute.ts +271 -0
  368. package/src/config/env-config.ts +24 -0
  369. package/src/config/index.ts +1 -0
  370. package/src/constants/breakpoints.ts +7 -0
  371. package/src/constants/index.ts +5 -0
  372. package/src/container/AiInbox.tsx +1879 -0
  373. package/src/container/AiInboxWithLoader.tsx +356 -0
  374. package/src/container/AiLandingInput.tsx +200 -0
  375. package/src/container/Inbox.tsx +1095 -0
  376. package/src/container/InboxAiMessagesLoader.tsx +129 -0
  377. package/src/container/InboxContainer.tsx +61 -0
  378. package/src/container/InboxTemplate1.tsx +1553 -0
  379. package/src/container/InboxTemplate1WithLoader.tsx +338 -0
  380. package/src/container/InboxTemplate2.tsx +1617 -0
  381. package/src/container/InboxWithAiLoader.tsx +177 -0
  382. package/src/container/InboxWithLoader.tsx +341 -0
  383. package/src/container/ServiceInbox.tsx +188 -0
  384. package/src/container/TestInboxWithAiLoader.tsx +147 -0
  385. package/src/container/ThreadMessages.tsx +378 -0
  386. package/src/container/ThreadMessagesInbox.tsx +457 -0
  387. package/src/container/Threads.tsx +270 -0
  388. package/src/container/ThreadsInbox.tsx +351 -0
  389. package/src/container/apply-footer-styles.ts +17 -0
  390. package/src/container/index.ts +31 -0
  391. package/src/enums/index.ts +1 -0
  392. package/src/enums/messenger-slot-fill-name-enum.ts +10 -0
  393. package/src/hooks/index.ts +3 -0
  394. package/src/hooks/usePersistentModelConfig.ts +166 -0
  395. package/src/hooks/useStreamAssembler.ts +7 -0
  396. package/src/hooks/useTemplates.ts +75 -0
  397. package/src/index.ts +49 -0
  398. package/src/interfaces/index.ts +1 -0
  399. package/src/interfaces/message-widgets.interface.ts +21 -0
  400. package/src/machines/aiAgentMachine.simple.ts +89 -0
  401. package/src/machines/aiAgentMachine.ts +1296 -0
  402. package/src/machines/aiAgentMachine.ts.bk +1296 -0
  403. package/src/machines/index.ts +2 -0
  404. package/src/machines/types.ts +59 -0
  405. package/src/module.tsx +32 -0
  406. package/src/styles/responsive.css +76 -0
  407. package/src/templates/InboxWithAi.tsx +844 -0
  408. package/src/templates/index.ts +1 -0
  409. package/src/types/templates.ts +35 -0
  410. package/src/utils/utils.ts +3 -0
  411. package/src/xstate/index.ts +2 -0
  412. package/src/xstate/rightSidebar.machine.ts +304 -0
  413. package/src/xstate/rightSidebar.types.ts +58 -0
  414. package/tsconfig.json +14 -0
  415. package/webpack.config.js +92 -0
@@ -0,0 +1,1468 @@
1
+ import React, { useCallback, useMemo, useRef, useState, useEffect } from 'react';
2
+ import { useActor, useMachine } from '@xstate/react';
3
+ import { aiAgentMachine } from '../../machines/aiAgentMachine.simple';
4
+ import { InputComponent } from './InputComponent';
5
+ import { format, isToday, isYesterday, formatDistanceToNow } from 'date-fns';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { ModernMessageGroupComponent } from '../InboxMessage/message-widgets/ModernMessageGroup';
8
+ import { useUploadFiles } from '@messenger-box/platform-client';
9
+ import { IFileInfo, PostTypeEnum, AiAgentMessageRole, ICreateChannelInput } from 'common';
10
+ import { useSelector, shallowEqual } from 'react-redux';
11
+ import { Store, userSelector } from '@adminide-stack/user-auth0-client';
12
+ import { IUserState } from '@adminide-stack/core';
13
+ import { objectId } from '@messenger-box/core';
14
+ import { useApolloClient } from '@apollo/client';
15
+ import {
16
+ useSendMessagesMutation,
17
+ MessagesDocument,
18
+ useMessagesQuery,
19
+ OnChatMessageAddedDocument as CHAT_MESSAGE_ADDED,
20
+ useCreateChannelWorkflowJobMutation,
21
+ useOnChatMessageAddedSubscription,
22
+ } from 'common/graphql';
23
+ import { config } from '../../config';
24
+ import { orderBy, uniqBy } from 'lodash-es';
25
+ import { useParams, useNavigate } from '@remix-run/react';
26
+ import { RoomType } from 'common';
27
+ import { SubscriptionHandler } from '../InboxMessage/SubscriptionHandler';
28
+ import { usePersistentModelConfig } from '../../hooks/usePersistentModelConfig';
29
+
30
+ /** Resolver may expose role/fragment on propsConfiguration or legacy props (Mongo shape). */
31
+ const getPostRoleUpper = (m: any): string =>
32
+ String(
33
+ m?.propsConfiguration?.contents?.role ?? m?.propsConfiguration?.content?.role ?? m?.props?.role ?? '',
34
+ ).toUpperCase();
35
+
36
+ const getPostFragment = (m: any): Record<string, any> | undefined | null =>
37
+ m?.propsConfiguration?.contents?.fragment ?? m?.propsConfiguration?.content?.fragment ?? m?.props?.fragment;
38
+
39
+ const isAssistantPost = (m: any): boolean => {
40
+ if (getPostRoleUpper(m) === 'ASSISTANT') return true;
41
+ const typ = String(m?.type ?? '').toUpperCase();
42
+ return typ === 'AIASSISTANT' || typ === 'ASSISTANT';
43
+ };
44
+
45
+ const isAssistantResponseComplete = (fragment: Record<string, any> | undefined | null): boolean => {
46
+ if (!fragment) return false;
47
+ if (fragment.isCreatingSandbox === false) return true;
48
+ if (fragment.isCreatingSandbox === true) return false;
49
+ const url = fragment.sandboxUrl;
50
+ if (typeof url === 'string' && url.trim().length > 0) return true;
51
+ if (fragment.files && typeof fragment.files === 'object' && Object.keys(fragment.files).length > 0) return true;
52
+ if (typeof fragment.summary === 'string' && fragment.summary.trim().length > 0) return true;
53
+ if (fragment.isError === true || fragment.type === 'ERROR') return true;
54
+ if (String(fragment.type ?? '').toUpperCase() === 'RESULT') return true;
55
+ return false;
56
+ };
57
+
58
+ // const { MESSAGES_PER_PAGE } = config;
59
+
60
+ interface AIAgentProps {
61
+ channelId?: string;
62
+ onSendMessage?: (message: string, files?: File[]) => Promise<void>;
63
+ placeholder?: string;
64
+ className?: string;
65
+ currentUser?: any;
66
+ channelName?: string;
67
+ isDesktopView?: boolean;
68
+ isSmallScreen?: boolean;
69
+ showDateSeparators?: boolean;
70
+ messages?: any[];
71
+ setMessages?: (messages: any[]) => void;
72
+ selectedPost?: any;
73
+ setSelectedPost?: (selectedPost: any) => void;
74
+ setIsLoading?: (isLoading: boolean) => void;
75
+ isLoading?: boolean;
76
+ sendMessageInput?: ICreateChannelInput;
77
+ isShowOnlyInbox?: boolean;
78
+ showModeSelector?: boolean;
79
+ showStopButton?: boolean;
80
+ onStop?: () => void;
81
+ leftItemsOverrides?: any;
82
+ rightItemsOverrides?: any;
83
+ inputToolBarProps?: any;
84
+ projectId?: string;
85
+ [key: string]: any; // Allow other props to be passed through to Inbox
86
+ }
87
+
88
+ export const AIAgent: React.FC<AIAgentProps> = ({
89
+ channelId,
90
+ projectId,
91
+ onSendMessage,
92
+ placeholder = 'Ask me anything...',
93
+ className = '',
94
+ currentUser,
95
+ isDesktopView = false,
96
+ isSmallScreen = false,
97
+ showDateSeparators = false,
98
+ setMessages,
99
+ setSelectedPost,
100
+ messages,
101
+ selectedPost,
102
+ setIsLoading,
103
+ isLoading,
104
+ sendMessageInput,
105
+ isShowOnlyInbox = false,
106
+ showModeSelector = false,
107
+ showStopButton = false,
108
+ onStop,
109
+ templates,
110
+ selectedTemplate,
111
+ suggestedTemplate,
112
+ onSelectTemplate,
113
+ templateSelectedLabel,
114
+ templateModalItems,
115
+ showTemplateModal,
116
+ onOpenTemplateModal,
117
+ onCloseTemplateModal,
118
+ onSelectTemplateById,
119
+ onClearTemplate,
120
+ onAcceptSuggestedTemplate,
121
+ isAnalyzingQuery,
122
+ onQueryChange,
123
+ leftItemsOverrides,
124
+ rightItemsOverrides,
125
+ inputToolBarProps,
126
+ }) => {
127
+ const [state, send] = useMachine(aiAgentMachine);
128
+ const apolloClient = useApolloClient();
129
+ const { startUpload } = useUploadFiles();
130
+ const [sendMsg] = useSendMessagesMutation();
131
+ const [createChannelWorkflowJob] = useCreateChannelWorkflowJobMutation();
132
+ const auth: any = useSelector<Store.Auth, IUserState>(userSelector, shallowEqual);
133
+ const { id: pathChannelId } = useParams();
134
+ const navigate = useNavigate();
135
+ const { modelConfig, updateModelConfig, getValidatedConfig, hasApiKey } = usePersistentModelConfig();
136
+ const [postId, setPostId] = useState<string | null>(null);
137
+ /** Cleared when the first real assistant message replaces or supersedes the optimistic placeholder */
138
+ const optimisticAssistantMessageIdRef = useRef<string | null>(null);
139
+ const scrollPendingRef = useRef<ReturnType<typeof setTimeout> | null>(null);
140
+ const streamScrollRafRef = useRef<number | null>(null);
141
+ const prevLastMessageIdRef = useRef<string | null>(null);
142
+ // const [isLoading, setIsLoading] = useState(false);
143
+ const [errorData, setError] = useState<string | null>(null);
144
+ // Get channelId from props or path params
145
+ const actualChannelId = channelId || pathChannelId;
146
+
147
+ // const { data: chatMessageAddedData } = useOnChatMessageAddedSubscription({
148
+ // variables: { channelId: actualChannelId?.toString() || '' },
149
+ // skip: !actualChannelId,
150
+ // });
151
+
152
+ // Subscribe to sandbox errors if projectId is provided
153
+
154
+ // Direct message query from InboxWithAiLoader.tsx
155
+ const messagesQuery = useMessagesQuery({
156
+ variables: {
157
+ channelId: actualChannelId?.toString(),
158
+ parentId: null,
159
+ limit: 50,
160
+ },
161
+ skip: !actualChannelId,
162
+ fetchPolicy: 'cache-and-network',
163
+ errorPolicy: 'all',
164
+ notifyOnNetworkStatusChange: true,
165
+ returnPartialData: true,
166
+ pollInterval: 0,
167
+ context: {
168
+ cacheKey: 'messages-list',
169
+ },
170
+ });
171
+
172
+ // console.log('messagesQuery...', JSON.stringify(messagesQuery?.data?.messages?.data));
173
+
174
+ const { messages: aiMessages, error, isTyping } = state.context;
175
+ const { t } = useTranslation('translations');
176
+
177
+ const [isOpen, setIsOpen] = useState(false);
178
+ const [selectedElement, setSelectedElement] = useState<any>(null);
179
+ const [activeTab, setActiveTab] = useState<'chat' | 'history'>('chat');
180
+ const bottomRef = useRef<HTMLDivElement | null>(null);
181
+ const [sandboxErrors, setSandboxErrors] = useState<any[]>([]);
182
+ const [currentFiles, setCurrentFiles] = useState<Record<string, string>>({});
183
+ const [canvasLayers, setCanvasLayers] = useState<any[]>([]);
184
+ // New state variables for message display control
185
+ const [isSuccessThinking, setIsSuccessThinking] = useState(false);
186
+ const successThinkingTimeoutRef = useRef<any>(null);
187
+
188
+ // When showing only inbox, force Chat tab and hide tab switcher UI
189
+ useEffect(() => {
190
+ if (isShowOnlyInbox && activeTab !== 'chat') {
191
+ setActiveTab('chat');
192
+ }
193
+ }, [isShowOnlyInbox, activeTab]);
194
+
195
+ // Get regular messages from direct query
196
+ const {
197
+ data: messagesData,
198
+ loading: messageLoading,
199
+ refetch: refetchMessages,
200
+ fetchMore: fetchMoreMessages,
201
+ subscribeToMore,
202
+ } = messagesQuery;
203
+
204
+ useEffect(() => {
205
+ if (actualChannelId) {
206
+ refetchMessages({
207
+ channelId: actualChannelId?.toString(),
208
+ parentId: null,
209
+ limit: 50,
210
+ });
211
+ }
212
+ }, [actualChannelId, refetchMessages]);
213
+
214
+ // useEffect(() => {
215
+ // if (chatMessageAddedData?.chatMessageAdded) {
216
+ // console.log(
217
+ // 'chatMessageAddedData?.chatMessageAdded',
218
+ // JSON.stringify(chatMessageAddedData?.chatMessageAdded, null, 2),
219
+ // );
220
+
221
+ // // Stop the success thinking loader once a new message arrives
222
+ // if (isSuccessThinking) {
223
+ // setIsSuccessThinking(false);
224
+ // if (successThinkingTimeoutRef.current) {
225
+ // clearTimeout(successThinkingTimeoutRef.current);
226
+ // successThinkingTimeoutRef.current = null;
227
+ // }
228
+ // }
229
+ // if (isShowOnlyInbox) {
230
+ // setIsLoading(false);
231
+ // }
232
+ // }
233
+ // console.log('isShowOnlyInbox', isShowOnlyInbox, ' isLoading', isLoading);
234
+ // }, [chatMessageAddedData?.chatMessageAdded, isShowOnlyInbox, setIsLoading]);
235
+
236
+ useEffect(() => {
237
+ if (messagesData?.messages?.data?.length >= 1) {
238
+ setPostId(messagesData.messages.data[0]?.id);
239
+ }
240
+ // console.log('messagesData?.messages?.data',JSON.stringify(messagesData?.messages?.data,null,2))
241
+ }, [messagesData?.messages?.data]);
242
+
243
+ useEffect(() => {
244
+ if (sendMessageInput?.postData?.content && sendMessageInput?.postData?.content.trim() !== '') {
245
+ console.log('sendMessageInput...', JSON.stringify(sendMessageInput?.postData?.content, null, 2));
246
+ handleSend(sendMessageInput?.postData?.content || '', []);
247
+ }
248
+ }, [sendMessageInput?.postData?.content]);
249
+
250
+ // Handle sandbox error subscription updates
251
+
252
+ // Scroll to bottom — cancels any pending scroll so streaming updates do not queue many smooth scrolls
253
+ const scrollToBottom = useCallback((behavior: ScrollBehavior = 'smooth', delay: number = 0) => {
254
+ if (scrollPendingRef.current) {
255
+ clearTimeout(scrollPendingRef.current);
256
+ scrollPendingRef.current = null;
257
+ }
258
+ scrollPendingRef.current = setTimeout(() => {
259
+ scrollPendingRef.current = null;
260
+ if (bottomRef.current) {
261
+ bottomRef.current.scrollIntoView({
262
+ behavior,
263
+ block: 'end',
264
+ inline: 'nearest',
265
+ });
266
+ }
267
+ }, delay);
268
+ }, []);
269
+
270
+ const regularMessages = useMemo(() => {
271
+ if (!messagesData?.messages?.data) return [];
272
+ const mainMessages = messagesData.messages.data || [];
273
+ const replyMessages = messagesData.messages.data[0]?.replies?.data || [];
274
+ const allMessages = [...mainMessages, ...replyMessages];
275
+ const getMsgId = (m: any) => String(m?.id ?? m?._id ?? '');
276
+ const getCreatedAt = (m: any) => {
277
+ const v = m?.createdAt;
278
+ if (!v) return 0;
279
+ const t = typeof v === 'number' ? v : new Date(v).getTime();
280
+ return Number.isNaN(t) ? 0 : t;
281
+ };
282
+ const uniq = uniqBy(allMessages, (m: any) => getMsgId(m));
283
+ const ids = new Set(uniq.map((m: any) => getMsgId(m)));
284
+ const roots = uniq.filter((m: any) => !m?.parentId || !ids.has(String(m.parentId)));
285
+ const replies = uniq.filter((m: any) => m?.parentId && ids.has(String(m.parentId)));
286
+ const rootsSorted = orderBy(roots, [getCreatedAt], ['asc']);
287
+ const result: any[] = [];
288
+ for (const root of rootsSorted) {
289
+ result.push(root);
290
+ const children = orderBy(
291
+ replies.filter((r: any) => String(r.parentId) === getMsgId(root)),
292
+ [getCreatedAt],
293
+ ['asc'],
294
+ );
295
+ result.push(...children);
296
+ }
297
+ const orphanReplies = replies.filter((r: any) => !result.some((x: any) => getMsgId(x) === getMsgId(r)));
298
+ return [...result, ...orderBy(orphanReplies, [getCreatedAt], ['asc'])];
299
+ }, [messagesData?.messages?.data]);
300
+
301
+ console.log('regularMessages...........', JSON.stringify(regularMessages, null, 2));
302
+
303
+ // True while the latest assistant post is still building a sandbox (or fragment not yet complete)
304
+ const isCreatingSandbox = useMemo(() => {
305
+ if (isShowOnlyInbox) return false;
306
+ if (!regularMessages || regularMessages.length === 0) return false;
307
+
308
+ const mostRecentAssistant = regularMessages.slice().reverse().find(isAssistantPost);
309
+ if (!mostRecentAssistant) return false;
310
+
311
+ const fragment = getPostFragment(mostRecentAssistant);
312
+
313
+ if (fragment?.isCreatingSandbox === true) return true;
314
+ if (isAssistantResponseComplete(fragment)) return false;
315
+
316
+ // Assistant row exists but no completion signals yet — still in progress
317
+ if (fragment && Object.keys(fragment).length > 0) return true;
318
+ return false;
319
+ }, [regularMessages, isShowOnlyInbox]);
320
+
321
+ // handleSend sets these on submit; clear them when the latest assistant message is clearly done
322
+ useEffect(() => {
323
+ if (isShowOnlyInbox) return;
324
+ if (!regularMessages?.length) return;
325
+ const mostRecentAssistant = regularMessages.slice().reverse().find(isAssistantPost);
326
+ if (!mostRecentAssistant) return;
327
+ const fragment = getPostFragment(mostRecentAssistant);
328
+ if (!isAssistantResponseComplete(fragment)) return;
329
+ setIsSuccessThinking(false);
330
+ setIsLoading?.(false);
331
+ }, [regularMessages, isShowOnlyInbox, setIsLoading]);
332
+
333
+ // Send regular messages to AI agent machine for context
334
+ useEffect(() => {
335
+ if (regularMessages && regularMessages.length > 0) {
336
+ send({ type: 'UPDATE_REGULAR_MESSAGES', messages: regularMessages });
337
+ setMessages(regularMessages);
338
+ const currentMessage = regularMessages?.[regularMessages.length - 1];
339
+ setSelectedPost(regularMessages[regularMessages.length - 1]);
340
+ setCurrentFiles(currentMessage?.propsConfiguration?.contents?.fragment?.files ?? {});
341
+ let canvasLayers = currentMessage?.propsConfiguration?.contents?.fragment?.canvasLayers ?? [];
342
+ const summary = currentMessage?.propsConfiguration?.contents?.fragment?.summary ?? null;
343
+ // If not in direct field, try to extract from summary
344
+ if (!canvasLayers && summary) {
345
+ const canvasLayersMatch = summary?.match(/<canvas_layers>([\s\S]*?)<\/canvas_layers>/);
346
+ if (canvasLayersMatch) {
347
+ try {
348
+ canvasLayers = JSON.parse(canvasLayersMatch[1]);
349
+ } catch (error) {
350
+ console.error('Failed to parse canvas layers from summary:', error);
351
+ }
352
+ }
353
+ }
354
+ // Update canvas layers if available
355
+ if (canvasLayers && Array.isArray(canvasLayers)) {
356
+ setCanvasLayers(canvasLayers);
357
+ }
358
+
359
+ console.log('currenmessage', currentMessage);
360
+ if (currentMessage?.propsConfiguration?.contents?.role === 'ASSISTANT') {
361
+ //setIsLoading(false);
362
+ }
363
+
364
+ if (isShowOnlyInbox) {
365
+ setIsLoading(false);
366
+ }
367
+
368
+ // Scroll behavior (Perplexity-style): smooth when a new last message appears; coalesce updates on the same id
369
+ const last = regularMessages[regularMessages.length - 1];
370
+ const lastId = last?.id != null ? String(last.id) : null;
371
+ const isNewLastRow = lastId !== prevLastMessageIdRef.current;
372
+ prevLastMessageIdRef.current = lastId;
373
+
374
+ if (isNewLastRow) {
375
+ if (streamScrollRafRef.current != null) {
376
+ cancelAnimationFrame(streamScrollRafRef.current);
377
+ streamScrollRafRef.current = null;
378
+ }
379
+ scrollToBottom('smooth', 0);
380
+ } else if (streamScrollRafRef.current == null) {
381
+ streamScrollRafRef.current = requestAnimationFrame(() => {
382
+ streamScrollRafRef.current = null;
383
+ scrollToBottom('auto', 0);
384
+ });
385
+ }
386
+ }
387
+ }, [regularMessages, send, isShowOnlyInbox, setIsLoading, scrollToBottom]);
388
+
389
+ const onOpen = (element?: any) => {
390
+ setSelectedElement(element);
391
+ setIsOpen(true);
392
+ };
393
+
394
+ const onClose = () => {
395
+ setIsOpen(false);
396
+ setSelectedElement(null);
397
+ };
398
+
399
+ const handleSend = useCallback(
400
+ async (message: string, files: any[] = []) => {
401
+ // Allow sending if there's either a message or files
402
+ if ((!message || !message.trim()) && (!files || files.length === 0)) return;
403
+
404
+ const validated = getValidatedConfig();
405
+ if (!validated && !hasApiKey) {
406
+ // Warn but continue — the user's message should still be persisted
407
+ // even if the AI cannot respond without an API key.
408
+ console.warn(
409
+ '⚠️ No AI API key configured. Message will be saved but AI cannot respond. ' +
410
+ 'Open Settings (gear icon) to add your API key.',
411
+ );
412
+ }
413
+
414
+ const {
415
+ extensionId: _omitExtensionId,
416
+ formId: _omitFormId,
417
+ functionId: _omitFunctionId,
418
+ stepName: _omitStepName,
419
+ metadata: _omitMetadata,
420
+ ...modelConfigWithoutExtensionId
421
+ } = (modelConfig as any) || ({} as any);
422
+ let createChannelInputData = sendMessageInput
423
+ ? {
424
+ ...sendMessageInput,
425
+ channelId: sendMessageInput?.channelId || actualChannelId,
426
+ title: sendMessageInput?.title || 'AI Assistant',
427
+ description: sendMessageInput?.description || 'AI Assistant',
428
+ displayName: sendMessageInput?.displayName || 'AI Assistant',
429
+ topic: sendMessageInput?.topic || 'AI Assistant',
430
+ // projectId: projectId,
431
+ type: sendMessageInput?.type || RoomType.Aiassistant,
432
+ postData: {
433
+ ...sendMessageInput?.postData,
434
+ postId: sendMessageInput?.postData?.postId || postId || undefined,
435
+ type: sendMessageInput?.postData?.type || PostTypeEnum.Aiassistant,
436
+ content: sendMessageInput?.postData?.content || message,
437
+ props: {
438
+ ...sendMessageInput?.postData?.props,
439
+ template:
440
+ sendMessageInput?.postData?.props?.template || modelConfig?.template || 'vite-react',
441
+ //projectId: projectId,
442
+ role: sendMessageInput?.postData?.props?.role || AiAgentMessageRole.User,
443
+ fragment: sendMessageInput?.postData?.props?.fragment || {},
444
+ },
445
+ },
446
+ additionalProperties: sendMessageInput?.additionalProperties || {
447
+ modelConfig: modelConfigWithoutExtensionId,
448
+ },
449
+ }
450
+ : null;
451
+ const createChannelInput: ICreateChannelInput = createChannelInputData || {
452
+ channelId: actualChannelId,
453
+ title: 'AI Assistant',
454
+ description: 'AI Assistant',
455
+ displayName: 'AI Assistant',
456
+ topic: 'AI Assistant',
457
+ // projectId: projectId,
458
+ type: RoomType.Aiassistant,
459
+ postData: {
460
+ postId: postId || undefined,
461
+ type: PostTypeEnum.Aiassistant,
462
+ content: message,
463
+ props: {
464
+ template: modelConfig?.template || 'vite-react',
465
+ //projectId: projectId,
466
+ role: AiAgentMessageRole.User,
467
+ fragment: {},
468
+ },
469
+ },
470
+ additionalProperties: {
471
+ modelConfig: modelConfigWithoutExtensionId,
472
+ },
473
+ };
474
+
475
+ // Start the AI thinking loader immediately on send
476
+ if (successThinkingTimeoutRef.current) {
477
+ clearTimeout(successThinkingTimeoutRef.current);
478
+ successThinkingTimeoutRef.current = null;
479
+ }
480
+ setIsSuccessThinking(true);
481
+ setIsLoading(true);
482
+
483
+ // Optimistic update: Add assistant message with isCreatingSandbox: true
484
+ if (!isShowOnlyInbox && actualChannelId) {
485
+ try {
486
+ const previousOptimisticId = optimisticAssistantMessageIdRef.current;
487
+ const optimisticAssistantMessageId = objectId();
488
+ optimisticAssistantMessageIdRef.current = optimisticAssistantMessageId;
489
+ const optimisticAssistantMessage = {
490
+ __typename: 'Post',
491
+ id: optimisticAssistantMessageId,
492
+ content: '',
493
+ message: '',
494
+ createdAt: new Date().toISOString(),
495
+ updatedAt: new Date().toISOString(),
496
+ author: {
497
+ __typename: 'User',
498
+ id: 'ai-assistant',
499
+ username: 'ai-assistant',
500
+ givenName: 'AI',
501
+ familyName: 'Assistant',
502
+ fullName: 'AI Assistant',
503
+ email: 'ai@assistant.com',
504
+ picture: null,
505
+ alias: [],
506
+ tokens: [],
507
+ },
508
+ propsConfiguration: {
509
+ __typename: 'PostPropsConfiguration',
510
+ contents: {
511
+ __typename: 'PostContents',
512
+ role: 'ASSISTANT',
513
+ fragment: {
514
+ isCreatingSandbox: true,
515
+ },
516
+ },
517
+ },
518
+ props: {},
519
+ files: [],
520
+ replies: null,
521
+ channel: null,
522
+ isPinned: false,
523
+ isDelivered: false,
524
+ isRead: false,
525
+ parentId: null,
526
+ fromServer: null,
527
+ type: PostTypeEnum.Aiassistant,
528
+ };
529
+
530
+ // Update cache optimistically
531
+ const messagesQuery = {
532
+ query: MessagesDocument,
533
+ variables: {
534
+ channelId: actualChannelId.toString(),
535
+ parentId: null,
536
+ limit: 50,
537
+ },
538
+ };
539
+
540
+ try {
541
+ const existingData = apolloClient.readQuery(messagesQuery) as any;
542
+ if (existingData?.messages) {
543
+ const oldRows = existingData.messages.data || [];
544
+ let nextRows = previousOptimisticId
545
+ ? oldRows.filter((m: any) => String(m?.id) !== String(previousOptimisticId))
546
+ : [...oldRows];
547
+ if (!nextRows.some((m: any) => String(m?.id) === String(optimisticAssistantMessageId))) {
548
+ nextRows = [...nextRows, optimisticAssistantMessage];
549
+ }
550
+ const prevTotal = existingData.messages.totalCount ?? oldRows.length;
551
+ const newTotal = prevTotal + (nextRows.length - oldRows.length);
552
+
553
+ apolloClient.writeQuery({
554
+ ...messagesQuery,
555
+ data: {
556
+ messages: {
557
+ ...existingData.messages,
558
+ data: nextRows,
559
+ totalCount: Math.max(0, newTotal),
560
+ },
561
+ },
562
+ });
563
+ }
564
+ } catch (error) {
565
+ // Cache might not exist yet, that's okay
566
+ console.debug('Optimistic update failed (cache might not exist):', error);
567
+ }
568
+ } catch (error) {
569
+ console.error('Failed to create optimistic update:', error);
570
+ }
571
+ }
572
+
573
+ // Safety auto-stop in case no event arrives
574
+ // successThinkingTimeoutRef.current = setTimeout(() => {
575
+ // setIsSuccessThinking(false);
576
+ // successThinkingTimeoutRef.current = null;
577
+ // }, 15000);
578
+ // If no channelId, mirror AiLandingInput: create channel+project, seed first post, then navigate
579
+ try {
580
+ // const postId = objectId();
581
+ // Do not include extensionId inside modelConfig when sending additionalProperties
582
+
583
+ await createChannelWorkflowJob({
584
+ variables: {
585
+ createChannelInput: createChannelInput,
586
+ extensionInput: {
587
+ // prefer saved extensionId from modelConfig; otherwise env default
588
+ extensionId: modelConfig?.extensionId,
589
+ stepName: modelConfig?.stepName || 'extractCodeFromExtension',
590
+ formId: modelConfig?.formId || 'form-builder-proxy',
591
+ functionId: modelConfig?.functionId || 'create-channel-function',
592
+ metadata: modelConfig?.metadata || {},
593
+ source: 'final-submission',
594
+ },
595
+ },
596
+ onCompleted: (data: any) => {
597
+ // if (!data?.createChannelWorkflowJob) {
598
+ // setIsSuccessThinking(false);
599
+ // setIsLoading(false);
600
+ // return;
601
+ // }
602
+ // setIsSuccessThinking(false);
603
+ // setIsLoading(false);
604
+ },
605
+ onError: (error: any) => {
606
+ console.error('Error creating channel:', error);
607
+ setIsSuccessThinking(false);
608
+ setIsLoading(false);
609
+ },
610
+ });
611
+ } catch (err) {
612
+ console.error('Failed to create new AI project/channel from AIAgent:', err);
613
+ setIsSuccessThinking(false);
614
+ setIsLoading(false);
615
+ }
616
+ },
617
+ [
618
+ actualChannelId,
619
+ postId,
620
+ auth,
621
+ startUpload,
622
+ sendMsg,
623
+ scrollToBottom,
624
+ getValidatedConfig,
625
+ hasApiKey,
626
+ modelConfig,
627
+ navigate,
628
+ createChannelWorkflowJob,
629
+ sendMessageInput,
630
+ apolloClient,
631
+ isShowOnlyInbox,
632
+ ],
633
+ );
634
+
635
+ const fixError = useCallback(
636
+ (errorMessage: string) => {
637
+ // Use sendMessage to fix the error, which will use createProject flow
638
+ return handleSend(errorMessage);
639
+ },
640
+ [handleSend],
641
+ );
642
+
643
+ const handleStop = useCallback(() => {
644
+ // Stop the current operation
645
+
646
+ console.log('Stop button clicked - stopping current operation');
647
+
648
+ // Call the onStop prop if provided
649
+ onStop?.();
650
+ }, [setIsLoading, onStop]);
651
+
652
+ const handleRetry = useCallback(() => {
653
+ send({ type: 'RETRY' });
654
+ }, [send]);
655
+
656
+ const handleClearError = useCallback(() => {
657
+ send({ type: 'CLEAR_ERROR' });
658
+ }, [send]);
659
+
660
+ // Use only default/regular messages and ignore AI messages — preserve type (THINKING, TOOLUSE, CODEBLOCK, etc.) for ModernMessageGroup slots
661
+ const allMessages = useMemo(() => {
662
+ if (!regularMessages) return [] as any[];
663
+
664
+ const mapped = (regularMessages || []).map((m, idx) => ({
665
+ id: m.id || `regular-${idx}`,
666
+ message: (m as any).message || (m as any).content || '',
667
+ createdAt: new Date((m as any).createdAt || Date.now()),
668
+ type: (m as any).type,
669
+ propsConfiguration: (m as any).propsConfiguration,
670
+ props: (m as any).props,
671
+ files: (m as any).files,
672
+ sender: 'user',
673
+ author: (m as any).author,
674
+ isUserMessage: true,
675
+ }));
676
+
677
+ // Check if we have a completed AIASSISTANT (final response) — if so, hide THINKING
678
+ const hasCompletedResponse = mapped.some((m: any) => {
679
+ const t = (m as any).type;
680
+ const frag = (m as any)?.props?.fragment ?? (m as any)?.propsConfiguration?.contents?.fragment;
681
+ return (t === 'AIASSISTANT' || t === 'ASSISTANT') && frag && (frag.sandboxUrl || frag.files);
682
+ });
683
+
684
+ return mapped.filter((m: any) => {
685
+ if ((m as any).type !== 'THINKING') return true;
686
+ // Hide THINKING when: dismissed in payload, or when we have a completed response
687
+ const att = (m as any)?.props?.attachment ?? (m as any)?.propsConfiguration?.contents?.attachment;
688
+ if (att == null) return false;
689
+ if (att.dismissed === true) return false;
690
+ if (att.isThinking === false && !String(att.thought || '').trim()) return false;
691
+ if (hasCompletedResponse) return false; // Final response exists — hide lingering THINKING
692
+ return true;
693
+ });
694
+ }, [regularMessages, currentUser]);
695
+
696
+ // Derive sandbox-style errors from message fragments so we can show the Fix Error UI
697
+ // Returns unique errors globally (deduplicated by error message/content)
698
+ // Map errors to their respective messages (messageId -> errors[])
699
+ const errorsByMessageId = useMemo(() => {
700
+ if (!regularMessages || regularMessages.length === 0) return new Map<string, any[]>();
701
+
702
+ const errorsMap = new Map<string, any[]>();
703
+
704
+ // Collect errors from all messages and map them to message IDs
705
+ (regularMessages || []).forEach((m: any) => {
706
+ const fragment = m?.propsConfiguration?.contents?.fragment;
707
+ if (!fragment) return;
708
+
709
+ const isErrorFragment = fragment?.isError === true || fragment?.type === 'ERROR';
710
+ if (!isErrorFragment) return;
711
+
712
+ const errorId = fragment.id || m.id || objectId();
713
+ const messageId = m.id || 'unknown';
714
+
715
+ const errorMessage =
716
+ fragment.errorMessage ||
717
+ fragment.summary ||
718
+ (m as any).message ||
719
+ (m as any).content ||
720
+ 'An error occurred in the AI sandbox.';
721
+
722
+ const error = {
723
+ id: errorId,
724
+ messageId: messageId,
725
+ errorType: fragment.errorType || 'RUNTIME_ERROR',
726
+ timestamp: fragment.timestamp || m.createdAt || new Date().toISOString(),
727
+ sandboxId: fragment.sandboxId || fragment.projectId || actualChannelId || 'unknown-sandbox',
728
+ message: errorMessage,
729
+ stack: fragment.stack || '',
730
+ url: fragment.sandboxUrl || fragment.url,
731
+ fixable: fragment.fixable !== false,
732
+ };
733
+
734
+ // Add error to the message's error list
735
+ if (!errorsMap.has(messageId)) {
736
+ errorsMap.set(messageId, []);
737
+ }
738
+ errorsMap.get(messageId)!.push(error);
739
+ });
740
+
741
+ return errorsMap;
742
+ }, [regularMessages, actualChannelId]);
743
+
744
+ // Build list with date separators similar to MessagesBuilderUi
745
+ const messageListWithDates = useMemo(() => {
746
+ let currentDate = '';
747
+ const res: any[] = [];
748
+
749
+ if (showDateSeparators) {
750
+ allMessages?.forEach((msg: any) => {
751
+ const date = new Date(msg.createdAt);
752
+ let msgDate: string;
753
+ if (isToday(date)) msgDate = t('tailwind_ui_inbox.today');
754
+ else if (isYesterday(date)) msgDate = t('tailwind_ui_inbox.yesterday');
755
+ else msgDate = format(date, 'eee, do MMMM');
756
+
757
+ if (msgDate !== currentDate) {
758
+ res.push({ type: 'date', content: msgDate });
759
+ currentDate = msgDate;
760
+ }
761
+ res.push(msg);
762
+ });
763
+
764
+ if (allMessages && allMessages.length > 0) {
765
+ const todayLabel = t('tailwind_ui_inbox.today');
766
+ if (currentDate !== todayLabel) {
767
+ res.push({ type: 'date', content: todayLabel });
768
+ }
769
+ }
770
+ } else {
771
+ // No date separaters, keep messages as-is
772
+ allMessages?.forEach((msg: any) => res.push(msg));
773
+ }
774
+
775
+ return res;
776
+ }, [allMessages, t, showDateSeparators]);
777
+
778
+ // Group messages by date sections for Slack-like rendering
779
+ const messagesByDate = useMemo(() => {
780
+ const sections: { date: string | null; messages: any[] }[] = [];
781
+ let currentSection: { date: string | null; messages: any[] } = { date: null, messages: [] };
782
+
783
+ messageListWithDates.forEach((item: any) => {
784
+ if (item?.type === 'date') {
785
+ if (currentSection.messages.length > 0) {
786
+ sections.push(currentSection);
787
+ }
788
+ currentSection = { date: item.content, messages: [] };
789
+ } else {
790
+ currentSection.messages.push(item);
791
+ }
792
+ });
793
+
794
+ if (currentSection.messages.length > 0) {
795
+ sections.push(currentSection);
796
+ }
797
+
798
+ return sections;
799
+ }, [messageListWithDates]);
800
+
801
+ // Show all messages without limiting
802
+ const limitedMessagesByDate = useMemo(() => {
803
+ if (!messagesByDate || messagesByDate.length === 0) return [];
804
+ return messagesByDate;
805
+ }, [messagesByDate]);
806
+
807
+ // Ensure we show complete conversation pairs (user message + AI response)
808
+ const completeConversationMessages = useMemo(() => {
809
+ if (!limitedMessagesByDate || limitedMessagesByDate.length === 0) return [];
810
+
811
+ const completeSections: { date: string | null; messages: any[] }[] = [];
812
+
813
+ limitedMessagesByDate.forEach((section) => {
814
+ const completeMessages: any[] = [];
815
+ const sectionMessages = [...section.messages];
816
+
817
+ console.log('🔄 Processing section for complete conversations:', {
818
+ sectionDate: section.date,
819
+ totalMessages: sectionMessages.length,
820
+ messages: sectionMessages.map((m) => ({
821
+ sender: m.sender,
822
+ isUserMessage: m.isUserMessage,
823
+ message: m.message?.substring(0, 30) + '...',
824
+ })),
825
+ });
826
+
827
+ // Group messages into conversation pairs
828
+ for (let i = 0; i < sectionMessages.length; i++) {
829
+ const currentMsg = sectionMessages[i];
830
+
831
+ // If this is a user message, look for its AI response
832
+ if (currentMsg.sender === 'user' || currentMsg.isUserMessage) {
833
+ completeMessages.push(currentMsg);
834
+
835
+ // Look for the corresponding AI response (next message should be AI)
836
+ if (i + 1 < sectionMessages.length) {
837
+ const nextMsg = sectionMessages[i + 1];
838
+ if (nextMsg.sender === 'ai' || !nextMsg.isUserMessage) {
839
+ completeMessages.push(nextMsg);
840
+ i++; // Skip the next message since we've already added it
841
+ }
842
+ }
843
+ } else if (currentMsg.sender === 'ai' || !currentMsg.isUserMessage) {
844
+ // If this is an AI message without a preceding user message, still show it
845
+ completeMessages.push(currentMsg);
846
+ }
847
+ }
848
+
849
+ console.log('🔄 Complete messages for section:', {
850
+ sectionDate: section.date,
851
+ completeMessages: completeMessages.map((m) => ({
852
+ sender: m.sender,
853
+ isUserMessage: m.isUserMessage,
854
+ message: m.message?.substring(0, 30) + '...',
855
+ })),
856
+ });
857
+
858
+ if (completeMessages.length > 0) {
859
+ completeSections.push({ ...section, messages: completeMessages });
860
+ }
861
+ });
862
+
863
+ return completeSections;
864
+ }, [limitedMessagesByDate]);
865
+
866
+ // Auto scroll to bottom when messages, typing status, or AI responses change
867
+ useEffect(() => {
868
+ // scrollToBottom('smooth', 100);
869
+ }, [completeConversationMessages?.length, isTyping, aiMessages.length, scrollToBottom]);
870
+
871
+ // Cleanup any pending timeout / scroll on unmount
872
+ useEffect(() => {
873
+ return () => {
874
+ if (successThinkingTimeoutRef.current) {
875
+ clearTimeout(successThinkingTimeoutRef.current);
876
+ }
877
+ if (scrollPendingRef.current) {
878
+ clearTimeout(scrollPendingRef.current);
879
+ scrollPendingRef.current = null;
880
+ }
881
+ if (streamScrollRafRef.current != null) {
882
+ cancelAnimationFrame(streamScrollRafRef.current);
883
+ streamScrollRafRef.current = null;
884
+ }
885
+ };
886
+ }, []);
887
+
888
+ const extractCleanContent = useCallback((summary: string): string => {
889
+ // console.log('summary...........', summary);
890
+ if (!summary) return 'Project generated successfully!';
891
+
892
+ const summeryData = summary
893
+ .replace(/<canvas_layers>[\s\S]*?<\/canvas_layers>/g, '')
894
+ .replace(/<task_summary>([\s\S]*?)<\/task_summary>/g, '');
895
+ if (summeryData && summeryData.trim() !== '' && summeryData.trim()?.length > 0) {
896
+ return summeryData || 'Project generated successfully!';
897
+ }
898
+ // Extract content from <task_summary> tags
899
+ const taskSummaryMatch = summary.match(/<task_summary>([\s\S]*?)<\/task_summary>/);
900
+ if (taskSummaryMatch) {
901
+ // const removedCanvasLayers = summary.replace(/<canvas_layers>[\s\S]*?<\/canvas_layers>/g, '').replace(/<task_summary>([\s\S]*?)<\/task_summary>/g, '');
902
+ return taskSummaryMatch?.[1]?.trim() ?? 'Project generated successfully!';
903
+ }
904
+
905
+ // If no task_summary tags, remove canvas_layers and return the rest
906
+ const withoutCanvasLayers = summary.replace(/<canvas_layers>[\s\S]*?<\/canvas_layers>/g, '').trim();
907
+ return withoutCanvasLayers || 'Project generated successfully!';
908
+ }, []);
909
+
910
+ return (
911
+ <div className={`flex flex-col h-full ${className}`}>
912
+ {/* Header with Tabs (hidden when isShowOnlyInbox is true) */}
913
+ {!isShowOnlyInbox && (
914
+ <div className="border-b border-gray-200 bg-white">
915
+ <div className="flex items-center justify-between px-4 py-3">
916
+ {/* Tabs */}
917
+ <div className="flex space-x-6">
918
+ <button
919
+ onClick={() => setActiveTab('chat')}
920
+ className={`relative ${
921
+ activeTab === 'chat'
922
+ ? 'text-blue-600 font-medium'
923
+ : 'text-gray-500 hover:text-gray-700'
924
+ } text-sm transition-colors`}
925
+ >
926
+ <span>Chat</span>
927
+ {activeTab === 'chat' && (
928
+ <div className="absolute bottom-0 left-0 w-full h-0.5 bg-blue-600"></div>
929
+ )}
930
+ </button>
931
+ <button
932
+ onClick={() => setActiveTab('history')}
933
+ className={`relative ${
934
+ activeTab === 'history'
935
+ ? 'text-blue-600 font-medium'
936
+ : 'text-gray-500 hover:text-gray-700'
937
+ } text-sm transition-colors`}
938
+ >
939
+ <span>History</span>
940
+ {activeTab === 'history' && (
941
+ <div className="absolute bottom-0 left-0 w-full h-0.5 bg-blue-600"></div>
942
+ )}
943
+ </button>
944
+ </div>
945
+
946
+ {/* New Chat Button */}
947
+ {/* <button
948
+ onClick={() => {
949
+ // Clear AI messages by sending update event to the machine
950
+ send({ type: 'UPDATE', value: { messages: [] } });
951
+ }}
952
+ className="px-4 py-2 text-sm text-gray-700 border border-gray-300 rounded-lg hover:bg-gray-200 transition-colors"
953
+ style={{ borderRadius: '10px' }}
954
+ >
955
+ New Chat
956
+ </button> */}
957
+ </div>
958
+ </div>
959
+ )}
960
+
961
+ {/* Tab Content */}
962
+ {activeTab === 'history' ? (
963
+ /* History Tab Content */
964
+ <div className="flex-1 overflow-y-auto bg-white">
965
+ {/* Search Bar */}
966
+ <div className="px-4 py-3 border-b border-gray-200">
967
+ <div className="relative">
968
+ <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
969
+ <svg
970
+ className="h-5 w-5 text-gray-400"
971
+ fill="none"
972
+ viewBox="0 0 24 24"
973
+ stroke="currentColor"
974
+ >
975
+ <path
976
+ strokeLinecap="round"
977
+ strokeLinejoin="round"
978
+ strokeWidth={2}
979
+ d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
980
+ />
981
+ </svg>
982
+ </div>
983
+ <input
984
+ type="text"
985
+ placeholder="Search messages..."
986
+ className="block w-full pl-10 pr-12 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"
987
+ />
988
+ <div className="absolute inset-y-0 right-0 pr-3 flex items-center">
989
+ <button className="text-gray-400 hover:text-gray-600">
990
+ <svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
991
+ <path
992
+ strokeLinecap="round"
993
+ strokeLinejoin="round"
994
+ strokeWidth={2}
995
+ d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"
996
+ />
997
+ </svg>
998
+ </button>
999
+ </div>
1000
+ </div>
1001
+ </div>
1002
+
1003
+ {/* Message History List */}
1004
+ <div className="px-4 py-2">
1005
+ {regularMessages && regularMessages.length > 0 ? (
1006
+ regularMessages
1007
+ .filter((msg: any) => (msg as any)?.propsConfiguration?.contents?.role === 'USER')
1008
+ .map((msg: any, index: number) => {
1009
+ const messageTime = new Date(msg.createdAt);
1010
+
1011
+ return (
1012
+ <div key={msg.id || index} className="mb-4">
1013
+ {/* Restore to this point button */}
1014
+ <div className="flex items-center justify-end mb-2">
1015
+ {/* <button className="text-blue-600 text-sm underline hover:text-blue-800 flex items-center">
1016
+ <svg
1017
+ className="w-4 h-4 mr-1"
1018
+ fill="none"
1019
+ viewBox="0 0 24 24"
1020
+ stroke="currentColor"
1021
+ >
1022
+ <path
1023
+ strokeLinecap="round"
1024
+ strokeLinejoin="round"
1025
+ strokeWidth={2}
1026
+ d="M15 19l-7-7 7-7"
1027
+ />
1028
+ </svg>
1029
+ Restore to this point
1030
+ </button> */}
1031
+ </div>
1032
+
1033
+ {/* Message using same container as Chat tab */}
1034
+ <ModernMessageGroupComponent
1035
+ messages={[
1036
+ {
1037
+ id: msg.id,
1038
+ message:
1039
+ (msg as any)?.propsConfiguration?.contents?.role ===
1040
+ 'ASSISTANT'
1041
+ ? msg.propsConfiguration?.contents?.fragment?.summary
1042
+ ? extractCleanContent(
1043
+ msg.propsConfiguration?.contents?.fragment
1044
+ ?.summary,
1045
+ )
1046
+ : msg.message
1047
+ : msg.message,
1048
+ author: msg.author || {
1049
+ id: 'user',
1050
+ givenName: 'User',
1051
+ familyName: '',
1052
+ fullName: 'User',
1053
+ username: 'user',
1054
+ email: '',
1055
+ picture: null,
1056
+ alias: [],
1057
+ tokens: [],
1058
+ },
1059
+ createdAt: msg.createdAt,
1060
+ type: (msg as any)?.type || PostTypeEnum.Aiassistant,
1061
+ isDelivered: false,
1062
+ isRead: false,
1063
+ parentId: null,
1064
+ fromServer: null,
1065
+ updatedAt: msg.createdAt,
1066
+ propsConfiguration: {
1067
+ ...(msg as any)?.propsConfiguration,
1068
+ contents: {
1069
+ ...(msg as any)?.propsConfiguration?.contents,
1070
+ attachment:
1071
+ (msg as any)?.props?.attachment ??
1072
+ (msg as any)?.propsConfiguration?.contents
1073
+ ?.attachment,
1074
+ },
1075
+ },
1076
+ props: (msg as any)?.props,
1077
+ files: msg.files,
1078
+ replies: null,
1079
+ channel: null,
1080
+ isPinned: false,
1081
+ },
1082
+ ]}
1083
+ currentUser={currentUser as any}
1084
+ onOpen={onOpen}
1085
+ onMessageClick={(msg) => setSelectedPost(msg)}
1086
+ isDesktopView={isDesktopView}
1087
+ isSmallScreen={isSmallScreen}
1088
+ showAuthorName={true}
1089
+ showAvatar={true}
1090
+ />
1091
+ </div>
1092
+ );
1093
+ })
1094
+ ) : (
1095
+ // Fallback entries when no messages
1096
+ <>
1097
+ {/* History Entry 1 */}
1098
+ <div className="mb-4">
1099
+ <div className="flex items-center justify-end mb-2">
1100
+ <button className="text-blue-600 text-sm underline hover:text-blue-800 flex items-center">
1101
+ <svg
1102
+ className="w-4 h-4 mr-1"
1103
+ fill="none"
1104
+ viewBox="0 0 24 24"
1105
+ stroke="currentColor"
1106
+ >
1107
+ <path
1108
+ strokeLinecap="round"
1109
+ strokeLinejoin="round"
1110
+ strokeWidth={2}
1111
+ d="M15 19l-7-7 7-7"
1112
+ />
1113
+ </svg>
1114
+ Restore to this point
1115
+ </button>
1116
+ </div>
1117
+ <div className="bg-gray-100 rounded-lg p-3">
1118
+ <p className="text-sm text-gray-900">Sample message for demonstration</p>
1119
+ </div>
1120
+ </div>
1121
+ </>
1122
+ )}
1123
+ </div>
1124
+ </div>
1125
+ ) : (
1126
+ /* Chat Tab Content */
1127
+ <div className="flex-1 overflow-y-auto bg-white">
1128
+ {/* Messages Display - Styled like MessagesBuilderUi */}
1129
+ <div
1130
+ className={`w-full pb-4 pt-2 ${
1131
+ isDesktopView ? 'space-y-3 max-w-full mx-auto' : isSmallScreen ? 'space-y-2' : 'space-y-2'
1132
+ }`}
1133
+ >
1134
+ {/* Load Past Messages Button */}
1135
+ {/* Load Past Messages disabled to show all messages */}
1136
+
1137
+ {/* Show placeholder when no messages */}
1138
+ {(!completeConversationMessages || completeConversationMessages.length === 0) && (
1139
+ <div className="px-4 py-8 text-center">
1140
+ <div className="text-gray-500 text-lg font-medium mb-2">
1141
+ Describe your idea and I'll help you create it step by step
1142
+ </div>
1143
+ <div className="text-gray-400 text-sm">
1144
+ Start a new conversation by typing your message below
1145
+ </div>
1146
+ </div>
1147
+ )}
1148
+
1149
+ {completeConversationMessages?.map((section, sectionIndex) => (
1150
+ <div key={`section-${sectionIndex}`} className="w-full px-4">
1151
+ {showDateSeparators && section.date && (
1152
+ <div className="flex items-center justify-center my-3">
1153
+ <div className="flex-grow border-t border-gray-200"></div>
1154
+ <div className="mx-4 px-3 py-1 bg-white border border-gray-200 rounded-full text-xs font-medium text-gray-600">
1155
+ {section.date}
1156
+ </div>
1157
+ <div className="flex-grow border-t border-gray-200"></div>
1158
+ </div>
1159
+ )}
1160
+
1161
+ <div className={`${isDesktopView ? 'mb-2' : 'mb-1'}`}>
1162
+ {section.messages.map((msg: any, msgIndex: number) => {
1163
+ // Get errors for this specific message
1164
+ const messageErrors = errorsByMessageId.get(msg.id) || [];
1165
+
1166
+ return (
1167
+ <div key={msg.id || msgIndex} className="mb-3">
1168
+ {/* AI Message Indicator */}
1169
+ {msg.isAIMessage && (
1170
+ <div className="flex items-center mb-2">
1171
+ <div className="w-2 h-2 bg-blue-500 rounded-full mr-2"></div>
1172
+ <span className="text-xs text-blue-600 font-medium">
1173
+ AI Assistant
1174
+ </span>
1175
+ </div>
1176
+ )}
1177
+
1178
+ {msg.isLoading ? (
1179
+ // Show loader for loading messages
1180
+ <div className="flex items-center space-x-2 bg-gray-50 border border-gray-200 px-4 py-3 rounded-lg">
1181
+ <div className="w-4 h-4 border-2 border-gray-300 border-t-gray-500 rounded-full animate-spin"></div>
1182
+ <span className="text-sm text-gray-600">
1183
+ {msg.isProcessing ? 'Thinking...' : 'Thinking...'}
1184
+ </span>
1185
+ </div>
1186
+ ) : (
1187
+ // Show normal message for non-loading messages
1188
+ <ModernMessageGroupComponent
1189
+ messages={[
1190
+ {
1191
+ id: msg.id,
1192
+ message:
1193
+ (msg as any)?.propsConfiguration?.contents?.role ===
1194
+ 'ASSISTANT'
1195
+ ? msg.propsConfiguration?.contents?.fragment
1196
+ ?.summary
1197
+ ? extractCleanContent(
1198
+ msg.propsConfiguration?.contents
1199
+ ?.fragment?.summary,
1200
+ )
1201
+ : msg.message
1202
+ : msg.message,
1203
+ author:
1204
+ msg.sender === 'user'
1205
+ ? msg.author
1206
+ : {
1207
+ id: 'ai-assistant',
1208
+ givenName: 'AI',
1209
+ familyName: 'Assistant',
1210
+ fullName: 'AI Assistant',
1211
+ username: 'ai-assistant',
1212
+ email: 'ai@assistant.com',
1213
+ picture: null,
1214
+ alias: [],
1215
+ tokens: [],
1216
+ },
1217
+ createdAt: msg.createdAt,
1218
+ type: (msg as any)?.type || PostTypeEnum.Aiassistant,
1219
+ isDelivered: false,
1220
+ isRead: false,
1221
+ parentId: null,
1222
+ fromServer: null,
1223
+ updatedAt: msg.createdAt,
1224
+ propsConfiguration: {
1225
+ ...(msg as any)?.propsConfiguration,
1226
+ contents: {
1227
+ ...(msg as any)?.propsConfiguration?.contents,
1228
+ attachment:
1229
+ (msg as any)?.props?.attachment ??
1230
+ (msg as any)?.propsConfiguration?.contents
1231
+ ?.attachment,
1232
+ },
1233
+ },
1234
+ props: (msg as any)?.props,
1235
+ files: msg.files,
1236
+ replies: null,
1237
+ channel: null,
1238
+ isPinned: false,
1239
+ },
1240
+ ]}
1241
+ currentUser={currentUser as any}
1242
+ onOpen={onOpen}
1243
+ onMessageClick={(msg) => setSelectedPost(msg)}
1244
+ isDesktopView={isDesktopView}
1245
+ isSmallScreen={isSmallScreen}
1246
+ showTimestamp={false}
1247
+ sandboxErrors={messageErrors}
1248
+ currentFiles={currentFiles}
1249
+ onFixError={fixError}
1250
+ />
1251
+ )}
1252
+ </div>
1253
+ );
1254
+ })}
1255
+ </div>
1256
+ </div>
1257
+ ))}
1258
+
1259
+ {/* Typing indicator */}
1260
+ {(isTyping || isSuccessThinking || isLoading || isCreatingSandbox) && (
1261
+ <div className="px-4">
1262
+ <div className="flex justify-start">
1263
+ <div className="bg-gray-50 border border-gray-200 px-4 py-3 rounded-lg">
1264
+ <div className="flex items-center space-x-2">
1265
+ <div className="w-4 h-4 border-2 border-gray-300 border-t-gray-500 rounded-full animate-spin"></div>
1266
+ <span className="text-sm text-gray-600">Thinking...</span>
1267
+ </div>
1268
+ </div>
1269
+ </div>
1270
+ </div>
1271
+ )}
1272
+
1273
+ <div ref={bottomRef} />
1274
+ </div>
1275
+
1276
+ {/* Subscription Handler for real-time message updates */}
1277
+ <SubscriptionHandler
1278
+ subscribeToMore={subscribeToMore}
1279
+ document={CHAT_MESSAGE_ADDED}
1280
+ variables={{ channelId: actualChannelId?.toString() }}
1281
+ enabled={!!actualChannelId && !!subscribeToMore}
1282
+ updateQuery={(prev: any, { subscriptionData }: any) => {
1283
+ if (!subscriptionData.data) return prev;
1284
+ const newMessage = subscriptionData.data.chatMessageAdded;
1285
+ console.log('newMessage...........', newMessage);
1286
+ if (!newMessage?.id) return prev;
1287
+
1288
+ const existing = prev?.messages?.data || [];
1289
+ const attachment =
1290
+ newMessage?.props?.attachment ?? newMessage?.propsConfiguration?.contents?.attachment;
1291
+ // Treat as dismiss: explicit dismissed flag, or THINKING with empty/inactive attachment, or THINKING with attachment: null
1292
+ const isDismissed =
1293
+ attachment?.dismissed === true ||
1294
+ (newMessage?.type === 'THINKING' &&
1295
+ (attachment == null ||
1296
+ (attachment?.isThinking === false &&
1297
+ !String(attachment?.thought || '').trim())));
1298
+
1299
+ let newData: any[];
1300
+ let newTotalCount: number;
1301
+
1302
+ if (isDismissed) {
1303
+ // Remove THINKING when dismissed
1304
+ newData = existing.filter((m: any) => m.id !== newMessage.id);
1305
+ newTotalCount = Math.max(
1306
+ 0,
1307
+ (prev?.messages?.totalCount || 0) - (existing.length - newData.length),
1308
+ );
1309
+ } else {
1310
+ const idx = existing.findIndex((m: any) => m.id === newMessage.id);
1311
+ if (idx >= 0) {
1312
+ // Replace existing message (same id)
1313
+ newData = [...existing.slice(0, idx), newMessage, ...existing.slice(idx + 1)];
1314
+ newTotalCount = prev?.messages?.totalCount || 0;
1315
+ } else {
1316
+ newData = [...existing, newMessage];
1317
+ newTotalCount = (prev?.messages?.totalCount || 0) + 1;
1318
+ }
1319
+ }
1320
+ // Preserve server order (posts are persisted in sequence). Dedupe by id only.
1321
+ if (!isDismissed) {
1322
+ const optId = optimisticAssistantMessageIdRef.current;
1323
+ if (optId && newMessage?.id) {
1324
+ if (String(newMessage.id) === String(optId)) {
1325
+ optimisticAssistantMessageIdRef.current = null;
1326
+ } else {
1327
+ const typ = String(newMessage.type || '').toUpperCase();
1328
+ const role = newMessage?.propsConfiguration?.contents?.role;
1329
+ const realAssistantChunk =
1330
+ [
1331
+ 'THINKING',
1332
+ 'TOOLUSE',
1333
+ 'CODEBLOCK',
1334
+ 'SERVICE',
1335
+ 'AIASSISTANT',
1336
+ 'ASSISTANT',
1337
+ ].includes(typ) || role === 'ASSISTANT';
1338
+ if (realAssistantChunk) {
1339
+ newData = newData.filter((m: any) => String(m?.id) !== String(optId));
1340
+ optimisticAssistantMessageIdRef.current = null;
1341
+ }
1342
+ }
1343
+ }
1344
+ newData = uniqBy(newData, 'id');
1345
+ }
1346
+
1347
+ return {
1348
+ ...prev,
1349
+ messages: {
1350
+ ...prev?.messages,
1351
+ data: newData,
1352
+ totalCount: newTotalCount,
1353
+ },
1354
+ };
1355
+ }}
1356
+ onError={(error) => {
1357
+ console.error('Subscription error:', error);
1358
+ }}
1359
+ />
1360
+ </div>
1361
+ )}
1362
+
1363
+ {/* Error Display */}
1364
+ {error && (
1365
+ <div className="mx-4 mb-4 p-3 bg-red-50 border border-red-200 rounded-lg">
1366
+ <div className="flex items-center justify-between">
1367
+ <div className="text-red-800 text-sm">{error}</div>
1368
+ <div className="flex space-x-2">
1369
+ <button
1370
+ onClick={handleRetry}
1371
+ className="px-2 py-1 text-xs bg-red-100 text-red-700 rounded hover:bg-red-200 transition-colors"
1372
+ >
1373
+ Retry
1374
+ </button>
1375
+ <button
1376
+ onClick={handleClearError}
1377
+ className="px-2 py-1 text-xs bg-gray-100 text-gray-700 rounded hover:bg-gray-200 transition-colors"
1378
+ >
1379
+ Dismiss
1380
+ </button>
1381
+ </div>
1382
+ </div>
1383
+ </div>
1384
+ )}
1385
+
1386
+ {/* Input Area - Only show for Chat tab */}
1387
+ {activeTab === 'chat' &&
1388
+ (() => {
1389
+ // Compute final showStopButton value: use prop if provided, otherwise compute from conditions
1390
+ // const finalShowStopButton =
1391
+ // showStopButton !== undefined
1392
+ // ? showStopButton
1393
+ // : !isShowOnlyInbox && (isCreatingSandbox || isLoading || isSuccessThinking);
1394
+
1395
+ const isShowStopButton = showStopButton && (isCreatingSandbox || isSuccessThinking) ? true : false;
1396
+
1397
+ return (
1398
+ <div className="border-t border-gray-200 bg-white">
1399
+ {/* Removed temporary test button */}
1400
+ <InputComponent
1401
+ channelId={actualChannelId}
1402
+ handleSend={handleSend}
1403
+ placeholder={placeholder}
1404
+ modelConfig={modelConfig}
1405
+ onModelConfigChange={updateModelConfig}
1406
+ textareaStyles={
1407
+ isShowOnlyInbox ? { height: '80px', minHeight: '80px', maxHeight: '80px' } : {}
1408
+ }
1409
+ showModeSelector={showModeSelector}
1410
+ showStopButton={isShowStopButton}
1411
+ onStop={isShowStopButton ? handleStop : undefined}
1412
+ templates={templates}
1413
+ selectedTemplate={selectedTemplate}
1414
+ suggestedTemplate={suggestedTemplate}
1415
+ onSelectTemplate={onSelectTemplate}
1416
+ templateSelectedLabel={templateSelectedLabel}
1417
+ templateModalItems={templateModalItems}
1418
+ showTemplateModal={showTemplateModal}
1419
+ onOpenTemplateModal={onOpenTemplateModal}
1420
+ onCloseTemplateModal={onCloseTemplateModal}
1421
+ onSelectTemplateById={onSelectTemplateById}
1422
+ onClearTemplate={onClearTemplate}
1423
+ onAcceptSuggestedTemplate={onAcceptSuggestedTemplate}
1424
+ isAnalyzingQuery={isAnalyzingQuery}
1425
+ onQueryChange={onQueryChange}
1426
+ leftItemsOverrides={leftItemsOverrides}
1427
+ rightItemsOverrides={rightItemsOverrides}
1428
+ inputToolBarProps={inputToolBarProps}
1429
+ />
1430
+ </div>
1431
+ );
1432
+ })()}
1433
+
1434
+ {/* Optional Modal for user content like MessagesBuilderUi */}
1435
+ {isOpen ? (
1436
+ <div>
1437
+ <div className="fixed inset-0 bg-black bg-opacity-50 z-40" onClick={onClose} />
1438
+ <div className="fixed z-50 left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2">
1439
+ <div
1440
+ className="bg-white w-[1036px] h-[700px] rounded-lg shadow-xl"
1441
+ style={{ boxShadow: '0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)' }}
1442
+ >
1443
+ <div className="flex justify-between border-b border-gray-300 pb-4 pt-4">
1444
+ <button
1445
+ onClick={onClose}
1446
+ className="w-8 ml-3 text-black hover:text-black focus:outline-none"
1447
+ >
1448
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1449
+ <path
1450
+ strokeLinecap="round"
1451
+ strokeLinejoin="round"
1452
+ strokeWidth={2}
1453
+ d="M6 18L18 6M6 6l12 12"
1454
+ />
1455
+ </svg>
1456
+ </button>
1457
+ </div>
1458
+ <div className="p-4">
1459
+ {/* Keep minimal until full UserModalContent is needed */}
1460
+ <div className="text-sm text-gray-700">{selectedElement?.author?.username}</div>
1461
+ </div>
1462
+ </div>
1463
+ </div>
1464
+ </div>
1465
+ ) : null}
1466
+ </div>
1467
+ );
1468
+ };