@lobehub/chat 1.36.0 → 1.36.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,64 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.36.2](https://github.com/lobehub/lobe-chat/compare/v1.36.1...v1.36.2)
6
+
7
+ <sup>Released on **2024-12-07**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Refactor async params route to adapt next15 breaking change.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Refactor async params route to adapt next15 breaking change, closes [#4905](https://github.com/lobehub/lobe-chat/issues/4905) ([5d61950](https://github.com/lobehub/lobe-chat/commit/5d61950))
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
+
30
+ ### [Version 1.36.1](https://github.com/lobehub/lobe-chat/compare/v1.36.0...v1.36.1)
31
+
32
+ <sup>Released on **2024-12-07**</sup>
33
+
34
+ #### ♻ Code Refactoring
35
+
36
+ - **misc**: Remove proxy url settings for NextAuth.
37
+
38
+ #### 💄 Styles
39
+
40
+ - **misc**: Add gemini-exp-1206 model.
41
+
42
+ <br/>
43
+
44
+ <details>
45
+ <summary><kbd>Improvements and Fixes</kbd></summary>
46
+
47
+ #### Code refactoring
48
+
49
+ - **misc**: Remove proxy url settings for NextAuth, closes [#4826](https://github.com/lobehub/lobe-chat/issues/4826) ([a502c17](https://github.com/lobehub/lobe-chat/commit/a502c17))
50
+
51
+ #### Styles
52
+
53
+ - **misc**: Add gemini-exp-1206 model, closes [#4909](https://github.com/lobehub/lobe-chat/issues/4909) ([9ff2c03](https://github.com/lobehub/lobe-chat/commit/9ff2c03))
54
+
55
+ </details>
56
+
57
+ <div align="right">
58
+
59
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
60
+
61
+ </div>
62
+
5
63
  ## [Version 1.36.0](https://github.com/lobehub/lobe-chat/compare/v1.35.14...v1.36.0)
6
64
 
7
65
  <sup>Released on **2024-12-06**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Refactor async params route to adapt next15 breaking change."
6
+ ]
7
+ },
8
+ "date": "2024-12-07",
9
+ "version": "1.36.2"
10
+ },
11
+ {
12
+ "children": {
13
+ "improvements": [
14
+ "Add gemini-exp-1206 model."
15
+ ]
16
+ },
17
+ "date": "2024-12-07",
18
+ "version": "1.36.1"
19
+ },
2
20
  {
3
21
  "children": {
4
22
  "features": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.36.0",
3
+ "version": "1.36.2",
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",
@@ -203,6 +203,7 @@
203
203
  "react-layout-kit": "^1.9.0",
204
204
  "react-lazy-load": "^4.0.1",
205
205
  "react-pdf": "^9.1.1",
206
+ "react-scan": "^0.0.40",
206
207
  "react-virtuoso": "^4.12.0",
207
208
  "react-wrap-balancer": "^1.1.1",
208
209
  "remark": "^14.0.3",
@@ -27,7 +27,7 @@ vi.mock('@/utils/server/jwt', () => ({
27
27
  describe('checkAuth', () => {
28
28
  const mockHandler: RequestHandler = vi.fn();
29
29
  const mockRequest = new Request('https://example.com');
30
- const mockOptions = { params: { provider: 'mock' } };
30
+ const mockOptions = { params: Promise.resolve({ provider: 'mock' }) };
31
31
 
32
32
  beforeEach(() => {
33
33
  vi.clearAllMocks();
@@ -11,7 +11,7 @@ import { getJWTPayload } from '@/utils/server/jwt';
11
11
  import { checkAuthMethod } from './utils';
12
12
 
13
13
  type CreateRuntime = (jwtPayload: JWTPayload) => AgentRuntime;
14
- type RequestOptions = { createRuntime?: CreateRuntime; params: { provider: string } };
14
+ type RequestOptions = { createRuntime?: CreateRuntime; params: Promise<{ provider: string }> };
15
15
 
16
16
  export type RequestHandler = (
17
17
  req: Request,
@@ -56,7 +56,8 @@ export const checkAuth =
56
56
 
57
57
  const error = errorContent || e;
58
58
 
59
- return createErrorResponse(errorType, { error, ...res, provider: options.params?.provider });
59
+ const params = await options.params;
60
+ return createErrorResponse(errorType, { error, ...res, provider: params?.provider });
60
61
  }
61
62
 
62
63
  return handler(req, { ...options, jwtPayload });
@@ -3,7 +3,11 @@ import { AssistantStore } from '@/server/modules/AssistantStore';
3
3
 
4
4
  export const runtime = 'edge';
5
5
 
6
- export const GET = async (req: Request, { params }: { params: { id: string } }) => {
6
+ type Params = Promise<{ id: string }>;
7
+
8
+ export const GET = async (req: Request, segmentData: { params: Params }) => {
9
+ const params = await segmentData.params;
10
+
7
11
  const { searchParams } = new URL(req.url);
8
12
 
9
13
  const locale = searchParams.get('locale');
@@ -58,7 +58,7 @@ afterEach(() => {
58
58
  describe('POST handler', () => {
59
59
  describe('init chat model', () => {
60
60
  it('should initialize AgentRuntime correctly with valid authorization', async () => {
61
- const mockParams = { provider: 'test-provider' };
61
+ const mockParams = Promise.resolve({ provider: 'test-provider' });
62
62
 
63
63
  // 设置 getJWTPayload 和 initAgentRuntimeWithUserPayload 的模拟返回值
64
64
  vi.mocked(getJWTPayload).mockResolvedValueOnce({
@@ -83,7 +83,7 @@ describe('POST handler', () => {
83
83
  });
84
84
 
85
85
  it('should return Unauthorized error when LOBE_CHAT_AUTH_HEADER is missing', async () => {
86
- const mockParams = { provider: 'test-provider' };
86
+ const mockParams = Promise.resolve({ provider: 'test-provider' });
87
87
  const requestWithoutAuthHeader = new Request(new URL('https://test.com'), {
88
88
  method: 'POST',
89
89
  body: JSON.stringify({ model: 'test-model' }),
@@ -110,7 +110,7 @@ describe('POST handler', () => {
110
110
  azureApiVersion: 'v1',
111
111
  });
112
112
 
113
- const mockParams = { provider: 'test-provider' };
113
+ const mockParams = Promise.resolve({ provider: 'test-provider' });
114
114
  // 设置 initAgentRuntimeWithUserPayload 的模拟返回值
115
115
  vi.mocked(getAuth).mockReturnValue({} as any);
116
116
  vi.mocked(checkAuthMethod).mockReset();
@@ -141,7 +141,7 @@ describe('POST handler', () => {
141
141
  });
142
142
 
143
143
  it('should return InternalServerError error when throw a unknown error', async () => {
144
- const mockParams = { provider: 'test-provider' };
144
+ const mockParams = Promise.resolve({ provider: 'test-provider' });
145
145
  vi.mocked(getJWTPayload).mockRejectedValueOnce(new Error('unknown error'));
146
146
 
147
147
  const response = await POST(request, { params: mockParams });
@@ -166,7 +166,7 @@ describe('POST handler', () => {
166
166
  userId: 'abc',
167
167
  });
168
168
 
169
- const mockParams = { provider: 'test-provider' };
169
+ const mockParams = Promise.resolve({ provider: 'test-provider' });
170
170
  const mockChatPayload = { message: 'Hello, world!' };
171
171
  request = new Request(new URL('https://test.com'), {
172
172
  headers: { [LOBE_CHAT_AUTH_HEADER]: 'Bearer some-valid-token' },
@@ -192,7 +192,7 @@ describe('POST handler', () => {
192
192
  azureApiVersion: 'v1',
193
193
  });
194
194
 
195
- const mockParams = { provider: 'test-provider' };
195
+ const mockParams = Promise.resolve({ provider: 'test-provider' });
196
196
  const mockChatPayload = { message: 'Hello, world!' };
197
197
  request = new Request(new URL('https://test.com'), {
198
198
  headers: { [LOBE_CHAT_AUTH_HEADER]: 'Bearer some-valid-token' },
@@ -13,7 +13,7 @@ import { getTracePayload } from '@/utils/trace';
13
13
  export const runtime = 'edge';
14
14
 
15
15
  export const POST = checkAuth(async (req: Request, { params, jwtPayload, createRuntime }) => {
16
- const { provider } = params;
16
+ const { provider } = await params;
17
17
 
18
18
  try {
19
19
  // ============ 1. init chat model ============ //
@@ -23,6 +23,8 @@ describe('Anthropic POST function tests', () => {
23
23
  it('should call UniverseRoute with correct parameters', async () => {
24
24
  const mockRequest = new Request('https://example.com', { method: 'POST' });
25
25
  await POST(mockRequest);
26
- expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, { params: { provider: 'anthropic' } });
26
+ expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, {
27
+ params: Promise.resolve({ provider: 'anthropic' }),
28
+ });
27
29
  });
28
30
  });
@@ -18,4 +18,4 @@ export const preferredRegion = [
18
18
  ];
19
19
 
20
20
  export const POST = async (req: Request) =>
21
- UniverseRoute(req, { params: { provider: 'anthropic' } });
21
+ UniverseRoute(req, { params: Promise.resolve({ provider: 'anthropic' }) });
@@ -28,6 +28,8 @@ describe('Google POST function tests', () => {
28
28
  it('should call UniverseRoute with correct parameters', async () => {
29
29
  const mockRequest = new Request('https://example.com', { method: 'POST' });
30
30
  await POST(mockRequest);
31
- expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, { params: { provider: 'google' } });
31
+ expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, {
32
+ params: Promise.resolve({ provider: 'google' }),
33
+ });
32
34
  });
33
35
  });
@@ -21,4 +21,5 @@ export const preferredRegion = [
21
21
  'gru1',
22
22
  ];
23
23
 
24
- export const POST = async (req: Request) => UniverseRoute(req, { params: { provider: 'google' } });
24
+ export const POST = async (req: Request) =>
25
+ UniverseRoute(req, { params: Promise.resolve({ provider: 'google' }) });
@@ -19,6 +19,8 @@ describe('Minimax POST function tests', () => {
19
19
  it('should call UniverseRoute with correct parameters', async () => {
20
20
  const mockRequest = new Request('https://example.com', { method: 'POST' });
21
21
  await POST(mockRequest);
22
- expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, { params: { provider: 'minimax' } });
22
+ expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, {
23
+ params: Promise.resolve({ provider: 'minimax' }),
24
+ });
23
25
  });
24
26
  });
@@ -2,4 +2,5 @@ import { POST as UniverseRoute } from '../[provider]/route';
2
2
 
3
3
  export const runtime = 'nodejs';
4
4
 
5
- export const POST = async (req: Request) => UniverseRoute(req, { params: { provider: 'minimax' } });
5
+ export const POST = async (req: Request) =>
6
+ UniverseRoute(req, { params: Promise.resolve({ provider: 'minimax' }) });
@@ -12,7 +12,7 @@ const noNeedAPIKey = (provider: string) =>
12
12
  [ModelProvider.OpenRouter, ModelProvider.TogetherAI].includes(provider as any);
13
13
 
14
14
  export const GET = checkAuth(async (req, { params, jwtPayload }) => {
15
- const { provider } = params;
15
+ const { provider } = await params;
16
16
 
17
17
  try {
18
18
  const hasDefaultApiKey = jwtPayload.apiKey || 'dont-need-api-key-for-model-list';
@@ -23,6 +23,8 @@ describe('OpenAI POST function tests', () => {
23
23
  it('should call UniverseRoute with correct parameters', async () => {
24
24
  const mockRequest = new Request('https://example.com', { method: 'POST' });
25
25
  await POST(mockRequest);
26
- expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, { params: { provider: 'openai' } });
26
+ expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, {
27
+ params: Promise.resolve({ provider: 'openai' }),
28
+ });
27
29
  });
28
30
  });
@@ -22,4 +22,5 @@ export const preferredRegion = [
22
22
  'syd1',
23
23
  ];
24
24
 
25
- export const POST = async (req: Request) => UniverseRoute(req, { params: { provider: 'openai' } });
25
+ export const POST = async (req: Request) =>
26
+ UniverseRoute(req, { params: Promise.resolve({ provider: 'openai' }) });
@@ -21,7 +21,7 @@ describe('Wenxin POST function tests', () => {
21
21
  await POST(mockRequest);
22
22
  expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, {
23
23
  createRuntime: expect.anything(),
24
- params: { provider: 'wenxin' },
24
+ params: Promise.resolve({ provider: 'wenxin' }),
25
25
  });
26
26
  });
27
27
  });
@@ -26,5 +26,5 @@ export const POST = async (req: Request) =>
26
26
 
27
27
  return new AgentRuntime(instance);
28
28
  },
29
- params: { provider: ModelProvider.Wenxin },
29
+ params: Promise.resolve({ provider: ModelProvider.Wenxin }),
30
30
  });
@@ -48,7 +48,7 @@ export const preferredRegion = [
48
48
  // );
49
49
 
50
50
  export const POST = checkAuth(async (req: Request, { params, jwtPayload }) => {
51
- const { provider } = params;
51
+ const { provider } = await params;
52
52
 
53
53
  try {
54
54
  // ============ 1. init chat model ============ //
@@ -0,0 +1,11 @@
1
+ import { Monitoring } from 'react-scan/dist/core/monitor/params/next';
2
+
3
+ interface ReactScanProps {
4
+ apiKey: string;
5
+ }
6
+
7
+ const ReactScan = ({ apiKey }: ReactScanProps) => (
8
+ <Monitoring apiKey={apiKey} url="https://monitoring.react-scan.com/api/v1/ingest" />
9
+ );
10
+
11
+ export default ReactScan;
@@ -9,6 +9,7 @@ const Plausible = dynamic(() => import('./Plausible'));
9
9
  const Posthog = dynamic(() => import('./Posthog'));
10
10
  const Umami = dynamic(() => import('./Umami'));
11
11
  const Clarity = dynamic(() => import('./Clarity'));
12
+ const ReactScan = dynamic(() => import('./ReactScan'));
12
13
 
13
14
  const Analytics = () => {
14
15
  return (
@@ -37,6 +38,9 @@ const Analytics = () => {
37
38
  {analyticsEnv.ENABLED_CLARITY_ANALYTICS && (
38
39
  <Clarity projectId={analyticsEnv.CLARITY_PROJECT_ID} />
39
40
  )}
41
+ {!!analyticsEnv.REACT_SCAN_MONITOR_API_KEY && (
42
+ <ReactScan apiKey={analyticsEnv.REACT_SCAN_MONITOR_API_KEY} />
43
+ )}
40
44
  </>
41
45
  );
42
46
  };
@@ -26,6 +26,8 @@ export const getAnalyticsConfig = () => {
26
26
 
27
27
  ENABLE_GOOGLE_ANALYTICS: z.boolean(),
28
28
  GOOGLE_ANALYTICS_MEASUREMENT_ID: z.string().optional(),
29
+
30
+ REACT_SCAN_MONITOR_API_KEY: z.string().optional(),
29
31
  },
30
32
  runtimeEnv: {
31
33
  // Plausible Analytics
@@ -55,6 +57,10 @@ export const getAnalyticsConfig = () => {
55
57
  // Google Analytics
56
58
  ENABLE_GOOGLE_ANALYTICS: !!process.env.GOOGLE_ANALYTICS_MEASUREMENT_ID,
57
59
  GOOGLE_ANALYTICS_MEASUREMENT_ID: process.env.GOOGLE_ANALYTICS_MEASUREMENT_ID,
60
+
61
+ // React Scan Monitor
62
+ // https://dashboard.react-scan.com
63
+ REACT_SCAN_MONITOR_API_KEY: process.env.REACT_SCAN_MONITOR_API_KEY,
58
64
  },
59
65
  });
60
66
  };
@@ -16,6 +16,8 @@ declare global {
16
16
 
17
17
  NEXT_AUTH_SSO_PROVIDERS?: string;
18
18
 
19
+ NEXT_AUTH_DEBUG?: string;
20
+
19
21
  AUTH0_CLIENT_ID?: string;
20
22
  AUTH0_CLIENT_SECRET?: string;
21
23
  AUTH0_ISSUER?: string;
@@ -156,6 +158,7 @@ export const getAuthConfig = () => {
156
158
  // NEXT-AUTH
157
159
  NEXT_AUTH_SECRET: z.string().optional(),
158
160
  NEXT_AUTH_SSO_PROVIDERS: z.string().optional().default('auth0'),
161
+ NEXT_AUTH_DEBUG: z.boolean().optional().default(false),
159
162
 
160
163
  // Auth0
161
164
  AUTH0_CLIENT_ID: z.string().optional(),
@@ -217,6 +220,7 @@ export const getAuthConfig = () => {
217
220
  NEXT_PUBLIC_ENABLE_NEXT_AUTH: !!process.env.NEXT_AUTH_SECRET,
218
221
  NEXT_AUTH_SSO_PROVIDERS: process.env.NEXT_AUTH_SSO_PROVIDERS,
219
222
  NEXT_AUTH_SECRET: process.env.NEXT_AUTH_SECRET,
223
+ NEXT_AUTH_DEBUG: !!process.env.NEXT_AUTH_DEBUG,
220
224
 
221
225
  // Auth0
222
226
  AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID,
@@ -5,10 +5,26 @@ const Google: ModelProviderCard = {
5
5
  chatModels: [
6
6
  {
7
7
  description:
8
- 'Gemini Exp 1121 是 Google 最新的实验性多模态AI模型,拥有改进的编码、推理和视觉能力。',
9
- displayName: 'Gemini Experimental 1121',
8
+ 'Gemini Exp 1206 是 Google 最新的实验性多模态AI模型,与历史版本相比有一定的质量提升。',
9
+ displayName: 'Gemini Experimental 1206',
10
10
  enabled: true,
11
11
  functionCall: true,
12
+ id: 'gemini-exp-1206',
13
+ maxOutput: 8192,
14
+ pricing: {
15
+ cachedInput: 0,
16
+ input: 0,
17
+ output: 0,
18
+ },
19
+ releasedAt: '2024-12-06',
20
+ tokens: 2_097_152 + 8192,
21
+ vision: true,
22
+ },
23
+ {
24
+ description:
25
+ 'Gemini Exp 1121 是 Google 的实验性多模态AI模型,拥有改进的编码、推理和视觉能力。',
26
+ displayName: 'Gemini Experimental 1121',
27
+ functionCall: true,
12
28
  id: 'gemini-exp-1121',
13
29
  maxOutput: 8192,
14
30
  pricing: {
@@ -1,5 +1,4 @@
1
1
  import type { NextAuthConfig } from 'next-auth';
2
- import urlJoin from 'url-join';
3
2
 
4
3
  import { authEnv } from '@/config/auth';
5
4
 
@@ -40,8 +39,8 @@ export default {
40
39
  return session;
41
40
  },
42
41
  },
42
+ debug: authEnv.NEXT_AUTH_DEBUG,
43
43
  providers: initSSOProviders(),
44
- redirectProxyUrl: process.env.APP_URL ? urlJoin(process.env.APP_URL, '/api/auth') : undefined,
45
44
  secret: authEnv.NEXT_AUTH_SECRET,
46
45
  trustHost: process.env?.AUTH_TRUST_HOST ? process.env.AUTH_TRUST_HOST === 'true' : true,
47
46
  } satisfies NextAuthConfig;