@lobehub/chat 1.88.0 → 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,39 @@
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
+
5
38
  ## [Version 1.88.0](https://github.com/lobehub/lobe-chat/compare/v1.87.9...v1.88.0)
6
39
 
7
40
  <sup>Released on **2025-05-23**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,16 @@
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
+ },
2
14
  {
3
15
  "children": {
4
16
  "features": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.88.0",
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",
@@ -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: {
@@ -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;
@@ -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