@messenger-box/tailwind-ui-inbox 10.0.3-alpha.184 → 10.0.3-alpha.185

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 (59) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/components/AIAgent/AIAgent.d.ts +2 -0
  3. package/lib/components/AIAgent/AIAgent.d.ts.map +1 -1
  4. package/lib/components/AIAgent/AIAgent.js +232 -89
  5. package/lib/components/AIAgent/AIAgent.js.map +1 -1
  6. package/lib/components/InboxMessage/InputComponent.d.ts +3 -1
  7. package/lib/components/InboxMessage/InputComponent.d.ts.map +1 -1
  8. package/lib/components/InboxMessage/InputComponent.js +6 -2
  9. package/lib/components/InboxMessage/InputComponent.js.map +1 -1
  10. package/lib/components/InboxMessage/RightSidebarAi.d.ts +2 -0
  11. package/lib/components/InboxMessage/RightSidebarAi.d.ts.map +1 -1
  12. package/lib/components/InboxMessage/RightSidebarAi.js.map +1 -1
  13. package/lib/components/ModelConfigPanel.d.ts +4 -0
  14. package/lib/components/ModelConfigPanel.d.ts.map +1 -1
  15. package/lib/components/ModelConfigPanel.js +17 -2
  16. package/lib/components/ModelConfigPanel.js.map +1 -1
  17. package/lib/container/AiLandingInput.d.ts +2 -0
  18. package/lib/container/AiLandingInput.d.ts.map +1 -1
  19. package/lib/container/AiLandingInput.js +4 -0
  20. package/lib/container/AiLandingInput.js.map +1 -1
  21. package/lib/container/Inbox.js +1 -1
  22. package/lib/container/InboxAiMessagesLoader.d.ts +2 -0
  23. package/lib/container/InboxAiMessagesLoader.d.ts.map +1 -1
  24. package/lib/container/InboxAiMessagesLoader.js +5 -1
  25. package/lib/container/InboxAiMessagesLoader.js.map +1 -1
  26. package/lib/container/InboxContainer.d.ts +2 -0
  27. package/lib/container/InboxContainer.d.ts.map +1 -1
  28. package/lib/container/InboxContainer.js.map +1 -1
  29. package/lib/container/InboxWithAiLoader.d.ts +2 -0
  30. package/lib/container/InboxWithAiLoader.d.ts.map +1 -1
  31. package/lib/container/InboxWithAiLoader.js +9 -3
  32. package/lib/container/InboxWithAiLoader.js.map +1 -1
  33. package/lib/container/ServiceInbox.js +1 -1
  34. package/lib/container/ServiceInbox.js.map +1 -1
  35. package/lib/container/TestInboxWithAiLoader.d.ts.map +1 -1
  36. package/lib/container/TestInboxWithAiLoader.js +5 -1
  37. package/lib/container/TestInboxWithAiLoader.js.map +1 -1
  38. package/lib/container/ThreadMessages.js +1 -1
  39. package/lib/container/ThreadMessages.js.map +1 -1
  40. package/lib/container/ThreadMessagesInbox.js +1 -1
  41. package/lib/container/ThreadMessagesInbox.js.map +1 -1
  42. package/lib/container/Threads.js +1 -1
  43. package/lib/container/Threads.js.map +1 -1
  44. package/lib/templates/InboxWithAi.d.ts +2 -0
  45. package/lib/templates/InboxWithAi.d.ts.map +1 -1
  46. package/lib/templates/InboxWithAi.js +24 -5
  47. package/lib/templates/InboxWithAi.js.map +1 -1
  48. package/lib/templates/InboxWithAi.tsx +25 -2
  49. package/package.json +2 -2
  50. package/src/components/AIAgent/AIAgent.tsx +291 -112
  51. package/src/components/InboxMessage/InputComponent.tsx +6 -0
  52. package/src/components/InboxMessage/RightSidebarAi.tsx +2 -0
  53. package/src/components/ModelConfigPanel.tsx +55 -37
  54. package/src/container/AiLandingInput.tsx +6 -0
  55. package/src/container/InboxAiMessagesLoader.tsx +6 -0
  56. package/src/container/InboxContainer.tsx +2 -0
  57. package/src/container/InboxWithAiLoader.tsx +8 -0
  58. package/src/container/TestInboxWithAiLoader.tsx +4 -0
  59. package/src/templates/InboxWithAi.tsx +25 -2
@@ -48,6 +48,8 @@ interface AIAgentProps {
48
48
  sendMessageInput?: ICreateChannelInput;
49
49
  isShowOnlyInbox?: boolean;
50
50
  showModeSelector?: boolean;
51
+ showStopButton?: boolean;
52
+ onStop?: () => void;
51
53
  [key: string]: any; // Allow other props to be passed through to Inbox
52
54
  }
53
55
 
@@ -69,9 +71,11 @@ export const AIAgent: React.FC<AIAgentProps> = ({
69
71
  sendMessageInput,
70
72
  isShowOnlyInbox = false,
71
73
  showModeSelector = false,
74
+ showStopButton = false,
75
+ onStop,
72
76
  }) => {
73
77
  const [state, send] = useMachine(aiAgentMachine);
74
- // const apolloClient = useApolloClient();
78
+ const apolloClient = useApolloClient();
75
79
  const { startUpload } = useUploadFiles();
76
80
  const [sendMsg] = useSendMessagesMutation();
77
81
  const [createChannelWorkflowJob] = useCreateChannelWorkflowJobMutation();
@@ -116,7 +120,7 @@ export const AIAgent: React.FC<AIAgentProps> = ({
116
120
  },
117
121
  });
118
122
 
119
- console.log('messagesQuery...', JSON.stringify(messagesQuery?.data?.messages?.data));
123
+ // console.log('messagesQuery...', JSON.stringify(messagesQuery?.data?.messages?.data));
120
124
 
121
125
  const { messages: aiMessages, error, isTyping } = state.context;
122
126
  const { t } = useTranslation('translations');
@@ -217,6 +221,48 @@ export const AIAgent: React.FC<AIAgentProps> = ({
217
221
  return orderBy(uniqBy(allMessages, 'id'), ['createdAt'], ['asc']);
218
222
  }, [messagesData?.messages?.data]);
219
223
 
224
+ // Check if any ASSISTANT message has isCreatingSandbox: true in fragment
225
+ // Only hide loader when isCreatingSandbox is explicitly false, not when it's undefined/missing
226
+ const isCreatingSandbox = useMemo(() => {
227
+ if (isShowOnlyInbox) return false; // Only check when isShowOnlyInbox is false
228
+ if (!regularMessages || regularMessages.length === 0) return false;
229
+
230
+ // Find the most recent ASSISTANT message
231
+ const mostRecentAssistant = regularMessages
232
+ .slice()
233
+ .reverse()
234
+ .find((m: any) => m?.propsConfiguration?.contents?.role === 'ASSISTANT');
235
+
236
+ if (!mostRecentAssistant) return false;
237
+
238
+ const fragment = mostRecentAssistant?.propsConfiguration?.contents?.fragment;
239
+
240
+ // If isCreatingSandbox is explicitly true, show loader
241
+ if (fragment?.isCreatingSandbox === true) {
242
+ return true;
243
+ }
244
+
245
+ // If isCreatingSandbox is explicitly false, hide loader
246
+ if (fragment?.isCreatingSandbox === false) {
247
+ return false;
248
+ }
249
+
250
+ // If isCreatingSandbox is undefined/missing, check if message is complete
251
+ // If incomplete (no files, no summary, no error), we're still creating - show loader
252
+ if (fragment) {
253
+ const hasFiles = fragment.files && Object.keys(fragment.files).length > 0;
254
+ const hasSummary = fragment.summary && fragment.summary.trim().length > 0;
255
+ const hasError = fragment.isError === true || fragment.type === 'ERROR';
256
+
257
+ // If message is incomplete (no files, no summary, no error), we're still creating
258
+ if (!hasFiles && !hasSummary && !hasError) {
259
+ return true;
260
+ }
261
+ }
262
+
263
+ return false;
264
+ }, [regularMessages, isShowOnlyInbox]);
265
+
220
266
  // Send regular messages to AI agent machine for context
221
267
  useEffect(() => {
222
268
  if (regularMessages && regularMessages.length > 0) {
@@ -345,6 +391,92 @@ export const AIAgent: React.FC<AIAgentProps> = ({
345
391
  }
346
392
  setIsSuccessThinking(true);
347
393
  setIsLoading(true);
394
+
395
+ // Optimistic update: Add assistant message with isCreatingSandbox: true
396
+ if (!isShowOnlyInbox && actualChannelId) {
397
+ try {
398
+ const optimisticAssistantMessageId = objectId();
399
+ const optimisticAssistantMessage = {
400
+ __typename: 'Post',
401
+ id: optimisticAssistantMessageId,
402
+ content: '',
403
+ message: '',
404
+ createdAt: new Date().toISOString(),
405
+ updatedAt: new Date().toISOString(),
406
+ author: {
407
+ __typename: 'User',
408
+ id: 'ai-assistant',
409
+ username: 'ai-assistant',
410
+ givenName: 'AI',
411
+ familyName: 'Assistant',
412
+ fullName: 'AI Assistant',
413
+ email: 'ai@assistant.com',
414
+ picture: null,
415
+ alias: [],
416
+ tokens: [],
417
+ },
418
+ propsConfiguration: {
419
+ __typename: 'PostPropsConfiguration',
420
+ contents: {
421
+ __typename: 'PostContents',
422
+ role: 'ASSISTANT',
423
+ fragment: {
424
+ isCreatingSandbox: true,
425
+ },
426
+ },
427
+ },
428
+ props: {},
429
+ files: [],
430
+ replies: null,
431
+ channel: null,
432
+ isPinned: false,
433
+ isDelivered: false,
434
+ isRead: false,
435
+ parentId: null,
436
+ fromServer: null,
437
+ type: PostTypeEnum.Aiassistant,
438
+ };
439
+
440
+ // Update cache optimistically
441
+ const messagesQuery = {
442
+ query: MessagesDocument,
443
+ variables: {
444
+ channelId: actualChannelId.toString(),
445
+ parentId: null,
446
+ limit: 1,
447
+ },
448
+ };
449
+
450
+ try {
451
+ const existingData = apolloClient.readQuery(messagesQuery) as any;
452
+ if (existingData?.messages) {
453
+ // Check if optimistic message already exists
454
+ const existingOptimistic = existingData.messages.data?.find(
455
+ (m: any) => m.id === optimisticAssistantMessageId,
456
+ );
457
+
458
+ if (!existingOptimistic) {
459
+ apolloClient.writeQuery({
460
+ ...messagesQuery,
461
+ data: {
462
+ messages: {
463
+ ...existingData.messages,
464
+ data: [...(existingData.messages.data || []), optimisticAssistantMessage],
465
+ totalCount: (existingData.messages.totalCount || 0) + 1,
466
+ },
467
+ },
468
+ });
469
+ }
470
+ }
471
+ } catch (error) {
472
+ // Cache might not exist yet, that's okay
473
+ console.debug('Optimistic update failed (cache might not exist):', error);
474
+ }
475
+ } catch (error) {
476
+ console.error('Failed to create optimistic update:', error);
477
+ }
478
+ }
479
+
348
480
  // Safety auto-stop in case no event arrives
349
481
  // successThinkingTimeoutRef.current = setTimeout(() => {
350
482
  // setIsSuccessThinking(false);
@@ -402,6 +534,8 @@ export const AIAgent: React.FC<AIAgentProps> = ({
402
534
  navigate,
403
535
  createChannelWorkflowJob,
404
536
  sendMessageInput,
537
+ apolloClient,
538
+ isShowOnlyInbox,
405
539
  ],
406
540
  );
407
541
 
@@ -413,6 +547,15 @@ export const AIAgent: React.FC<AIAgentProps> = ({
413
547
  [handleSend],
414
548
  );
415
549
 
550
+ const handleStop = useCallback(() => {
551
+ // Stop the current operation
552
+
553
+ console.log('Stop button clicked - stopping current operation');
554
+
555
+ // Call the onStop prop if provided
556
+ onStop?.();
557
+ }, [setIsLoading, onStop]);
558
+
416
559
  const handleRetry = useCallback(() => {
417
560
  send({ type: 'RETRY' });
418
561
  }, [send]);
@@ -441,11 +584,14 @@ export const AIAgent: React.FC<AIAgentProps> = ({
441
584
  }, [regularMessages, currentUser]);
442
585
 
443
586
  // Derive sandbox-style errors from message fragments so we can show the Fix Error UI
444
- const derivedFragmentErrors = useMemo(() => {
445
- if (!regularMessages || regularMessages.length === 0) return [];
587
+ // Returns unique errors globally (deduplicated by error message/content)
588
+ // Map errors to their respective messages (messageId -> errors[])
589
+ const errorsByMessageId = useMemo(() => {
590
+ if (!regularMessages || regularMessages.length === 0) return new Map<string, any[]>();
446
591
 
447
- const errors: any[] = [];
592
+ const errorsMap = new Map<string, any[]>();
448
593
 
594
+ // Collect errors from all messages and map them to message IDs
449
595
  (regularMessages || []).forEach((m: any) => {
450
596
  const fragment = m?.propsConfiguration?.contents?.fragment;
451
597
  if (!fragment) return;
@@ -453,24 +599,36 @@ export const AIAgent: React.FC<AIAgentProps> = ({
453
599
  const isErrorFragment = fragment?.isError === true || fragment?.type === 'ERROR';
454
600
  if (!isErrorFragment) return;
455
601
 
456
- errors.push({
457
- id: fragment.id || m.id || objectId(),
602
+ const errorId = fragment.id || m.id || objectId();
603
+ const messageId = m.id || 'unknown';
604
+
605
+ const errorMessage =
606
+ fragment.errorMessage ||
607
+ fragment.summary ||
608
+ (m as any).message ||
609
+ (m as any).content ||
610
+ 'An error occurred in the AI sandbox.';
611
+
612
+ const error = {
613
+ id: errorId,
614
+ messageId: messageId,
458
615
  errorType: fragment.errorType || 'RUNTIME_ERROR',
459
616
  timestamp: fragment.timestamp || m.createdAt || new Date().toISOString(),
460
617
  sandboxId: fragment.sandboxId || fragment.projectId || actualChannelId || 'unknown-sandbox',
461
- message:
462
- fragment.errorMessage ||
463
- fragment.summary ||
464
- (m as any).message ||
465
- (m as any).content ||
466
- 'An error occurred in the AI sandbox.',
618
+ message: errorMessage,
467
619
  stack: fragment.stack || '',
468
620
  url: fragment.sandboxUrl || fragment.url,
469
- fixable: fragment.fixable !== false, // default to true unless explicitly false
470
- });
621
+ fixable: fragment.fixable !== false,
622
+ };
623
+
624
+ // Add error to the message's error list
625
+ if (!errorsMap.has(messageId)) {
626
+ errorsMap.set(messageId, []);
627
+ }
628
+ errorsMap.get(messageId)!.push(error);
471
629
  });
472
630
 
473
- return errors;
631
+ return errorsMap;
474
632
  }, [regularMessages, actualChannelId]);
475
633
 
476
634
  // Build list with date separators similar to MessagesBuilderUi
@@ -876,93 +1034,98 @@ export const AIAgent: React.FC<AIAgentProps> = ({
876
1034
  )}
877
1035
 
878
1036
  <div className={`${isDesktopView ? 'mb-2' : 'mb-1'}`}>
879
- {section.messages.map((msg: any, msgIndex: number) => (
880
- <div key={msg.id || msgIndex} className="mb-3">
881
- {/* AI Message Indicator */}
882
- {msg.isAIMessage && (
883
- <div className="flex items-center mb-2">
884
- <div className="w-2 h-2 bg-blue-500 rounded-full mr-2"></div>
885
- <span className="text-xs text-blue-600 font-medium">
886
- AI Assistant
887
- </span>
888
- </div>
889
- )}
890
-
891
- {msg.isLoading ? (
892
- // Show loader for loading messages
893
- <div className="flex items-center space-x-2 bg-gray-50 border border-gray-200 px-4 py-3 rounded-lg">
894
- <div className="w-4 h-4 border-2 border-gray-300 border-t-gray-500 rounded-full animate-spin"></div>
895
- <span className="text-sm text-gray-600">
896
- {msg.isProcessing ? 'Thinking...' : 'Thinking...'}
897
- </span>
898
- </div>
899
- ) : (
900
- // Show normal message for non-loading messages
901
- <ModernMessageGroupComponent
902
- messages={[
903
- {
904
- id: msg.id,
905
- // message: msg.message,
906
- message:
907
- (msg as any)?.propsConfiguration?.contents?.role ===
908
- 'ASSISTANT'
909
- ? msg.propsConfiguration?.contents?.fragment
910
- ?.summary
911
- ? extractCleanContent(
912
- msg.propsConfiguration?.contents?.fragment
913
- ?.summary,
914
- )
915
- : msg.message
916
- : msg.message,
917
- author:
918
- msg.sender === 'user'
919
- ? msg.author
920
- : {
921
- id: 'ai-assistant',
922
- givenName: 'AI',
923
- familyName: 'Assistant',
924
- fullName: 'AI Assistant',
925
- username: 'ai-assistant',
926
- email: 'ai@assistant.com',
927
- picture: null,
928
- alias: [],
929
- tokens: [],
930
- },
931
- createdAt: msg.createdAt,
932
- //type: 'Simple' as any,
933
- type: PostTypeEnum.Aiassistant,
934
- isDelivered: false,
935
- isRead: false,
936
- parentId: null,
937
- fromServer: null,
938
- updatedAt: msg.createdAt,
939
- propsConfiguration: msg.propsConfiguration,
940
- props: msg.props,
941
- files: msg.files,
942
- replies: null,
943
- channel: null,
944
- isPinned: false,
945
- },
946
- ]}
947
- currentUser={currentUser as any}
948
- onOpen={onOpen}
949
- onMessageClick={(msg) => setSelectedPost(msg)}
950
- isDesktopView={isDesktopView}
951
- isSmallScreen={isSmallScreen}
952
- showTimestamp={false}
953
- sandboxErrors={[...sandboxErrors, ...derivedFragmentErrors]}
954
- currentFiles={currentFiles}
955
- onFixError={fixError}
956
- />
957
- )}
958
- </div>
959
- ))}
1037
+ {section.messages.map((msg: any, msgIndex: number) => {
1038
+ // Get errors for this specific message
1039
+ const messageErrors = errorsByMessageId.get(msg.id) || [];
1040
+
1041
+ return (
1042
+ <div key={msg.id || msgIndex} className="mb-3">
1043
+ {/* AI Message Indicator */}
1044
+ {msg.isAIMessage && (
1045
+ <div className="flex items-center mb-2">
1046
+ <div className="w-2 h-2 bg-blue-500 rounded-full mr-2"></div>
1047
+ <span className="text-xs text-blue-600 font-medium">
1048
+ AI Assistant
1049
+ </span>
1050
+ </div>
1051
+ )}
1052
+
1053
+ {msg.isLoading ? (
1054
+ // Show loader for loading messages
1055
+ <div className="flex items-center space-x-2 bg-gray-50 border border-gray-200 px-4 py-3 rounded-lg">
1056
+ <div className="w-4 h-4 border-2 border-gray-300 border-t-gray-500 rounded-full animate-spin"></div>
1057
+ <span className="text-sm text-gray-600">
1058
+ {msg.isProcessing ? 'Thinking...' : 'Thinking...'}
1059
+ </span>
1060
+ </div>
1061
+ ) : (
1062
+ // Show normal message for non-loading messages
1063
+ <ModernMessageGroupComponent
1064
+ messages={[
1065
+ {
1066
+ id: msg.id,
1067
+ // message: msg.message,
1068
+ message:
1069
+ (msg as any)?.propsConfiguration?.contents?.role ===
1070
+ 'ASSISTANT'
1071
+ ? msg.propsConfiguration?.contents?.fragment
1072
+ ?.summary
1073
+ ? extractCleanContent(
1074
+ msg.propsConfiguration?.contents
1075
+ ?.fragment?.summary,
1076
+ )
1077
+ : msg.message
1078
+ : msg.message,
1079
+ author:
1080
+ msg.sender === 'user'
1081
+ ? msg.author
1082
+ : {
1083
+ id: 'ai-assistant',
1084
+ givenName: 'AI',
1085
+ familyName: 'Assistant',
1086
+ fullName: 'AI Assistant',
1087
+ username: 'ai-assistant',
1088
+ email: 'ai@assistant.com',
1089
+ picture: null,
1090
+ alias: [],
1091
+ tokens: [],
1092
+ },
1093
+ createdAt: msg.createdAt,
1094
+ //type: 'Simple' as any,
1095
+ type: PostTypeEnum.Aiassistant,
1096
+ isDelivered: false,
1097
+ isRead: false,
1098
+ parentId: null,
1099
+ fromServer: null,
1100
+ updatedAt: msg.createdAt,
1101
+ propsConfiguration: msg.propsConfiguration,
1102
+ props: msg.props,
1103
+ files: msg.files,
1104
+ replies: null,
1105
+ channel: null,
1106
+ isPinned: false,
1107
+ },
1108
+ ]}
1109
+ currentUser={currentUser as any}
1110
+ onOpen={onOpen}
1111
+ onMessageClick={(msg) => setSelectedPost(msg)}
1112
+ isDesktopView={isDesktopView}
1113
+ isSmallScreen={isSmallScreen}
1114
+ showTimestamp={false}
1115
+ sandboxErrors={messageErrors}
1116
+ currentFiles={currentFiles}
1117
+ onFixError={fixError}
1118
+ />
1119
+ )}
1120
+ </div>
1121
+ );
1122
+ })}
960
1123
  </div>
961
1124
  </div>
962
1125
  ))}
963
1126
 
964
1127
  {/* Typing indicator */}
965
- {(isTyping || isSuccessThinking || isLoading) && (
1128
+ {(isTyping || isSuccessThinking || isLoading || isCreatingSandbox) && (
966
1129
  <div className="px-4">
967
1130
  <div className="flex justify-start">
968
1131
  <div className="bg-gray-50 border border-gray-200 px-4 py-3 rounded-lg">
@@ -1034,20 +1197,36 @@ export const AIAgent: React.FC<AIAgentProps> = ({
1034
1197
  )}
1035
1198
 
1036
1199
  {/* Input Area - Only show for Chat tab */}
1037
- {activeTab === 'chat' && (
1038
- <div className="border-t border-gray-200 bg-white">
1039
- {/* Removed temporary test button */}
1040
- <InputComponent
1041
- channelId={actualChannelId}
1042
- handleSend={handleSend}
1043
- placeholder={placeholder}
1044
- modelConfig={modelConfig}
1045
- onModelConfigChange={updateModelConfig}
1046
- textareaStyles={isShowOnlyInbox ? { height: '80px', minHeight: '80px', maxHeight: '80px' } : {}}
1047
- showModeSelector={showModeSelector}
1048
- />
1049
- </div>
1050
- )}
1200
+ {activeTab === 'chat' &&
1201
+ (() => {
1202
+ // Compute final showStopButton value: use prop if provided, otherwise compute from conditions
1203
+ // const finalShowStopButton =
1204
+ // showStopButton !== undefined
1205
+ // ? showStopButton
1206
+ // : !isShowOnlyInbox && (isCreatingSandbox || isLoading || isSuccessThinking);
1207
+
1208
+ const isShowStopButton =
1209
+ showStopButton && !isShowOnlyInbox ? isCreatingSandbox || isSuccessThinking : false;
1210
+
1211
+ return (
1212
+ <div className="border-t border-gray-200 bg-white">
1213
+ {/* Removed temporary test button */}
1214
+ <InputComponent
1215
+ channelId={actualChannelId}
1216
+ handleSend={handleSend}
1217
+ placeholder={placeholder}
1218
+ modelConfig={modelConfig}
1219
+ onModelConfigChange={updateModelConfig}
1220
+ textareaStyles={
1221
+ isShowOnlyInbox ? { height: '80px', minHeight: '80px', maxHeight: '80px' } : {}
1222
+ }
1223
+ showModeSelector={showModeSelector}
1224
+ showStopButton={isShowStopButton}
1225
+ onStop={isShowStopButton ? handleStop : undefined}
1226
+ />
1227
+ </div>
1228
+ );
1229
+ })()}
1051
1230
 
1052
1231
  {/* Optional Modal for user content like MessagesBuilderUi */}
1053
1232
  {isOpen ? (
@@ -17,6 +17,8 @@ type MessageInputProps = {
17
17
  showModelToolbarProjectSettings?: boolean;
18
18
  isShowMeta?: boolean;
19
19
  showModeSelector?: boolean;
20
+ showStopButton?: boolean;
21
+ onStop?: () => void;
20
22
  };
21
23
 
22
24
  export const InputComponent = ({
@@ -30,6 +32,8 @@ export const InputComponent = ({
30
32
  showModelToolbarProjectSettings = false,
31
33
  isShowMeta = false,
32
34
  showModeSelector = false,
35
+ showStopButton = false,
36
+ onStop,
33
37
  }: MessageInputProps) => {
34
38
  const [message, setMessage] = useState('');
35
39
  const [sending, setSending] = useState(false);
@@ -184,6 +188,8 @@ export const InputComponent = ({
184
188
  showProjectSettings={showModelToolbarProjectSettings}
185
189
  isShowMeta={isShowMeta}
186
190
  showModeSelector={showModeSelector}
191
+ showStopButton={showStopButton}
192
+ onStop={onStop}
187
193
  />
188
194
  </div>
189
195
  </div>
@@ -29,6 +29,8 @@ export interface IRightSidebarAi extends React.HTMLAttributes<HTMLDivElement> {
29
29
  handleRecreateSandbox?: (messageId: string) => void | Promise<any>;
30
30
  isCreatingSandbox?: boolean;
31
31
  setIsCreatingSandbox?: (isCreatingSandbox: boolean) => void;
32
+ showStopButton?: boolean;
33
+ onStop?: () => void;
32
34
  [key: string]: any;
33
35
  }
34
36