@lobehub/chat 1.87.9 → 1.88.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,73 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.88.1](https://github.com/lobehub/lobe-chat/compare/v1.88.0...v1.88.1)
6
+
7
+ <sup>Released on **2025-05-24**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: User nickName & username selector in desktop.
12
+
13
+ #### 💄 Styles
14
+
15
+ - **misc**: Support Gemini 2.5 thought reasoning.
16
+
17
+ <br/>
18
+
19
+ <details>
20
+ <summary><kbd>Improvements and Fixes</kbd></summary>
21
+
22
+ #### What's fixed
23
+
24
+ - **misc**: User nickName & username selector in desktop, closes [#7899](https://github.com/lobehub/lobe-chat/issues/7899) ([bf51746](https://github.com/lobehub/lobe-chat/commit/bf51746))
25
+
26
+ #### Styles
27
+
28
+ - **misc**: Support Gemini 2.5 thought reasoning, closes [#7686](https://github.com/lobehub/lobe-chat/issues/7686) ([f34c4de](https://github.com/lobehub/lobe-chat/commit/f34c4de))
29
+
30
+ </details>
31
+
32
+ <div align="right">
33
+
34
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
35
+
36
+ </div>
37
+
38
+ ## [Version 1.88.0](https://github.com/lobehub/lobe-chat/compare/v1.87.9...v1.88.0)
39
+
40
+ <sup>Released on **2025-05-23**</sup>
41
+
42
+ #### ✨ Features
43
+
44
+ - **misc**: Add claude 4 series.
45
+
46
+ #### 🐛 Bug Fixes
47
+
48
+ - **misc**: Fix missing email field to user, update agent config of client db will override old config.
49
+
50
+ <br/>
51
+
52
+ <details>
53
+ <summary><kbd>Improvements and Fixes</kbd></summary>
54
+
55
+ #### What's improved
56
+
57
+ - **misc**: Add claude 4 series, closes [#7939](https://github.com/lobehub/lobe-chat/issues/7939) ([9b4f950](https://github.com/lobehub/lobe-chat/commit/9b4f950))
58
+
59
+ #### What's fixed
60
+
61
+ - **misc**: Fix missing email field to user, closes [#7913](https://github.com/lobehub/lobe-chat/issues/7913) ([d314130](https://github.com/lobehub/lobe-chat/commit/d314130))
62
+ - **misc**: Update agent config of client db will override old config, closes [#7918](https://github.com/lobehub/lobe-chat/issues/7918) ([f7cda68](https://github.com/lobehub/lobe-chat/commit/f7cda68))
63
+
64
+ </details>
65
+
66
+ <div align="right">
67
+
68
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
69
+
70
+ </div>
71
+
5
72
  ### [Version 1.87.9](https://github.com/lobehub/lobe-chat/compare/v1.87.8...v1.87.9)
6
73
 
7
74
  <sup>Released on **2025-05-23**</sup>
package/README.md CHANGED
@@ -327,14 +327,14 @@ In addition, these plugins are not limited to news aggregation, but can also ext
327
327
 
328
328
  <!-- PLUGIN LIST -->
329
329
 
330
- | Recent Submits | Description |
331
- | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
332
- | [PortfolioMeta](https://lobechat.com/discover/plugin/StockData)<br/><sup>By **portfoliometa** on **2025-03-23**</sup> | Analyze stocks and get comprehensive real-time investment data and analytics.<br/>`stock` |
333
- | [Web](https://lobechat.com/discover/plugin/web)<br/><sup>By **Proghit** on **2025-01-24**</sup> | Smart web search that reads and analyzes pages to deliver comprehensive answers from Google results.<br/>`web` `search` |
334
- | [Bing_websearch](https://lobechat.com/discover/plugin/Bingsearch-identifier)<br/><sup>By **FineHow** on **2024-12-22**</sup> | Search for information from the internet base BingApi<br/>`bingsearch` |
335
- | [Google CSE](https://lobechat.com/discover/plugin/google-cse)<br/><sup>By **vsnthdev** on **2024-12-02**</sup> | Searches Google through their official CSE API.<br/>`web` `search` |
336
-
337
- > 📊 Total plugins: [<kbd>**43**</kbd>](https://lobechat.com/discover/plugins)
330
+ | Recent Submits | Description |
331
+ | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
332
+ | [Web](https://lobechat.com/discover/plugin/web)<br/><sup>By **Proghit** on **2025-01-24**</sup> | Smart web search that reads and analyzes pages to deliver comprehensive answers from Google results.<br/>`web` `search` |
333
+ | [Bing_websearch](https://lobechat.com/discover/plugin/Bingsearch-identifier)<br/><sup>By **FineHow** on **2024-12-22**</sup> | Search for information from the internet base BingApi<br/>`bingsearch` |
334
+ | [Google CSE](https://lobechat.com/discover/plugin/google-cse)<br/><sup>By **vsnthdev** on **2024-12-02**</sup> | Searches Google through their official CSE API.<br/>`web` `search` |
335
+ | [Tongyi wanxiang Image Generator](https://lobechat.com/discover/plugin/alps-tongyi-image)<br/><sup>By **YoungTx** on **2024-08-09**</sup> | This plugin uses Alibaba's Tongyi Wanxiang model to generate images based on text prompts.<br/>`image` `tongyi` `wanxiang` |
336
+
337
+ > 📊 Total plugins: [<kbd>**42**</kbd>](https://lobechat.com/discover/plugins)
338
338
 
339
339
  <!-- PLUGIN LIST -->
340
340
 
package/README.zh-CN.md CHANGED
@@ -320,14 +320,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
320
320
 
321
321
  <!-- PLUGIN LIST -->
322
322
 
323
- | 最近新增 | 描述 |
324
- | -------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
325
- | [PortfolioMeta](https://lobechat.com/discover/plugin/StockData)<br/><sup>By **portfoliometa** on **2025-03-23**</sup> | 分析股票并获取全面的实时投资数据和分析。<br/>`股票` |
326
- | [网页](https://lobechat.com/discover/plugin/web)<br/><sup>By **Proghit** on **2025-01-24**</sup> | 智能网页搜索,读取和分析页面,以提供来自 Google 结果的全面答案。<br/>`网页` `搜索` |
327
- | [必应网页搜索](https://lobechat.com/discover/plugin/Bingsearch-identifier)<br/><sup>By **FineHow** on **2024-12-22**</sup> | 通过 BingApi 搜索互联网上的信息<br/>`bingsearch` |
328
- | [谷歌自定义搜索引擎](https://lobechat.com/discover/plugin/google-cse)<br/><sup>By **vsnthdev** on **2024-12-02**</sup> | 通过他们的官方自定义搜索引擎 API 搜索谷歌。<br/>`网络` `搜索` |
329
-
330
- > 📊 Total plugins: [<kbd>**43**</kbd>](https://lobechat.com/discover/plugins)
323
+ | 最近新增 | 描述 |
324
+ | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
325
+ | [网页](https://lobechat.com/discover/plugin/web)<br/><sup>By **Proghit** on **2025-01-24**</sup> | 智能网页搜索,读取和分析页面,以提供来自 Google 结果的全面答案。<br/>`网页` `搜索` |
326
+ | [必应网页搜索](https://lobechat.com/discover/plugin/Bingsearch-identifier)<br/><sup>By **FineHow** on **2024-12-22**</sup> | 通过 BingApi 搜索互联网上的信息<br/>`bingsearch` |
327
+ | [谷歌自定义搜索引擎](https://lobechat.com/discover/plugin/google-cse)<br/><sup>By **vsnthdev** on **2024-12-02**</sup> | 通过他们的官方自定义搜索引擎 API 搜索谷歌。<br/>`网络` `搜索` |
328
+ | [通义万象图像生成器](https://lobechat.com/discover/plugin/alps-tongyi-image)<br/><sup>By **YoungTx** on **2024-08-09**</sup> | 此插件使用阿里巴巴的通义万象模型根据文本提示生成图像。<br/>`图像` `通义` `万象` |
329
+
330
+ > 📊 Total plugins: [<kbd>**42**</kbd>](https://lobechat.com/discover/plugins)
331
331
 
332
332
  <!-- PLUGIN LIST -->
333
333
 
package/changelog/v1.json CHANGED
@@ -1,4 +1,28 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "fixes": [
5
+ "User nickName & username selector in desktop."
6
+ ],
7
+ "improvements": [
8
+ "Support Gemini 2.5 thought reasoning."
9
+ ]
10
+ },
11
+ "date": "2025-05-24",
12
+ "version": "1.88.1"
13
+ },
14
+ {
15
+ "children": {
16
+ "features": [
17
+ "Add claude 4 series."
18
+ ],
19
+ "fixes": [
20
+ "Fix missing email field to user, update agent config of client db will override old config."
21
+ ]
22
+ },
23
+ "date": "2025-05-23",
24
+ "version": "1.88.0"
25
+ },
2
26
  {
3
27
  "children": {
4
28
  "improvements": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.87.9",
3
+ "version": "1.88.1",
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,55 @@
1
1
  import { AIChatModelCard } from '@/types/aiModel';
2
2
 
3
3
  const anthropicChatModels: AIChatModelCard[] = [
4
+ {
5
+ abilities: {
6
+ functionCall: true,
7
+ reasoning: true,
8
+ vision: true,
9
+ },
10
+ contextWindowTokens: 200_000,
11
+ description:
12
+ 'Claude 4 Sonnet 可以产生近乎即时的响应或延长的逐步思考,用户可以清晰地看到这些过程。API 用户还可以对模型思考的时间进行细致的控制',
13
+ displayName: 'Claude 4 Sonnet',
14
+ enabled: true,
15
+ id: 'claude-sonnet-4-20250514',
16
+ maxOutput: 8192,
17
+ pricing: {
18
+ cachedInput: 0.3,
19
+ input: 3,
20
+ output: 15,
21
+ writeCacheInput: 3.75,
22
+ },
23
+ releasedAt: '2025-05-23',
24
+ settings: {
25
+ extendParams: ['disableContextCaching', 'enableReasoning', 'reasoningBudgetToken'],
26
+ },
27
+ type: 'chat',
28
+ },
29
+ {
30
+ abilities: {
31
+ functionCall: true,
32
+ vision: true,
33
+ },
34
+ contextWindowTokens: 200_000,
35
+ description:
36
+ 'Claude Opus 4 是 Anthropic 用于处理高度复杂任务的最强大模型。它在性能、智能、流畅性和理解力方面表现卓越。',
37
+ displayName: 'Claude Opus 4',
38
+ enabled: true,
39
+ id: 'claude-opus-4-20250514',
40
+ maxOutput: 8192,
41
+ pricing: {
42
+ cachedInput: 1.5,
43
+ input: 15,
44
+ output: 75,
45
+ writeCacheInput: 18.75,
46
+ },
47
+ releasedAt: '2025-05-23',
48
+ settings: {
49
+ extendParams: ['disableContextCaching', 'enableReasoning', 'reasoningBudgetToken'],
50
+ },
51
+ type: 'chat',
52
+ },
4
53
  {
5
54
  abilities: {
6
55
  functionCall: true,
@@ -145,7 +194,6 @@ const anthropicChatModels: AIChatModelCard[] = [
145
194
  description:
146
195
  'Claude 3 Opus 是 Anthropic 用于处理高度复杂任务的最强大模型。它在性能、智能、流畅性和理解力方面表现卓越。',
147
196
  displayName: 'Claude 3 Opus',
148
- enabled: true,
149
197
  id: 'claude-3-opus-20240229',
150
198
  maxOutput: 4096,
151
199
  pricing: {
@@ -285,7 +285,7 @@ const googleChatModels: AIChatModelCard[] = [
285
285
  contextWindowTokens: 2_008_192,
286
286
  description:
287
287
  'Gemini 1.5 Pro 002 是最新的生产就绪模型,提供更高质量的输出,特别在数学、长上下文和视觉任务方面有显著提升。',
288
- displayName: 'Gemini 1.5 Pro 002',
288
+ displayName: 'Gemini 1.5 Pro 002 (Paid)',
289
289
  id: 'gemini-1.5-pro-002', // Deprecated on 2025-09-24
290
290
  maxOutput: 8192,
291
291
  pricing: {
@@ -303,7 +303,7 @@ const googleChatModels: AIChatModelCard[] = [
303
303
  },
304
304
  contextWindowTokens: 2_008_192,
305
305
  description: 'Gemini 1.5 Pro 001 是可扩展的多模态AI解决方案,支持广泛的复杂任务。',
306
- displayName: 'Gemini 1.5 Pro 001',
306
+ displayName: 'Gemini 1.5 Pro 001 (Paid)',
307
307
  id: 'gemini-1.5-pro-001', // Deprecated on 2025-05-27
308
308
  maxOutput: 8192,
309
309
  pricing: {
@@ -12,6 +12,10 @@ export const disableStreamModels = new Set(['o1', 'o1-2024-12-17']);
12
12
  * models support context caching
13
13
  */
14
14
  export const contextCachingModels = new Set([
15
+ 'claude-opus-4-latest',
16
+ 'claude-opus-4-20250514',
17
+ 'claude-sonnet-4-latest',
18
+ 'claude-sonnet-4-20250514',
15
19
  'claude-3-7-sonnet-latest',
16
20
  'claude-3-7-sonnet-20250219',
17
21
  'claude-3-5-sonnet-latest',
@@ -22,6 +26,10 @@ export const contextCachingModels = new Set([
22
26
  ]);
23
27
 
24
28
  export const thinkingWithToolClaudeModels = new Set([
29
+ 'claude-opus-4-latest',
30
+ 'claude-opus-4-20250514',
31
+ 'claude-sonnet-4-latest',
32
+ 'claude-sonnet-4-20250514',
25
33
  'claude-3-7-sonnet-latest',
26
34
  'claude-3-7-sonnet-20250219',
27
35
  ]);
@@ -747,18 +747,35 @@ describe('SessionModel', () => {
747
747
  });
748
748
 
749
749
  describe('updateConfig', () => {
750
- it('should update agent config', async () => {
751
- // Create test agent
750
+ it('should update agent config via sessionId', async () => {
751
+ // Create test session with agent
752
+ const sessionId = 'test-session';
752
753
  const agentId = 'test-agent';
753
- await serverDB.insert(agents).values({
754
- id: agentId,
755
- userId,
756
- model: 'gpt-3.5-turbo',
757
- title: 'Original Title',
754
+
755
+ await serverDB.transaction(async (trx) => {
756
+ await trx.insert(sessions).values({
757
+ id: sessionId,
758
+ userId,
759
+ type: 'agent',
760
+ });
761
+
762
+ await trx.insert(agents).values({
763
+ id: agentId,
764
+ userId,
765
+ model: 'gpt-3.5-turbo',
766
+ title: 'Original Title',
767
+ description: 'Original description',
768
+ });
769
+
770
+ await trx.insert(agentsToSessions).values({
771
+ sessionId,
772
+ agentId,
773
+ userId,
774
+ });
758
775
  });
759
776
 
760
- // Update config
761
- await sessionModel.updateConfig(agentId, {
777
+ // Update config using sessionId
778
+ await sessionModel.updateConfig(sessionId, {
762
779
  model: 'gpt-4',
763
780
  title: 'Updated Title',
764
781
  description: 'New description',
@@ -777,23 +794,162 @@ describe('SessionModel', () => {
777
794
  });
778
795
  });
779
796
 
780
- it('should not update config for other users agents', async () => {
797
+ it('should merge config with existing agent config', async () => {
798
+ // Create test session with agent having existing config
799
+ const sessionId = 'test-session-merge';
800
+ const agentId = 'test-agent-merge';
801
+
802
+ await serverDB.transaction(async (trx) => {
803
+ await trx.insert(sessions).values({
804
+ id: sessionId,
805
+ userId,
806
+ type: 'agent',
807
+ });
808
+
809
+ await trx.insert(agents).values({
810
+ id: agentId,
811
+ userId,
812
+ model: 'gpt-3.5-turbo',
813
+ title: 'Original Title',
814
+ description: 'Original description',
815
+ systemRole: 'Original role',
816
+ });
817
+
818
+ await trx.insert(agentsToSessions).values({
819
+ sessionId,
820
+ agentId,
821
+ userId,
822
+ });
823
+ });
824
+
825
+ // Update only some fields
826
+ await sessionModel.updateConfig(sessionId, {
827
+ model: 'gpt-4',
828
+ title: 'Updated Title',
829
+ // Don't update description and systemRole
830
+ });
831
+
832
+ // Verify merge behavior - updated fields changed, others preserved
833
+ const updatedAgent = await serverDB
834
+ .select()
835
+ .from(agents)
836
+ .where(and(eq(agents.id, agentId), eq(agents.userId, userId)));
837
+
838
+ expect(updatedAgent[0]).toMatchObject({
839
+ model: 'gpt-4',
840
+ title: 'Updated Title',
841
+ description: 'Original description', // Should be preserved
842
+ systemRole: 'Original role', // Should be preserved
843
+ });
844
+ });
845
+
846
+ it('should return early if session does not exist', async () => {
847
+ // Try to update config for non-existent session
848
+ const result = await sessionModel.updateConfig('non-existent-session', {
849
+ model: 'gpt-4',
850
+ title: 'Updated Title',
851
+ });
852
+
853
+ // Should return undefined/early without throwing
854
+ expect(result).toBeUndefined();
855
+ });
856
+
857
+ it('should throw error if session has no associated agent', async () => {
858
+ // Create session without agent
859
+ const sessionId = 'session-no-agent';
860
+
861
+ await serverDB.insert(sessions).values({
862
+ id: sessionId,
863
+ userId,
864
+ type: 'agent',
865
+ });
866
+
867
+ // Try to update config - should throw error
868
+ await expect(
869
+ sessionModel.updateConfig(sessionId, {
870
+ model: 'gpt-4',
871
+ title: 'Updated Title',
872
+ }),
873
+ ).rejects.toThrow(
874
+ 'this session is not assign with agent, please contact with admin to fix this issue.',
875
+ );
876
+ });
877
+
878
+ it('should return early if data is null or undefined', async () => {
879
+ // Create test session with agent
880
+ const sessionId = 'test-session-null';
881
+ const agentId = 'test-agent-null';
882
+
883
+ await serverDB.transaction(async (trx) => {
884
+ await trx.insert(sessions).values({
885
+ id: sessionId,
886
+ userId,
887
+ type: 'agent',
888
+ });
889
+
890
+ await trx.insert(agents).values({
891
+ id: agentId,
892
+ userId,
893
+ model: 'gpt-3.5-turbo',
894
+ title: 'Original Title',
895
+ });
896
+
897
+ await trx.insert(agentsToSessions).values({
898
+ sessionId,
899
+ agentId,
900
+ userId,
901
+ });
902
+ });
903
+
904
+ // Test with null data
905
+ const result1 = await sessionModel.updateConfig(sessionId, null);
906
+ expect(result1).toBeUndefined();
907
+
908
+ // Test with undefined data
909
+ const result2 = await sessionModel.updateConfig(sessionId, undefined);
910
+ expect(result2).toBeUndefined();
911
+
912
+ // Test with empty object
913
+ const result3 = await sessionModel.updateConfig(sessionId, {});
914
+ expect(result3).toBeUndefined();
915
+ });
916
+
917
+ it('should not update config for other users sessions', async () => {
781
918
  // Create agent for another user
919
+ const sessionId = 'other-session';
782
920
  const agentId = 'other-agent';
783
921
  await serverDB.insert(users).values([{ id: 'other-user' }]);
784
- await serverDB.insert(agents).values({
785
- id: agentId,
786
- userId: 'other-user',
787
- model: 'gpt-3.5-turbo',
788
- title: 'Original Title',
922
+
923
+ await serverDB.transaction(async (trx) => {
924
+ await trx.insert(sessions).values({
925
+ id: sessionId,
926
+ userId: 'other-user',
927
+ type: 'agent',
928
+ });
929
+
930
+ await trx.insert(agents).values({
931
+ id: agentId,
932
+ userId: 'other-user',
933
+ model: 'gpt-3.5-turbo',
934
+ title: 'Original Title',
935
+ });
936
+
937
+ await trx.insert(agentsToSessions).values({
938
+ sessionId,
939
+ agentId,
940
+ userId: 'other-user',
941
+ });
789
942
  });
790
943
 
791
- // Try to update other user's agent
792
- await sessionModel.updateConfig(agentId, {
944
+ // Try to update other user's session - should return early
945
+ const result = await sessionModel.updateConfig(sessionId, {
793
946
  model: 'gpt-4',
794
947
  title: 'Updated Title',
795
948
  });
796
949
 
950
+ // Should return undefined as session doesn't belong to current user
951
+ expect(result).toBeUndefined();
952
+
797
953
  // Verify no changes were made
798
954
  const agent = await serverDB.select().from(agents).where(eq(agents.id, agentId));
799
955
 
@@ -393,13 +393,23 @@ export class SessionModel {
393
393
  .returning();
394
394
  };
395
395
 
396
- updateConfig = async (id: string, data: Partial<AgentItem>) => {
397
- if (Object.keys(data).length === 0) return;
396
+ updateConfig = async (sessionId: string, data: DeepPartial<AgentItem> | undefined | null) => {
397
+ if (!data || Object.keys(data).length === 0) return;
398
398
 
399
+ const session = await this.findByIdOrSlug(sessionId);
400
+ if (!session) return;
401
+
402
+ if (!session.agent) {
403
+ throw new Error(
404
+ 'this session is not assign with agent, please contact with admin to fix this issue.',
405
+ );
406
+ }
407
+
408
+ const mergedValue = merge(session.agent, data);
399
409
  return this.db
400
410
  .update(agents)
401
- .set(data)
402
- .where(and(eq(agents.id, id), eq(agents.userId, this.userId)));
411
+ .set(mergedValue)
412
+ .where(and(eq(agents.id, session.agent.id), eq(agents.userId, this.userId)));
403
413
  };
404
414
 
405
415
  // **************** Helper *************** //
@@ -82,6 +82,10 @@ interface LobeGoogleAIParams {
82
82
  isVertexAi?: boolean;
83
83
  }
84
84
 
85
+ interface GoogleAIThinkingConfig {
86
+ includeThoughts?: boolean;
87
+ }
88
+
85
89
  export class LobeGoogleAI implements LobeRuntimeAI {
86
90
  private client: GoogleGenerativeAI;
87
91
  private isVertexAi: boolean;
@@ -106,6 +110,10 @@ export class LobeGoogleAI implements LobeRuntimeAI {
106
110
  const payload = this.buildPayload(rawPayload);
107
111
  const model = payload.model;
108
112
 
113
+ const thinkingConfig: GoogleAIThinkingConfig = {
114
+ includeThoughts: true,
115
+ };
116
+
109
117
  const contents = await this.buildGoogleMessages(payload.messages);
110
118
 
111
119
  const inputStartAt = Date.now();
@@ -117,6 +125,7 @@ export class LobeGoogleAI implements LobeRuntimeAI {
117
125
  // @ts-expect-error - Google SDK 0.24.0 doesn't have this property for now with
118
126
  response_modalities: modelsWithModalities.has(model) ? ['Text', 'Image'] : undefined,
119
127
  temperature: payload.temperature,
128
+ thinkingConfig,
120
129
  topP: payload.top_p,
121
130
  },
122
131
  model,
@@ -76,6 +76,15 @@ const transformGoogleGenerativeAIStream = (
76
76
  const text = chunk.text?.();
77
77
 
78
78
  if (candidate) {
79
+ // 首先检查是否为 reasoning 内容 (thought: true)
80
+ if (Array.isArray(candidate.content.parts) && candidate.content.parts.length > 0) {
81
+ for (const part of candidate.content.parts) {
82
+ if (part && part.text && (part as any).thought === true) {
83
+ return { data: part.text, id: context.id, type: 'reasoning' };
84
+ }
85
+ }
86
+ }
87
+
79
88
  // return the grounding
80
89
  if (candidate.groundingMetadata) {
81
90
  const { webSearchQueries, groundingChunks } = candidate.groundingMetadata;
@@ -10,7 +10,6 @@ import { AgentChatConfigSchema } from '@/types/agent';
10
10
  import { LobeMetaDataSchema } from '@/types/meta';
11
11
  import { BatchTaskResult } from '@/types/service';
12
12
  import { ChatSessionList } from '@/types/session';
13
- import { merge } from '@/utils/merge';
14
13
 
15
14
  const sessionProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
16
15
  const { ctx } = opts;
@@ -156,12 +155,8 @@ export const sessionRouter = router({
156
155
  }),
157
156
  )
158
157
  .mutation(async ({ input, ctx }) => {
159
- const session = await ctx.sessionModel.findByIdOrSlug(input.id);
160
-
161
- if (!session) return;
162
-
163
- return ctx.sessionModel.updateConfig(session.agent.id, {
164
- chatConfig: merge(session.agent.chatConfig, input.value),
158
+ return ctx.sessionModel.updateConfig(input.id, {
159
+ chatConfig: input.value,
165
160
  });
166
161
  }),
167
162
  updateSessionConfig: sessionProcedure
@@ -172,18 +167,7 @@ export const sessionRouter = router({
172
167
  }),
173
168
  )
174
169
  .mutation(async ({ input, ctx }) => {
175
- const session = await ctx.sessionModel.findByIdOrSlug(input.id);
176
-
177
- if (!session || !input.value) return;
178
-
179
- if (!session.agent) {
180
- throw new Error(
181
- 'this session is not assign with agent, please contact with admin to fix this issue.',
182
- );
183
- }
184
-
185
- const mergedValue = merge(session.agent, input.value);
186
- return ctx.sessionModel.updateConfig(session.agent.id, mergedValue);
170
+ return ctx.sessionModel.updateConfig(input.id, input.value);
187
171
  }),
188
172
  });
189
173
 
@@ -10,6 +10,9 @@ vi.mock('@/config/app', () => ({
10
10
  appEnv: {
11
11
  DEFAULT_AGENT_CONFIG: 'model=gpt-4;temperature=0.7',
12
12
  },
13
+ getAppConfig: () => ({
14
+ DEFAULT_AGENT_CONFIG: 'model=gpt-4;temperature=0.7',
15
+ }),
13
16
  }));
14
17
 
15
18
  vi.mock('@/server/globalConfig/parseDefaultAgent', () => ({
@@ -1,7 +1,6 @@
1
- import { appEnv } from '@/config/app';
2
1
  import { SessionModel } from '@/database/models/session';
3
2
  import { LobeChatDatabase } from '@/database/type';
4
- import { parseAgentConfig } from '@/server/globalConfig/parseDefaultAgent';
3
+ import { getServerDefaultAgentConfig } from '@/server/globalConfig';
5
4
 
6
5
  export class AgentService {
7
6
  private readonly userId: string;
@@ -14,9 +13,7 @@ export class AgentService {
14
13
 
15
14
  async createInbox() {
16
15
  const sessionModel = new SessionModel(this.db, this.userId);
17
-
18
- const defaultAgentConfig = parseAgentConfig(appEnv.DEFAULT_AGENT_CONFIG) || {};
19
-
16
+ const defaultAgentConfig = getServerDefaultAgentConfig();
20
17
  await sessionModel.createInbox(defaultAgentConfig);
21
18
  }
22
19
  }
@@ -106,10 +106,7 @@ export class ClientService extends BaseClientService implements ISessionService
106
106
  };
107
107
 
108
108
  updateSessionConfig: ISessionService['updateSessionConfig'] = async (activeId, config) => {
109
- const session = await this.sessionModel.findByIdOrSlug(activeId);
110
- if (!session || !config) return;
111
-
112
- return this.sessionModel.updateConfig(session.agent.id, config as AgentItem);
109
+ return this.sessionModel.updateConfig(activeId, config as AgentItem);
113
110
  };
114
111
 
115
112
  updateSessionMeta: ISessionService['updateSessionMeta'] = async (activeId, meta) => {
@@ -11,6 +11,7 @@ vi.mock('i18next', () => ({
11
11
 
12
12
  // 定义一个变量来存储 enableAuth 的值
13
13
  let enableAuth = true;
14
+ let isDesktop = false;
14
15
 
15
16
  // 模拟 @/const/auth 模块
16
17
  vi.mock('@/const/auth', () => ({
@@ -19,14 +20,23 @@ vi.mock('@/const/auth', () => ({
19
20
  },
20
21
  }));
21
22
 
23
+ // 模拟 @/const/version 模块
24
+ vi.mock('@/const/version', () => ({
25
+ get isDesktop() {
26
+ return isDesktop;
27
+ },
28
+ }));
29
+
22
30
  afterEach(() => {
23
31
  enableAuth = true;
32
+ isDesktop = false;
24
33
  });
25
34
 
26
35
  describe('userProfileSelectors', () => {
27
36
  describe('nickName', () => {
28
- it('should return default nickname when auth is disabled', () => {
37
+ it('should return default nickname when auth is disabled and not desktop', () => {
29
38
  enableAuth = false;
39
+ isDesktop = false;
30
40
 
31
41
  const store: UserStore = {
32
42
  isSignedIn: false,
@@ -38,6 +48,19 @@ describe('userProfileSelectors', () => {
38
48
  expect(t).toHaveBeenCalledWith('userPanel.defaultNickname', { ns: 'common' });
39
49
  });
40
50
 
51
+ it('should return user fullName when auth is disabled and is desktop', () => {
52
+ enableAuth = false;
53
+ isDesktop = true;
54
+
55
+ const store: UserStore = {
56
+ isSignedIn: false,
57
+ user: { fullName: 'John Doe' },
58
+ enableAuth: () => false,
59
+ } as unknown as UserStore;
60
+
61
+ expect(userProfileSelectors.nickName(store)).toBe('John Doe');
62
+ });
63
+
41
64
  it('should return user fullName when signed in', () => {
42
65
  enableAuth = true;
43
66
 
@@ -75,8 +98,9 @@ describe('userProfileSelectors', () => {
75
98
  });
76
99
 
77
100
  describe('username', () => {
78
- it('should return default username when auth is disabled', () => {
101
+ it('should return default username when auth is disabled and not desktop', () => {
79
102
  enableAuth = false;
103
+ isDesktop = false;
80
104
 
81
105
  const store: UserStore = {
82
106
  isSignedIn: false,
@@ -87,6 +111,19 @@ describe('userProfileSelectors', () => {
87
111
  expect(userProfileSelectors.username(store)).toBe('LobeChat');
88
112
  });
89
113
 
114
+ it('should return user username when auth is disabled and is desktop', () => {
115
+ enableAuth = false;
116
+ isDesktop = true;
117
+
118
+ const store: UserStore = {
119
+ isSignedIn: false,
120
+ user: { username: 'johndoe' },
121
+ enableAuth: () => false,
122
+ } as unknown as UserStore;
123
+
124
+ expect(userProfileSelectors.username(store)).toBe('johndoe');
125
+ });
126
+
90
127
  it('should return user username when signed in', () => {
91
128
  const store: UserStore = {
92
129
  isSignedIn: true,
@@ -4,19 +4,31 @@ import { enableAuth, enableClerk, enableNextAuth } from '@/const/auth';
4
4
  import { BRANDING_NAME } from '@/const/branding';
5
5
  import { UserStore } from '@/store/user';
6
6
  import { LobeUser } from '@/types/user';
7
+ import { isDesktop } from '@/const/version';
7
8
 
8
9
  const DEFAULT_USERNAME = BRANDING_NAME;
9
10
 
10
11
  const nickName = (s: UserStore) => {
11
- if (!enableAuth) return t('userPanel.defaultNickname', { ns: 'common' });
12
+ const defaultNickName = s.user?.fullName || s.user?.username;
13
+ if (!enableAuth) {
14
+ if (isDesktop) {
15
+ return defaultNickName;
16
+ }
17
+ return t('userPanel.defaultNickname', { ns: 'common' });
18
+ }
12
19
 
13
- if (s.isSignedIn) return s.user?.fullName || s.user?.username;
20
+ if (s.isSignedIn) return defaultNickName;
14
21
 
15
22
  return t('userPanel.anonymousNickName', { ns: 'common' });
16
23
  };
17
24
 
18
25
  const username = (s: UserStore) => {
19
- if (!enableAuth) return DEFAULT_USERNAME;
26
+ if (!enableAuth) {
27
+ if (isDesktop) {
28
+ return s.user?.username;
29
+ }
30
+ return DEFAULT_USERNAME;
31
+ }
20
32
 
21
33
  if (s.isSignedIn) return s.user?.username;
22
34
 
@@ -83,6 +83,7 @@ describe('createCommonSlice', () => {
83
83
  settings: {
84
84
  general: { fontSize: 14 },
85
85
  },
86
+ email: 'test@example.com'
86
87
  };
87
88
 
88
89
  vi.spyOn(userService, 'getUserState').mockResolvedValueOnce(mockUserState);
@@ -104,6 +105,7 @@ describe('createCommonSlice', () => {
104
105
  // 验证状态是否正确更新
105
106
  expect(useUserStore.getState().user?.avatar).toBe(mockUserState.avatar);
106
107
  expect(useUserStore.getState().settings).toEqual(mockUserState.settings);
108
+ expect(useUserStore.getState().user?.email).toEqual(mockUserState.email);
107
109
  expect(successCallback).toHaveBeenCalledWith(mockUserState);
108
110
  });
109
111
 
@@ -93,6 +93,7 @@ export const createCommonSlice: StateCreator<
93
93
  data.avatar || data.userId
94
94
  ? merge(get().user, {
95
95
  avatar: data.avatar,
96
+ email: data.email,
96
97
  firstName: data.firstName,
97
98
  fullName: data.fullName,
98
99
  id: data.userId,