@lobehub/chat 1.82.0 → 1.82.2

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 (102) hide show
  1. package/.cursor/rules/desktop-local-tools-implement.mdc +80 -0
  2. package/.env.desktop +2 -1
  3. package/.github/scripts/pr-comment.js +4 -9
  4. package/CHANGELOG.md +51 -0
  5. package/changelog/v1.json +18 -0
  6. package/locales/ar/electron.json +38 -2
  7. package/locales/ar/plugin.json +51 -31
  8. package/locales/bg-BG/electron.json +38 -2
  9. package/locales/bg-BG/plugin.json +51 -31
  10. package/locales/de-DE/electron.json +38 -2
  11. package/locales/de-DE/plugin.json +29 -9
  12. package/locales/en-US/electron.json +38 -2
  13. package/locales/en-US/plugin.json +29 -9
  14. package/locales/es-ES/electron.json +38 -2
  15. package/locales/es-ES/plugin.json +51 -31
  16. package/locales/fa-IR/electron.json +38 -2
  17. package/locales/fa-IR/plugin.json +51 -31
  18. package/locales/fr-FR/electron.json +38 -2
  19. package/locales/fr-FR/plugin.json +51 -31
  20. package/locales/it-IT/electron.json +38 -2
  21. package/locales/it-IT/plugin.json +51 -31
  22. package/locales/ja-JP/electron.json +38 -2
  23. package/locales/ja-JP/plugin.json +51 -31
  24. package/locales/ko-KR/electron.json +38 -2
  25. package/locales/ko-KR/plugin.json +29 -9
  26. package/locales/nl-NL/electron.json +38 -2
  27. package/locales/nl-NL/plugin.json +51 -31
  28. package/locales/pl-PL/electron.json +38 -2
  29. package/locales/pl-PL/plugin.json +29 -9
  30. package/locales/pt-BR/electron.json +38 -2
  31. package/locales/pt-BR/plugin.json +51 -31
  32. package/locales/ru-RU/electron.json +38 -2
  33. package/locales/ru-RU/plugin.json +51 -31
  34. package/locales/tr-TR/electron.json +38 -2
  35. package/locales/tr-TR/plugin.json +51 -31
  36. package/locales/vi-VN/electron.json +38 -2
  37. package/locales/vi-VN/plugin.json +29 -9
  38. package/locales/zh-CN/electron.json +38 -2
  39. package/locales/zh-CN/plugin.json +30 -10
  40. package/locales/zh-TW/electron.json +38 -2
  41. package/locales/zh-TW/plugin.json +51 -31
  42. package/package.json +1 -1
  43. package/packages/electron-client-ipc/src/events/update.ts +3 -3
  44. package/src/app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/Mode.tsx +222 -0
  45. package/src/app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/Option.tsx +104 -0
  46. package/src/app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/Sync.tsx +42 -0
  47. package/src/app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/Waiting.tsx +203 -0
  48. package/src/app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/Connection/index.tsx +57 -0
  49. package/src/app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/UpdateModal.tsx +242 -0
  50. package/src/app/[variants]/(main)/_layout/Desktop/ElectronTitlebar/UpdateNotification.tsx +193 -0
  51. package/src/app/[variants]/(main)/_layout/Desktop/{Titlebar.tsx → ElectronTitlebar/index.tsx} +15 -1
  52. package/src/app/[variants]/(main)/_layout/Desktop/SideBar/BottomActions.tsx +3 -2
  53. package/src/app/[variants]/(main)/_layout/Desktop/index.tsx +1 -1
  54. package/src/app/[variants]/layout.tsx +2 -1
  55. package/src/config/aiModels/openrouter.ts +6 -6
  56. package/src/features/Conversation/components/MarkdownElements/LocalFile/Render/LocalFile.tsx +65 -0
  57. package/src/features/Conversation/components/MarkdownElements/LocalFile/Render/index.tsx +29 -0
  58. package/src/features/Conversation/components/MarkdownElements/LocalFile/index.ts +16 -0
  59. package/src/features/Conversation/components/MarkdownElements/index.ts +7 -1
  60. package/src/features/Conversation/components/MarkdownElements/remarkPlugins/__snapshots__/createRemarkSelfClosingTagPlugin.test.ts.snap +260 -0
  61. package/src/features/Conversation/components/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.test.ts +204 -0
  62. package/src/features/Conversation/components/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts +133 -0
  63. package/src/features/Conversation/components/MarkdownElements/type.ts +5 -1
  64. package/src/features/PluginDevModal/MCPManifestForm/ArgsInput.tsx +20 -0
  65. package/src/features/PluginDevModal/MCPManifestForm/MCPTypeSelect.tsx +176 -0
  66. package/src/features/PluginDevModal/MCPManifestForm/index.tsx +289 -0
  67. package/src/features/PluginDevModal/MCPManifestForm/utils.test.ts +262 -0
  68. package/src/features/PluginDevModal/MCPManifestForm/utils.ts +151 -0
  69. package/src/features/PluginDevModal/index.tsx +31 -22
  70. package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.ts +1 -1
  71. package/src/libs/mcp/__tests__/__snapshots__/index.test.ts.snap +0 -56
  72. package/src/locales/default/electron.ts +38 -2
  73. package/src/locales/default/plugin.ts +28 -8
  74. package/src/server/modules/ElectronIPCClient/index.ts +36 -0
  75. package/src/server/routers/lambda/session.ts +2 -6
  76. package/src/server/routers/tools/mcp.ts +6 -0
  77. package/src/server/services/file/impls/index.ts +9 -1
  78. package/src/server/services/file/impls/local.test.ts +299 -0
  79. package/src/server/services/file/impls/local.ts +183 -0
  80. package/src/server/services/mcp/index.ts +26 -0
  81. package/src/services/aiModel/index.ts +5 -1
  82. package/src/services/aiProvider/index.ts +5 -1
  83. package/src/services/electron/autoUpdate.ts +4 -0
  84. package/src/services/file/index.ts +5 -1
  85. package/src/services/mcp.ts +13 -2
  86. package/src/services/message/index.ts +5 -1
  87. package/src/services/plugin/index.ts +5 -1
  88. package/src/services/session/index.ts +5 -1
  89. package/src/services/tableViewer/desktop.ts +15 -0
  90. package/src/services/tableViewer/index.ts +4 -1
  91. package/src/services/thread/index.ts +5 -1
  92. package/src/services/topic/index.ts +5 -1
  93. package/src/services/user/index.ts +5 -1
  94. package/src/store/electron/actions/app.ts +59 -0
  95. package/src/store/electron/actions/sync.ts +5 -1
  96. package/src/store/electron/initialState.ts +3 -1
  97. package/src/store/electron/store.ts +6 -1
  98. package/src/store/tool/slices/customPlugin/action.ts +16 -4
  99. package/src/utils/client/GlobalAgentContextManager.ts +85 -0
  100. package/src/utils/promptTemplate.test.ts +78 -0
  101. package/src/utils/promptTemplate.ts +17 -0
  102. package/src/features/PluginDevModal/MCPManifestForm.tsx +0 -164
@@ -36,10 +36,14 @@ const DevModal = memo<DevModalProps>(
36
36
  form.setFieldsValue(value);
37
37
  }, []);
38
38
 
39
+ useEffect(() => {
40
+ if (mode === 'create' && !open) form.resetFields();
41
+ }, [open]);
42
+
39
43
  const buttonStyle = mobile ? { flex: 1 } : { margin: 0 };
40
44
 
41
45
  const footer = (
42
- <Flexbox flex={1} gap={12} horizontal justify={'flex-end'}>
46
+ <Flexbox flex={1} gap={12} horizontal justify={'space-between'}>
43
47
  {isEditMode ? (
44
48
  <Popconfirm
45
49
  arrow={false}
@@ -60,25 +64,29 @@ const DevModal = memo<DevModalProps>(
60
64
  {t('delete', { ns: 'common' })}
61
65
  </Button>
62
66
  </Popconfirm>
63
- ) : null}
64
- <Button
65
- onClick={() => {
66
- onOpenChange(false);
67
- }}
68
- style={buttonStyle}
69
- >
70
- {t('cancel', { ns: 'common' })}
71
- </Button>
72
- <Button
73
- loading={submitting}
74
- onClick={() => {
75
- form.submit();
76
- }}
77
- style={buttonStyle}
78
- type={'primary'}
79
- >
80
- {t(isEditMode ? 'dev.update' : 'dev.save')}
81
- </Button>
67
+ ) : (
68
+ <div />
69
+ )}
70
+ <Flexbox gap={12} horizontal>
71
+ <Button
72
+ onClick={() => {
73
+ onOpenChange(false);
74
+ }}
75
+ style={buttonStyle}
76
+ >
77
+ {t('cancel', { ns: 'common' })}
78
+ </Button>
79
+ <Button
80
+ loading={submitting}
81
+ onClick={() => {
82
+ form.submit();
83
+ }}
84
+ style={buttonStyle}
85
+ type={'primary'}
86
+ >
87
+ {t(isEditMode ? 'dev.update' : 'dev.save')}
88
+ </Button>
89
+ </Flexbox>
82
90
  </Flexbox>
83
91
  );
84
92
 
@@ -100,6 +108,7 @@ const DevModal = memo<DevModalProps>(
100
108
  >
101
109
  <Modal
102
110
  allowFullscreen
111
+ destroyOnClose
103
112
  footer={footer}
104
113
  okText={t('dev.save')}
105
114
  onCancel={(e) => {
@@ -166,10 +175,10 @@ const DevModal = memo<DevModalProps>(
166
175
  showIcon
167
176
  type={'info'}
168
177
  />
169
- <UrlManifestForm form={form} isEditMode={mode === 'edit'} />
178
+ <UrlManifestForm form={form} isEditMode={isEditMode} />
170
179
  </>
171
180
  )}
172
- {configMode === 'mcp' && <MCPManifestForm form={form} />}
181
+ {configMode === 'mcp' && <MCPManifestForm form={form} isEditMode={isEditMode} />}
173
182
  <PluginPreview form={form} />
174
183
  </Flexbox>
175
184
  </Modal>
@@ -354,7 +354,7 @@ export const LobeOpenAICompatibleFactory = <T extends Record<string, any> = any>
354
354
  async textToImage(payload: TextToImagePayload) {
355
355
  try {
356
356
  const res = await this.client.images.generate(payload);
357
- return res.data.map((o) => o.url) as string[];
357
+ return (res.data || []).map((o) => o.url) as string[];
358
358
  } catch (error) {
359
359
  throw this.handleError(error);
360
360
  }
@@ -1,61 +1,5 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`MCPClient > Stdio Transport (using SDK Mock Server) > should list tools via stdio 1`] = `
4
- [
5
- {
6
- "description": "Echoes back a message with 'Hello' prefix",
7
- "inputSchema": {
8
- "$schema": "http://json-schema.org/draft-07/schema#",
9
- "additionalProperties": false,
10
- "properties": {
11
- "message": {
12
- "description": "The message to echo",
13
- "type": "string",
14
- },
15
- },
16
- "required": [
17
- "message",
18
- ],
19
- "type": "object",
20
- },
21
- "name": "echo",
22
- },
23
- {
24
- "description": "Lists all available tools and methods",
25
- "inputSchema": {
26
- "$schema": "http://json-schema.org/draft-07/schema#",
27
- "additionalProperties": false,
28
- "properties": {},
29
- "type": "object",
30
- },
31
- "name": "debug",
32
- },
33
- {
34
- "description": "Adds two numbers",
35
- "inputSchema": {
36
- "$schema": "http://json-schema.org/draft-07/schema#",
37
- "additionalProperties": false,
38
- "properties": {
39
- "a": {
40
- "description": "The first number",
41
- "type": "number",
42
- },
43
- "b": {
44
- "description": "The second number",
45
- "type": "number",
46
- },
47
- },
48
- "required": [
49
- "a",
50
- "b",
51
- ],
52
- "type": "object",
53
- },
54
- "name": "add",
55
- },
56
- ]
57
- `;
58
-
59
3
  exports[`MCPClient > Stdio Transport > should list tools via stdio 1`] = `
60
4
  [
61
5
  {
@@ -17,18 +17,54 @@ const electron = {
17
17
  statusDisconnected: '未连接',
18
18
  urlRequired: '请输入服务器地址',
19
19
  },
20
+ sync: {
21
+ continue: '继续',
22
+ inCloud: '当前使用云端同步',
23
+ inLocalStorage: '当前使用本地存储',
24
+ isIniting: '正在初始化...',
25
+ lobehubCloud: {
26
+ description: '官方提供的云版本',
27
+ title: 'LobeHub Cloud',
28
+ },
29
+ local: {
30
+ description: '使用本地数据库,完全离线可用',
31
+ title: '本地数据库',
32
+ },
33
+ mode: {
34
+ cloudSync: '云端同步',
35
+ localStorage: '本地存储',
36
+ title: '选择你的连接模式',
37
+ useSelfHosted: '使用自托管实例?',
38
+ },
39
+ selfHosted: {
40
+ description: '自行部署的社区版本',
41
+ title: '自托管实例',
42
+ },
43
+ },
20
44
  updater: {
45
+ checkingUpdate: '检查新版本',
46
+ checkingUpdateDesc: '正在获取版本信息...',
47
+ downloadNewVersion: '下载新版本',
21
48
  downloadingUpdate: '正在下载更新',
22
49
  downloadingUpdateDesc: '更新正在下载中,请稍候...',
50
+ installLater: '下次启动时更新',
51
+ isLatestVersion: '当前已是最新版本',
52
+ isLatestVersionDesc: '非常棒,使用的版本 {{version}} 已是最前沿的版本。',
23
53
  later: '稍后更新',
24
54
  newVersionAvailable: '新版本可用',
25
55
  newVersionAvailableDesc: '发现新版本 {{version}},是否立即下载?',
26
- restartAndInstall: '重启并安装',
56
+ restartAndInstall: '安装更新并重启',
27
57
  updateError: '更新错误',
28
58
  updateReady: '更新已就绪',
29
- updateReadyDesc: 'Lobe Chat {{version}} 已下载完成,重启应用后即可完成安装。',
59
+ updateReadyDesc: '新版本 {{version}} 已下载完成,重启应用后即可完成安装。',
30
60
  upgradeNow: '立即更新',
31
61
  },
62
+ waitingOAuth: {
63
+ cancel: '取消',
64
+ description: '浏览器已打开授权页面,请在浏览器中完成授权',
65
+ helpText: '如果浏览器没有自动打开,请点击取消后重新尝试',
66
+ title: '等待授权连接',
67
+ },
32
68
  };
33
69
 
34
70
  export default electron;
@@ -7,6 +7,7 @@ export default {
7
7
  payload: '插件载荷',
8
8
  pluginState: '插件 State',
9
9
  response: '返回结果',
10
+ title: '插件详情',
10
11
  tool_call: '工具调用请求',
11
12
  },
12
13
  detailModal: {
@@ -47,15 +48,16 @@ export default {
47
48
  },
48
49
  mcp: {
49
50
  args: {
50
- desc: '传递给 STDIO 命令的参数列表',
51
+ desc: '传递给 STDIO 命令的参数列表,一般在这里输入 MCP 服务器名称',
51
52
  label: '命令参数',
52
- placeholder: '例如:--port 8080 --debug',
53
- tooltip: '输入参数后按回车或使用逗号/空格分隔',
53
+ placeholder: '例如:mcp-hello-world',
54
+ required: '请输入启动参数',
54
55
  },
55
56
  command: {
56
- desc: '用于启动 MCP STDIO 插件的可执行文件或脚本',
57
+ desc: '用于启动 MCP STDIO Server 的可执行文件或脚本',
57
58
  label: '命令',
58
- placeholder: '例如:python main.py /path/to/executable',
59
+ placeholder: '例如:npx / uv / docker 等',
60
+ required: '请输入启动命令',
59
61
  },
60
62
  endpoint: {
61
63
  desc: '输入你的 MCP Streamable HTTP Server 的地址',
@@ -63,17 +65,31 @@ export default {
63
65
  },
64
66
  identifier: {
65
67
  desc: '为你的 MCP 插件指定一个名称,需要使用英文字符',
66
- invalid: '只能输入英文字符、数字 、- 和_ 这两个符号',
68
+ invalid: '标识符只能包含字母、数字、连字符和下划线',
67
69
  label: 'MCP 插件名称',
68
70
  placeholder: '例如:my-mcp-plugin',
71
+ required: '请输入 MCP 服务标识符',
69
72
  },
73
+ previewManifest: '预览插件描述文件',
74
+ testConnection: '测试连接',
75
+ testConnectionTip: '测试连接成功后 MCP 插件才可以被正常使用',
70
76
  type: {
71
77
  desc: '选择 MCP 插件的通信方式,网页版只支持 Streamable HTTP',
78
+ httpFeature1: '兼容网页版与桌面端',
79
+ httpFeature2: '连接远程 MCP 服务器, 无需额外安装配置',
80
+ httpShortDesc: '基于流式 HTTP 的通信协议',
72
81
  label: 'MCP 插件类型',
82
+ stdioFeature1: '更低的通信延迟, 适合本地执行',
83
+ stdioFeature2: '需在本地安装运行 MCP 服务器',
84
+ stdioNotAvailable: 'STDIO 模式仅在桌面版可用',
85
+ stdioShortDesc: '基于标准输入输出的通信协议',
86
+ title: 'MCP 插件类型',
73
87
  },
74
88
  url: {
75
- desc: '输入你的 MCP HTTP 插件的 Endpoint 地址',
76
- label: 'HTTP Endpoint URL',
89
+ desc: '输入你的 MCP Server Streamable HTTP 地址,不会以 /sse 结尾',
90
+ invalid: '请输入有效的 URL 地址',
91
+ label: 'Streamable HTTP Endpoint URL',
92
+ required: '请输入 MCP 服务 URL',
77
93
  },
78
94
  },
79
95
  meta: {
@@ -101,12 +117,14 @@ export default {
101
117
  label: '标识符',
102
118
  pattenErrorMessage: '只能输入英文字符、数字 、- 和_ 这两个符号',
103
119
  },
120
+ lobe: '{{appName}} 插件',
104
121
  manifest: {
105
122
  desc: '{{appName}}将会通过该链接安装插件',
106
123
  label: '插件描述文件 (Manifest) URL',
107
124
  preview: '预览 Manifest',
108
125
  refresh: '刷新',
109
126
  },
127
+ openai: 'OpenAI 插件',
110
128
  title: {
111
129
  desc: '插件标题',
112
130
  label: '标题',
@@ -149,6 +167,7 @@ export default {
149
167
  noManifest: '描述文件不存在',
150
168
  openAPIInvalid: 'OpenAPI 解析失败,错误: \n\n {{error}}',
151
169
  reinstallError: '插件 {{name}} 刷新失败',
170
+ testConnectionFailed: '获取 Manifest 失败: {{error}}',
152
171
  urlError: '该链接没有返回 JSON 格式的内容, 请确保是有效的链接',
153
172
  },
154
173
  inspector: {
@@ -227,5 +246,6 @@ export default {
227
246
  },
228
247
  title: '插件商店',
229
248
  },
249
+ unknownError: '未知错误',
230
250
  unknownPlugin: '未知插件',
231
251
  };
@@ -0,0 +1,36 @@
1
+ import { ElectronIpcClient } from '@lobechat/electron-server-ipc';
2
+
3
+ class LobeHubElectronIpcClient extends ElectronIpcClient {
4
+ // 获取数据库路径
5
+ getDatabasePath = async (): Promise<string> => {
6
+ return this.sendRequest<string>('getDatabasePath');
7
+ };
8
+
9
+ // 获取用户数据路径
10
+ getUserDataPath = async (): Promise<string> => {
11
+ return this.sendRequest<string>('getUserDataPath');
12
+ };
13
+
14
+ getDatabaseSchemaHash = async () => {
15
+ return this.sendRequest<string>('setDatabaseSchemaHash');
16
+ };
17
+
18
+ setDatabaseSchemaHash = async (hash: string | undefined) => {
19
+ if (!hash) return;
20
+
21
+ return this.sendRequest('setDatabaseSchemaHash', hash);
22
+ };
23
+
24
+ getFilePathById = async (id: string) => {
25
+ return this.sendRequest<string>('getStaticFilePath', id);
26
+ };
27
+
28
+ deleteFiles = async (paths: string[]) => {
29
+ return this.sendRequest<{ errors?: { message: string; path: string }[]; success: boolean }>(
30
+ 'deleteFiles',
31
+ paths,
32
+ );
33
+ };
34
+ }
35
+
36
+ export const electronIpcClient = new LobeHubElectronIpcClient();
@@ -97,14 +97,10 @@ export const sessionRouter = router({
97
97
  }),
98
98
 
99
99
  getGroupedSessions: publicProcedure.query(async ({ ctx }): Promise<ChatSessionList> => {
100
- if (!ctx.userId)
101
- return {
102
- sessionGroups: [],
103
- sessions: [],
104
- };
100
+ if (!ctx.userId) return { sessionGroups: [], sessions: [] };
105
101
 
106
102
  const serverDB = await getServerDB();
107
- const sessionModel = new SessionModel(serverDB, ctx.userId);
103
+ const sessionModel = new SessionModel(serverDB, ctx.userId!);
108
104
 
109
105
  return sessionModel.queryWithGroups();
110
106
  }),
@@ -35,6 +35,12 @@ const checkStdioEnvironment = (params: z.infer<typeof mcpClientParamsSchema>) =>
35
35
  const mcpProcedure = isServerMode ? authedProcedure : passwordProcedure;
36
36
 
37
37
  export const mcpRouter = router({
38
+ getStdioMcpServerManifest: mcpProcedure.input(stdioParamsSchema).query(async ({ input }) => {
39
+ // Stdio check can be done here or rely on the service/client layer
40
+ checkStdioEnvironment(input);
41
+
42
+ return await mcpService.getStdioMcpServerManifest(input.name, input.command, input.args);
43
+ }),
38
44
  getStreamableMcpServerManifest: mcpProcedure
39
45
  .input(
40
46
  z.object({
@@ -1,11 +1,19 @@
1
+ import { isDesktop } from '@/const/version';
2
+
3
+ import { DesktopLocalFileImpl } from './local';
1
4
  import { S3StaticFileImpl } from './s3';
2
5
  import { FileServiceImpl } from './type';
3
6
 
4
7
  /**
5
8
  * 创建文件服务模块
9
+ * 根据环境自动选择使用S3或桌面本地文件实现
6
10
  */
7
11
  export const createFileServiceModule = (): FileServiceImpl => {
8
- // 默认使用 S3 实现
12
+ // 如果在桌面应用环境,使用本地文件实现
13
+ if (isDesktop) {
14
+ return new DesktopLocalFileImpl();
15
+ }
16
+
9
17
  return new S3StaticFileImpl();
10
18
  };
11
19