@lobehub/chat 1.77.10 → 1.77.12
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/.github/scripts/pr-comment.js +111 -55
- package/CHANGELOG.md +51 -0
- package/changelog/v1.json +18 -0
- package/docs/self-hosting/environment-variables/basic.mdx +39 -0
- package/docs/self-hosting/environment-variables/basic.zh-CN.mdx +40 -1
- package/locales/ar/hotkey.json +4 -0
- package/locales/ar/models.json +6 -0
- package/locales/bg-BG/hotkey.json +4 -0
- package/locales/bg-BG/models.json +6 -0
- package/locales/de-DE/hotkey.json +4 -0
- package/locales/de-DE/models.json +6 -0
- package/locales/en-US/hotkey.json +4 -0
- package/locales/en-US/models.json +6 -0
- package/locales/es-ES/hotkey.json +4 -0
- package/locales/es-ES/models.json +6 -0
- package/locales/fa-IR/hotkey.json +4 -0
- package/locales/fa-IR/models.json +6 -0
- package/locales/fr-FR/hotkey.json +4 -0
- package/locales/fr-FR/models.json +6 -0
- package/locales/it-IT/hotkey.json +4 -0
- package/locales/it-IT/models.json +6 -0
- package/locales/ja-JP/hotkey.json +4 -0
- package/locales/ja-JP/models.json +6 -0
- package/locales/ko-KR/hotkey.json +4 -0
- package/locales/ko-KR/models.json +6 -0
- package/locales/nl-NL/hotkey.json +4 -0
- package/locales/nl-NL/models.json +6 -0
- package/locales/pl-PL/hotkey.json +4 -0
- package/locales/pl-PL/models.json +6 -0
- package/locales/pt-BR/hotkey.json +4 -0
- package/locales/pt-BR/models.json +6 -0
- package/locales/ru-RU/hotkey.json +4 -0
- package/locales/ru-RU/models.json +6 -0
- package/locales/tr-TR/hotkey.json +4 -0
- package/locales/tr-TR/models.json +6 -0
- package/locales/vi-VN/hotkey.json +4 -0
- package/locales/vi-VN/models.json +6 -0
- package/locales/zh-CN/hotkey.json +4 -0
- package/locales/zh-CN/models.json +7 -1
- package/locales/zh-TW/hotkey.json +4 -0
- package/locales/zh-TW/models.json +6 -0
- package/package.json +1 -1
- package/packages/electron-client-ipc/src/dispatch.ts +29 -0
- package/packages/electron-client-ipc/src/events/index.ts +9 -2
- package/packages/electron-client-ipc/src/events/menu.ts +5 -0
- package/packages/electron-client-ipc/src/events/search.ts +4 -0
- package/packages/electron-client-ipc/src/events/system.ts +3 -0
- package/packages/electron-client-ipc/src/events/windows.ts +8 -0
- package/packages/electron-client-ipc/src/index.ts +1 -0
- package/packages/web-crawler/src/crawler.ts +3 -1
- package/scripts/migrateServerDB/index.ts +3 -2
- package/src/app/(backend)/webapi/assistant/store/route.ts +7 -1
- package/src/app/(backend)/webapi/plugin/store/route.ts +6 -1
- package/src/app/[variants]/(main)/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +1 -0
- package/src/app/[variants]/(main)/_layout/Desktop/SideBar/TopActions.tsx +3 -2
- package/src/app/[variants]/(main)/_layout/Desktop/SideBar/index.tsx +24 -5
- package/src/app/[variants]/(main)/_layout/Desktop/Titlebar.tsx +27 -0
- package/src/app/[variants]/(main)/_layout/Desktop/index.tsx +32 -3
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/InboxWelcome/AgentsSuggest.tsx +3 -0
- package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/index.tsx +12 -2
- package/src/app/[variants]/(main)/chat/(workspace)/page.tsx +2 -1
- package/src/app/[variants]/(main)/settings/hotkey/features/HotkeySetting.tsx +15 -6
- package/src/app/[variants]/(main)/settings/hotkey/page.tsx +10 -1
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +3 -1
- package/src/app/desktop/devtools/page.tsx +37 -38
- package/src/config/aiModels/google.ts +25 -1
- package/src/config/aiModels/novita.ts +1 -32
- package/src/config/aiModels/ollama.ts +12 -1
- package/src/config/aiModels/qwen.ts +1 -1
- package/src/const/hotkeys.ts +10 -0
- package/src/features/Conversation/Error/index.tsx +10 -0
- package/src/features/DevPanel/PostgresViewer/SchemaSidebar/index.tsx +1 -1
- package/src/features/User/UserPanel/index.tsx +1 -1
- package/src/features/User/__tests__/PanelContent.test.tsx +1 -0
- package/src/libs/agent-runtime/error.ts +1 -0
- package/src/libs/agent-runtime/ollama/index.ts +16 -12
- package/src/libs/trpc/index.ts +8 -1
- package/src/libs/trpc/middleware/userAuth.ts +2 -3
- package/src/locales/default/hotkey.ts +4 -0
- package/src/server/globalConfig/genServerAiProviderConfig.ts +12 -3
- package/src/server/globalConfig/index.ts +6 -1
- package/src/server/globalConfig/parseSystemAgent.test.ts +56 -0
- package/src/server/globalConfig/parseSystemAgent.ts +25 -0
- package/src/server/modules/AssistantStore/index.ts +8 -0
- package/src/server/services/changelog/index.test.ts +2 -0
- package/src/server/services/changelog/index.ts +6 -2
- package/src/services/__tests__/chat.test.ts +3 -0
- package/src/services/electron/devtools.ts +1 -1
- package/src/store/user/slices/modelList/selectors/modelConfig.ts +4 -0
- package/src/styles/global.ts +14 -0
- package/src/types/hotkey.ts +1 -0
- package/src/utils/errorResponse.ts +2 -0
- package/tsconfig.json +1 -6
- package/packages/electron-client-ipc/src/events/devtools.ts +0 -6
- package/src/app/[variants]/(main)/settings/hotkey/index.tsx +0 -9
- package/src/types/electron.ts +0 -11
- package/src/utils/electron/dispatch.ts +0 -10
@@ -5,7 +5,15 @@ import { AiFullModelCard } from '@/types/aiModel';
|
|
5
5
|
import { ProviderConfig } from '@/types/user/settings';
|
6
6
|
import { extractEnabledModels, transformToAiChatModelList } from '@/utils/parseModels';
|
7
7
|
|
8
|
-
|
8
|
+
interface ProviderSpecificConfig {
|
9
|
+
enabled?: boolean;
|
10
|
+
enabledKey?: string;
|
11
|
+
fetchOnClient?: boolean;
|
12
|
+
modelListKey?: string;
|
13
|
+
withDeploymentName?: boolean;
|
14
|
+
}
|
15
|
+
|
16
|
+
export const genServerAiProvidersConfig = (specificConfig: Record<any, ProviderSpecificConfig>) => {
|
9
17
|
const llmConfig = getLLMConfig() as Record<string, any>;
|
10
18
|
|
11
19
|
return Object.values(ModelProvider).reduce(
|
@@ -26,8 +34,9 @@ export const genServerAiProvidersConfig = (specificConfig: Record<any, any>) =>
|
|
26
34
|
|
27
35
|
config[provider] = {
|
28
36
|
enabled:
|
29
|
-
providerConfig.enabled
|
30
|
-
|
37
|
+
typeof providerConfig.enabled !== 'undefined'
|
38
|
+
? providerConfig.enabled
|
39
|
+
: llmConfig[providerConfig.enabledKey || `ENABLED_${providerUpperCase}`],
|
31
40
|
|
32
41
|
enabledModels: extractEnabledModels(
|
33
42
|
providerModelList,
|
@@ -4,6 +4,7 @@ import { fileEnv } from '@/config/file';
|
|
4
4
|
import { knowledgeEnv } from '@/config/knowledge';
|
5
5
|
import { langfuseEnv } from '@/config/langfuse';
|
6
6
|
import { enableNextAuth } from '@/const/auth';
|
7
|
+
import { isDesktop } from '@/const/version';
|
7
8
|
import { parseSystemAgent } from '@/server/globalConfig/parseSystemAgent';
|
8
9
|
import { GlobalServerConfig } from '@/types/serverConfig';
|
9
10
|
|
@@ -36,7 +37,11 @@ export const getServerGlobalConfig = async () => {
|
|
36
37
|
|
37
38
|
/* ↑ cloud slot ↑ */
|
38
39
|
ollama: {
|
39
|
-
|
40
|
+
enabled: isDesktop ? true : undefined,
|
41
|
+
fetchOnClient: isDesktop ? false : !process.env.OLLAMA_PROXY_URL,
|
42
|
+
},
|
43
|
+
openai: {
|
44
|
+
enabled: isDesktop ? false : undefined,
|
40
45
|
},
|
41
46
|
volcengine: {
|
42
47
|
withDeploymentName: true,
|
@@ -92,4 +92,60 @@ describe('parseSystemAgent', () => {
|
|
92
92
|
|
93
93
|
expect(parseSystemAgent(envValue)).toEqual(expected);
|
94
94
|
});
|
95
|
+
|
96
|
+
it('should apply default setting to all system agents when default is specified', () => {
|
97
|
+
const envValue = 'default=ollama/deepseek-v3';
|
98
|
+
|
99
|
+
const result = parseSystemAgent(envValue);
|
100
|
+
|
101
|
+
expect(result.topic).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
102
|
+
expect(result.translation).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
103
|
+
expect(result.agentMeta).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
104
|
+
expect(result.historyCompress).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
105
|
+
expect(result.thread).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
106
|
+
expect(result.queryRewrite).toEqual({
|
107
|
+
provider: 'ollama',
|
108
|
+
model: 'deepseek-v3',
|
109
|
+
enabled: true,
|
110
|
+
});
|
111
|
+
});
|
112
|
+
|
113
|
+
it('should override default setting with specific settings', () => {
|
114
|
+
const envValue = 'default=ollama/deepseek-v3,topic=openai/gpt-4';
|
115
|
+
|
116
|
+
const result = parseSystemAgent(envValue);
|
117
|
+
|
118
|
+
expect(result.topic).toEqual({ provider: 'openai', model: 'gpt-4' });
|
119
|
+
|
120
|
+
expect(result.translation).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
121
|
+
expect(result.agentMeta).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
122
|
+
expect(result.historyCompress).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
123
|
+
expect(result.thread).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
124
|
+
expect(result.queryRewrite).toEqual({
|
125
|
+
provider: 'ollama',
|
126
|
+
model: 'deepseek-v3',
|
127
|
+
enabled: true,
|
128
|
+
});
|
129
|
+
});
|
130
|
+
|
131
|
+
it('should properly handle priority when topic appears before default in the string', () => {
|
132
|
+
// 即使 topic 在 default 之前出现,topic 的设置仍然应该优先
|
133
|
+
const envValue = 'topic=openai/gpt-4,default=ollama/deepseek-v3';
|
134
|
+
|
135
|
+
const result = parseSystemAgent(envValue);
|
136
|
+
|
137
|
+
// topic 应该保持自己的设置而不被 default 覆盖
|
138
|
+
expect(result.topic).toEqual({ provider: 'openai', model: 'gpt-4' });
|
139
|
+
|
140
|
+
// 其他系统智能体应该使用默认配置
|
141
|
+
expect(result.translation).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
142
|
+
expect(result.agentMeta).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
143
|
+
expect(result.historyCompress).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
144
|
+
expect(result.thread).toEqual({ provider: 'ollama', model: 'deepseek-v3' });
|
145
|
+
expect(result.queryRewrite).toEqual({
|
146
|
+
provider: 'ollama',
|
147
|
+
model: 'deepseek-v3',
|
148
|
+
enabled: true,
|
149
|
+
});
|
150
|
+
});
|
95
151
|
});
|
@@ -13,6 +13,9 @@ export const parseSystemAgent = (envString: string = ''): Partial<UserSystemAgen
|
|
13
13
|
|
14
14
|
const pairs = envValue.split(',');
|
15
15
|
|
16
|
+
// 用于存储默认设置,如果有 default=provider/model 的情况
|
17
|
+
let defaultSetting: { model: string; provider: string } | undefined;
|
18
|
+
|
16
19
|
for (const pair of pairs) {
|
17
20
|
const [key, value] = pair.split('=').map((s) => s.trim());
|
18
21
|
|
@@ -24,6 +27,15 @@ export const parseSystemAgent = (envString: string = ''): Partial<UserSystemAgen
|
|
24
27
|
throw new Error('Missing model or provider value');
|
25
28
|
}
|
26
29
|
|
30
|
+
// 如果是 default 键,保存默认设置
|
31
|
+
if (key === 'default') {
|
32
|
+
defaultSetting = {
|
33
|
+
model: model.trim(),
|
34
|
+
provider: provider.trim(),
|
35
|
+
};
|
36
|
+
continue;
|
37
|
+
}
|
38
|
+
|
27
39
|
if (protectedKeys.includes(key)) {
|
28
40
|
config[key as keyof UserSystemAgentConfig] = {
|
29
41
|
enabled: key === 'queryRewrite' ? true : undefined,
|
@@ -36,5 +48,18 @@ export const parseSystemAgent = (envString: string = ''): Partial<UserSystemAgen
|
|
36
48
|
}
|
37
49
|
}
|
38
50
|
|
51
|
+
// 如果有默认设置,应用到所有未设置的系统智能体
|
52
|
+
if (defaultSetting) {
|
53
|
+
for (const key of protectedKeys) {
|
54
|
+
if (!config[key as keyof UserSystemAgentConfig]) {
|
55
|
+
config[key as keyof UserSystemAgentConfig] = {
|
56
|
+
enabled: key === 'queryRewrite' ? true : undefined,
|
57
|
+
model: defaultSetting.model,
|
58
|
+
provider: defaultSetting.provider,
|
59
|
+
} as any;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
39
64
|
return config;
|
40
65
|
};
|
@@ -66,6 +66,14 @@ export class AssistantStore {
|
|
66
66
|
|
67
67
|
return data;
|
68
68
|
} catch (e) {
|
69
|
+
// it means failed to fetch
|
70
|
+
if ((e as Error).message.includes('fetch failed')) {
|
71
|
+
return {
|
72
|
+
agents: [],
|
73
|
+
schemaVersion: 1,
|
74
|
+
};
|
75
|
+
}
|
76
|
+
|
69
77
|
console.error('[AgentIndexFetchError] failed to fetch agent index, error detail:');
|
70
78
|
console.error(e);
|
71
79
|
|
@@ -79,6 +79,7 @@ describe('ChangelogService', () => {
|
|
79
79
|
describe('getChangelogIndex', () => {
|
80
80
|
it('should fetch and merge changelog data', async () => {
|
81
81
|
const mockResponse = {
|
82
|
+
ok: true,
|
82
83
|
json: vi.fn().mockResolvedValue({
|
83
84
|
cloud: [{ id: 'cloud1', date: '2023-01-01', versionRange: ['1.0.0'] }],
|
84
85
|
community: [{ id: 'community1', date: '2023-01-02', versionRange: ['1.1.0'] }],
|
@@ -104,6 +105,7 @@ describe('ChangelogService', () => {
|
|
104
105
|
it('should return only community items when config type is community', async () => {
|
105
106
|
service.config.type = 'community';
|
106
107
|
const mockResponse = {
|
108
|
+
ok: true,
|
107
109
|
json: vi.fn().mockResolvedValue({
|
108
110
|
cloud: [{ id: 'cloud1', date: '2023-01-01', versionRange: ['1.0.0'] }],
|
109
111
|
community: [{ id: 'community1', date: '2023-01-02', versionRange: ['1.1.0'] }],
|
@@ -55,9 +55,13 @@ export class ChangelogService {
|
|
55
55
|
next: { revalidate: 3600, tags: [FetchCacheTag.Changelog] },
|
56
56
|
});
|
57
57
|
|
58
|
-
|
58
|
+
if (res.ok) {
|
59
|
+
const data = await res.json();
|
60
|
+
|
61
|
+
return this.mergeChangelogs(data.cloud, data.community).slice(0, 5);
|
62
|
+
}
|
59
63
|
|
60
|
-
return
|
64
|
+
return [];
|
61
65
|
} catch (e) {
|
62
66
|
const cause = (e as Error).cause as { code: string };
|
63
67
|
if (cause?.code.includes('ETIMEDOUT')) {
|
@@ -65,6 +65,7 @@ beforeEach(() => {
|
|
65
65
|
vi.mock('@/const/version', () => ({
|
66
66
|
isServerMode: false,
|
67
67
|
isDeprecatedEdition: true,
|
68
|
+
isDesktop: false,
|
68
69
|
}));
|
69
70
|
});
|
70
71
|
|
@@ -878,6 +879,7 @@ describe('ChatService', () => {
|
|
878
879
|
vi.doMock('@/const/version', () => ({
|
879
880
|
isServerMode: true,
|
880
881
|
isDeprecatedEdition: false,
|
882
|
+
isDesktop: false,
|
881
883
|
}));
|
882
884
|
|
883
885
|
// 需要在修改模拟后重新导入相关模块
|
@@ -965,6 +967,7 @@ describe('ChatService', () => {
|
|
965
967
|
vi.doMock('@/const/version', () => ({
|
966
968
|
isServerMode: true,
|
967
969
|
isDeprecatedEdition: true,
|
970
|
+
isDesktop: false,
|
968
971
|
}));
|
969
972
|
|
970
973
|
// 需要在修改模拟后重新导入相关模块
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { isProviderDisableBrowserRequest } from '@/config/modelProviders';
|
2
|
+
import { isDesktop } from '@/const/version';
|
2
3
|
import { UserStore } from '@/store/user';
|
3
4
|
import { GlobalLLMProviderKey } from '@/types/user/settings';
|
4
5
|
|
@@ -19,6 +20,9 @@ const providerWhitelist = new Set(['ollama']);
|
|
19
20
|
const isProviderFetchOnClient = (provider: GlobalLLMProviderKey | string) => (s: UserStore) => {
|
20
21
|
const config = getProviderConfigById(provider)(s);
|
21
22
|
|
23
|
+
// if is desktop, force on Server.
|
24
|
+
if (isDesktop) return false;
|
25
|
+
|
22
26
|
// If the provider already disable browser request in model config, force on Server.
|
23
27
|
if (isProviderDisableBrowserRequest(provider)) return false;
|
24
28
|
|
package/src/styles/global.ts
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
import { Theme, css } from 'antd-style';
|
2
|
+
import { rgba } from 'polished';
|
3
|
+
|
4
|
+
import { isDesktop } from '@/const/version';
|
2
5
|
|
3
6
|
// fix ios input keyboard
|
4
7
|
// overflow: hidden;
|
@@ -22,6 +25,17 @@ export default ({ token }: { prefixCls: string; token: Theme }) => css`
|
|
22
25
|
}
|
23
26
|
}
|
24
27
|
|
28
|
+
html {
|
29
|
+
background: ${isDesktop ? 'none' : token.colorBgLayout};
|
30
|
+
}
|
31
|
+
|
32
|
+
body {
|
33
|
+
/* 提高合成层级,强制硬件加速,否则会有渲染黑边出现 */
|
34
|
+
will-change: opacity;
|
35
|
+
transform: translateZ(0);
|
36
|
+
background: ${isDesktop ? rgba(token.colorBgLayout, 0.66) : token.colorBgLayout};
|
37
|
+
}
|
38
|
+
|
25
39
|
* {
|
26
40
|
scrollbar-color: ${token.colorFill} transparent;
|
27
41
|
scrollbar-width: thin;
|
package/src/types/hotkey.ts
CHANGED
@@ -10,6 +10,7 @@ export const HotkeyEnum = {
|
|
10
10
|
EditMessage: 'editMessage',
|
11
11
|
OpenChatSettings: 'openChatSettings',
|
12
12
|
OpenHotkeyHelper: 'openHotkeyHelper',
|
13
|
+
OpenSettings: 'openSettings',
|
13
14
|
RegenerateMessage: 'regenerateMessage',
|
14
15
|
SaveTopic: 'saveTopic',
|
15
16
|
Search: 'search',
|
@@ -40,6 +40,8 @@ const getStatus = (errorType: ILobeAgentRuntimeErrorType | ErrorType) => {
|
|
40
40
|
return 471;
|
41
41
|
}
|
42
42
|
|
43
|
+
// all local provider connection error
|
44
|
+
case AgentRuntimeErrorType.OllamaServiceUnavailable:
|
43
45
|
case ChatErrorType.OllamaServiceUnavailable:
|
44
46
|
case AgentRuntimeErrorType.OllamaBizError: {
|
45
47
|
return 472;
|
package/tsconfig.json
CHANGED
package/src/types/electron.ts
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
import { DispatchInvoke } from '@lobechat/electron-client-ipc';
|
2
|
-
|
3
|
-
/**
|
4
|
-
* client 端请求 sketch 端 event 数据的方法
|
5
|
-
*/
|
6
|
-
export const dispatch: DispatchInvoke = async (event, ...data) => {
|
7
|
-
if (!window.electronAPI) throw new Error('electronAPI not found');
|
8
|
-
|
9
|
-
return window.electronAPI.invoke(event, ...data);
|
10
|
-
};
|