@lobehub/chat 1.33.5 → 1.34.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 (203) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/locales/ar/chat.json +7 -0
  4. package/locales/ar/common.json +2 -0
  5. package/locales/ar/models.json +24 -0
  6. package/locales/ar/setting.json +5 -0
  7. package/locales/ar/thread.json +5 -0
  8. package/locales/bg-BG/chat.json +7 -0
  9. package/locales/bg-BG/common.json +2 -0
  10. package/locales/bg-BG/models.json +24 -0
  11. package/locales/bg-BG/setting.json +5 -0
  12. package/locales/bg-BG/thread.json +5 -0
  13. package/locales/de-DE/chat.json +7 -0
  14. package/locales/de-DE/common.json +2 -0
  15. package/locales/de-DE/models.json +24 -0
  16. package/locales/de-DE/setting.json +5 -0
  17. package/locales/de-DE/thread.json +5 -0
  18. package/locales/en-US/chat.json +7 -0
  19. package/locales/en-US/common.json +2 -0
  20. package/locales/en-US/models.json +24 -0
  21. package/locales/en-US/setting.json +5 -0
  22. package/locales/en-US/thread.json +5 -0
  23. package/locales/es-ES/chat.json +7 -0
  24. package/locales/es-ES/common.json +2 -0
  25. package/locales/es-ES/models.json +24 -0
  26. package/locales/es-ES/setting.json +5 -0
  27. package/locales/es-ES/thread.json +5 -0
  28. package/locales/fa-IR/chat.json +7 -0
  29. package/locales/fa-IR/common.json +2 -0
  30. package/locales/fa-IR/models.json +24 -0
  31. package/locales/fa-IR/setting.json +5 -0
  32. package/locales/fa-IR/thread.json +5 -0
  33. package/locales/fr-FR/chat.json +7 -0
  34. package/locales/fr-FR/common.json +2 -0
  35. package/locales/fr-FR/models.json +24 -0
  36. package/locales/fr-FR/setting.json +5 -0
  37. package/locales/fr-FR/thread.json +5 -0
  38. package/locales/it-IT/chat.json +7 -0
  39. package/locales/it-IT/common.json +2 -0
  40. package/locales/it-IT/models.json +24 -0
  41. package/locales/it-IT/setting.json +5 -0
  42. package/locales/it-IT/thread.json +5 -0
  43. package/locales/ja-JP/chat.json +7 -0
  44. package/locales/ja-JP/common.json +2 -0
  45. package/locales/ja-JP/models.json +24 -0
  46. package/locales/ja-JP/setting.json +5 -0
  47. package/locales/ja-JP/thread.json +5 -0
  48. package/locales/ko-KR/chat.json +7 -0
  49. package/locales/ko-KR/common.json +2 -0
  50. package/locales/ko-KR/models.json +24 -0
  51. package/locales/ko-KR/setting.json +5 -0
  52. package/locales/ko-KR/thread.json +5 -0
  53. package/locales/nl-NL/chat.json +7 -0
  54. package/locales/nl-NL/common.json +2 -0
  55. package/locales/nl-NL/models.json +24 -0
  56. package/locales/nl-NL/setting.json +5 -0
  57. package/locales/nl-NL/thread.json +5 -0
  58. package/locales/pl-PL/chat.json +7 -0
  59. package/locales/pl-PL/common.json +2 -0
  60. package/locales/pl-PL/models.json +24 -0
  61. package/locales/pl-PL/setting.json +5 -0
  62. package/locales/pl-PL/thread.json +5 -0
  63. package/locales/pt-BR/chat.json +7 -0
  64. package/locales/pt-BR/common.json +2 -0
  65. package/locales/pt-BR/models.json +24 -0
  66. package/locales/pt-BR/setting.json +5 -0
  67. package/locales/pt-BR/thread.json +5 -0
  68. package/locales/ru-RU/chat.json +7 -0
  69. package/locales/ru-RU/common.json +2 -0
  70. package/locales/ru-RU/models.json +24 -0
  71. package/locales/ru-RU/setting.json +5 -0
  72. package/locales/ru-RU/thread.json +5 -0
  73. package/locales/tr-TR/chat.json +7 -0
  74. package/locales/tr-TR/common.json +2 -0
  75. package/locales/tr-TR/models.json +24 -0
  76. package/locales/tr-TR/setting.json +5 -0
  77. package/locales/tr-TR/thread.json +5 -0
  78. package/locales/vi-VN/chat.json +7 -0
  79. package/locales/vi-VN/common.json +2 -0
  80. package/locales/vi-VN/models.json +24 -0
  81. package/locales/vi-VN/setting.json +5 -0
  82. package/locales/vi-VN/thread.json +5 -0
  83. package/locales/zh-CN/chat.json +7 -0
  84. package/locales/zh-CN/common.json +2 -0
  85. package/locales/zh-CN/models.json +24 -0
  86. package/locales/zh-CN/setting.json +5 -0
  87. package/locales/zh-CN/thread.json +5 -0
  88. package/locales/zh-TW/chat.json +7 -0
  89. package/locales/zh-TW/common.json +2 -0
  90. package/locales/zh-TW/models.json +24 -0
  91. package/locales/zh-TW/setting.json +5 -0
  92. package/locales/zh-TW/thread.json +5 -0
  93. package/package.json +1 -1
  94. package/src/app/(main)/chat/(workspace)/@conversation/default.tsx +2 -0
  95. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatHydration/index.tsx +11 -2
  96. package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/Footer/index.tsx +7 -9
  97. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +7 -2
  98. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/Thread.tsx +62 -0
  99. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/ThreadItem.tsx +68 -0
  100. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/index.tsx +62 -2
  101. package/src/app/(main)/chat/(workspace)/@conversation/features/ThreadHydration.tsx +47 -0
  102. package/src/app/(main)/chat/(workspace)/@portal/_layout/Desktop.tsx +3 -2
  103. package/src/app/(main)/chat/(workspace)/@portal/_layout/Mobile.tsx +47 -6
  104. package/src/app/(main)/chat/(workspace)/@topic/features/SkeletonList.tsx +3 -2
  105. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/ByTimeMode/index.tsx +10 -3
  106. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/FlatMode/index.tsx +1 -1
  107. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/ThreadItem/Content.tsx +164 -0
  108. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/ThreadItem/index.tsx +98 -0
  109. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{TopicItem.tsx → TopicItem/index.tsx} +33 -22
  110. package/src/app/(main)/chat/(workspace)/_layout/Desktop/Portal.tsx +12 -5
  111. package/src/app/(main)/chat/(workspace)/_layout/Mobile/index.tsx +1 -2
  112. package/src/const/message.ts +2 -0
  113. package/src/const/settings/systemAgent.ts +1 -0
  114. package/src/database/server/migrations/0012_add_thread.sql +39 -0
  115. package/src/database/server/migrations/meta/0012_snapshot.json +3671 -0
  116. package/src/database/server/migrations/meta/_journal.json +7 -0
  117. package/src/database/server/models/_template.ts +2 -2
  118. package/src/database/server/models/message.ts +1 -0
  119. package/src/database/server/models/thread.ts +79 -0
  120. package/src/database/server/schemas/lobechat/message.ts +2 -1
  121. package/src/database/server/schemas/lobechat/relations.ts +13 -1
  122. package/src/database/server/schemas/lobechat/topic.ts +30 -1
  123. package/src/database/server/utils/idGenerator.ts +1 -0
  124. package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +6 -4
  125. package/src/features/ChatInput/ActionBar/Token/index.tsx +24 -5
  126. package/src/features/ChatInput/ActionBar/config.ts +3 -2
  127. package/src/features/ChatInput/Desktop/index.tsx +15 -7
  128. package/src/features/ChatInput/Mobile/index.tsx +4 -4
  129. package/src/features/Conversation/Actions/Assistant.tsx +24 -5
  130. package/src/features/Conversation/Actions/User.tsx +21 -4
  131. package/src/features/Conversation/Actions/index.ts +1 -66
  132. package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/index.tsx +3 -1
  133. package/src/features/Conversation/Messages/{Tool/index.tsx → Assistant/ToolCallItem/Tool.tsx} +10 -11
  134. package/src/features/Conversation/Messages/Assistant/ToolCallItem/index.tsx +5 -3
  135. package/src/features/Conversation/Messages/Assistant/index.tsx +22 -14
  136. package/src/features/Conversation/Messages/index.ts +0 -2
  137. package/src/features/Conversation/components/AutoScroll.tsx +1 -1
  138. package/src/features/Conversation/components/ChatItem/ActionsBar.tsx +79 -5
  139. package/src/features/Conversation/components/ChatItem/InPortalThreadContext.ts +3 -0
  140. package/src/features/Conversation/components/ChatItem/index.tsx +16 -5
  141. package/src/features/Conversation/components/MarkdownElements/LobeArtifact/Render/index.tsx +9 -1
  142. package/src/features/Conversation/components/ThreadDivider/index.tsx +19 -0
  143. package/src/features/Conversation/hooks/useChatListActionsBar.tsx +19 -4
  144. package/src/features/Portal/Thread/Chat/ChatInput/Footer.tsx +90 -0
  145. package/src/features/Portal/Thread/Chat/ChatInput/TextArea.tsx +30 -0
  146. package/src/features/Portal/Thread/Chat/ChatInput/index.tsx +66 -0
  147. package/src/features/Portal/Thread/Chat/ChatInput/useSend.ts +50 -0
  148. package/src/features/Portal/Thread/Chat/ChatItem.tsx +62 -0
  149. package/src/features/Portal/Thread/Chat/ChatList.tsx +49 -0
  150. package/src/features/Portal/Thread/Chat/ThreadDivider/index.tsx +19 -0
  151. package/src/features/Portal/Thread/Chat/index.tsx +28 -0
  152. package/src/features/Portal/Thread/Header/Active.tsx +35 -0
  153. package/src/features/Portal/Thread/Header/New.tsx +37 -0
  154. package/src/features/Portal/Thread/Header/Title.tsx +18 -0
  155. package/src/features/Portal/Thread/Header/index.tsx +20 -0
  156. package/src/features/Portal/Thread/hook.ts +8 -0
  157. package/src/features/Portal/Thread/index.ts +12 -0
  158. package/src/features/Portal/router.tsx +2 -1
  159. package/src/hooks/useFetchTopics.ts +7 -1
  160. package/src/locales/default/chat.ts +8 -1
  161. package/src/locales/default/common.ts +3 -0
  162. package/src/locales/default/index.ts +2 -0
  163. package/src/locales/default/setting.ts +5 -0
  164. package/src/locales/default/thread.ts +5 -0
  165. package/src/server/routers/lambda/index.ts +2 -0
  166. package/src/server/routers/lambda/thread.ts +83 -0
  167. package/src/services/thread.ts +54 -0
  168. package/src/store/chat/initialState.ts +3 -0
  169. package/src/store/chat/selectors.ts +2 -1
  170. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +1 -1
  171. package/src/store/chat/slices/aiChat/actions/__tests__/rag.test.ts +1 -1
  172. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +31 -8
  173. package/src/store/chat/slices/aiChat/actions/rag.ts +1 -1
  174. package/src/store/chat/slices/message/selectors.test.ts +3 -3
  175. package/src/store/chat/slices/message/selectors.ts +50 -29
  176. package/src/store/chat/slices/plugin/action.ts +26 -8
  177. package/src/store/chat/slices/portal/action.ts +1 -0
  178. package/src/store/chat/slices/portal/initialState.ts +1 -0
  179. package/src/store/chat/slices/portal/selectors/thread.ts +17 -0
  180. package/src/store/chat/slices/portal/selectors.ts +2 -0
  181. package/src/store/chat/slices/thread/action.ts +326 -0
  182. package/src/store/chat/slices/thread/initialState.ts +34 -0
  183. package/src/store/chat/slices/thread/reducer.ts +48 -0
  184. package/src/store/chat/slices/thread/selectors/index.ts +202 -0
  185. package/src/store/chat/slices/thread/selectors/util.ts +22 -0
  186. package/src/store/chat/slices/topic/action.ts +5 -1
  187. package/src/store/chat/store.ts +5 -2
  188. package/src/store/global/initialState.ts +4 -0
  189. package/src/store/global/selectors.ts +4 -0
  190. package/src/store/user/slices/settings/selectors/systemAgent.ts +2 -0
  191. package/src/types/message/index.ts +17 -1
  192. package/src/types/topic/index.ts +1 -0
  193. package/src/types/topic/thread.ts +42 -0
  194. package/src/types/user/settings/systemAgent.ts +1 -0
  195. package/src/app/(main)/chat/(workspace)/@portal/features/Header.tsx +0 -11
  196. package/src/app/(main)/chat/(workspace)/_layout/Mobile/PortalModal.tsx +0 -35
  197. /package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/Footer/SendMore.tsx +0 -0
  198. /package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/Footer/ShortcutHint.tsx +0 -0
  199. /package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{DefaultContent.tsx → TopicItem/DefaultContent.tsx} +0 -0
  200. /package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{TopicContent.tsx → TopicItem/TopicContent.tsx} +0 -0
  201. /package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/PluginResultJSON.tsx +0 -0
  202. /package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/Settings.tsx +0 -0
  203. /package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/style.ts +0 -0
@@ -32,6 +32,8 @@ interface ProcessMessageParams {
32
32
  * the RAG query content, should be embedding and used in the semantic search
33
33
  */
34
34
  ragQuery?: string;
35
+ threadId?: string;
36
+ inPortalThread?: boolean;
35
37
  }
36
38
 
37
39
  export interface AIGenerateAction {
@@ -79,7 +81,15 @@ export interface AIGenerateAction {
79
81
  /**
80
82
  * Resends a specific message, optionally using a trace ID for tracking
81
83
  */
82
- internal_resendMessage: (id: string, traceId?: string) => Promise<void>;
84
+ internal_resendMessage: (
85
+ id: string,
86
+ params?: {
87
+ traceId?: string;
88
+ messages?: ChatMessage[];
89
+ threadId?: string;
90
+ inPortalThread?: boolean;
91
+ },
92
+ ) => Promise<void>;
83
93
  /**
84
94
  * Toggles the loading state for AI message generation, managing the UI feedback
85
95
  */
@@ -102,7 +112,7 @@ export const generateAIChat: StateCreator<
102
112
  > = (set, get) => ({
103
113
  delAndRegenerateMessage: async (id) => {
104
114
  const traceId = chatSelectors.getTraceIdByMessageId(id)(get());
105
- get().internal_resendMessage(id, traceId);
115
+ get().internal_resendMessage(id, { traceId });
106
116
  get().deleteMessage(id);
107
117
 
108
118
  // trace the delete and regenerate message
@@ -110,14 +120,14 @@ export const generateAIChat: StateCreator<
110
120
  },
111
121
  regenerateMessage: async (id) => {
112
122
  const traceId = chatSelectors.getTraceIdByMessageId(id)(get());
113
- await get().internal_resendMessage(id, traceId);
123
+ await get().internal_resendMessage(id, { traceId });
114
124
 
115
125
  // trace the delete and regenerate message
116
126
  get().internal_traceMessage(id, { eventType: TraceEventType.RegenerateMessage });
117
127
  },
118
128
 
119
129
  sendMessage: async ({ message, files, onlyAddUserMessage, isWelcomeQuestion }) => {
120
- const { internal_coreProcessMessage, activeTopicId, activeId } = get();
130
+ const { internal_coreProcessMessage, activeTopicId, activeId, activeThreadId } = get();
121
131
  if (!activeId) return;
122
132
 
123
133
  const fileIdList = files?.map((f) => f.id);
@@ -137,6 +147,7 @@ export const generateAIChat: StateCreator<
137
147
  sessionId: activeId,
138
148
  // if there is activeTopicId,then add topicId to message
139
149
  topicId: activeTopicId,
150
+ threadId: activeThreadId,
140
151
  };
141
152
 
142
153
  const agentConfig = getAgentChatConfig();
@@ -213,6 +224,7 @@ export const generateAIChat: StateCreator<
213
224
  await internal_coreProcessMessage(messages, id, {
214
225
  isWelcomeQuestion,
215
226
  ragQuery: get().internal_shouldUseRAG() ? message : undefined,
227
+ threadId: activeThreadId,
216
228
  });
217
229
 
218
230
  set({ isCreatingMessage: false }, false, n('creatingMessage/stop'));
@@ -308,6 +320,7 @@ export const generateAIChat: StateCreator<
308
320
  parentId: userMessageId,
309
321
  sessionId: get().activeId,
310
322
  topicId: activeTopicId, // if there is activeTopicId,then add it to topicId
323
+ threadId: params?.threadId,
311
324
  fileChunks,
312
325
  ragQueryId,
313
326
  };
@@ -320,7 +333,10 @@ export const generateAIChat: StateCreator<
320
333
  // 4. if it's the function call message, trigger the function method
321
334
  if (isFunctionCall) {
322
335
  await refreshMessages();
323
- await triggerToolCalls(assistantId);
336
+ await triggerToolCalls(assistantId, {
337
+ threadId: params?.threadId,
338
+ inPortalThread: params?.inPortalThread,
339
+ });
324
340
  }
325
341
 
326
342
  // 5. summary history if context messages is larger than historyCount
@@ -482,9 +498,12 @@ export const generateAIChat: StateCreator<
482
498
  };
483
499
  },
484
500
 
485
- internal_resendMessage: async (messageId, traceId) => {
501
+ internal_resendMessage: async (
502
+ messageId,
503
+ { traceId, messages: outChats, threadId: outThreadId, inPortalThread } = {},
504
+ ) => {
486
505
  // 1. 构造所有相关的历史记录
487
- const chats = chatSelectors.activeBaseChats(get());
506
+ const chats = outChats ?? chatSelectors.mainAIChats(get());
488
507
 
489
508
  const currentIndex = chats.findIndex((c) => c.id === messageId);
490
509
  if (currentIndex < 0) return;
@@ -511,15 +530,19 @@ export const generateAIChat: StateCreator<
511
530
 
512
531
  if (contextMessages.length <= 0) return;
513
532
 
514
- const { internal_coreProcessMessage } = get();
533
+ const { internal_coreProcessMessage, activeThreadId } = get();
515
534
 
516
535
  const latestMsg = contextMessages.findLast((s) => s.role === 'user');
517
536
 
518
537
  if (!latestMsg) return;
519
538
 
539
+ const threadId = outThreadId ?? activeThreadId;
540
+
520
541
  await internal_coreProcessMessage(contextMessages, latestMsg.id, {
521
542
  traceId,
522
543
  ragQuery: get().internal_shouldUseRAG() ? latestMsg.content : undefined,
544
+ threadId,
545
+ inPortalThread,
523
546
  });
524
547
  },
525
548
 
@@ -146,7 +146,7 @@ export const chatRag: StateCreator<ChatStore, [['zustand/devtools', never]], [],
146
146
  // delete the current ragQuery
147
147
  await get().deleteUserMessageRagQuery(id);
148
148
 
149
- const chats = chatSelectors.currentChatsWithHistoryConfig(get());
149
+ const chats = chatSelectors.mainAIChatsWithHistoryConfig(get());
150
150
 
151
151
  await get().internal_rewriteQuery(
152
152
  id,
@@ -170,7 +170,7 @@ describe('chatSelectors', () => {
170
170
  activeId: 'abc',
171
171
  });
172
172
 
173
- const chats = chatSelectors.currentChatsWithHistoryConfig(state);
173
+ const chats = chatSelectors.mainAIChatsWithHistoryConfig(state);
174
174
  expect(chats).toHaveLength(3);
175
175
  expect(chats).toEqual(mockedChats);
176
176
  });
@@ -196,7 +196,7 @@ describe('chatSelectors', () => {
196
196
  });
197
197
  });
198
198
 
199
- const chats = chatSelectors.currentChatsWithHistoryConfig(state);
199
+ const chats = chatSelectors.mainAIChatsWithHistoryConfig(state);
200
200
 
201
201
  expect(chats).toHaveLength(2);
202
202
  expect(chats).toEqual([
@@ -262,7 +262,7 @@ describe('chatSelectors', () => {
262
262
  .join('');
263
263
 
264
264
  // Call the selector and verify the result
265
- const concatenatedString = chatSelectors.chatsMessageString(state);
265
+ const concatenatedString = chatSelectors.mainAIChatsMessageString(state);
266
266
  expect(concatenatedString).toBe(expectedString);
267
267
 
268
268
  // Restore the mocks after the test
@@ -52,35 +52,48 @@ const activeBaseChatsWithoutTool = (s: ChatStoreState) => {
52
52
  return messages.filter((m) => m.role !== 'tool');
53
53
  };
54
54
 
55
- /**
56
- * Main display chats
57
- * 根据当前不同的状态,返回不同的消息列表
58
- */
59
- const mainDisplayChats = (s: ChatStoreState): ChatMessage[] => {
60
- return activeBaseChatsWithoutTool(s);
55
+ const getChatsWithThread = (s: ChatStoreState, messages: ChatMessage[]) => {
61
56
  // 如果没有 activeThreadId,则返回所有的主消息
62
- // const mains = activeBaseChats(s).filter((m) => !m.threadId);
63
- // if (!s.activeThreadId) return mains;
64
- //
65
- // const thread = s.threadMaps[s.activeTopicId!]?.find((t) => t.id === s.activeThreadId);
66
- //
67
- // if (!thread) return mains;
68
- //
69
- // const sourceIndex = mains.findIndex((m) => m.id === thread.sourceMessageId);
70
- // const sliced = mains.slice(0, sourceIndex + 1);
71
- //
72
- // return [...sliced, ...activeBaseChats(s).filter((m) => m.threadId === s.activeThreadId)];
57
+ if (!s.activeThreadId) return messages.filter((m) => !m.threadId);
58
+
59
+ const thread = s.threadMaps[s.activeTopicId!]?.find((t) => t.id === s.activeThreadId);
60
+
61
+ if (!thread) return messages.filter((m) => !m.threadId);
62
+
63
+ const sourceIndex = messages.findIndex((m) => m.id === thread.sourceMessageId);
64
+ const sliced = messages.slice(0, sourceIndex + 1);
65
+
66
+ return [...sliced, ...messages.filter((m) => m.threadId === s.activeThreadId)];
67
+ };
68
+
69
+ // ============= Main Display Chats ========== //
70
+ // =========================================== //
71
+ const mainDisplayChats = (s: ChatStoreState): ChatMessage[] => {
72
+ const displayChats = activeBaseChatsWithoutTool(s);
73
+
74
+ return getChatsWithThread(s, displayChats);
73
75
  };
74
76
 
75
77
  const mainDisplayChatIDs = (s: ChatStoreState) => mainDisplayChats(s).map((s) => s.id);
76
78
 
77
- const currentChatsWithHistoryConfig = (s: ChatStoreState): ChatMessage[] => {
78
- const chats = activeBaseChats(s);
79
+ const mainAIChats = (s: ChatStoreState): ChatMessage[] => {
80
+ const messages = activeBaseChats(s);
81
+
82
+ return getChatsWithThread(s, messages);
83
+ };
84
+
85
+ const mainAIChatsWithHistoryConfig = (s: ChatStoreState): ChatMessage[] => {
86
+ const chats = mainAIChats(s);
79
87
  const config = agentSelectors.currentAgentChatConfig(useAgentStore.getState());
80
88
 
81
89
  return chatHelpers.getSlicedMessagesWithConfig(chats, config);
82
90
  };
83
91
 
92
+ const mainAIChatsMessageString = (s: ChatStoreState): string => {
93
+ const chats = mainAIChatsWithHistoryConfig(s);
94
+ return chats.map((m) => m.content).join('');
95
+ };
96
+
84
97
  const currentToolMessages = (s: ChatStoreState) => {
85
98
  const messages = activeBaseChats(s);
86
99
 
@@ -110,14 +123,15 @@ const showInboxWelcome = (s: ChatStoreState): boolean => {
110
123
  return data.length === 0;
111
124
  };
112
125
 
113
- const chatsMessageString = (s: ChatStoreState): string => {
114
- const chats = currentChatsWithHistoryConfig(s);
115
- return chats.map((m) => m.content).join('');
116
- };
117
-
118
126
  const getMessageById = (id: string) => (s: ChatStoreState) =>
119
127
  chatHelpers.getMessageById(activeBaseChats(s), id);
120
128
 
129
+ const countMessagesByThreadId = (id: string) => (s: ChatStoreState) => {
130
+ const messages = activeBaseChats(s).filter((m) => m.threadId === id);
131
+
132
+ return messages.length;
133
+ };
134
+
121
135
  const getMessageByToolCallId = (id: string) => (s: ChatStoreState) => {
122
136
  const messages = activeBaseChats(s);
123
137
  return messages.find((m) => m.tool_call_id === id);
@@ -147,10 +161,15 @@ const isToolCallStreaming = (id: string, index: number) => (s: ChatStoreState) =
147
161
  return isLoading[index];
148
162
  };
149
163
 
150
- const isAIGenerating = (s: ChatStoreState) => s.chatLoadingIds.length > 0;
151
- const isInRAGFlow = (s: ChatStoreState) => s.messageRAGLoadingIds.length > 0;
164
+ const isAIGenerating = (s: ChatStoreState) =>
165
+ s.chatLoadingIds.some((id) => mainDisplayChatIDs(s).includes(id));
166
+ const isInRAGFlow = (s: ChatStoreState) =>
167
+ s.messageRAGLoadingIds.some((id) => mainDisplayChatIDs(s).includes(id));
168
+
152
169
  const isCreatingMessage = (s: ChatStoreState) => s.isCreatingMessage;
153
- const isHasMessageLoading = (s: ChatStoreState) => s.messageLoadingIds.length > 0;
170
+
171
+ const isHasMessageLoading = (s: ChatStoreState) =>
172
+ s.messageLoadingIds.some((id) => mainDisplayChatIDs(s).includes(id));
154
173
 
155
174
  /**
156
175
  * this function is used to determine whether the send button should be disabled
@@ -168,10 +187,9 @@ const isSendButtonDisabledByMessage = (s: ChatStoreState) =>
168
187
  export const chatSelectors = {
169
188
  activeBaseChats,
170
189
  activeBaseChatsWithoutTool,
171
- chatsMessageString,
190
+ countMessagesByThreadId,
172
191
  currentChatKey,
173
192
  currentChatLoadingState,
174
- currentChatsWithHistoryConfig,
175
193
  currentToolMessages,
176
194
  currentUserFiles,
177
195
  getMessageById,
@@ -189,6 +207,9 @@ export const chatSelectors = {
189
207
  isSendButtonDisabledByMessage,
190
208
  isToolCallStreaming,
191
209
  latestMessage,
210
+ mainAIChats,
211
+ mainAIChatsMessageString,
212
+ mainAIChatsWithHistoryConfig,
192
213
  mainDisplayChatIDs,
193
214
  mainDisplayChats,
194
215
  showInboxWelcome,
@@ -25,7 +25,8 @@ import { merge } from '@/utils/merge';
25
25
  import { safeParseJSON } from '@/utils/safeParseJSON';
26
26
  import { setNamespace } from '@/utils/storeDebug';
27
27
 
28
- import { chatSelectors } from '../../slices/message/selectors';
28
+ import { chatSelectors } from '../message/selectors';
29
+ import { threadSelectors } from '../thread/selectors';
29
30
 
30
31
  const n = setNamespace('plugin');
31
32
 
@@ -44,10 +45,18 @@ export interface ChatPluginAction {
44
45
  invokeStandaloneTypePlugin: (id: string, payload: ChatToolPayload) => Promise<void>;
45
46
 
46
47
  reInvokeToolMessage: (id: string) => Promise<void>;
47
- triggerAIMessage: (params: { parentId?: string; traceId?: string }) => Promise<void>;
48
+ triggerAIMessage: (params: {
49
+ parentId?: string;
50
+ traceId?: string;
51
+ threadId?: string;
52
+ inPortalThread?: boolean;
53
+ }) => Promise<void>;
48
54
  summaryPluginContent: (id: string) => Promise<void>;
49
55
 
50
- triggerToolCalls: (id: string) => Promise<void>;
56
+ triggerToolCalls: (
57
+ id: string,
58
+ params?: { threadId?: string; inPortalThread?: boolean },
59
+ ) => Promise<void>;
51
60
  updatePluginState: (id: string, value: any) => Promise<void>;
52
61
  updatePluginArguments: <T = any>(id: string, value: T) => Promise<void>;
53
62
 
@@ -200,10 +209,18 @@ export const chatPlugin: StateCreator<
200
209
  await get().internal_invokeDifferentTypePlugin(id, payload);
201
210
  },
202
211
 
203
- triggerAIMessage: async ({ parentId, traceId }) => {
212
+ triggerAIMessage: async ({ parentId, traceId, threadId, inPortalThread }) => {
204
213
  const { internal_coreProcessMessage } = get();
205
- const chats = chatSelectors.activeBaseChats(get());
206
- await internal_coreProcessMessage(chats, parentId ?? chats.at(-1)!.id, { traceId });
214
+
215
+ const chats = inPortalThread
216
+ ? threadSelectors.portalAIChatsWithHistoryConfig(get())
217
+ : chatSelectors.mainAIChatsWithHistoryConfig(get());
218
+
219
+ await internal_coreProcessMessage(chats, parentId ?? chats.at(-1)!.id, {
220
+ traceId,
221
+ threadId,
222
+ inPortalThread,
223
+ });
207
224
  },
208
225
 
209
226
  summaryPluginContent: async (id) => {
@@ -228,7 +245,7 @@ export const chatPlugin: StateCreator<
228
245
  );
229
246
  },
230
247
 
231
- triggerToolCalls: async (assistantId) => {
248
+ triggerToolCalls: async (assistantId, { threadId, inPortalThread } = {}) => {
232
249
  const message = chatSelectors.getMessageById(assistantId)(get());
233
250
  if (!message || !message.tools) return;
234
251
 
@@ -242,6 +259,7 @@ export const chatPlugin: StateCreator<
242
259
  role: 'tool',
243
260
  sessionId: get().activeId,
244
261
  tool_call_id: payload.id,
262
+ threadId,
245
263
  topicId: get().activeTopicId, // if there is activeTopicId,then add it to topicId
246
264
  };
247
265
 
@@ -263,7 +281,7 @@ export const chatPlugin: StateCreator<
263
281
 
264
282
  const traceId = chatSelectors.getTraceIdByMessageId(latestToolId)(get());
265
283
 
266
- await get().triggerAIMessage({ traceId });
284
+ await get().triggerAIMessage({ traceId, threadId, inPortalThread });
267
285
  },
268
286
  updatePluginState: async (id, value) => {
269
287
  const { refreshMessages } = get();
@@ -51,6 +51,7 @@ export const chatPortalSlice: StateCreator<
51
51
 
52
52
  set({ portalMessageDetail: messageId }, false, 'openMessageDetail');
53
53
  },
54
+
54
55
  openToolUI: (id, identifier) => {
55
56
  get().togglePortal(true);
56
57
 
@@ -11,6 +11,7 @@ export interface ChatPortalState {
11
11
  portalArtifactDisplayMode?: 'code' | 'preview';
12
12
  portalFile?: PortalFile;
13
13
  portalMessageDetail?: string;
14
+ portalThreadId?: string;
14
15
  portalToolMessage?: { id: string; identifier: string };
15
16
  showPortal: boolean;
16
17
  }
@@ -0,0 +1,17 @@
1
+ import type { ChatStoreState } from '@/store/chat';
2
+
3
+ const showThread = (s: ChatStoreState) => !!s.threadStartMessageId || !!s.portalThreadId;
4
+
5
+ const newThreadMode = (s: ChatStoreState) => s.newThreadMode;
6
+
7
+ const portalCurrentThread = (s: ChatStoreState) => {
8
+ if (!s.portalThreadId || !s.activeTopicId) return;
9
+
10
+ return (s.threadMaps[s.activeTopicId] || []).find((t) => t.id === s.portalThreadId);
11
+ };
12
+
13
+ export const portalThreadSelectors = {
14
+ newThreadMode,
15
+ portalCurrentThread,
16
+ showThread,
17
+ };
@@ -71,3 +71,5 @@ export const chatPortalSelectors = {
71
71
  artifactCodeLanguage,
72
72
  isArtifactTagClosed,
73
73
  };
74
+
75
+ export * from './selectors/thread';