@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.
- package/CHANGELOG.md +25 -0
- package/changelog/v1.json +9 -0
- package/locales/ar/chat.json +7 -0
- package/locales/ar/common.json +2 -0
- package/locales/ar/models.json +24 -0
- package/locales/ar/setting.json +5 -0
- package/locales/ar/thread.json +5 -0
- package/locales/bg-BG/chat.json +7 -0
- package/locales/bg-BG/common.json +2 -0
- package/locales/bg-BG/models.json +24 -0
- package/locales/bg-BG/setting.json +5 -0
- package/locales/bg-BG/thread.json +5 -0
- package/locales/de-DE/chat.json +7 -0
- package/locales/de-DE/common.json +2 -0
- package/locales/de-DE/models.json +24 -0
- package/locales/de-DE/setting.json +5 -0
- package/locales/de-DE/thread.json +5 -0
- package/locales/en-US/chat.json +7 -0
- package/locales/en-US/common.json +2 -0
- package/locales/en-US/models.json +24 -0
- package/locales/en-US/setting.json +5 -0
- package/locales/en-US/thread.json +5 -0
- package/locales/es-ES/chat.json +7 -0
- package/locales/es-ES/common.json +2 -0
- package/locales/es-ES/models.json +24 -0
- package/locales/es-ES/setting.json +5 -0
- package/locales/es-ES/thread.json +5 -0
- package/locales/fa-IR/chat.json +7 -0
- package/locales/fa-IR/common.json +2 -0
- package/locales/fa-IR/models.json +24 -0
- package/locales/fa-IR/setting.json +5 -0
- package/locales/fa-IR/thread.json +5 -0
- package/locales/fr-FR/chat.json +7 -0
- package/locales/fr-FR/common.json +2 -0
- package/locales/fr-FR/models.json +24 -0
- package/locales/fr-FR/setting.json +5 -0
- package/locales/fr-FR/thread.json +5 -0
- package/locales/it-IT/chat.json +7 -0
- package/locales/it-IT/common.json +2 -0
- package/locales/it-IT/models.json +24 -0
- package/locales/it-IT/setting.json +5 -0
- package/locales/it-IT/thread.json +5 -0
- package/locales/ja-JP/chat.json +7 -0
- package/locales/ja-JP/common.json +2 -0
- package/locales/ja-JP/models.json +24 -0
- package/locales/ja-JP/setting.json +5 -0
- package/locales/ja-JP/thread.json +5 -0
- package/locales/ko-KR/chat.json +7 -0
- package/locales/ko-KR/common.json +2 -0
- package/locales/ko-KR/models.json +24 -0
- package/locales/ko-KR/setting.json +5 -0
- package/locales/ko-KR/thread.json +5 -0
- package/locales/nl-NL/chat.json +7 -0
- package/locales/nl-NL/common.json +2 -0
- package/locales/nl-NL/models.json +24 -0
- package/locales/nl-NL/setting.json +5 -0
- package/locales/nl-NL/thread.json +5 -0
- package/locales/pl-PL/chat.json +7 -0
- package/locales/pl-PL/common.json +2 -0
- package/locales/pl-PL/models.json +24 -0
- package/locales/pl-PL/setting.json +5 -0
- package/locales/pl-PL/thread.json +5 -0
- package/locales/pt-BR/chat.json +7 -0
- package/locales/pt-BR/common.json +2 -0
- package/locales/pt-BR/models.json +24 -0
- package/locales/pt-BR/setting.json +5 -0
- package/locales/pt-BR/thread.json +5 -0
- package/locales/ru-RU/chat.json +7 -0
- package/locales/ru-RU/common.json +2 -0
- package/locales/ru-RU/models.json +24 -0
- package/locales/ru-RU/setting.json +5 -0
- package/locales/ru-RU/thread.json +5 -0
- package/locales/tr-TR/chat.json +7 -0
- package/locales/tr-TR/common.json +2 -0
- package/locales/tr-TR/models.json +24 -0
- package/locales/tr-TR/setting.json +5 -0
- package/locales/tr-TR/thread.json +5 -0
- package/locales/vi-VN/chat.json +7 -0
- package/locales/vi-VN/common.json +2 -0
- package/locales/vi-VN/models.json +24 -0
- package/locales/vi-VN/setting.json +5 -0
- package/locales/vi-VN/thread.json +5 -0
- package/locales/zh-CN/chat.json +7 -0
- package/locales/zh-CN/common.json +2 -0
- package/locales/zh-CN/models.json +24 -0
- package/locales/zh-CN/setting.json +5 -0
- package/locales/zh-CN/thread.json +5 -0
- package/locales/zh-TW/chat.json +7 -0
- package/locales/zh-TW/common.json +2 -0
- package/locales/zh-TW/models.json +24 -0
- package/locales/zh-TW/setting.json +5 -0
- package/locales/zh-TW/thread.json +5 -0
- package/package.json +1 -1
- package/src/app/(main)/chat/(workspace)/@conversation/default.tsx +2 -0
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatHydration/index.tsx +11 -2
- package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/Footer/index.tsx +7 -9
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +7 -2
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/Thread.tsx +62 -0
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/ThreadItem.tsx +68 -0
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/index.tsx +62 -2
- package/src/app/(main)/chat/(workspace)/@conversation/features/ThreadHydration.tsx +47 -0
- package/src/app/(main)/chat/(workspace)/@portal/_layout/Desktop.tsx +3 -2
- package/src/app/(main)/chat/(workspace)/@portal/_layout/Mobile.tsx +47 -6
- package/src/app/(main)/chat/(workspace)/@topic/features/SkeletonList.tsx +3 -2
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/ByTimeMode/index.tsx +10 -3
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/FlatMode/index.tsx +1 -1
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/ThreadItem/Content.tsx +164 -0
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/ThreadItem/index.tsx +98 -0
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{TopicItem.tsx → TopicItem/index.tsx} +33 -22
- package/src/app/(main)/chat/(workspace)/_layout/Desktop/Portal.tsx +12 -5
- package/src/app/(main)/chat/(workspace)/_layout/Mobile/index.tsx +1 -2
- package/src/const/message.ts +2 -0
- package/src/const/settings/systemAgent.ts +1 -0
- package/src/database/server/migrations/0012_add_thread.sql +39 -0
- package/src/database/server/migrations/meta/0012_snapshot.json +3671 -0
- package/src/database/server/migrations/meta/_journal.json +7 -0
- package/src/database/server/models/_template.ts +2 -2
- package/src/database/server/models/message.ts +1 -0
- package/src/database/server/models/thread.ts +79 -0
- package/src/database/server/schemas/lobechat/message.ts +2 -1
- package/src/database/server/schemas/lobechat/relations.ts +13 -1
- package/src/database/server/schemas/lobechat/topic.ts +30 -1
- package/src/database/server/utils/idGenerator.ts +1 -0
- package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +6 -4
- package/src/features/ChatInput/ActionBar/Token/index.tsx +24 -5
- package/src/features/ChatInput/ActionBar/config.ts +3 -2
- package/src/features/ChatInput/Desktop/index.tsx +15 -7
- package/src/features/ChatInput/Mobile/index.tsx +4 -4
- package/src/features/Conversation/Actions/Assistant.tsx +24 -5
- package/src/features/Conversation/Actions/User.tsx +21 -4
- package/src/features/Conversation/Actions/index.ts +1 -66
- package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/index.tsx +3 -1
- package/src/features/Conversation/Messages/{Tool/index.tsx → Assistant/ToolCallItem/Tool.tsx} +10 -11
- package/src/features/Conversation/Messages/Assistant/ToolCallItem/index.tsx +5 -3
- package/src/features/Conversation/Messages/Assistant/index.tsx +22 -14
- package/src/features/Conversation/Messages/index.ts +0 -2
- package/src/features/Conversation/components/AutoScroll.tsx +1 -1
- package/src/features/Conversation/components/ChatItem/ActionsBar.tsx +79 -5
- package/src/features/Conversation/components/ChatItem/InPortalThreadContext.ts +3 -0
- package/src/features/Conversation/components/ChatItem/index.tsx +16 -5
- package/src/features/Conversation/components/MarkdownElements/LobeArtifact/Render/index.tsx +9 -1
- package/src/features/Conversation/components/ThreadDivider/index.tsx +19 -0
- package/src/features/Conversation/hooks/useChatListActionsBar.tsx +19 -4
- package/src/features/Portal/Thread/Chat/ChatInput/Footer.tsx +90 -0
- package/src/features/Portal/Thread/Chat/ChatInput/TextArea.tsx +30 -0
- package/src/features/Portal/Thread/Chat/ChatInput/index.tsx +66 -0
- package/src/features/Portal/Thread/Chat/ChatInput/useSend.ts +50 -0
- package/src/features/Portal/Thread/Chat/ChatItem.tsx +62 -0
- package/src/features/Portal/Thread/Chat/ChatList.tsx +49 -0
- package/src/features/Portal/Thread/Chat/ThreadDivider/index.tsx +19 -0
- package/src/features/Portal/Thread/Chat/index.tsx +28 -0
- package/src/features/Portal/Thread/Header/Active.tsx +35 -0
- package/src/features/Portal/Thread/Header/New.tsx +37 -0
- package/src/features/Portal/Thread/Header/Title.tsx +18 -0
- package/src/features/Portal/Thread/Header/index.tsx +20 -0
- package/src/features/Portal/Thread/hook.ts +8 -0
- package/src/features/Portal/Thread/index.ts +12 -0
- package/src/features/Portal/router.tsx +2 -1
- package/src/hooks/useFetchTopics.ts +7 -1
- package/src/locales/default/chat.ts +8 -1
- package/src/locales/default/common.ts +3 -0
- package/src/locales/default/index.ts +2 -0
- package/src/locales/default/setting.ts +5 -0
- package/src/locales/default/thread.ts +5 -0
- package/src/server/routers/lambda/index.ts +2 -0
- package/src/server/routers/lambda/thread.ts +83 -0
- package/src/services/thread.ts +54 -0
- package/src/store/chat/initialState.ts +3 -0
- package/src/store/chat/selectors.ts +2 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +1 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/rag.test.ts +1 -1
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +31 -8
- package/src/store/chat/slices/aiChat/actions/rag.ts +1 -1
- package/src/store/chat/slices/message/selectors.test.ts +3 -3
- package/src/store/chat/slices/message/selectors.ts +50 -29
- package/src/store/chat/slices/plugin/action.ts +26 -8
- package/src/store/chat/slices/portal/action.ts +1 -0
- package/src/store/chat/slices/portal/initialState.ts +1 -0
- package/src/store/chat/slices/portal/selectors/thread.ts +17 -0
- package/src/store/chat/slices/portal/selectors.ts +2 -0
- package/src/store/chat/slices/thread/action.ts +326 -0
- package/src/store/chat/slices/thread/initialState.ts +34 -0
- package/src/store/chat/slices/thread/reducer.ts +48 -0
- package/src/store/chat/slices/thread/selectors/index.ts +202 -0
- package/src/store/chat/slices/thread/selectors/util.ts +22 -0
- package/src/store/chat/slices/topic/action.ts +5 -1
- package/src/store/chat/store.ts +5 -2
- package/src/store/global/initialState.ts +4 -0
- package/src/store/global/selectors.ts +4 -0
- package/src/store/user/slices/settings/selectors/systemAgent.ts +2 -0
- package/src/types/message/index.ts +17 -1
- package/src/types/topic/index.ts +1 -0
- package/src/types/topic/thread.ts +42 -0
- package/src/types/user/settings/systemAgent.ts +1 -0
- package/src/app/(main)/chat/(workspace)/@portal/features/Header.tsx +0 -11
- package/src/app/(main)/chat/(workspace)/_layout/Mobile/PortalModal.tsx +0 -35
- /package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/Footer/SendMore.tsx +0 -0
- /package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/Footer/ShortcutHint.tsx +0 -0
- /package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{DefaultContent.tsx → TopicItem/DefaultContent.tsx} +0 -0
- /package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{TopicContent.tsx → TopicItem/TopicContent.tsx} +0 -0
- /package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/PluginResultJSON.tsx +0 -0
- /package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/Settings.tsx +0 -0
- /package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/style.ts +0 -0
@@ -3,7 +3,7 @@ import { and, desc } from 'drizzle-orm/expressions';
|
|
3
3
|
|
4
4
|
import { serverDB } from '@/database/server';
|
5
5
|
|
6
|
-
import { NewSessionGroup,
|
6
|
+
import { NewSessionGroup, SessionGroupItem, sessionGroups } from '../schemas/lobechat';
|
7
7
|
|
8
8
|
export class TemplateModel {
|
9
9
|
private userId: string;
|
@@ -44,7 +44,7 @@ export class TemplateModel {
|
|
44
44
|
});
|
45
45
|
};
|
46
46
|
|
47
|
-
async update(id: string, value: Partial<
|
47
|
+
async update(id: string, value: Partial<SessionGroupItem>) {
|
48
48
|
return serverDB
|
49
49
|
.update(sessionGroups)
|
50
50
|
.set({ ...value, updatedAt: new Date() })
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import { eq } from 'drizzle-orm';
|
2
|
+
import { and, desc } from 'drizzle-orm/expressions';
|
3
|
+
|
4
|
+
import { serverDB } from '@/database/server';
|
5
|
+
import { CreateThreadParams, ThreadStatus } from '@/types/topic';
|
6
|
+
|
7
|
+
import { ThreadItem, threads } from '../schemas/lobechat';
|
8
|
+
|
9
|
+
const queryColumns = {
|
10
|
+
createdAt: threads.createdAt,
|
11
|
+
id: threads.id,
|
12
|
+
parentThreadId: threads.parentThreadId,
|
13
|
+
sourceMessageId: threads.sourceMessageId,
|
14
|
+
status: threads.status,
|
15
|
+
title: threads.title,
|
16
|
+
topicId: threads.topicId,
|
17
|
+
type: threads.type,
|
18
|
+
updatedAt: threads.updatedAt,
|
19
|
+
};
|
20
|
+
|
21
|
+
export class ThreadModel {
|
22
|
+
private userId: string;
|
23
|
+
|
24
|
+
constructor(userId: string) {
|
25
|
+
this.userId = userId;
|
26
|
+
}
|
27
|
+
|
28
|
+
create = async (params: CreateThreadParams) => {
|
29
|
+
// @ts-ignore
|
30
|
+
const [result] = await serverDB
|
31
|
+
.insert(threads)
|
32
|
+
.values({ ...params, status: ThreadStatus.Active, userId: this.userId })
|
33
|
+
.onConflictDoNothing()
|
34
|
+
.returning();
|
35
|
+
|
36
|
+
return result;
|
37
|
+
};
|
38
|
+
|
39
|
+
delete = async (id: string) => {
|
40
|
+
return serverDB.delete(threads).where(and(eq(threads.id, id), eq(threads.userId, this.userId)));
|
41
|
+
};
|
42
|
+
|
43
|
+
deleteAll = async () => {
|
44
|
+
return serverDB.delete(threads).where(eq(threads.userId, this.userId));
|
45
|
+
};
|
46
|
+
|
47
|
+
query = async () => {
|
48
|
+
const data = await serverDB
|
49
|
+
.select(queryColumns)
|
50
|
+
.from(threads)
|
51
|
+
.where(eq(threads.userId, this.userId))
|
52
|
+
.orderBy(desc(threads.updatedAt));
|
53
|
+
|
54
|
+
return data as ThreadItem[];
|
55
|
+
};
|
56
|
+
|
57
|
+
queryByTopicId = async (topicId: string) => {
|
58
|
+
const data = await serverDB
|
59
|
+
.select(queryColumns)
|
60
|
+
.from(threads)
|
61
|
+
.where(and(eq(threads.topicId, topicId), eq(threads.userId, this.userId)))
|
62
|
+
.orderBy(desc(threads.updatedAt));
|
63
|
+
|
64
|
+
return data as ThreadItem[];
|
65
|
+
};
|
66
|
+
|
67
|
+
findById = async (id: string) => {
|
68
|
+
return serverDB.query.threads.findFirst({
|
69
|
+
where: and(eq(threads.id, id), eq(threads.userId, this.userId)),
|
70
|
+
});
|
71
|
+
};
|
72
|
+
|
73
|
+
async update(id: string, value: Partial<ThreadItem>) {
|
74
|
+
return serverDB
|
75
|
+
.update(threads)
|
76
|
+
.set({ ...value, updatedAt: new Date() })
|
77
|
+
.where(and(eq(threads.id, id), eq(threads.userId, this.userId)));
|
78
|
+
}
|
79
|
+
}
|
@@ -18,7 +18,7 @@ import { agents } from './agent';
|
|
18
18
|
import { files } from './file';
|
19
19
|
import { chunks, embeddings } from './rag';
|
20
20
|
import { sessions } from './session';
|
21
|
-
import { topics } from './topic';
|
21
|
+
import { threads, topics } from './topic';
|
22
22
|
import { users } from './user';
|
23
23
|
|
24
24
|
// @ts-ignore
|
@@ -51,6 +51,7 @@ export const messages = pgTable(
|
|
51
51
|
.notNull(),
|
52
52
|
sessionId: text('session_id').references(() => sessions.id, { onDelete: 'cascade' }),
|
53
53
|
topicId: text('topic_id').references(() => topics.id, { onDelete: 'cascade' }),
|
54
|
+
threadId: text('thread_id').references(() => threads.id, { onDelete: 'cascade' }),
|
54
55
|
// @ts-ignore
|
55
56
|
parentId: text('parent_id').references(() => messages.id, { onDelete: 'set null' }),
|
56
57
|
quotaId: text('quota_id').references(() => messages.id, { onDelete: 'set null' }),
|
@@ -8,7 +8,7 @@ import { files, knowledgeBases } from './file';
|
|
8
8
|
import { messages, messagesFiles } from './message';
|
9
9
|
import { unstructuredChunks } from './rag';
|
10
10
|
import { sessionGroups, sessions } from './session';
|
11
|
-
import { topics } from './topic';
|
11
|
+
import { threads, topics } from './topic';
|
12
12
|
|
13
13
|
export const agentsToSessions = pgTable(
|
14
14
|
'agents_to_sessions',
|
@@ -47,6 +47,13 @@ export const topicRelations = relations(topics, ({ one }) => ({
|
|
47
47
|
}),
|
48
48
|
}));
|
49
49
|
|
50
|
+
export const threadsRelations = relations(threads, ({ one }) => ({
|
51
|
+
sourceMessage: one(messages, {
|
52
|
+
fields: [threads.sourceMessageId],
|
53
|
+
references: [messages.id],
|
54
|
+
}),
|
55
|
+
}));
|
56
|
+
|
50
57
|
export const messagesRelations = relations(messages, ({ many, one }) => ({
|
51
58
|
filesToMessages: many(messagesFiles),
|
52
59
|
|
@@ -64,6 +71,11 @@ export const messagesRelations = relations(messages, ({ many, one }) => ({
|
|
64
71
|
fields: [messages.topicId],
|
65
72
|
references: [topics.id],
|
66
73
|
}),
|
74
|
+
|
75
|
+
thread: one(threads, {
|
76
|
+
fields: [messages.threadId],
|
77
|
+
references: [threads.id],
|
78
|
+
}),
|
67
79
|
}));
|
68
80
|
|
69
81
|
export const agentsRelations = relations(agents, ({ many }) => ({
|
@@ -1,8 +1,9 @@
|
|
1
1
|
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
2
2
|
import { boolean, jsonb, pgTable, text, unique } from 'drizzle-orm/pg-core';
|
3
|
+
import { createInsertSchema } from 'drizzle-zod';
|
3
4
|
|
4
5
|
import { idGenerator } from '../../utils/idGenerator';
|
5
|
-
import { timestamps } from './_helpers';
|
6
|
+
import { timestamps, timestamptz } from './_helpers';
|
6
7
|
import { sessions } from './session';
|
7
8
|
import { users } from './user';
|
8
9
|
|
@@ -30,3 +31,31 @@ export const topics = pgTable(
|
|
30
31
|
|
31
32
|
export type NewTopic = typeof topics.$inferInsert;
|
32
33
|
export type TopicItem = typeof topics.$inferSelect;
|
34
|
+
|
35
|
+
// @ts-ignore
|
36
|
+
export const threads = pgTable('threads', {
|
37
|
+
id: text('id')
|
38
|
+
.$defaultFn(() => idGenerator('threads', 16))
|
39
|
+
.primaryKey(),
|
40
|
+
|
41
|
+
title: text('title'),
|
42
|
+
type: text('type', { enum: ['continuation', 'standalone'] }).notNull(),
|
43
|
+
status: text('status', { enum: ['active', 'deprecated', 'archived'] }).default('active'),
|
44
|
+
topicId: text('topic_id')
|
45
|
+
.references(() => topics.id, { onDelete: 'cascade' })
|
46
|
+
.notNull(),
|
47
|
+
sourceMessageId: text('source_message_id').notNull(),
|
48
|
+
// @ts-ignore
|
49
|
+
parentThreadId: text('parent_thread_id').references(() => threads.id, { onDelete: 'set null' }),
|
50
|
+
|
51
|
+
userId: text('user_id')
|
52
|
+
.references(() => users.id, { onDelete: 'cascade' })
|
53
|
+
.notNull(),
|
54
|
+
|
55
|
+
lastActiveAt: timestamptz('last_active_at').defaultNow(),
|
56
|
+
...timestamps,
|
57
|
+
});
|
58
|
+
|
59
|
+
export type NewThread = typeof threads.$inferInsert;
|
60
|
+
export type ThreadItem = typeof threads.$inferSelect;
|
61
|
+
export const insertThreadSchema = createInsertSchema(threads);
|
@@ -10,7 +10,7 @@ import { useTokenCount } from '@/hooks/useTokenCount';
|
|
10
10
|
import { useAgentStore } from '@/store/agent';
|
11
11
|
import { agentSelectors } from '@/store/agent/selectors';
|
12
12
|
import { useChatStore } from '@/store/chat';
|
13
|
-
import {
|
13
|
+
import { topicSelectors } from '@/store/chat/selectors';
|
14
14
|
import { useToolStore } from '@/store/tool';
|
15
15
|
import { toolSelectors } from '@/store/tool/selectors';
|
16
16
|
import { useUserStore } from '@/store/user';
|
@@ -18,13 +18,15 @@ import { modelProviderSelectors } from '@/store/user/selectors';
|
|
18
18
|
|
19
19
|
import TokenProgress from './TokenProgress';
|
20
20
|
|
21
|
-
|
21
|
+
interface TokenTagProps {
|
22
|
+
total: string;
|
23
|
+
}
|
24
|
+
const Token = memo<TokenTagProps>(({ total: messageString }) => {
|
22
25
|
const { t } = useTranslation(['chat', 'components']);
|
23
26
|
const theme = useTheme();
|
24
27
|
|
25
|
-
const [input,
|
28
|
+
const [input, historySummary] = useChatStore((s) => [
|
26
29
|
s.inputMessage,
|
27
|
-
chatSelectors.chatsMessageString(s),
|
28
30
|
topicSelectors.currentActiveTopicSummary(s)?.content || '',
|
29
31
|
]);
|
30
32
|
|
@@ -1,18 +1,37 @@
|
|
1
1
|
import dynamic from 'next/dynamic';
|
2
|
-
import { memo } from 'react';
|
2
|
+
import { PropsWithChildren, memo } from 'react';
|
3
3
|
|
4
4
|
import { useAgentStore } from '@/store/agent';
|
5
|
-
import { agentSelectors } from '@/store/agent/
|
5
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
6
|
+
import { useChatStore } from '@/store/chat';
|
7
|
+
import { chatSelectors, threadSelectors } from '@/store/chat/selectors';
|
6
8
|
import { useUserStore } from '@/store/user';
|
7
9
|
import { modelProviderSelectors } from '@/store/user/selectors';
|
8
10
|
|
9
11
|
const LargeTokenContent = dynamic(() => import('./TokenTag'), { ssr: false });
|
10
12
|
|
11
|
-
const Token = memo(() => {
|
13
|
+
const Token = memo<PropsWithChildren>(({ children }) => {
|
12
14
|
const model = useAgentStore(agentSelectors.currentAgentModel);
|
13
15
|
const showTag = useUserStore(modelProviderSelectors.isModelHasMaxToken(model));
|
14
16
|
|
15
|
-
return showTag &&
|
17
|
+
return showTag && children;
|
16
18
|
});
|
19
|
+
export const MainToken = memo(() => {
|
20
|
+
const total = useChatStore(chatSelectors.mainAIChatsMessageString);
|
17
21
|
|
18
|
-
|
22
|
+
return (
|
23
|
+
<Token>
|
24
|
+
<LargeTokenContent total={total} />
|
25
|
+
</Token>
|
26
|
+
);
|
27
|
+
});
|
28
|
+
|
29
|
+
export const PortalToken = memo(() => {
|
30
|
+
const total = useChatStore(threadSelectors.portalDisplayChatsString);
|
31
|
+
|
32
|
+
return (
|
33
|
+
<Token>
|
34
|
+
<LargeTokenContent total={total} />
|
35
|
+
</Token>
|
36
|
+
);
|
37
|
+
});
|
@@ -4,7 +4,7 @@ import History from './History';
|
|
4
4
|
import Knowledge from './Knowledge';
|
5
5
|
import ModelSwitch from './ModelSwitch';
|
6
6
|
import Temperature from './Temperature';
|
7
|
-
import
|
7
|
+
import { MainToken, PortalToken } from './Token';
|
8
8
|
import Tools from './Tools';
|
9
9
|
import Upload from './Upload';
|
10
10
|
|
@@ -13,10 +13,11 @@ export const actionMap = {
|
|
13
13
|
fileUpload: Upload,
|
14
14
|
history: History,
|
15
15
|
knowledgeBase: Knowledge,
|
16
|
+
mainToken: MainToken,
|
16
17
|
model: ModelSwitch,
|
18
|
+
portalToken: PortalToken,
|
17
19
|
stt: STT,
|
18
20
|
temperature: Temperature,
|
19
|
-
token: Token,
|
20
21
|
tools: Tools,
|
21
22
|
} as const;
|
22
23
|
|
@@ -8,23 +8,31 @@ import { CHAT_TEXTAREA_HEIGHT, CHAT_TEXTAREA_MAX_HEIGHT } from '@/const/layoutTo
|
|
8
8
|
|
9
9
|
import { ActionKeys } from '../ActionBar/config';
|
10
10
|
import LocalFiles from './FilePreview';
|
11
|
-
import Footer from './Footer';
|
12
11
|
import Head from './Header';
|
13
12
|
|
13
|
+
export type FooterRender = (params: {
|
14
|
+
expand: boolean;
|
15
|
+
onExpandChange: (expand: boolean) => void;
|
16
|
+
}) => ReactNode;
|
17
|
+
|
14
18
|
interface DesktopChatInputProps {
|
15
|
-
footer?: {
|
16
|
-
saveTopic?: boolean;
|
17
|
-
shortcutHint?: boolean;
|
18
|
-
};
|
19
19
|
inputHeight: number;
|
20
20
|
leftActions: ActionKeys[];
|
21
21
|
onInputHeightChange?: (height: number) => void;
|
22
|
+
renderFooter: FooterRender;
|
22
23
|
renderTextArea: (onSend: () => void) => ReactNode;
|
23
24
|
rightActions: ActionKeys[];
|
24
25
|
}
|
25
26
|
|
26
27
|
const DesktopChatInput = memo<DesktopChatInputProps>(
|
27
|
-
({
|
28
|
+
({
|
29
|
+
leftActions,
|
30
|
+
rightActions,
|
31
|
+
renderTextArea,
|
32
|
+
inputHeight,
|
33
|
+
onInputHeightChange,
|
34
|
+
renderFooter,
|
35
|
+
}) => {
|
28
36
|
const [expand, setExpand] = useState<boolean>(false);
|
29
37
|
|
30
38
|
const onSend = useCallback(() => {
|
@@ -63,7 +71,7 @@ const DesktopChatInput = memo<DesktopChatInputProps>(
|
|
63
71
|
setExpand={setExpand}
|
64
72
|
/>
|
65
73
|
{renderTextArea(onSend)}
|
66
|
-
|
74
|
+
{renderFooter({ expand, onExpandChange: setExpand })}
|
67
75
|
</Flexbox>
|
68
76
|
</DraggablePanel>
|
69
77
|
</>
|
@@ -16,17 +16,17 @@ import Files from './Files';
|
|
16
16
|
import InputArea from './InputArea';
|
17
17
|
import SendButton from './Send';
|
18
18
|
|
19
|
-
const defaultLeftActions = [
|
19
|
+
const defaultLeftActions: ActionKeys[] = [
|
20
20
|
'model',
|
21
21
|
'fileUpload',
|
22
22
|
'knowledgeBase',
|
23
23
|
'temperature',
|
24
24
|
'history',
|
25
25
|
'tools',
|
26
|
-
'
|
27
|
-
]
|
26
|
+
'mainToken',
|
27
|
+
];
|
28
28
|
|
29
|
-
const defaultRightActions = ['clear']
|
29
|
+
const defaultRightActions: ActionKeys[] = ['clear'];
|
30
30
|
|
31
31
|
const MobileChatInput = memo(() => {
|
32
32
|
const theme = useTheme();
|
@@ -1,17 +1,36 @@
|
|
1
1
|
import { ActionIconGroup } from '@lobehub/ui';
|
2
|
-
import {
|
2
|
+
import { ActionIconGroupItems } from '@lobehub/ui/es/ActionIconGroup';
|
3
|
+
import { memo, useContext, useMemo } from 'react';
|
3
4
|
|
5
|
+
import { useChatStore } from '@/store/chat';
|
6
|
+
import { threadSelectors } from '@/store/chat/selectors';
|
7
|
+
|
8
|
+
import { InPortalThreadContext } from '../components/ChatItem/InPortalThreadContext';
|
4
9
|
import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
|
5
10
|
import { RenderAction } from '../types';
|
6
11
|
import { ErrorActionsBar } from './Error';
|
7
12
|
import { useCustomActions } from './customAction';
|
8
13
|
|
9
|
-
export const AssistantActionsBar: RenderAction = memo(({
|
10
|
-
const
|
14
|
+
export const AssistantActionsBar: RenderAction = memo(({ onActionClick, error, tools, id }) => {
|
15
|
+
const [isThreadMode, hasThread] = useChatStore((s) => [
|
16
|
+
!!s.activeThreadId,
|
17
|
+
threadSelectors.hasThreadBySourceMsgId(id)(s),
|
18
|
+
]);
|
19
|
+
|
20
|
+
const { regenerate, edit, delAndRegenerate, copy, divider, del, branching } =
|
21
|
+
useChatListActionsBar({ hasThread });
|
22
|
+
|
11
23
|
const { translate, tts } = useCustomActions();
|
12
24
|
const hasTools = !!tools;
|
13
25
|
|
14
|
-
|
26
|
+
const inPortalThread = useContext(InPortalThreadContext);
|
27
|
+
const inThread = isThreadMode || inPortalThread;
|
28
|
+
|
29
|
+
const items = useMemo(() => {
|
30
|
+
if (hasTools) return [delAndRegenerate, copy];
|
31
|
+
|
32
|
+
return [edit, copy, inThread ? null : branching].filter(Boolean) as ActionIconGroupItems[];
|
33
|
+
}, [inThread, hasTools]);
|
15
34
|
|
16
35
|
if (error) return <ErrorActionsBar onActionClick={onActionClick} />;
|
17
36
|
|
@@ -28,7 +47,7 @@ export const AssistantActionsBar: RenderAction = memo(({ id, onActionClick, erro
|
|
28
47
|
delAndRegenerate,
|
29
48
|
del,
|
30
49
|
]}
|
31
|
-
items={
|
50
|
+
items={items}
|
32
51
|
onActionClick={onActionClick}
|
33
52
|
type="ghost"
|
34
53
|
/>
|
@@ -1,18 +1,35 @@
|
|
1
1
|
import { ActionIconGroup } from '@lobehub/ui';
|
2
|
-
import {
|
2
|
+
import { ActionIconGroupItems } from '@lobehub/ui/es/ActionIconGroup';
|
3
|
+
import { memo, useContext, useMemo } from 'react';
|
3
4
|
|
5
|
+
import { useChatStore } from '@/store/chat';
|
6
|
+
import { threadSelectors } from '@/store/chat/slices/thread/selectors';
|
7
|
+
|
8
|
+
import { InPortalThreadContext } from '../components/ChatItem/InPortalThreadContext';
|
4
9
|
import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
|
5
10
|
import { RenderAction } from '../types';
|
6
11
|
import { useCustomActions } from './customAction';
|
7
12
|
|
8
|
-
export const UserActionsBar: RenderAction = memo(({ onActionClick }) => {
|
9
|
-
const
|
13
|
+
export const UserActionsBar: RenderAction = memo(({ onActionClick, id }) => {
|
14
|
+
const [isThreadMode, hasThread] = useChatStore((s) => [
|
15
|
+
!!s.activeThreadId,
|
16
|
+
threadSelectors.hasThreadBySourceMsgId(id)(s),
|
17
|
+
]);
|
18
|
+
const { regenerate, edit, copy, divider, del, branching } = useChatListActionsBar({ hasThread });
|
10
19
|
const { translate, tts } = useCustomActions();
|
11
20
|
|
21
|
+
const inPortalThread = useContext(InPortalThreadContext);
|
22
|
+
const inThread = isThreadMode || inPortalThread;
|
23
|
+
|
24
|
+
const items = useMemo(
|
25
|
+
() => [regenerate, edit, inThread ? null : branching].filter(Boolean) as ActionIconGroupItems[],
|
26
|
+
[inThread],
|
27
|
+
);
|
28
|
+
|
12
29
|
return (
|
13
30
|
<ActionIconGroup
|
14
31
|
dropdownMenu={[edit, copy, divider, tts, translate, divider, regenerate, del]}
|
15
|
-
items={
|
32
|
+
items={items}
|
16
33
|
onActionClick={onActionClick}
|
17
34
|
type="ghost"
|
18
35
|
/>
|
@@ -1,11 +1,6 @@
|
|
1
|
-
import { App } from 'antd';
|
2
|
-
import { useCallback } from 'react';
|
3
|
-
import { useTranslation } from 'react-i18next';
|
4
|
-
|
5
|
-
import { useChatStore } from '@/store/chat';
|
6
1
|
import { MessageRoleType } from '@/types/message';
|
7
2
|
|
8
|
-
import {
|
3
|
+
import { RenderAction } from '../types';
|
9
4
|
import { AssistantActionsBar } from './Assistant';
|
10
5
|
import { DefaultActionsBar } from './Fallback';
|
11
6
|
import { ToolActionsBar } from './Tool';
|
@@ -17,63 +12,3 @@ export const renderActions: Record<MessageRoleType, RenderAction> = {
|
|
17
12
|
tool: ToolActionsBar,
|
18
13
|
user: UserActionsBar,
|
19
14
|
};
|
20
|
-
|
21
|
-
export const useActionsClick = (): OnActionsClick => {
|
22
|
-
const { t } = useTranslation('common');
|
23
|
-
const [
|
24
|
-
deleteMessage,
|
25
|
-
regenerateMessage,
|
26
|
-
translateMessage,
|
27
|
-
ttsMessage,
|
28
|
-
delAndRegenerateMessage,
|
29
|
-
copyMessage,
|
30
|
-
] = useChatStore((s) => [
|
31
|
-
s.deleteMessage,
|
32
|
-
s.regenerateMessage,
|
33
|
-
s.translateMessage,
|
34
|
-
s.ttsMessage,
|
35
|
-
s.delAndRegenerateMessage,
|
36
|
-
s.copyMessage,
|
37
|
-
]);
|
38
|
-
const { message } = App.useApp();
|
39
|
-
|
40
|
-
return useCallback<OnActionsClick>(async (action, { id, content, error }) => {
|
41
|
-
switch (action.key) {
|
42
|
-
case 'copy': {
|
43
|
-
await copyMessage(id, content);
|
44
|
-
message.success(t('copySuccess', { defaultValue: 'Copy Success' }));
|
45
|
-
break;
|
46
|
-
}
|
47
|
-
|
48
|
-
case 'del': {
|
49
|
-
deleteMessage(id);
|
50
|
-
break;
|
51
|
-
}
|
52
|
-
|
53
|
-
case 'regenerate': {
|
54
|
-
regenerateMessage(id);
|
55
|
-
// if this message is an error message, we need to delete it
|
56
|
-
if (error) deleteMessage(id);
|
57
|
-
break;
|
58
|
-
}
|
59
|
-
|
60
|
-
case 'delAndRegenerate': {
|
61
|
-
delAndRegenerateMessage(id);
|
62
|
-
break;
|
63
|
-
}
|
64
|
-
|
65
|
-
case 'tts': {
|
66
|
-
ttsMessage(id);
|
67
|
-
break;
|
68
|
-
}
|
69
|
-
}
|
70
|
-
|
71
|
-
if (action.keyPath.at(-1) === 'translate') {
|
72
|
-
// click the menu item with translate item, the result is:
|
73
|
-
// key: 'en-US'
|
74
|
-
// keyPath: ['en-US','translate']
|
75
|
-
const lang = action.keyPath[0];
|
76
|
-
translateMessage(id, lang);
|
77
|
-
}
|
78
|
-
}, []);
|
79
|
-
};
|
package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/index.tsx
RENAMED
@@ -34,6 +34,7 @@ export interface InspectorProps {
|
|
34
34
|
loading?: boolean;
|
35
35
|
payload?: ChatPluginPayload;
|
36
36
|
setShow?: (showRender: boolean) => void;
|
37
|
+
showPortal?: boolean;
|
37
38
|
showRender?: boolean;
|
38
39
|
}
|
39
40
|
|
@@ -47,6 +48,7 @@ const Inspector = memo<InspectorProps>(
|
|
47
48
|
content,
|
48
49
|
identifier = 'unknown',
|
49
50
|
id,
|
51
|
+
showPortal = true,
|
50
52
|
}) => {
|
51
53
|
const { t } = useTranslation(['plugin', 'portal']);
|
52
54
|
const { styles } = useStyles();
|
@@ -111,7 +113,7 @@ const Inspector = memo<InspectorProps>(
|
|
111
113
|
</Flexbox>
|
112
114
|
|
113
115
|
<Flexbox horizontal>
|
114
|
-
{!isMobile && showRightAction && (
|
116
|
+
{!isMobile && showRightAction && showPortal && (
|
115
117
|
<ActionIcon
|
116
118
|
icon={BetweenVerticalStart}
|
117
119
|
onClick={() => {
|
package/src/features/Conversation/Messages/{Tool/index.tsx → Assistant/ToolCallItem/Tool.tsx}
RENAMED
@@ -1,8 +1,8 @@
|
|
1
1
|
import { Icon } from '@lobehub/ui';
|
2
|
-
import { ConfigProvider, Empty
|
2
|
+
import { ConfigProvider, Empty } from 'antd';
|
3
3
|
import { useTheme } from 'antd-style';
|
4
4
|
import { LucideSquareArrowLeft, LucideSquareArrowRight } from 'lucide-react';
|
5
|
-
import {
|
5
|
+
import { memo, useContext, useState } from 'react';
|
6
6
|
import { useTranslation } from 'react-i18next';
|
7
7
|
import { Center, Flexbox } from 'react-layout-kit';
|
8
8
|
|
@@ -11,10 +11,14 @@ import { useChatStore } from '@/store/chat';
|
|
11
11
|
import { chatPortalSelectors, chatSelectors } from '@/store/chat/selectors';
|
12
12
|
import { ChatMessage } from '@/types/message';
|
13
13
|
|
14
|
-
import Arguments from '
|
14
|
+
import Arguments from '../../components/Arguments';
|
15
15
|
import Inspector from './Inspector';
|
16
16
|
|
17
|
-
const
|
17
|
+
const Tool = memo<
|
18
|
+
ChatMessage & {
|
19
|
+
showPortal?: boolean;
|
20
|
+
}
|
21
|
+
>(({ id, content, pluginState, plugin, showPortal }) => {
|
18
22
|
const [loading, isMessageToolUIOpen] = useChatStore((s) => [
|
19
23
|
chatSelectors.isPluginApiInvoking(id)(s),
|
20
24
|
chatPortalSelectors.isPluginUIOpen(id)(s),
|
@@ -35,6 +39,7 @@ const Message = memo<ChatMessage>(({ id, content, pluginState, plugin }) => {
|
|
35
39
|
loading={loading}
|
36
40
|
payload={plugin}
|
37
41
|
setShow={setShow}
|
42
|
+
showPortal={showPortal}
|
38
43
|
showRender={showRender}
|
39
44
|
/>
|
40
45
|
{isMessageToolUIOpen ? (
|
@@ -69,10 +74,4 @@ const Message = memo<ChatMessage>(({ id, content, pluginState, plugin }) => {
|
|
69
74
|
);
|
70
75
|
});
|
71
76
|
|
72
|
-
export
|
73
|
-
<Suspense
|
74
|
-
fallback={<Skeleton.Button active style={{ height: 46, minWidth: 200, width: '100%' }} />}
|
75
|
-
>
|
76
|
-
<Message {...props} />
|
77
|
-
</Suspense>
|
78
|
-
));
|
77
|
+
export default Tool;
|
@@ -13,8 +13,8 @@ import { chatSelectors } from '@/store/chat/selectors';
|
|
13
13
|
import { pluginHelpers, useToolStore } from '@/store/tool';
|
14
14
|
import { toolSelectors } from '@/store/tool/selectors';
|
15
15
|
|
16
|
-
import { ToolMessage } from '../../Tool';
|
17
16
|
import Arguments from '../../components/Arguments';
|
17
|
+
import ToolMessage from './Tool';
|
18
18
|
import { useStyles } from './style';
|
19
19
|
|
20
20
|
export interface InspectorProps {
|
@@ -24,13 +24,15 @@ export interface InspectorProps {
|
|
24
24
|
identifier: string;
|
25
25
|
index: number;
|
26
26
|
messageId: string;
|
27
|
+
showPortal?: boolean;
|
27
28
|
style?: CSSProperties;
|
28
29
|
}
|
29
30
|
|
30
31
|
const CallItem = memo<InspectorProps>(
|
31
|
-
({ arguments: requestArgs, apiName, messageId, id, index, identifier, style }) => {
|
32
|
+
({ arguments: requestArgs, apiName, messageId, id, index, identifier, style, showPortal }) => {
|
32
33
|
const { t } = useTranslation('plugin');
|
33
34
|
const { styles } = useStyles();
|
35
|
+
|
34
36
|
const [open, setOpen] = useState(false);
|
35
37
|
const loading = useChatStore(chatSelectors.isToolCallStreaming(messageId, index));
|
36
38
|
const toolMessage = useChatStore(chatSelectors.getMessageByToolCallId(id));
|
@@ -42,7 +44,7 @@ const CallItem = memo<InspectorProps>(
|
|
42
44
|
|
43
45
|
// when tool calling stop streaming, we should show the tool message
|
44
46
|
return !loading && toolMessage ? (
|
45
|
-
<ToolMessage {...toolMessage} />
|
47
|
+
<ToolMessage {...toolMessage} showPortal={showPortal} />
|
46
48
|
) : (
|
47
49
|
<Flexbox gap={8} style={style}>
|
48
50
|
<Flexbox
|