@lobehub/chat 1.136.6 → 1.136.7

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.
@@ -36,7 +36,7 @@ jobs:
36
36
  - name: Install bun
37
37
  uses: oven-sh/setup-bun@v2
38
38
  with:
39
- bun-version: ${{ secrets.BUN_VERSION }}
39
+ bun-version: 1.2.23
40
40
 
41
41
  - name: Install deps
42
42
  run: bun i
@@ -188,7 +188,7 @@ jobs:
188
188
  else
189
189
  ARCH_SUFFIX="x64"
190
190
  fi
191
-
191
+
192
192
  mv latest-mac.yml "latest-mac-${ARCH_SUFFIX}.yml"
193
193
  echo "✅ Renamed latest-mac.yml to latest-mac-${ARCH_SUFFIX}.yml (detected: $SYSTEM_ARCH)"
194
194
  ls -la latest-mac-*.yml
@@ -234,7 +234,7 @@ jobs:
234
234
  - name: Install bun
235
235
  uses: oven-sh/setup-bun@v2
236
236
  with:
237
- bun-version: ${{ secrets.BUN_VERSION }}
237
+ bun-version: 1.2.23
238
238
 
239
239
  # 下载所有平台的构建产物
240
240
  - name: Download artifacts
@@ -32,7 +32,7 @@ jobs:
32
32
  - name: Install bun
33
33
  uses: oven-sh/setup-bun@v2
34
34
  with:
35
- bun-version: ${{ secrets.BUN_VERSION }}
35
+ bun-version: 1.2.23
36
36
 
37
37
  - name: Install deps
38
38
  run: bun i
@@ -170,7 +170,7 @@ jobs:
170
170
  else
171
171
  ARCH_SUFFIX="x64"
172
172
  fi
173
-
173
+
174
174
  mv latest-mac.yml "latest-mac-${ARCH_SUFFIX}.yml"
175
175
  echo "✅ Renamed latest-mac.yml to latest-mac-${ARCH_SUFFIX}.yml (detected: $SYSTEM_ARCH)"
176
176
  ls -la latest-mac-*.yml
@@ -216,7 +216,7 @@ jobs:
216
216
  - name: Install bun
217
217
  uses: oven-sh/setup-bun@v2
218
218
  with:
219
- bun-version: ${{ secrets.BUN_VERSION }}
219
+ bun-version: 1.2.23
220
220
 
221
221
  # 下载所有平台的构建产物
222
222
  - name: Download artifacts
@@ -41,7 +41,7 @@ jobs:
41
41
  - name: Install bun
42
42
  uses: oven-sh/setup-bun@v2
43
43
  with:
44
- bun-version: ${{ secrets.BUN_VERSION }}
44
+ bun-version: 1.2.23
45
45
 
46
46
  - name: Install deps
47
47
  run: bun i
@@ -71,7 +71,7 @@ jobs:
71
71
  - name: Install bun
72
72
  uses: oven-sh/setup-bun@v2
73
73
  with:
74
- bun-version: ${{ secrets.BUN_VERSION }}
74
+ bun-version: 1.2.23
75
75
 
76
76
  - name: Install deps
77
77
  run: bun i
@@ -104,7 +104,7 @@ jobs:
104
104
  - name: Install bun
105
105
  uses: oven-sh/setup-bun@v2
106
106
  with:
107
- bun-version: ${{ secrets.BUN_VERSION }}
107
+ bun-version: 1.2.23
108
108
 
109
109
  - name: Install deps
110
110
  run: bun i
@@ -148,7 +148,7 @@ jobs:
148
148
  - name: Install bun
149
149
  uses: oven-sh/setup-bun@v2
150
150
  with:
151
- bun-version: ${{ secrets.BUN_VERSION }}
151
+ bun-version: 1.2.23
152
152
 
153
153
  - name: Install deps
154
154
  run: bun i
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.136.7](https://github.com/lobehub/lobe-chat/compare/v1.136.6...v1.136.7)
6
+
7
+ <sup>Released on **2025-10-11**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Disable rich text in markdown editor.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Disable rich text in markdown editor, closes [#9637](https://github.com/lobehub/lobe-chat/issues/9637) ([9349ce2](https://github.com/lobehub/lobe-chat/commit/9349ce2))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ### [Version 1.136.6](https://github.com/lobehub/lobe-chat/compare/v1.136.5...v1.136.6)
6
31
 
7
32
  <sup>Released on **2025-10-11**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "fixes": [
5
+ "Disable rich text in markdown editor."
6
+ ]
7
+ },
8
+ "date": "2025-10-11",
9
+ "version": "1.136.7"
10
+ },
2
11
  {
3
12
  "children": {},
4
13
  "date": "2025-10-11",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.136.6",
3
+ "version": "1.136.7",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -1,6 +1,8 @@
1
1
  import { TopicDisplayMode, UserPreference } from '@lobechat/types';
2
2
 
3
3
  export const DEFAULT_PREFERENCE: UserPreference = {
4
+ disableInputMarkdownRender: false,
5
+ enableGroupChat: false,
4
6
  guide: {
5
7
  moveSettingsToAvatar: true,
6
8
  topic: true,
@@ -35,6 +35,14 @@ export const UserGuideSchema = z.object({
35
35
  export type UserGuide = z.infer<typeof UserGuideSchema>;
36
36
 
37
37
  export interface UserPreference {
38
+ /**
39
+ * disable markdown rendering in chat input editor
40
+ */
41
+ disableInputMarkdownRender?: boolean;
42
+ /**
43
+ * enable multi-agent group chat mode
44
+ */
45
+ enableGroupChat?: boolean;
38
46
  guide?: UserGuide;
39
47
  hideSyncAlert?: boolean;
40
48
  telemetry: boolean | null;
@@ -1,11 +1,10 @@
1
1
  import { ActionIcon, ActionIconProps } from '@lobehub/ui';
2
- import { Book, Github } from 'lucide-react';
2
+ import { Github } from 'lucide-react';
3
3
  import Link from 'next/link';
4
4
  import { memo } from 'react';
5
- import { useTranslation } from 'react-i18next';
6
5
  import { Flexbox } from 'react-layout-kit';
7
6
 
8
- import { DOCUMENTS_REFER_URL, GITHUB } from '@/const/url';
7
+ import { GITHUB } from '@/const/url';
9
8
  import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
10
9
 
11
10
  const ICON_SIZE: ActionIconProps['size'] = {
@@ -15,8 +14,8 @@ const ICON_SIZE: ActionIconProps['size'] = {
15
14
  };
16
15
 
17
16
  const BottomActions = memo(() => {
18
- const { t } = useTranslation('common');
19
- const { hideGitHub, hideDocs } = useServerConfigStore(featureFlagsSelectors);
17
+ // const { t } = useTranslation('common');
18
+ const { hideGitHub } = useServerConfigStore(featureFlagsSelectors);
20
19
 
21
20
  return (
22
21
  <Flexbox gap={8}>
@@ -30,16 +29,14 @@ const BottomActions = memo(() => {
30
29
  />
31
30
  </Link>
32
31
  )}
33
- {!hideDocs && (
34
- <Link aria-label={t('document')} href={DOCUMENTS_REFER_URL} target={'_blank'}>
35
- <ActionIcon
36
- icon={Book}
37
- size={ICON_SIZE}
38
- title={t('document')}
39
- tooltipProps={{ placement: 'right' }}
40
- />
41
- </Link>
42
- )}
32
+ {/*<Link aria-label={t('labs')} href={'/labs'}>*/}
33
+ {/* <ActionIcon*/}
34
+ {/* icon={FlaskConical}*/}
35
+ {/* size={ICON_SIZE}*/}
36
+ {/* title={t('labs')}*/}
37
+ {/* tooltipProps={{ placement: 'right' }}*/}
38
+ {/* />*/}
39
+ {/*</Link>*/}
43
40
  </Flexbox>
44
41
  );
45
42
  });
@@ -0,0 +1,43 @@
1
+ 'use client';
2
+
3
+ import { createStyles } from 'antd-style';
4
+ import { memo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { Flexbox } from 'react-layout-kit';
7
+
8
+ const useStyles = createStyles(({ css, token }) => ({
9
+ container: css`
10
+ width: 100%;
11
+ max-width: 800px;
12
+ margin-block: 0;
13
+ margin-inline: auto;
14
+ padding-block: 24px 8px;
15
+ padding-inline: 16px;
16
+ `,
17
+ desc: css`
18
+ color: ${token.colorTextSecondary};
19
+ `,
20
+ title: css`
21
+ font-size: 22px;
22
+ font-weight: 600;
23
+ color: ${token.colorText};
24
+ `,
25
+ }));
26
+
27
+ const Hero = memo(() => {
28
+ const { styles } = useStyles();
29
+ const { t } = useTranslation('labs');
30
+
31
+ return (
32
+ <div className={styles.container}>
33
+ <Flexbox gap={8}>
34
+ <div className={styles.title}>🪄 {t('title')}</div>
35
+ <div className={styles.desc}>{t('desc')}</div>
36
+ </Flexbox>
37
+ </div>
38
+ );
39
+ });
40
+
41
+ Hero.displayName = 'LabsHero';
42
+
43
+ export default Hero;
@@ -0,0 +1,85 @@
1
+ 'use client';
2
+
3
+ import { Switch } from 'antd';
4
+ import { createStyles } from 'antd-style';
5
+ import { PropsWithChildren, memo } from 'react';
6
+ import { Flexbox } from 'react-layout-kit';
7
+
8
+ interface LabCardProps {
9
+ checked: boolean;
10
+ desc: string;
11
+ loading: boolean;
12
+ meta?: string;
13
+ onChange: (v: boolean) => void;
14
+ title: string;
15
+ }
16
+
17
+ const useStyles = createStyles(({ css, token }) => ({
18
+ card: css`
19
+ width: 100%;
20
+ max-width: 800px;
21
+ margin-block: 0;
22
+ margin-inline: auto;
23
+ padding: 16px;
24
+ border: 1px solid ${token.colorBorderSecondary};
25
+ border-radius: 12px;
26
+
27
+ background: ${token.colorBgContainer};
28
+ `,
29
+ desc: css`
30
+ color: ${token.colorTextSecondary};
31
+ `,
32
+ meta: css`
33
+ font-size: 12px;
34
+ color: ${token.colorTextTertiary};
35
+ `,
36
+ row: css`
37
+ display: grid;
38
+ grid-template-columns: 240px 1fr 80px;
39
+ gap: 16px;
40
+ align-items: center;
41
+ `,
42
+ thumb: css`
43
+ height: 128px;
44
+ border-radius: ${token.borderRadiusLG}px;
45
+ background: linear-gradient(135deg, ${token.colorFillTertiary}, ${token.colorFillQuaternary});
46
+ `,
47
+ title: css`
48
+ font-size: 16px;
49
+ font-weight: 600;
50
+ color: ${token.colorText};
51
+ `,
52
+ wrap: css`
53
+ width: 100%;
54
+ `,
55
+ }));
56
+
57
+ const LabCard = memo<PropsWithChildren<LabCardProps>>(
58
+ ({ title, desc, checked, onChange, meta, loading }) => {
59
+ const { styles } = useStyles();
60
+
61
+ return (
62
+ <div className={styles.wrap}>
63
+ <div className={styles.card}>
64
+ <div className={styles.row}>
65
+ <div className={styles.thumb} />
66
+ <Flexbox gap={6}>
67
+ <div className={styles.title}>{title}</div>
68
+ <div className={styles.desc}>{desc}</div>
69
+ {meta ? <div className={styles.meta}>{meta}</div> : null}
70
+ </Flexbox>
71
+ {!loading && (
72
+ <Flexbox align={'flex-end'} height={'100%'} justify={'center'} paddingInline={8}>
73
+ <Switch checked={checked} onChange={onChange} />
74
+ </Flexbox>
75
+ )}
76
+ </div>
77
+ </div>
78
+ </div>
79
+ );
80
+ },
81
+ );
82
+
83
+ LabCard.displayName = 'LabCard';
84
+
85
+ export default LabCard;
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+
3
+ import { memo, useCallback } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { Flexbox } from 'react-layout-kit';
6
+
7
+ import { useUserStore } from '@/store/user';
8
+ import { preferenceSelectors } from '@/store/user/selectors';
9
+
10
+ import Hero from './components/Hero';
11
+ import LabCard from './components/LabCard';
12
+
13
+ const LabsPage = memo(() => {
14
+ const { t } = useTranslation('labs');
15
+
16
+ const [isPreferenceInit, inputMarkdownRender, enableGroupChat, updatePreference] = useUserStore(
17
+ (s) => [
18
+ preferenceSelectors.isPreferenceInit(s),
19
+ preferenceSelectors.inputMarkdownRender(s),
20
+ preferenceSelectors.enableGroupChat(s),
21
+ s.updatePreference,
22
+ ],
23
+ );
24
+
25
+ const onToggleMarkdown = useCallback(
26
+ (checked: boolean) => updatePreference({ disableInputMarkdownRender: !checked }),
27
+ [updatePreference],
28
+ );
29
+ const onToggleGroupChat = useCallback(
30
+ (checked: boolean) => updatePreference({ enableGroupChat: checked }),
31
+ [updatePreference],
32
+ );
33
+
34
+ return (
35
+ <Flexbox gap={16} padding={8} style={{ alignItems: 'center', width: '100%' }}>
36
+ <Hero />
37
+
38
+ <LabCard
39
+ checked={inputMarkdownRender}
40
+ desc={t('features.inputMarkdown.desc')}
41
+ loading={!isPreferenceInit}
42
+ onChange={onToggleMarkdown}
43
+ title={t('features.inputMarkdown.title')}
44
+ />
45
+
46
+ <LabCard
47
+ checked={enableGroupChat}
48
+ desc={t('features.groupChat.desc')}
49
+ loading={!isPreferenceInit}
50
+ onChange={onToggleGroupChat}
51
+ title={t('features.groupChat.title')}
52
+ />
53
+ </Flexbox>
54
+ );
55
+ });
56
+
57
+ LabsPage.displayName = 'LabsPage';
58
+
59
+ export default LabsPage;
@@ -12,7 +12,8 @@ import {
12
12
  } from '@lobehub/editor';
13
13
  import { Editor, FloatMenu, SlashMenu, useEditorState } from '@lobehub/editor/react';
14
14
  import { combineKeys } from '@lobehub/ui';
15
- import { memo, useEffect, useRef } from 'react';
15
+ import { css, cx } from 'antd-style';
16
+ import { memo, useEffect, useMemo, useRef } from 'react';
16
17
  import { useHotkeysContext } from 'react-hotkeys-hook';
17
18
 
18
19
  import { useUserStore } from '@/store/user';
@@ -22,6 +23,12 @@ import { useChatInputStore, useStoreApi } from '../store';
22
23
  import Placeholder from './Placeholder';
23
24
  import { useSlashItems } from './useSlashItems';
24
25
 
26
+ const className = cx(css`
27
+ p {
28
+ margin-block-end: 0;
29
+ }
30
+ `);
31
+
25
32
  const InputEditor = memo<{ defaultRows?: number }>(() => {
26
33
  const [editor, slashMenuRef, send, updateMarkdownContent, expand] = useChatInputStore((s) => [
27
34
  s.editor,
@@ -55,11 +62,40 @@ const InputEditor = memo<{ defaultRows?: number }>(() => {
55
62
  };
56
63
  }, [state.isEmpty]);
57
64
 
65
+ const enableMarkdown = useUserStore(preferenceSelectors.inputMarkdownRender);
66
+ const plugins = useMemo(
67
+ () =>
68
+ !enableMarkdown
69
+ ? undefined
70
+ : [
71
+ ReactListPlugin,
72
+ ReactLinkPlugin,
73
+ ReactCodePlugin,
74
+ ReactCodeblockPlugin,
75
+ ReactHRPlugin,
76
+ ReactTablePlugin,
77
+ Editor.withProps(ReactMathPlugin, {
78
+ renderComp: expand
79
+ ? undefined
80
+ : (props) => (
81
+ <FloatMenu
82
+ {...props}
83
+ getPopupContainer={() => (slashMenuRef as any)?.current}
84
+ />
85
+ ),
86
+ }),
87
+ ],
88
+ [enableMarkdown],
89
+ );
90
+
58
91
  return (
59
92
  <Editor
60
93
  autoFocus
94
+ className={className}
61
95
  content={''}
62
96
  editor={editor}
97
+ enablePasteMarkdown={enableMarkdown}
98
+ markdownOption={enableMarkdown}
63
99
  onBlur={() => {
64
100
  disableScope(HotkeyEnum.AddUserMessage);
65
101
  }}
@@ -109,21 +145,7 @@ const InputEditor = memo<{ defaultRows?: number }>(() => {
109
145
  }
110
146
  }}
111
147
  placeholder={<Placeholder />}
112
- plugins={[
113
- ReactListPlugin,
114
- ReactLinkPlugin,
115
- ReactCodePlugin,
116
- ReactCodeblockPlugin,
117
- ReactHRPlugin,
118
- ReactTablePlugin,
119
- Editor.withProps(ReactMathPlugin, {
120
- renderComp: expand
121
- ? undefined
122
- : (props) => (
123
- <FloatMenu {...props} getPopupContainer={() => (slashMenuRef as any)?.current} />
124
- ),
125
- }),
126
- ]}
148
+ plugins={plugins}
127
149
  slashOption={{
128
150
  items: slashItems,
129
151
  renderComp: expand
@@ -239,6 +239,7 @@ export default {
239
239
  },
240
240
  information: '社区与资讯',
241
241
  installPWA: '安装浏览器应用 (PWA)',
242
+ labs: '实验室',
242
243
  lang: {
243
244
  'ar': '阿拉伯语',
244
245
  'bg-BG': '保加利亚语',
@@ -13,6 +13,7 @@ import file from './file';
13
13
  import hotkey from './hotkey';
14
14
  import image from './image';
15
15
  import knowledgeBase from './knowledgeBase';
16
+ import labs from './labs';
16
17
  import metadata from './metadata';
17
18
  import migration from './migration';
18
19
  import modelProvider from './modelProvider';
@@ -45,6 +46,7 @@ const resources = {
45
46
  hotkey,
46
47
  image,
47
48
  knowledgeBase,
49
+ labs,
48
50
  metadata,
49
51
  migration,
50
52
  modelProvider,
@@ -0,0 +1,14 @@
1
+ export default {
2
+ desc: '这里会不定期更新我们正在探索的新功能,欢迎试用!',
3
+ features: {
4
+ groupChat: {
5
+ desc: '启用多智能体群聊编排能力。',
6
+ title: '群聊(多智能体)',
7
+ },
8
+ inputMarkdown: {
9
+ desc: '在输入区域实时渲染 Markdown(粗体、代码块、表格等)。',
10
+ title: '输入框 Markdown 渲染',
11
+ },
12
+ },
13
+ title: '实验室',
14
+ };
package/src/middleware.ts CHANGED
@@ -33,6 +33,7 @@ export const config = {
33
33
  '/',
34
34
  '/discover',
35
35
  '/discover(.*)',
36
+ '/labs',
36
37
  '/chat',
37
38
  '/chat(.*)',
38
39
  '/changelog(.*)',
@@ -21,8 +21,11 @@ const shouldTriggerFileInKnowledgeBaseTip = (s: UserStore) =>
21
21
  const isPreferenceInit = (s: UserStore) => s.isUserStateInit;
22
22
 
23
23
  export const preferenceSelectors = {
24
+ enableGroupChat: (s: UserStore) => s.preference.enableGroupChat || false,
24
25
  hideSettingsMoveGuide,
25
26
  hideSyncAlert,
27
+ // TODO: 等到 lab 样式搞完再开启
28
+ inputMarkdownRender: (s: UserStore) => false && !s.preference.disableInputMarkdownRender,
26
29
  isPreferenceInit,
27
30
  shouldTriggerFileInKnowledgeBaseTip,
28
31
  showUploadFileInKnowledgeBaseTip,
@@ -1,41 +0,0 @@
1
- import { LobeDBSchemaMap } from '@/database/_deprecated/core/db';
2
-
3
- export type OnSyncEvent = (tableKey: keyof LobeDBSchemaMap) => void;
4
- export type OnSyncStatusChange = (status: PeerSyncStatus) => void;
5
- export type OnAwarenessChange = (state: SyncAwarenessState[]) => void;
6
-
7
- // export type PeerSyncStatus = 'syncing' | 'synced' | 'ready' | 'unconnected';
8
-
9
- export enum PeerSyncStatus {
10
- Connecting = 'connecting',
11
- Disabled = 'disabled',
12
- Ready = 'ready',
13
- Synced = 'synced',
14
- Syncing = 'syncing',
15
- Unconnected = 'unconnected',
16
- }
17
-
18
- export interface StartDataSyncParams {
19
- channel: {
20
- name: string;
21
- password?: string;
22
- };
23
- onAwarenessChange: OnAwarenessChange;
24
- onSyncEvent: OnSyncEvent;
25
- onSyncStatusChange: OnSyncStatusChange;
26
- signaling: string;
27
- user: SyncUserInfo;
28
- }
29
-
30
- export interface SyncUserInfo {
31
- browser?: string;
32
- id: string;
33
- isMobile: boolean;
34
- name?: string;
35
- os?: string;
36
- }
37
-
38
- export interface SyncAwarenessState extends SyncUserInfo {
39
- clientID: number;
40
- current: boolean;
41
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes