@lobehub/chat 1.79.10 → 1.80.1

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 (57) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/changelog/v1.json +27 -0
  3. package/docs/development/basic/feature-development.mdx +370 -619
  4. package/docs/development/basic/feature-development.zh-CN.mdx +368 -611
  5. package/docs/development/database-schema.dbml +2 -0
  6. package/locales/ar/setting.json +16 -0
  7. package/locales/bg-BG/setting.json +16 -0
  8. package/locales/de-DE/setting.json +16 -0
  9. package/locales/en-US/setting.json +16 -0
  10. package/locales/es-ES/setting.json +16 -0
  11. package/locales/fa-IR/setting.json +16 -0
  12. package/locales/fr-FR/setting.json +16 -0
  13. package/locales/it-IT/setting.json +16 -0
  14. package/locales/ja-JP/setting.json +16 -0
  15. package/locales/ko-KR/setting.json +16 -0
  16. package/locales/nl-NL/setting.json +16 -0
  17. package/locales/pl-PL/setting.json +16 -0
  18. package/locales/pt-BR/setting.json +16 -0
  19. package/locales/ru-RU/setting.json +16 -0
  20. package/locales/tr-TR/setting.json +16 -0
  21. package/locales/vi-VN/setting.json +16 -0
  22. package/locales/zh-CN/setting.json +16 -0
  23. package/locales/zh-TW/setting.json +16 -0
  24. package/package.json +1 -1
  25. package/scripts/generate-oidc-jwk.mjs +2 -1
  26. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/OpeningQuestions.tsx +78 -0
  27. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/WelcomeMessage.tsx +24 -4
  28. package/src/app/[variants]/(main)/chat/(workspace)/features/AgentSettings/CategoryContent/useCategory.tsx +6 -1
  29. package/src/app/[variants]/(main)/chat/(workspace)/features/AgentSettings/index.tsx +2 -0
  30. package/src/const/settings/agent.ts +1 -0
  31. package/src/database/_deprecated/schemas/session.ts +2 -0
  32. package/src/database/client/migrations.json +9 -0
  33. package/src/database/migrations/0021_add_agent_opening_settings.sql +2 -0
  34. package/src/database/migrations/meta/0021_snapshot.json +4988 -0
  35. package/src/database/migrations/meta/_journal.json +7 -0
  36. package/src/database/repositories/dataImporter/deprecated/__tests__/fixtures/messages.json +2 -0
  37. package/src/database/repositories/dataImporter/deprecated/__tests__/index.test.ts +19 -0
  38. package/src/database/schemas/agent.ts +3 -0
  39. package/src/features/AgentSetting/AgentOpening/OpeningMessage.tsx +80 -0
  40. package/src/features/AgentSetting/AgentOpening/OpeningQuestions.tsx +144 -0
  41. package/src/features/AgentSetting/AgentOpening/index.tsx +52 -0
  42. package/src/features/AgentSetting/store/selectors.ts +3 -0
  43. package/src/features/ChatInput/ActionBar/Upload/ClientMode.tsx +7 -6
  44. package/src/hooks/useModelSupportFiles.ts +15 -0
  45. package/src/libs/agent-runtime/stepfun/index.ts +7 -1
  46. package/src/libs/agent-runtime/zhipu/index.ts +17 -10
  47. package/src/locales/default/setting.ts +16 -0
  48. package/src/migrations/FromV5ToV6/types/v6.ts +2 -0
  49. package/src/server/routers/lambda/session.ts +8 -1
  50. package/src/services/import/client.test.ts +18 -0
  51. package/src/services/session/server.test.ts +2 -0
  52. package/src/store/agent/slices/chat/selectors/__snapshots__/agent.test.ts.snap +1 -0
  53. package/src/store/agent/slices/chat/selectors/agent.ts +7 -0
  54. package/src/store/aiInfra/slices/aiModel/selectors.ts +7 -0
  55. package/src/store/global/initialState.ts +1 -0
  56. package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +2 -0
  57. package/src/types/agent/index.ts +12 -0
@@ -147,6 +147,13 @@
147
147
  "when": 1744458287757,
148
148
  "tag": "0020_add_oidc",
149
149
  "breakpoints": true
150
+ },
151
+ {
152
+ "idx": 21,
153
+ "version": "7",
154
+ "when": 1744602998656,
155
+ "tag": "0021_add_agent_opening_settings",
156
+ "breakpoints": true
150
157
  }
151
158
  ],
152
159
  "version": "6"
@@ -926,6 +926,8 @@
926
926
  "ttsService": "openai",
927
927
  "voice": { "openai": "alloy" }
928
928
  },
929
+ "openingMessage": "I'm an AI assistant, how can I help you today?",
930
+ "openingQuestions": ["Question 1", "Question 2"],
929
931
  "chatConfig": {
930
932
  "autoCreateTopicThreshold": 2,
931
933
  "displayMode": "chat",
@@ -94,6 +94,7 @@ describe('DataImporter', () => {
94
94
  params: {},
95
95
  systemRole: 'abc',
96
96
  tts: {} as any,
97
+ openingQuestions: [],
97
98
  },
98
99
  meta: {
99
100
  title: 'Session 1',
@@ -110,6 +111,7 @@ describe('DataImporter', () => {
110
111
  params: {},
111
112
  systemRole: 'abc',
112
113
  tts: {} as any,
114
+ openingQuestions: [],
113
115
  },
114
116
  meta: {
115
117
  title: 'Session 2',
@@ -156,6 +158,7 @@ describe('DataImporter', () => {
156
158
  params: {},
157
159
  systemRole: 'abc',
158
160
  tts: {} as any,
161
+ openingQuestions: [],
159
162
  },
160
163
  meta: {
161
164
  title: 'Session 1',
@@ -172,6 +175,7 @@ describe('DataImporter', () => {
172
175
  params: {},
173
176
  systemRole: 'abc',
174
177
  tts: {} as any,
178
+ openingQuestions: [],
175
179
  },
176
180
  meta: {
177
181
  title: 'Session 2',
@@ -207,6 +211,7 @@ describe('DataImporter', () => {
207
211
  params: {},
208
212
  systemRole: 'abc',
209
213
  tts: {} as any,
214
+ openingQuestions: [],
210
215
  },
211
216
  meta: {
212
217
  title: 'Session 1',
@@ -224,6 +229,7 @@ describe('DataImporter', () => {
224
229
  params: {},
225
230
  systemRole: 'abc',
226
231
  tts: {} as any,
232
+ openingQuestions: [],
227
233
  },
228
234
  meta: {
229
235
  title: 'Session 2',
@@ -241,6 +247,7 @@ describe('DataImporter', () => {
241
247
  params: {},
242
248
  systemRole: 'abc',
243
249
  tts: {} as any,
250
+ openingQuestions: [],
244
251
  },
245
252
  meta: {
246
253
  title: 'Session 3',
@@ -287,6 +294,7 @@ describe('DataImporter', () => {
287
294
  params: {},
288
295
  systemRole: 'Test Agent 1',
289
296
  tts: {} as any,
297
+ openingQuestions: [],
290
298
  },
291
299
  meta: {
292
300
  title: 'Session 1',
@@ -303,6 +311,7 @@ describe('DataImporter', () => {
303
311
  params: {},
304
312
  systemRole: 'Test Agent 2',
305
313
  tts: {} as any,
314
+ openingQuestions: [],
306
315
  },
307
316
  meta: {
308
317
  title: 'Session 2',
@@ -367,6 +376,7 @@ describe('DataImporter', () => {
367
376
  params: {},
368
377
  systemRole: 'Test Agent 1',
369
378
  tts: {} as any,
379
+ openingQuestions: [],
370
380
  },
371
381
  meta: {
372
382
  title: 'Session 1',
@@ -390,6 +400,7 @@ describe('DataImporter', () => {
390
400
  params: {},
391
401
  systemRole: 'Test Agent 1',
392
402
  tts: {} as any,
403
+ openingQuestions: [],
393
404
  },
394
405
  meta: {
395
406
  title: 'Session 1',
@@ -439,6 +450,7 @@ describe('DataImporter', () => {
439
450
  params: {},
440
451
  systemRole: 'abc',
441
452
  tts: {} as any,
453
+ openingQuestions: [],
442
454
  },
443
455
  meta: {
444
456
  title: 'Session 1',
@@ -455,6 +467,8 @@ describe('DataImporter', () => {
455
467
  params: {},
456
468
  systemRole: 'abc',
457
469
  tts: {} as any,
470
+ openingQuestions: [],
471
+ openingMessage: `Hello, I'm Agent 2, learn more from [xxx](https://xxx.com)`,
458
472
  },
459
473
  meta: {
460
474
  title: 'Session 2',
@@ -507,6 +521,7 @@ describe('DataImporter', () => {
507
521
  params: {},
508
522
  systemRole: 'abc',
509
523
  tts: {} as any,
524
+ openingQuestions: [],
510
525
  },
511
526
  meta: {
512
527
  title: 'Session 1',
@@ -582,6 +597,7 @@ describe('DataImporter', () => {
582
597
  params: {},
583
598
  systemRole: 'abc',
584
599
  tts: {} as any,
600
+ openingQuestions: [],
585
601
  },
586
602
  meta: {
587
603
  title: 'Session 1',
@@ -661,6 +677,7 @@ describe('DataImporter', () => {
661
677
  params: {},
662
678
  systemRole: 'abc',
663
679
  tts: {} as any,
680
+ openingQuestions: [],
664
681
  },
665
682
  meta: {
666
683
  title: 'Session 1',
@@ -872,6 +889,8 @@ describe('DataImporter', () => {
872
889
  enableAutoCreateTopic: true,
873
890
  historyCount: 1,
874
891
  },
892
+ openingQuestions: ['Question 1', 'Question 2'],
893
+ openingMessage: `Hello, I'm Agent 1, learn more from [xxx](https://xxx.com)`,
875
894
  },
876
895
  group: 'XlUbvOvL',
877
896
  meta: {
@@ -54,6 +54,9 @@ export const agents = pgTable(
54
54
  systemRole: text('system_role'),
55
55
  tts: jsonb('tts').$type<LobeAgentTTSConfig>(),
56
56
 
57
+ openingMessage: text('opening_message'),
58
+ openingQuestions: text('opening_questions').array().default([]),
59
+
57
60
  ...timestamps,
58
61
  },
59
62
  (t) => ({
@@ -0,0 +1,80 @@
1
+ 'use client';
2
+
3
+ import { EditableMessage } from '@lobehub/ui';
4
+ import { Button } from 'antd';
5
+ import { createStyles } from 'antd-style';
6
+ import { PencilLine } from 'lucide-react';
7
+ import { memo, useCallback, useState } from 'react';
8
+ import { useTranslation } from 'react-i18next';
9
+ import { Flexbox } from 'react-layout-kit';
10
+
11
+ import { useStore } from '../store';
12
+ import { selectors } from '../store/selectors';
13
+
14
+ export const useStyles = createStyles(({ css, token }) => ({
15
+ markdown: css`
16
+ border: unset;
17
+ `,
18
+ wrapper: css`
19
+ width: 100%;
20
+ padding: 8px;
21
+ border: 1px solid ${token.colorBorder};
22
+ border-radius: ${token.borderRadiusLG - 1}px;
23
+
24
+ background: ${token.colorBgContainer};
25
+ `,
26
+ }));
27
+
28
+ const OpeningMessage = memo(() => {
29
+ const { t } = useTranslation('setting');
30
+ const { styles } = useStyles();
31
+
32
+ const openingMessage = useStore(selectors.openingMessage);
33
+ const updateConfig = useStore((s) => s.setAgentConfig);
34
+ const setOpeningMessage = useCallback(
35
+ (message: string) => {
36
+ updateConfig({ openingMessage: message });
37
+ },
38
+ [updateConfig],
39
+ );
40
+
41
+ const [editing, setEditing] = useState(false);
42
+
43
+ const handleEdit = useCallback(() => {
44
+ setEditing(true);
45
+ }, []);
46
+
47
+ const editIconButton = !editing && openingMessage && (
48
+ <Button onClick={handleEdit} size={'small'}>
49
+ <PencilLine size={16} />
50
+ </Button>
51
+ );
52
+
53
+ return (
54
+ <div className={styles.wrapper}>
55
+ <Flexbox direction={'horizontal'}>
56
+ <EditableMessage
57
+ classNames={{
58
+ markdown: styles.markdown,
59
+ }}
60
+ editButtonSize={'small'}
61
+ editing={editing}
62
+ height={'auto'}
63
+ inputType={'pure'}
64
+ onChange={setOpeningMessage}
65
+ onEditingChange={setEditing}
66
+ placeholder={t('settingOpening.openingMessage.placeholder')}
67
+ showEditWhenEmpty
68
+ text={{
69
+ cancel: t('cancel', { ns: 'common' }),
70
+ confirm: t('ok', { ns: 'common' }),
71
+ }}
72
+ value={openingMessage ?? ''}
73
+ />
74
+ {editIconButton}
75
+ </Flexbox>
76
+ </div>
77
+ );
78
+ });
79
+
80
+ export default OpeningMessage;
@@ -0,0 +1,144 @@
1
+ 'use client';
2
+
3
+ import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
4
+ import { SortableList } from '@lobehub/ui';
5
+ import { Button, Empty, Input } from 'antd';
6
+ import { createStyles } from 'antd-style';
7
+ import { memo, useCallback, useMemo, useState } from 'react';
8
+ import { useTranslation } from 'react-i18next';
9
+ import { Flexbox } from 'react-layout-kit';
10
+
11
+ import { useStore } from '../store';
12
+ import { selectors } from '../store/selectors';
13
+
14
+ const useStyles = createStyles(({ css, token }) => ({
15
+ empty: css`
16
+ margin-block: 24px;
17
+ margin-inline: 0;
18
+ `,
19
+ questionItemContainer: css`
20
+ margin-block-end: 8px;
21
+ padding-block: 2px;
22
+ padding-inline: 10px 0;
23
+ background: ${token.colorBgContainer};
24
+ `,
25
+ questionItemContent: css`
26
+ flex: 1;
27
+ `,
28
+ questionsList: css`
29
+ width: 100%;
30
+ margin-block-start: 16px;
31
+ `,
32
+ repeatError: css`
33
+ margin: 0;
34
+ color: ${token.colorErrorText};
35
+ `,
36
+ }));
37
+
38
+ interface QuestionItem {
39
+ content: string;
40
+ id: number;
41
+ }
42
+
43
+ const OpeningQuestions = memo(() => {
44
+ const { t } = useTranslation('setting');
45
+ const { styles } = useStyles();
46
+ const [questionInput, setQuestionInput] = useState('');
47
+
48
+ const openingQuestions = useStore(selectors.openingQuestions);
49
+ const updateConfig = useStore((s) => s.setAgentConfig);
50
+ const setQuestions = useCallback(
51
+ (questions: string[]) => {
52
+ updateConfig({ openingQuestions: questions });
53
+ },
54
+ [updateConfig],
55
+ );
56
+
57
+ const addQuestion = useCallback(() => {
58
+ if (!questionInput.trim()) return;
59
+
60
+ setQuestions([...openingQuestions, questionInput.trim()]);
61
+ setQuestionInput('');
62
+ }, [openingQuestions, questionInput, setQuestions]);
63
+
64
+ const removeQuestion = useCallback(
65
+ (content: string) => {
66
+ const newQuestions = [...openingQuestions];
67
+ const index = newQuestions.indexOf(content);
68
+ newQuestions.splice(index, 1);
69
+ setQuestions(newQuestions);
70
+ },
71
+ [openingQuestions, setQuestions],
72
+ );
73
+
74
+ // 处理拖拽排序后的逻辑
75
+ const handleSortEnd = useCallback(
76
+ (items: QuestionItem[]) => {
77
+ setQuestions(items.map((item) => item.content));
78
+ },
79
+ [setQuestions],
80
+ );
81
+
82
+ const items: QuestionItem[] = useMemo(() => {
83
+ return openingQuestions.map((item, index) => ({
84
+ content: item,
85
+ id: index,
86
+ }));
87
+ }, [openingQuestions]);
88
+
89
+ const isRepeat = openingQuestions.includes(questionInput.trim());
90
+
91
+ return (
92
+ <Flexbox gap={8}>
93
+ <Flexbox gap={4}>
94
+ <Input
95
+ addonAfter={
96
+ <Button
97
+ // don't allow repeat
98
+ disabled={openingQuestions.includes(questionInput.trim())}
99
+ icon={<PlusOutlined />}
100
+ onClick={addQuestion}
101
+ size="small"
102
+ type="text"
103
+ />
104
+ }
105
+ onChange={(e) => setQuestionInput(e.target.value)}
106
+ onPressEnter={addQuestion}
107
+ placeholder={t('settingOpening.openingQuestions.placeholder')}
108
+ value={questionInput}
109
+ />
110
+
111
+ {isRepeat && (
112
+ <p className={styles.repeatError}>{t('settingOpening.openingQuestions.repeat')}</p>
113
+ )}
114
+ </Flexbox>
115
+
116
+ <div className={styles.questionsList}>
117
+ {openingQuestions.length > 0 ? (
118
+ <SortableList
119
+ items={items}
120
+ onChange={handleSortEnd}
121
+ renderItem={(item) => (
122
+ <SortableList.Item className={styles.questionItemContainer} id={item.id}>
123
+ <SortableList.DragHandle />
124
+ <div className={styles.questionItemContent}>{item.content}</div>
125
+ <Button
126
+ icon={<DeleteOutlined />}
127
+ onClick={() => removeQuestion(item.content)}
128
+ type="text"
129
+ />
130
+ </SortableList.Item>
131
+ )}
132
+ />
133
+ ) : (
134
+ <Empty
135
+ className={styles.empty}
136
+ description={t('settingOpening.openingQuestions.empty')}
137
+ />
138
+ )}
139
+ </div>
140
+ </Flexbox>
141
+ );
142
+ });
143
+
144
+ export default OpeningQuestions;
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+
3
+ import { Form } from '@lobehub/ui';
4
+ import { memo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ import { FORM_STYLE } from '@/const/layoutTokens';
8
+
9
+ import OpeningMessage from './OpeningMessage';
10
+ import OpeningQuestions from './OpeningQuestions';
11
+
12
+ const wrapperCol = {
13
+ style: {
14
+ maxWidth: '100%',
15
+ width: '100%',
16
+ },
17
+ };
18
+
19
+ const AgentOpening = memo(() => {
20
+ const { t } = useTranslation('setting');
21
+
22
+ return (
23
+ <Form
24
+ items={[
25
+ {
26
+ children: [
27
+ {
28
+ children: <OpeningMessage />,
29
+ desc: t('settingOpening.openingMessage.desc'),
30
+ label: t('settingOpening.openingMessage.title'),
31
+ layout: 'vertical',
32
+ wrapperCol,
33
+ },
34
+ {
35
+ children: <OpeningQuestions />,
36
+ desc: t('settingOpening.openingQuestions.desc'),
37
+ label: t('settingOpening.openingQuestions.title'),
38
+ layout: 'vertical',
39
+ wrapperCol,
40
+ },
41
+ ],
42
+ title: t('settingOpening.title'),
43
+ },
44
+ ]}
45
+ itemsType={'group'}
46
+ variant={'pure'}
47
+ {...FORM_STYLE}
48
+ />
49
+ );
50
+ });
51
+
52
+ export default AgentOpening;
@@ -6,6 +6,9 @@ import { Store } from './action';
6
6
  const chatConfig = (s: Store): LobeAgentChatConfig =>
7
7
  s.config.chatConfig || DEFAULT_AGENT_CHAT_CONFIG;
8
8
 
9
+ export const DEFAULT_OPENING_QUESTIONS: string[] = [];
9
10
  export const selectors = {
10
11
  chatConfig,
12
+ openingMessage: (s: Store) => s.config.openingMessage,
13
+ openingQuestions: (s: Store) => s.config.openingQuestions || DEFAULT_OPENING_QUESTIONS,
11
14
  };
@@ -7,8 +7,8 @@ import { useTranslation } from 'react-i18next';
7
7
  import { useAgentStore } from '@/store/agent';
8
8
  import { agentSelectors } from '@/store/agent/slices/chat';
9
9
  import { useFileStore } from '@/store/file';
10
- import { useUserStore } from '@/store/user';
11
- import { modelProviderSelectors } from '@/store/user/selectors';
10
+ import { useModelSupportFiles } from "@/hooks/useModelSupportFiles";
11
+ import { useModelSupportVision } from "@/hooks/useModelSupportVision";
12
12
 
13
13
  const FileUpload = memo(() => {
14
14
  const { t } = useTranslation('chat');
@@ -16,10 +16,11 @@ const FileUpload = memo(() => {
16
16
  const upload = useFileStore((s) => s.uploadChatFiles);
17
17
 
18
18
  const model = useAgentStore(agentSelectors.currentAgentModel);
19
- const [canUpload, enabledFiles] = useUserStore((s) => [
20
- modelProviderSelectors.isModelEnabledUpload(model)(s),
21
- modelProviderSelectors.isModelEnabledFiles(model)(s),
22
- ]);
19
+ const provider = useAgentStore(agentSelectors.currentAgentModelProvider);
20
+
21
+ const enabledFiles = useModelSupportFiles(model, provider);
22
+ const supportVision = useModelSupportVision(model, provider);
23
+ const canUpload = enabledFiles || supportVision;
23
24
 
24
25
  return (
25
26
  <Upload
@@ -0,0 +1,15 @@
1
+ import { isDeprecatedEdition } from '@/const/version';
2
+ import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
3
+ import { useUserStore } from '@/store/user';
4
+ import { modelProviderSelectors } from '@/store/user/selectors';
5
+
6
+ export const useModelSupportFiles = (model: string, provider: string) => {
7
+ const newValue = useAiInfraStore(aiModelSelectors.isModelSupportFiles(model, provider));
8
+
9
+ // TODO: remove this in V2.0
10
+ const oldValue = useUserStore(modelProviderSelectors.isModelEnabledFiles(model));
11
+ if (isDeprecatedEdition) return oldValue;
12
+ //
13
+
14
+ return newValue;
15
+ };
@@ -46,9 +46,14 @@ export const LobeStepfunAI = LobeOpenAICompatibleFactory({
46
46
 
47
47
  const visionKeywords = [
48
48
  'step-1o-',
49
+ 'step-r1-v-',
49
50
  'step-1v-',
50
51
  ];
51
52
 
53
+ const reasoningKeywords = [
54
+ 'step-r1-',
55
+ ];
56
+
52
57
  const modelsPage = await client.models.list() as any;
53
58
  const modelList: StepfunModelCard[] = modelsPage.data;
54
59
 
@@ -66,7 +71,8 @@ export const LobeStepfunAI = LobeOpenAICompatibleFactory({
66
71
  || false,
67
72
  id: model.id,
68
73
  reasoning:
69
- knownModel?.abilities?.reasoning
74
+ reasoningKeywords.some(keyword => model.id.toLowerCase().includes(keyword))
75
+ || knownModel?.abilities?.reasoning
70
76
  || false,
71
77
  vision:
72
78
  visionKeywords.some(keyword => model.id.toLowerCase().includes(keyword))
@@ -50,23 +50,30 @@ export const LobeZhipuAI = LobeOpenAICompatibleFactory({
50
50
  } as any;
51
51
  },
52
52
  },
53
- constructorOptions: {
54
- defaultHeaders: {
55
- 'Bigmodel-Organization': 'lobehub',
56
- 'Bigmodel-project': 'lobechat',
57
- },
58
- },
59
53
  debug: {
60
54
  chatCompletion: () => process.env.DEBUG_ZHIPU_CHAT_COMPLETION === '1',
61
55
  },
62
56
  models: async ({ client }) => {
63
57
  const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
64
58
 
59
+ const reasoningKeywords = [
60
+ 'glm-zero',
61
+ 'glm-z1',
62
+ ];
63
+
65
64
  // ref: https://open.bigmodel.cn/console/modelcenter/square
66
- client.baseURL = 'https://open.bigmodel.cn/api/fine-tuning/model_center/list?pageSize=100&pageNum=1';
65
+ const url = 'https://open.bigmodel.cn/api/fine-tuning/model_center/list?pageSize=100&pageNum=1';
66
+ const response = await fetch(url, {
67
+ headers: {
68
+ 'Authorization': `Bearer ${client.apiKey}`,
69
+ 'Bigmodel-Organization': 'lobehub',
70
+ 'Bigmodel-Project': 'lobechat',
71
+ },
72
+ method: 'GET',
73
+ });
74
+ const json = await response.json();
67
75
 
68
- const modelsPage = await client.models.list() as any;
69
- const modelList: ZhipuModelCard[] = modelsPage.body.rows;
76
+ const modelList: ZhipuModelCard[] = json.rows;
70
77
 
71
78
  return modelList
72
79
  .map((model) => {
@@ -83,7 +90,7 @@ export const LobeZhipuAI = LobeOpenAICompatibleFactory({
83
90
  || false,
84
91
  id: model.modelCode,
85
92
  reasoning:
86
- model.modelCode.toLowerCase().includes('glm-zero-preview')
93
+ reasoningKeywords.some(keyword => model.modelCode.toLowerCase().includes(keyword))
87
94
  || knownModel?.abilities?.reasoning
88
95
  || false,
89
96
  vision:
@@ -6,6 +6,7 @@ export default {
6
6
  chat: '聊天偏好',
7
7
  meta: '助手信息',
8
8
  modal: '模型设置',
9
+ opening: '开场设置',
9
10
  plugin: '插件设置',
10
11
  prompt: '角色设定',
11
12
  tts: '语音服务',
@@ -255,6 +256,21 @@ export default {
255
256
  title: '思维开放度',
256
257
  },
257
258
  },
259
+ settingOpening: {
260
+ openingMessage: {
261
+ desc: '打开会话时的开场消息,用来介绍助手的功能',
262
+ placeholder: '你好,我是自定义助手。你可以立即与我开始对话,也可以前往助手设置完善我的信息。',
263
+ title: '开场消息',
264
+ },
265
+ openingQuestions: {
266
+ desc: '会话开始时展示的引导性问题',
267
+ empty: '暂无问题',
268
+ placeholder: '请输入问题',
269
+ repeat: '问题已存在',
270
+ title: '开场问题',
271
+ },
272
+ title: '开场设置',
273
+ },
258
274
  settingPlugin: {
259
275
  title: '插件列表',
260
276
  },
@@ -29,6 +29,8 @@ export interface V6AgentConfig {
29
29
  chatConfig: ChatConfig;
30
30
  fewShots?: FewShots;
31
31
  model: string;
32
+ openingMessage?: string;
33
+ openingQuestions?: string[];
32
34
  params: LLMParams;
33
35
  plugins?: string[];
34
36
  provider?: string;
@@ -76,7 +76,14 @@ export const sessionRouter = router({
76
76
  .input(
77
77
  z.object({
78
78
  config: insertAgentSchema
79
- .omit({ chatConfig: true, plugins: true, tags: true, tts: true })
79
+ .omit({
80
+ chatConfig: true,
81
+ openingMessage: true,
82
+ openingQuestions: true,
83
+ plugins: true,
84
+ tags: true,
85
+ tts: true,
86
+ })
80
87
  .passthrough()
81
88
  .partial(),
82
89
  session: insertSessionSchema.omit({ createdAt: true, updatedAt: true }).partial(),