@lobehub/chat 1.18.1 → 1.19.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.
Potentially problematic release.
This version of @lobehub/chat might be problematic. Click here for more details.
- package/CHANGELOG.md +52 -0
- package/Dockerfile +2 -0
- package/Dockerfile.database +2 -0
- package/locales/ar/chat.json +6 -0
- package/locales/ar/error.json +1 -0
- package/locales/ar/modelProvider.json +7 -0
- package/locales/ar/portal.json +16 -0
- package/locales/bg-BG/chat.json +6 -0
- package/locales/bg-BG/error.json +1 -0
- package/locales/bg-BG/modelProvider.json +7 -0
- package/locales/bg-BG/portal.json +16 -0
- package/locales/de-DE/chat.json +6 -0
- package/locales/de-DE/error.json +1 -0
- package/locales/de-DE/modelProvider.json +7 -0
- package/locales/de-DE/portal.json +16 -0
- package/locales/en-US/chat.json +6 -0
- package/locales/en-US/error.json +1 -0
- package/locales/en-US/modelProvider.json +7 -0
- package/locales/en-US/portal.json +16 -0
- package/locales/es-ES/chat.json +6 -0
- package/locales/es-ES/error.json +1 -0
- package/locales/es-ES/modelProvider.json +7 -0
- package/locales/es-ES/portal.json +16 -0
- package/locales/fr-FR/chat.json +6 -0
- package/locales/fr-FR/error.json +1 -0
- package/locales/fr-FR/modelProvider.json +7 -0
- package/locales/fr-FR/portal.json +16 -0
- package/locales/it-IT/chat.json +6 -0
- package/locales/it-IT/error.json +1 -0
- package/locales/it-IT/modelProvider.json +7 -0
- package/locales/it-IT/portal.json +16 -0
- package/locales/ja-JP/chat.json +6 -0
- package/locales/ja-JP/error.json +1 -0
- package/locales/ja-JP/modelProvider.json +7 -0
- package/locales/ja-JP/portal.json +16 -0
- package/locales/ko-KR/chat.json +6 -0
- package/locales/ko-KR/error.json +1 -0
- package/locales/ko-KR/modelProvider.json +7 -0
- package/locales/ko-KR/portal.json +16 -0
- package/locales/nl-NL/chat.json +6 -0
- package/locales/nl-NL/error.json +1 -0
- package/locales/nl-NL/modelProvider.json +7 -0
- package/locales/nl-NL/portal.json +16 -0
- package/locales/pl-PL/chat.json +6 -0
- package/locales/pl-PL/error.json +1 -0
- package/locales/pl-PL/modelProvider.json +7 -0
- package/locales/pl-PL/portal.json +16 -0
- package/locales/pt-BR/chat.json +6 -0
- package/locales/pt-BR/error.json +1 -0
- package/locales/pt-BR/modelProvider.json +7 -0
- package/locales/pt-BR/portal.json +16 -0
- package/locales/ru-RU/chat.json +6 -0
- package/locales/ru-RU/error.json +1 -0
- package/locales/ru-RU/modelProvider.json +7 -0
- package/locales/ru-RU/portal.json +16 -0
- package/locales/tr-TR/chat.json +6 -0
- package/locales/tr-TR/error.json +1 -0
- package/locales/tr-TR/modelProvider.json +7 -0
- package/locales/tr-TR/portal.json +16 -0
- package/locales/vi-VN/chat.json +6 -0
- package/locales/vi-VN/error.json +1 -0
- package/locales/vi-VN/modelProvider.json +7 -0
- package/locales/vi-VN/portal.json +16 -0
- package/locales/zh-CN/chat.json +6 -0
- package/locales/zh-CN/error.json +2 -1
- package/locales/zh-CN/modelProvider.json +7 -0
- package/locales/zh-CN/portal.json +17 -1
- package/locales/zh-TW/chat.json +6 -0
- package/locales/zh-TW/error.json +1 -0
- package/locales/zh-TW/modelProvider.json +7 -0
- package/locales/zh-TW/portal.json +16 -0
- package/package.json +4 -1
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/Body/Renderer/HTML.tsx +25 -0
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/Body/Renderer/React.tsx +30 -0
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/Body/Renderer/SVG.tsx +114 -0
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/Body/Renderer/index.tsx +25 -0
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/Body/index.tsx +79 -0
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/Header.tsx +69 -0
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/index.ts +10 -0
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/useEnable.ts +4 -0
- package/src/app/(main)/chat/(workspace)/@portal/FilePreview/index.ts +2 -1
- package/src/app/(main)/chat/(workspace)/@portal/Home/Body/{Artifacts → Plugins}/index.tsx +1 -1
- package/src/app/(main)/chat/(workspace)/@portal/Home/Body/index.tsx +2 -2
- package/src/app/(main)/chat/(workspace)/@portal/MessageDetail/index.ts +2 -1
- package/src/app/(main)/chat/(workspace)/@portal/Plugins/Body/ToolRender.tsx +1 -1
- package/src/app/(main)/chat/(workspace)/@portal/Plugins/Body/index.tsx +1 -1
- package/src/app/(main)/chat/(workspace)/@portal/Plugins/Footer.tsx +1 -1
- package/src/app/(main)/chat/(workspace)/@portal/Plugins/index.ts +2 -1
- package/src/app/(main)/chat/(workspace)/@portal/Plugins/useEnable.ts +1 -1
- package/src/app/(main)/chat/(workspace)/@portal/_layout/Desktop.tsx +2 -4
- package/src/app/(main)/chat/(workspace)/@portal/features/Body.tsx +27 -0
- package/src/app/(main)/chat/(workspace)/@portal/router.tsx +3 -1
- package/src/app/(main)/chat/(workspace)/@portal/type.ts +7 -0
- package/src/app/(main)/chat/(workspace)/_layout/Desktop/Portal.tsx +3 -2
- package/src/app/(main)/discover/(detail)/assistant/[slug]/features/InfoSidebar/index.tsx +5 -8
- package/src/app/(main)/discover/(detail)/features/Back.tsx +0 -5
- package/src/app/(main)/discover/(detail)/features/DetailLayout.tsx +2 -34
- package/src/app/(main)/discover/(detail)/model/[...slugs]/features/InfoSidebar/index.tsx +3 -6
- package/src/app/(main)/discover/(detail)/model/[...slugs]/features/ProviderList/ProviderItem.tsx +14 -15
- package/src/app/(main)/discover/(detail)/plugin/[slug]/features/InfoSidebar/index.tsx +3 -6
- package/src/app/(main)/discover/(detail)/provider/[slug]/features/InfoSidebar/index.tsx +3 -6
- package/src/app/(main)/discover/(detail)/provider/[slug]/features/ModelList/ModelItem.tsx +14 -11
- package/src/app/(main)/discover/(list)/(home)/features/AssistantList.tsx +5 -11
- package/src/app/(main)/discover/(list)/(home)/features/ModelList.tsx +3 -3
- package/src/app/(main)/discover/(list)/(home)/features/PluginList.tsx +3 -6
- package/src/app/(main)/discover/(list)/assistants/features/List.tsx +7 -16
- package/src/app/(main)/discover/(list)/models/features/List.tsx +5 -11
- package/src/app/(main)/discover/(list)/plugins/features/List.tsx +7 -16
- package/src/app/(main)/discover/(list)/providers/features/List.tsx +5 -11
- package/src/app/(main)/discover/_layout/Desktop/index.tsx +3 -0
- package/src/app/(main)/discover/_layout/Mobile/index.tsx +8 -1
- package/src/app/(main)/settings/llm/ProviderList/Github/index.tsx +53 -0
- package/src/app/(main)/settings/llm/ProviderList/providers.tsx +6 -1
- package/src/app/api/chat/agentRuntime.ts +14 -0
- package/src/app/layout.tsx +2 -1
- package/src/components/NProgress/index.tsx +12 -0
- package/src/components/SidebarHeader/index.tsx +1 -1
- package/src/config/llm.ts +14 -0
- package/src/config/modelProviders/ai21.ts +37 -0
- package/src/config/modelProviders/anthropic.ts +4 -0
- package/src/config/modelProviders/github.ts +209 -0
- package/src/config/modelProviders/index.ts +8 -0
- package/src/const/layoutTokens.ts +1 -1
- package/src/const/plugin.test.ts +80 -0
- package/src/const/plugin.ts +12 -0
- package/src/const/settings/llm.ts +10 -0
- package/src/features/Conversation/Error/APIKeyForm/index.tsx +4 -0
- package/src/features/Conversation/Messages/Tool/Inspector/index.tsx +1 -1
- package/src/features/Conversation/Messages/Tool/index.tsx +1 -1
- package/src/features/Conversation/components/ChatItem/index.tsx +24 -2
- package/src/features/Conversation/components/ChatItem/utils.test.ts +150 -0
- package/src/features/Conversation/components/ChatItem/utils.ts +28 -0
- package/src/features/Conversation/components/InboxWelcome/AgentsSuggest.tsx +3 -6
- package/src/features/Conversation/components/MarkdownElements/LobeArtifact/Render/Icon.tsx +96 -0
- package/src/features/Conversation/components/MarkdownElements/LobeArtifact/Render/index.tsx +129 -0
- package/src/features/Conversation/components/MarkdownElements/LobeArtifact/index.ts +10 -0
- package/src/features/Conversation/components/MarkdownElements/LobeArtifact/rehypePlugin.ts +74 -0
- package/src/features/Conversation/components/MarkdownElements/LobeThinking/Render.tsx +86 -0
- package/src/features/Conversation/components/MarkdownElements/LobeThinking/index.ts +12 -0
- package/src/features/Conversation/components/MarkdownElements/LobeThinking/rehypePlugin.test.ts +124 -0
- package/src/features/Conversation/components/MarkdownElements/LobeThinking/rehypePlugin.ts +51 -0
- package/src/features/Conversation/components/MarkdownElements/index.ts +4 -0
- package/src/features/Conversation/components/MarkdownElements/type.ts +7 -0
- package/src/hooks/useInterceptingRoutes.ts +1 -16
- package/src/libs/agent-runtime/AgentRuntime.ts +14 -0
- package/src/libs/agent-runtime/ai21/index.test.ts +255 -0
- package/src/libs/agent-runtime/ai21/index.ts +18 -0
- package/src/libs/agent-runtime/error.ts +2 -0
- package/src/libs/agent-runtime/github/index.test.ts +246 -0
- package/src/libs/agent-runtime/github/index.ts +15 -0
- package/src/libs/agent-runtime/openrouter/__snapshots__/index.test.ts.snap +2215 -28
- package/src/libs/agent-runtime/openrouter/fixtures/models.json +3345 -37
- package/src/libs/agent-runtime/openrouter/index.ts +2 -1
- package/src/libs/agent-runtime/types/type.ts +2 -0
- package/src/locales/default/chat.ts +7 -0
- package/src/locales/default/error.ts +3 -0
- package/src/locales/default/modelProvider.ts +7 -0
- package/src/locales/default/portal.ts +17 -1
- package/src/server/globalConfig/index.ts +14 -0
- package/src/store/chat/slices/message/selectors.ts +30 -28
- package/src/store/chat/slices/portal/action.ts +15 -2
- package/src/store/chat/slices/portal/initialState.ts +11 -0
- package/src/store/chat/slices/portal/selectors.test.ts +29 -7
- package/src/store/chat/slices/portal/selectors.ts +56 -12
- package/src/styles/loading.ts +28 -0
- package/src/tools/artifacts/index.ts +13 -0
- package/src/tools/artifacts/systemRole.ts +338 -0
- package/src/tools/index.ts +6 -0
- package/src/types/user/settings/keyVaults.ts +2 -0
- package/src/utils/clipboard.ts +53 -0
- package/src/app/@modal/(.)discover/assistant/[slug]/page.tsx +0 -1
- package/src/app/@modal/(.)discover/layout.tsx +0 -29
- package/src/app/@modal/(.)discover/loading.tsx +0 -3
- package/src/app/@modal/(.)discover/model/[...slugs]/page.tsx +0 -1
- package/src/app/@modal/(.)discover/plugin/[slug]/page.tsx +0 -1
- package/src/app/@modal/(.)discover/provider/[slug]/page.tsx +0 -1
- package/src/app/redirect/page.tsx +0 -15
- package/src/components/InterceptingLink/index.tsx +0 -27
- /package/src/app/(main)/chat/(workspace)/@portal/Home/Body/{Artifacts → Plugins}/ArtifactList/Item/index.tsx +0 -0
- /package/src/app/(main)/chat/(workspace)/@portal/Home/Body/{Artifacts → Plugins}/ArtifactList/Item/style.ts +0 -0
- /package/src/app/(main)/chat/(workspace)/@portal/Home/Body/{Artifacts → Plugins}/ArtifactList/index.tsx +0 -0
@@ -23,7 +23,8 @@ export const LobeOpenRouterAI = LobeOpenAICompatibleFactory({
|
|
23
23
|
description: model.description,
|
24
24
|
displayName: model.name,
|
25
25
|
enabled: LOBE_DEFAULT_MODEL_LIST.find((m) => model.id.endsWith(m.id))?.enabled || false,
|
26
|
-
functionCall:
|
26
|
+
functionCall:
|
27
|
+
model.description.includes('function calling') || model.description.includes('tools'),
|
27
28
|
id: model.id,
|
28
29
|
maxTokens:
|
29
30
|
typeof model.top_provider.max_completion_tokens === 'number'
|
@@ -22,6 +22,7 @@ export interface CreateChatCompletionOptions {
|
|
22
22
|
}
|
23
23
|
|
24
24
|
export enum ModelProvider {
|
25
|
+
Ai21 = 'ai21',
|
25
26
|
Ai360 = 'ai360',
|
26
27
|
Anthropic = 'anthropic',
|
27
28
|
Azure = 'azure',
|
@@ -29,6 +30,7 @@ export enum ModelProvider {
|
|
29
30
|
Bedrock = 'bedrock',
|
30
31
|
DeepSeek = 'deepseek',
|
31
32
|
FireworksAI = 'fireworksai',
|
33
|
+
Github = 'github',
|
32
34
|
Google = 'google',
|
33
35
|
Groq = 'groq',
|
34
36
|
Minimax = 'minimax',
|
@@ -7,6 +7,12 @@ export default {
|
|
7
7
|
agentDefaultMessageWithSystemRole: '你好,我是 **{{name}}**,{{systemRole}},让我们开始对话吧!',
|
8
8
|
agentDefaultMessageWithoutEdit: '你好,我是 **{{name}}**,让我们开始对话吧!',
|
9
9
|
agentsAndConversations: '助手与会话',
|
10
|
+
artifact: {
|
11
|
+
generating: '生成中',
|
12
|
+
thinking: '思考中',
|
13
|
+
thought: '思考过程',
|
14
|
+
unknownTitle: '未命名作品',
|
15
|
+
},
|
10
16
|
backToBottom: '跳转至当前',
|
11
17
|
chatList: {
|
12
18
|
longMessageDetail: '查看详情',
|
@@ -160,6 +166,7 @@ export default {
|
|
160
166
|
clear: '删除语音',
|
161
167
|
},
|
162
168
|
updateAgent: '更新助理信息',
|
169
|
+
|
163
170
|
upload: {
|
164
171
|
action: {
|
165
172
|
fileUpload: '上传文件',
|
@@ -52,6 +52,13 @@ export default {
|
|
52
52
|
title: '使用自定义 Bedrock 鉴权信息',
|
53
53
|
},
|
54
54
|
},
|
55
|
+
github: {
|
56
|
+
personalAccessToken: {
|
57
|
+
desc: '填入你的 Github PAT,点击[这里](https://github.com/settings/tokens) 创建',
|
58
|
+
placeholder: 'ghp_xxxxxx',
|
59
|
+
title: 'Github PAT',
|
60
|
+
},
|
61
|
+
},
|
55
62
|
ollama: {
|
56
63
|
checker: {
|
57
64
|
desc: '测试代理地址是否正确填写',
|
@@ -6,13 +6,29 @@ export default {
|
|
6
6
|
file: '文件',
|
7
7
|
},
|
8
8
|
},
|
9
|
+
Plugins: '插件',
|
9
10
|
actions: {
|
10
11
|
genAiMessage: '创建助手消息',
|
11
12
|
summary: '总结',
|
12
13
|
summaryTooltip: '总结当前内容',
|
13
14
|
},
|
15
|
+
artifacts: {
|
16
|
+
display: {
|
17
|
+
code: '代码',
|
18
|
+
preview: '预览',
|
19
|
+
},
|
20
|
+
svg: {
|
21
|
+
copyAsImage: '复制为图片',
|
22
|
+
copyFail: '复制失败,错误原因:{{error}}',
|
23
|
+
copySuccess: '图片复制成功',
|
24
|
+
download: {
|
25
|
+
png: '下载为 PNG',
|
26
|
+
svg: '下载为 SVG',
|
27
|
+
},
|
28
|
+
},
|
29
|
+
},
|
14
30
|
emptyArtifactList: '当前 Artifacts 列表为空,请在会话中按需使用插件后再查看',
|
15
|
-
emptyKnowledgeList: '
|
31
|
+
emptyKnowledgeList: '当前知识列表为空',
|
16
32
|
files: '文件',
|
17
33
|
messageDetail: '消息详情',
|
18
34
|
title: '工作区',
|
@@ -6,6 +6,7 @@ import { getLLMConfig } from '@/config/llm';
|
|
6
6
|
import {
|
7
7
|
BedrockProviderCard,
|
8
8
|
FireworksAIProviderCard,
|
9
|
+
GithubProviderCard,
|
9
10
|
GoogleProviderCard,
|
10
11
|
GroqProviderCard,
|
11
12
|
NovitaProviderCard,
|
@@ -45,6 +46,9 @@ export const getServerGlobalConfig = () => {
|
|
45
46
|
ENABLED_GROQ,
|
46
47
|
GROQ_MODEL_LIST,
|
47
48
|
|
49
|
+
ENABLED_GITHUB,
|
50
|
+
GITHUB_MODEL_LIST,
|
51
|
+
|
48
52
|
ENABLED_DEEPSEEK,
|
49
53
|
ENABLED_PERPLEXITY,
|
50
54
|
ENABLED_ANTHROPIC,
|
@@ -60,6 +64,7 @@ export const getServerGlobalConfig = () => {
|
|
60
64
|
ENABLED_STEPFUN,
|
61
65
|
ENABLED_BAICHUAN,
|
62
66
|
ENABLED_TAICHU,
|
67
|
+
ENABLED_AI21,
|
63
68
|
ENABLED_AI360,
|
64
69
|
|
65
70
|
ENABLED_SILICONCLOUD,
|
@@ -97,6 +102,7 @@ export const getServerGlobalConfig = () => {
|
|
97
102
|
enabledAccessCode: ACCESS_CODES?.length > 0,
|
98
103
|
enabledOAuthSSO: enableNextAuth,
|
99
104
|
languageModel: {
|
105
|
+
ai21: { enabled: ENABLED_AI21 },
|
100
106
|
ai360: { enabled: ENABLED_AI360 },
|
101
107
|
anthropic: {
|
102
108
|
enabled: ENABLED_ANTHROPIC,
|
@@ -130,6 +136,14 @@ export const getServerGlobalConfig = () => {
|
|
130
136
|
}),
|
131
137
|
},
|
132
138
|
|
139
|
+
github: {
|
140
|
+
enabled: ENABLED_GITHUB,
|
141
|
+
enabledModels: extractEnabledModels(GITHUB_MODEL_LIST),
|
142
|
+
serverModelCards: transformToChatModelCards({
|
143
|
+
defaultChatModels: GithubProviderCard.chatModels,
|
144
|
+
modelString: GITHUB_MODEL_LIST,
|
145
|
+
}),
|
146
|
+
},
|
133
147
|
google: {
|
134
148
|
enabled: ENABLED_GOOGLE,
|
135
149
|
enabledModels: extractEnabledModels(GOOGLE_MODEL_LIST),
|
@@ -16,7 +16,7 @@ import { MetaData } from '@/types/meta';
|
|
16
16
|
import { merge } from '@/utils/merge';
|
17
17
|
|
18
18
|
import { chatHelpers } from '../../helpers';
|
19
|
-
import type {
|
19
|
+
import type { ChatStoreState } from '../../initialState';
|
20
20
|
|
21
21
|
const getMeta = (message: ChatMessage) => {
|
22
22
|
switch (message.role) {
|
@@ -36,10 +36,10 @@ const getMeta = (message: ChatMessage) => {
|
|
36
36
|
}
|
37
37
|
};
|
38
38
|
|
39
|
-
const currentChatKey = (s:
|
39
|
+
const currentChatKey = (s: ChatStoreState) => messageMapKey(s.activeId, s.activeTopicId);
|
40
40
|
|
41
41
|
// 当前激活的消息列表
|
42
|
-
const currentChats = (s:
|
42
|
+
const currentChats = (s: ChatStoreState): ChatMessage[] => {
|
43
43
|
if (!s.activeId) return [];
|
44
44
|
|
45
45
|
const messages = s.messagesMap[currentChatKey(s)] || [];
|
@@ -47,19 +47,19 @@ const currentChats = (s: ChatStore): ChatMessage[] => {
|
|
47
47
|
return messages.map((i) => ({ ...i, meta: getMeta(i) }));
|
48
48
|
};
|
49
49
|
|
50
|
-
const currentToolMessages = (s:
|
50
|
+
const currentToolMessages = (s: ChatStoreState) => {
|
51
51
|
const messages = currentChats(s);
|
52
52
|
|
53
53
|
return messages.filter((m) => m.role === 'tool');
|
54
54
|
};
|
55
55
|
|
56
|
-
const currentUserMessages = (s:
|
56
|
+
const currentUserMessages = (s: ChatStoreState) => {
|
57
57
|
const messages = currentChats(s);
|
58
58
|
|
59
59
|
return messages.filter((m) => m.role === 'user');
|
60
60
|
};
|
61
61
|
|
62
|
-
const currentUserFiles = (s:
|
62
|
+
const currentUserFiles = (s: ChatStoreState) => {
|
63
63
|
const userMessages = currentUserMessages(s);
|
64
64
|
|
65
65
|
return userMessages
|
@@ -70,7 +70,7 @@ const currentUserFiles = (s: ChatStore) => {
|
|
70
70
|
|
71
71
|
const initTime = Date.now();
|
72
72
|
|
73
|
-
const showInboxWelcome = (s:
|
73
|
+
const showInboxWelcome = (s: ChatStoreState): boolean => {
|
74
74
|
const isInbox = s.activeId === INBOX_SESSION_ID;
|
75
75
|
if (!isInbox) return false;
|
76
76
|
|
@@ -83,7 +83,7 @@ const showInboxWelcome = (s: ChatStore): boolean => {
|
|
83
83
|
// Custom message for new assistant initialization
|
84
84
|
const currentChatsWithGuideMessage =
|
85
85
|
(meta: MetaData) =>
|
86
|
-
(s:
|
86
|
+
(s: ChatStoreState): ChatMessage[] => {
|
87
87
|
// skip tool message
|
88
88
|
const data = currentChats(s).filter((m) => m.role !== 'tool');
|
89
89
|
|
@@ -120,47 +120,49 @@ const currentChatsWithGuideMessage =
|
|
120
120
|
return [emptyInboxGuideMessage];
|
121
121
|
};
|
122
122
|
|
123
|
-
const currentChatIDsWithGuideMessage = (s:
|
123
|
+
const currentChatIDsWithGuideMessage = (s: ChatStoreState) => {
|
124
124
|
const meta = sessionMetaSelectors.currentAgentMeta(useSessionStore.getState());
|
125
125
|
|
126
126
|
return currentChatsWithGuideMessage(meta)(s).map((s) => s.id);
|
127
127
|
};
|
128
128
|
|
129
|
-
const currentChatsWithHistoryConfig = (s:
|
129
|
+
const currentChatsWithHistoryConfig = (s: ChatStoreState): ChatMessage[] => {
|
130
130
|
const chats = currentChats(s);
|
131
131
|
const config = agentSelectors.currentAgentChatConfig(useAgentStore.getState());
|
132
132
|
|
133
133
|
return chatHelpers.getSlicedMessagesWithConfig(chats, config);
|
134
134
|
};
|
135
135
|
|
136
|
-
const chatsMessageString = (s:
|
136
|
+
const chatsMessageString = (s: ChatStoreState): string => {
|
137
137
|
const chats = currentChatsWithHistoryConfig(s);
|
138
138
|
return chats.map((m) => m.content).join('');
|
139
139
|
};
|
140
140
|
|
141
|
-
const getMessageById = (id: string) => (s:
|
141
|
+
const getMessageById = (id: string) => (s: ChatStoreState) =>
|
142
142
|
chatHelpers.getMessageById(currentChats(s), id);
|
143
143
|
|
144
|
-
const getMessageByToolCallId = (id: string) => (s:
|
144
|
+
const getMessageByToolCallId = (id: string) => (s: ChatStoreState) => {
|
145
145
|
const messages = currentChats(s);
|
146
146
|
return messages.find((m) => m.tool_call_id === id);
|
147
147
|
};
|
148
|
-
const getTraceIdByMessageId = (id: string) => (s:
|
148
|
+
const getTraceIdByMessageId = (id: string) => (s: ChatStoreState) => getMessageById(id)(s)?.traceId;
|
149
149
|
|
150
|
-
const latestMessage = (s:
|
150
|
+
const latestMessage = (s: ChatStoreState) => currentChats(s).at(-1);
|
151
151
|
|
152
|
-
const currentChatLoadingState = (s:
|
152
|
+
const currentChatLoadingState = (s: ChatStoreState) => !s.messagesInit;
|
153
153
|
|
154
|
-
const isCurrentChatLoaded = (s:
|
154
|
+
const isCurrentChatLoaded = (s: ChatStoreState) => !!s.messagesMap[currentChatKey(s)];
|
155
155
|
|
156
|
-
const isMessageEditing = (id: string) => (s:
|
157
|
-
const isMessageLoading = (id: string) => (s:
|
156
|
+
const isMessageEditing = (id: string) => (s: ChatStoreState) => s.messageEditingIds.includes(id);
|
157
|
+
const isMessageLoading = (id: string) => (s: ChatStoreState) => s.messageLoadingIds.includes(id);
|
158
158
|
|
159
|
-
const isMessageGenerating = (id: string) => (s:
|
160
|
-
const isMessageInRAGFlow = (id: string) => (s:
|
161
|
-
|
159
|
+
const isMessageGenerating = (id: string) => (s: ChatStoreState) => s.chatLoadingIds.includes(id);
|
160
|
+
const isMessageInRAGFlow = (id: string) => (s: ChatStoreState) =>
|
161
|
+
s.messageRAGLoadingIds.includes(id);
|
162
|
+
const isPluginApiInvoking = (id: string) => (s: ChatStoreState) =>
|
163
|
+
s.pluginApiLoadingIds.includes(id);
|
162
164
|
|
163
|
-
const isToolCallStreaming = (id: string, index: number) => (s:
|
165
|
+
const isToolCallStreaming = (id: string, index: number) => (s: ChatStoreState) => {
|
164
166
|
const isLoading = s.toolCallingStreamIds[id];
|
165
167
|
|
166
168
|
if (!isLoading) return false;
|
@@ -168,15 +170,15 @@ const isToolCallStreaming = (id: string, index: number) => (s: ChatStore) => {
|
|
168
170
|
return isLoading[index];
|
169
171
|
};
|
170
172
|
|
171
|
-
const isAIGenerating = (s:
|
172
|
-
const isInRAGFlow = (s:
|
173
|
-
const isCreatingMessage = (s:
|
174
|
-
const isHasMessageLoading = (s:
|
173
|
+
const isAIGenerating = (s: ChatStoreState) => s.chatLoadingIds.length > 0;
|
174
|
+
const isInRAGFlow = (s: ChatStoreState) => s.messageRAGLoadingIds.length > 0;
|
175
|
+
const isCreatingMessage = (s: ChatStoreState) => s.isCreatingMessage;
|
176
|
+
const isHasMessageLoading = (s: ChatStoreState) => s.messageLoadingIds.length > 0;
|
175
177
|
|
176
178
|
/**
|
177
179
|
* this function is used to determine whether the send button should be disabled
|
178
180
|
*/
|
179
|
-
const isSendButtonDisabledByMessage = (s:
|
181
|
+
const isSendButtonDisabledByMessage = (s: ChatStoreState) =>
|
180
182
|
// 1. when there is message loading
|
181
183
|
isHasMessageLoading(s) ||
|
182
184
|
// 2. when is creating the topic
|
@@ -2,16 +2,17 @@ import { StateCreator } from 'zustand/vanilla';
|
|
2
2
|
|
3
3
|
import { ChatStore } from '@/store/chat/store';
|
4
4
|
|
5
|
-
import { PortalFile } from './initialState';
|
5
|
+
import { PortalArtifact, PortalFile } from './initialState';
|
6
6
|
|
7
7
|
export interface ChatPortalAction {
|
8
|
+
closeArtifact: () => void;
|
8
9
|
closeFilePreview: () => void;
|
9
10
|
closeMessageDetail: () => void;
|
10
11
|
closeToolUI: () => void;
|
12
|
+
openArtifact: (artifact: PortalArtifact) => void;
|
11
13
|
openFilePreview: (portal: PortalFile) => void;
|
12
14
|
openMessageDetail: (messageId: string) => void;
|
13
15
|
openToolUI: (messageId: string, identifier: string) => void;
|
14
|
-
|
15
16
|
togglePortal: (open?: boolean) => void;
|
16
17
|
}
|
17
18
|
|
@@ -21,6 +22,10 @@ export const chatPortalSlice: StateCreator<
|
|
21
22
|
[],
|
22
23
|
ChatPortalAction
|
23
24
|
> = (set, get) => ({
|
25
|
+
closeArtifact: () => {
|
26
|
+
get().togglePortal(false);
|
27
|
+
set({ portalArtifact: undefined }, false, 'closeArtifact');
|
28
|
+
},
|
24
29
|
closeFilePreview: () => {
|
25
30
|
set({ portalFile: undefined }, false, 'closeFilePreview');
|
26
31
|
},
|
@@ -30,6 +35,11 @@ export const chatPortalSlice: StateCreator<
|
|
30
35
|
closeToolUI: () => {
|
31
36
|
set({ portalToolMessage: undefined }, false, 'closeToolUI');
|
32
37
|
},
|
38
|
+
openArtifact: (artifact) => {
|
39
|
+
get().togglePortal(true);
|
40
|
+
|
41
|
+
set({ portalArtifact: artifact }, false, 'openArtifact');
|
42
|
+
},
|
33
43
|
openFilePreview: (portal) => {
|
34
44
|
get().togglePortal(true);
|
35
45
|
|
@@ -49,4 +59,7 @@ export const chatPortalSlice: StateCreator<
|
|
49
59
|
const showInspector = open === undefined ? !get().showPortal : open;
|
50
60
|
set({ showPortal: showInspector }, false, 'toggleInspector');
|
51
61
|
},
|
62
|
+
// updateArtifactContent: (content) => {
|
63
|
+
// set({ portalArtifact: content }, false, 'updateArtifactContent');
|
64
|
+
// },
|
52
65
|
});
|
@@ -4,7 +4,17 @@ export interface PortalFile {
|
|
4
4
|
fileId: string;
|
5
5
|
}
|
6
6
|
|
7
|
+
export interface PortalArtifact {
|
8
|
+
children?: string;
|
9
|
+
id: string;
|
10
|
+
identifier?: string;
|
11
|
+
title?: string;
|
12
|
+
type?: string;
|
13
|
+
}
|
14
|
+
|
7
15
|
export interface ChatPortalState {
|
16
|
+
portalArtifact?: PortalArtifact;
|
17
|
+
portalArtifactDisplayMode?: 'code' | 'preview';
|
8
18
|
portalFile?: PortalFile;
|
9
19
|
portalMessageDetail?: string;
|
10
20
|
portalToolMessage?: { id: string; identifier: string };
|
@@ -12,5 +22,6 @@ export interface ChatPortalState {
|
|
12
22
|
}
|
13
23
|
|
14
24
|
export const initialChatPortalState: ChatPortalState = {
|
25
|
+
portalArtifactDisplayMode: 'preview',
|
15
26
|
showPortal: false,
|
16
27
|
};
|
@@ -21,12 +21,12 @@ describe('chatDockSelectors', () => {
|
|
21
21
|
|
22
22
|
describe('toolUIMessageId', () => {
|
23
23
|
it('should return undefined when dockToolMessage is not set', () => {
|
24
|
-
expect(chatPortalSelectors.
|
24
|
+
expect(chatPortalSelectors.toolMessageId(createState())).toBeUndefined();
|
25
25
|
});
|
26
26
|
|
27
27
|
it('should return the id when dockToolMessage is set', () => {
|
28
28
|
const state = createState({ portalToolMessage: { id: 'test-id', identifier: 'test' } });
|
29
|
-
expect(chatPortalSelectors.
|
29
|
+
expect(chatPortalSelectors.toolMessageId(state)).toBe('test-id');
|
30
30
|
});
|
31
31
|
});
|
32
32
|
|
@@ -36,8 +36,8 @@ describe('chatDockSelectors', () => {
|
|
36
36
|
portalToolMessage: { id: 'test-id', identifier: 'test' },
|
37
37
|
showPortal: false,
|
38
38
|
});
|
39
|
-
expect(chatPortalSelectors.
|
40
|
-
expect(chatPortalSelectors.
|
39
|
+
expect(chatPortalSelectors.isPluginUIOpen('test-id')(state)).toBe(false);
|
40
|
+
expect(chatPortalSelectors.isPluginUIOpen('other-id')(state)).toBe(false);
|
41
41
|
});
|
42
42
|
|
43
43
|
it('should return true when id matches and showDock is true', () => {
|
@@ -45,18 +45,18 @@ describe('chatDockSelectors', () => {
|
|
45
45
|
portalToolMessage: { id: 'test-id', identifier: 'test' },
|
46
46
|
showPortal: true,
|
47
47
|
});
|
48
|
-
expect(chatPortalSelectors.
|
48
|
+
expect(chatPortalSelectors.isPluginUIOpen('test-id')(state)).toBe(true);
|
49
49
|
});
|
50
50
|
});
|
51
51
|
|
52
52
|
describe('showToolUI', () => {
|
53
53
|
it('should return false when dockToolMessage is not set', () => {
|
54
|
-
expect(chatPortalSelectors.
|
54
|
+
expect(chatPortalSelectors.showPluginUI(createState())).toBe(false);
|
55
55
|
});
|
56
56
|
|
57
57
|
it('should return true when dockToolMessage is set', () => {
|
58
58
|
const state = createState({ portalToolMessage: { id: 'test-id', identifier: 'test' } });
|
59
|
-
expect(chatPortalSelectors.
|
59
|
+
expect(chatPortalSelectors.showPluginUI(state)).toBe(true);
|
60
60
|
});
|
61
61
|
});
|
62
62
|
|
@@ -70,4 +70,26 @@ describe('chatDockSelectors', () => {
|
|
70
70
|
expect(chatPortalSelectors.toolUIIdentifier(state)).toBe('test');
|
71
71
|
});
|
72
72
|
});
|
73
|
+
|
74
|
+
describe('showFilePreview', () => {
|
75
|
+
it('should return false when portalFile is not set', () => {
|
76
|
+
expect(chatPortalSelectors.showFilePreview(createState())).toBe(false);
|
77
|
+
});
|
78
|
+
|
79
|
+
it('should return true when portalFile is set', () => {
|
80
|
+
const state = createState({ portalFile: { fileId: 'file-id', chunkText: 'chunk' } });
|
81
|
+
expect(chatPortalSelectors.showFilePreview(state)).toBe(true);
|
82
|
+
});
|
83
|
+
});
|
84
|
+
|
85
|
+
describe('previewFileId', () => {
|
86
|
+
it('should return undefined when portalFile is not set', () => {
|
87
|
+
expect(chatPortalSelectors.previewFileId(createState())).toBeUndefined();
|
88
|
+
});
|
89
|
+
|
90
|
+
it('should return the fileId when portalFile is set', () => {
|
91
|
+
const state = createState({ portalFile: { fileId: 'file-id', chunkText: 'chunk' } });
|
92
|
+
expect(chatPortalSelectors.previewFileId(state)).toBe('file-id');
|
93
|
+
});
|
94
|
+
});
|
73
95
|
});
|
@@ -1,27 +1,71 @@
|
|
1
|
+
import { ARTIFACT_TAG_CLOSED_REGEX, ARTIFACT_TAG_REGEX } from '@/const/plugin';
|
1
2
|
import type { ChatStoreState } from '@/store/chat';
|
2
3
|
|
3
|
-
|
4
|
+
import { chatSelectors } from '../message/selectors';
|
5
|
+
|
4
6
|
const showPortal = (s: ChatStoreState) => s.showPortal;
|
5
7
|
|
6
|
-
const
|
7
|
-
|
8
|
+
const showMessageDetail = (s: ChatStoreState) => !!s.portalMessageDetail;
|
9
|
+
const messageDetailId = (s: ChatStoreState) => s.portalMessageDetail;
|
10
|
+
|
11
|
+
const showPluginUI = (s: ChatStoreState) => !!s.portalToolMessage;
|
12
|
+
|
13
|
+
const toolMessageId = (s: ChatStoreState) => s.portalToolMessage?.id;
|
14
|
+
const isPluginUIOpen = (id: string) => (s: ChatStoreState) =>
|
15
|
+
toolMessageId(s) === id && showPortal(s);
|
16
|
+
const toolUIIdentifier = (s: ChatStoreState) => s.portalToolMessage?.identifier;
|
8
17
|
|
9
|
-
const showArtifactUI = (s: ChatStoreState) => !!s.portalToolMessage;
|
10
18
|
const showFilePreview = (s: ChatStoreState) => !!s.portalFile;
|
11
|
-
const showMessageDetail = (s: ChatStoreState) => !!s.portalMessageDetail;
|
12
19
|
const previewFileId = (s: ChatStoreState) => s.portalFile?.fileId;
|
13
|
-
const messageDetailId = (s: ChatStoreState) => s.portalMessageDetail;
|
14
20
|
const chunkText = (s: ChatStoreState) => s.portalFile?.chunkText;
|
15
21
|
|
22
|
+
const showArtifactUI = (s: ChatStoreState) => !!s.portalArtifact;
|
23
|
+
const artifactTitle = (s: ChatStoreState) => s.portalArtifact?.title;
|
24
|
+
const artifactIdentifier = (s: ChatStoreState) => s.portalArtifact?.identifier || '';
|
25
|
+
const artifactMessageId = (s: ChatStoreState) => s.portalArtifact?.id;
|
26
|
+
const artifactType = (s: ChatStoreState) => s.portalArtifact?.type;
|
27
|
+
|
28
|
+
const artifactMessageContent = (id: string) => (s: ChatStoreState) => {
|
29
|
+
const message = chatSelectors.getMessageById(id)(s);
|
30
|
+
return message?.content || '';
|
31
|
+
};
|
32
|
+
|
33
|
+
const artifactCode = (id: string) => (s: ChatStoreState) => {
|
34
|
+
const messageContent = artifactMessageContent(id)(s);
|
35
|
+
const result = messageContent.match(ARTIFACT_TAG_REGEX);
|
36
|
+
|
37
|
+
return result?.groups?.content || '';
|
38
|
+
};
|
39
|
+
|
40
|
+
const isArtifactTagClosed = (id: string) => (s: ChatStoreState) => {
|
41
|
+
const content = artifactMessageContent(id)(s);
|
42
|
+
|
43
|
+
return ARTIFACT_TAG_CLOSED_REGEX.test(content || '');
|
44
|
+
};
|
45
|
+
|
46
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix, typescript-sort-keys/interface */
|
16
47
|
export const chatPortalSelectors = {
|
17
|
-
|
18
|
-
|
19
|
-
isArtifactMessageUIOpen,
|
20
|
-
messageDetailId,
|
48
|
+
isPluginUIOpen,
|
49
|
+
|
21
50
|
previewFileId,
|
22
|
-
showArtifactUI,
|
23
51
|
showFilePreview,
|
52
|
+
chunkText,
|
53
|
+
|
54
|
+
messageDetailId,
|
24
55
|
showMessageDetail,
|
56
|
+
|
57
|
+
showPluginUI,
|
25
58
|
showPortal,
|
26
|
-
|
59
|
+
|
60
|
+
toolMessageId,
|
61
|
+
toolUIIdentifier,
|
62
|
+
|
63
|
+
showArtifactUI,
|
64
|
+
artifactTitle,
|
65
|
+
artifactIdentifier,
|
66
|
+
artifactMessageId,
|
67
|
+
artifactType,
|
68
|
+
artifactCode,
|
69
|
+
artifactMessageContent,
|
70
|
+
isArtifactTagClosed,
|
27
71
|
};
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { css } from 'antd-style';
|
2
|
+
|
3
|
+
export const dotLoading = css`
|
4
|
+
&::after {
|
5
|
+
content: '\\2026'; /* ascii code for the ellipsis character */
|
6
|
+
|
7
|
+
overflow: hidden;
|
8
|
+
display: inline-block;
|
9
|
+
|
10
|
+
width: 0;
|
11
|
+
|
12
|
+
vertical-align: bottom;
|
13
|
+
|
14
|
+
animation: ellipsis steps(4, end) 900ms infinite;
|
15
|
+
}
|
16
|
+
|
17
|
+
@keyframes ellipsis {
|
18
|
+
to {
|
19
|
+
width: 1.25em;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
@keyframes ellipsis {
|
24
|
+
to {
|
25
|
+
width: 1.25em;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
`;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { systemPrompt } from '@/tools/artifacts/systemRole';
|
2
|
+
import { BuiltinToolManifest } from '@/types/tool';
|
3
|
+
|
4
|
+
export const ArtifactsManifest: BuiltinToolManifest = {
|
5
|
+
api: [],
|
6
|
+
identifier: 'lobe-artifacts',
|
7
|
+
meta: {
|
8
|
+
avatar: `data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAyNCIgaGVpZ2h0PSIxMDI0IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMDI0IiBoZWlnaHQ9IjEwMjQiIHJ4PSI1MTIiIGZpbGw9IiNDNDc4NUIiLz48cGF0aCBkPSJNNTEyIDYxMmM1NS4yMjggMCAxMDAtNDQuNzcyIDEwMC0xMDBzLTQ0Ljc3Mi0xMDAtMTAwLTEwMC0xMDAgNDQuNzcyLTEwMCAxMDAgNDQuNzcyIDEwMCAxMDAgMTAwWiIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjU2IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNNTEyIDY2MmExNDkuOTk4IDE0OS45OTggMCAwIDEtOTIuNTk3IDEzOC41ODIgMTUwLjAwMiAxNTAuMDAyIDAgMCAxLTIwNC41MjEtMTA5LjMxOCAxNDkuOTk4IDE0OS45OTggMCAwIDEgNjMuNzgzLTE1My45ODRBMTQ5Ljk5MiAxNDkuOTkyIDAgMCAxIDM2MiA1MTJhMTQ5Ljk5OSAxNDkuOTk5IDAgMSAxIDE1MC0xNTAgMTQ5Ljk5OCAxNDkuOTk4IDAgMCAxIDI5Ny4xMTgtMjkuMjYzQTE1MCAxNTAgMCAwIDEgNjYyIDUxMmMyOS42NjcgMCA1OC42NjggOC43OTcgODMuMzM1IDI1LjI4YTE0OS45OTUgMTQ5Ljk5NSAwIDAgMSA2My43ODMgMTUzLjk4NEExNTAgMTUwIDAgMCAxIDUxMiA2NjJaTTUxMiAzNjJ2NTBNMzYyIDUxMmg1ME02NjIgNTEyaC01ME01MTIgNjYydi01ME0zNzguNjY3IDM3OC42NjdsNjIuNjY2IDYyLjY2Nk01ODIuNjY3IDQ0MS4zMzNsNjIuNjY2LTYyLjY2Nk0zNzguNjY3IDY0NS4zMzNsNjIuNjY2LTYyLjY2Nk01ODIuNjY3IDU4Mi42NjdsNjIuNjY2IDYyLjY2NiIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjU2IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4=`,
|
9
|
+
title: 'Artifacts',
|
10
|
+
},
|
11
|
+
systemRole: systemPrompt,
|
12
|
+
type: 'builtin',
|
13
|
+
};
|