@lobehub/chat 0.150.1 → 0.150.3

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,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.150.3](https://github.com/lobehub/lobe-chat/compare/v0.150.2...v0.150.3)
6
+
7
+ <sup>Released on **2024-04-27**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Fix docker build.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Fix docker build, closes [#2236](https://github.com/lobehub/lobe-chat/issues/2236) ([749a843](https://github.com/lobehub/lobe-chat/commit/749a843))
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 0.150.2](https://github.com/lobehub/lobe-chat/compare/v0.150.1...v0.150.2)
31
+
32
+ <sup>Released on **2024-04-27**</sup>
33
+
34
+ #### 🐛 Bug Fixes
35
+
36
+ - **misc**: Fix display error when using `DEFAULT_AGENT_CONFIG` env.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's fixed
44
+
45
+ - **misc**: Fix display error when using `DEFAULT_AGENT_CONFIG` env, closes [#2231](https://github.com/lobehub/lobe-chat/issues/2231) ([42bc734](https://github.com/lobehub/lobe-chat/commit/42bc734))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 0.150.1](https://github.com/lobehub/lobe-chat/compare/v0.150.0...v0.150.1)
6
56
 
7
57
  <sup>Released on **2024-04-27**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.150.1",
3
+ "version": "0.150.3",
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",
@@ -82,6 +82,7 @@
82
82
  "dependencies": {
83
83
  "@ant-design/icons": "^5.3.6",
84
84
  "@anthropic-ai/sdk": "^0.18.0",
85
+ "@auth/core": "0.28.0",
85
86
  "@aws-sdk/client-bedrock-runtime": "^3.556.0",
86
87
  "@azure/openai": "^1.0.0-beta.12",
87
88
  "@cfworker/json-schema": "^1.12.8",
@@ -6,6 +6,7 @@ import { createStoreUpdater } from 'zustand-utils';
6
6
 
7
7
  import { useIsMobile } from '@/hooks/useIsMobile';
8
8
  import { useEnabledDataSync } from '@/hooks/useSyncData';
9
+ import { useAgentStore } from '@/store/agent';
9
10
  import { useGlobalStore } from '@/store/global';
10
11
 
11
12
  const StoreInitialization = memo(() => {
@@ -14,8 +15,10 @@ const StoreInitialization = memo(() => {
14
15
  s.useFetchUserConfig,
15
16
  s.useInitPreference,
16
17
  ]);
18
+ const useFetchDefaultAgentConfig = useAgentStore((s) => s.useFetchDefaultAgentConfig);
17
19
  // init the system preference
18
20
  useInitPreference();
21
+ useFetchDefaultAgentConfig();
19
22
 
20
23
  const { isLoading } = useFetchServerConfig();
21
24
  useFetchUserConfig(!isLoading);
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  import { NextRequest } from 'next/server';
3
3
 
4
- interface AuthContext {
4
+ export interface AuthContext {
5
5
  userId?: string | null;
6
6
  }
7
7
 
@@ -9,11 +9,9 @@ interface AuthContext {
9
9
  * Inner function for `createContext` where we create the context.
10
10
  * This is useful for testing when we don't want to mock Next.js' request/response
11
11
  */
12
- export function createContextInner(): AuthContext {
13
- return {
14
- userId: null,
15
- };
16
- }
12
+ export const createContextInner = async (): Promise<AuthContext> => ({
13
+ userId: null,
14
+ });
17
15
 
18
16
  export type Context = Awaited<ReturnType<typeof createContextInner>>;
19
17
 
@@ -0,0 +1,8 @@
1
+ /**
2
+ * This file contains the root router of your tRPC-backend
3
+ */
4
+ import { createCallerFactory } from '@/libs/trpc';
5
+
6
+ import { appRouter } from './routers';
7
+
8
+ export const createCaller = createCallerFactory(appRouter);
@@ -1,6 +1,6 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`GET /api/config > Model Provider env > CUSTOM_MODELS > custom deletion, addition, and renaming of models 1`] = `
3
+ exports[`configRouter > getGlobalConfig > Model Provider env > CUSTOM_MODELS > custom deletion, addition, and renaming of models 1`] = `
4
4
  [
5
5
  {
6
6
  "displayName": "llama",
@@ -22,7 +22,7 @@ exports[`GET /api/config > Model Provider env > CUSTOM_MODELS > custom deletion,
22
22
  ]
23
23
  `;
24
24
 
25
- exports[`GET /api/config > Model Provider env > OPENAI_MODEL_LIST > custom deletion, addition, and renaming of models 1`] = `
25
+ exports[`configRouter > getGlobalConfig > Model Provider env > OPENAI_MODEL_LIST > custom deletion, addition, and renaming of models 1`] = `
26
26
  {
27
27
  "enabledModels": [
28
28
  "llama",
@@ -51,7 +51,7 @@ exports[`GET /api/config > Model Provider env > OPENAI_MODEL_LIST > custom delet
51
51
  }
52
52
  `;
53
53
 
54
- exports[`GET /api/config > Model Provider env > OPENAI_MODEL_LIST > should work correct with gpt-4 1`] = `
54
+ exports[`configRouter > getGlobalConfig > Model Provider env > OPENAI_MODEL_LIST > should work correct with gpt-4 1`] = `
55
55
  [
56
56
  {
57
57
  "displayName": "GPT-3.5 Turbo (1106)",
@@ -106,7 +106,7 @@ exports[`GET /api/config > Model Provider env > OPENAI_MODEL_LIST > should work
106
106
  ]
107
107
  `;
108
108
 
109
- exports[`GET /api/config > Model Provider env > OPENROUTER_MODEL_LIST > custom deletion, addition, and renaming of models 1`] = `
109
+ exports[`configRouter > getGlobalConfig > Model Provider env > OPENROUTER_MODEL_LIST > custom deletion, addition, and renaming of models 1`] = `
110
110
  {
111
111
  "enabled": false,
112
112
  "enabledModels": [
@@ -0,0 +1,194 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+
3
+ /**
4
+ * This file contains the root router of your tRPC-backend
5
+ */
6
+ import { createCallerFactory } from '@/libs/trpc';
7
+ import { AuthContext, createContextInner } from '@/server/context';
8
+ import { GlobalServerConfig } from '@/types/serverConfig';
9
+
10
+ import { configRouter } from './index';
11
+
12
+ const createCaller = createCallerFactory(configRouter);
13
+ let ctx: AuthContext;
14
+ let router: ReturnType<typeof createCaller>;
15
+
16
+ beforeEach(async () => {
17
+ vi.resetAllMocks();
18
+ ctx = await createContextInner();
19
+ router = createCaller(ctx);
20
+ });
21
+
22
+ describe('configRouter', () => {
23
+ describe('getGlobalConfig', () => {
24
+ describe('Model Provider env', () => {
25
+ describe('OPENAI_MODEL_LIST', () => {
26
+ it('custom deletion, addition, and renaming of models', async () => {
27
+ process.env.OPENAI_MODEL_LIST =
28
+ '-all,+llama,+claude-2,-gpt-3.5-turbo,gpt-4-0125-preview=gpt-4-turbo,gpt-4-0125-preview=gpt-4-32k';
29
+
30
+ const response = await router.getGlobalConfig();
31
+
32
+ // Assert
33
+ const result = response.languageModel?.openai;
34
+
35
+ expect(result).toMatchSnapshot();
36
+ process.env.OPENAI_MODEL_LIST = '';
37
+ });
38
+
39
+ it('should work correct with gpt-4', async () => {
40
+ process.env.OPENAI_MODEL_LIST =
41
+ '-all,+gpt-3.5-turbo-1106,+gpt-3.5-turbo,+gpt-3.5-turbo-16k,+gpt-4,+gpt-4-32k,+gpt-4-1106-preview,+gpt-4-vision-preview';
42
+
43
+ const response = await router.getGlobalConfig();
44
+
45
+ const result = response.languageModel?.openai?.serverModelCards;
46
+
47
+ expect(result).toMatchSnapshot();
48
+
49
+ process.env.OPENAI_MODEL_LIST = '';
50
+ });
51
+
52
+ it('duplicate naming model', async () => {
53
+ process.env.OPENAI_MODEL_LIST =
54
+ 'gpt-4-0125-preview=gpt-4-turbo,gpt-4-0125-preview=gpt-4-32k';
55
+
56
+ const response = await router.getGlobalConfig();
57
+
58
+ const result = response.languageModel?.openai?.serverModelCards;
59
+
60
+ expect(result?.find((s) => s.id === 'gpt-4-0125-preview')?.displayName).toEqual(
61
+ 'gpt-4-32k',
62
+ );
63
+
64
+ process.env.OPENAI_MODEL_LIST = '';
65
+ });
66
+
67
+ it('should delete model', async () => {
68
+ process.env.OPENAI_MODEL_LIST = '-gpt-4';
69
+
70
+ const response = await router.getGlobalConfig();
71
+
72
+ const result = response.languageModel?.openai?.serverModelCards;
73
+
74
+ expect(result?.find((r) => r.id === 'gpt-4')).toBeUndefined();
75
+
76
+ process.env.OPENAI_MODEL_LIST = '';
77
+ });
78
+
79
+ it('show the hidden model', async () => {
80
+ process.env.OPENAI_MODEL_LIST = '+gpt-4-1106-preview';
81
+
82
+ const response = await router.getGlobalConfig();
83
+
84
+ const result = response.languageModel?.openai?.serverModelCards;
85
+
86
+ expect(result?.find((o) => o.id === 'gpt-4-1106-preview')).toEqual({
87
+ displayName: 'GPT-4 Turbo Preview (1106)',
88
+ functionCall: true,
89
+ enabled: true,
90
+ id: 'gpt-4-1106-preview',
91
+ tokens: 128000,
92
+ });
93
+
94
+ process.env.OPENAI_MODEL_LIST = '';
95
+ });
96
+
97
+ it('only add the model', async () => {
98
+ process.env.OPENAI_MODEL_LIST = 'model1,model2,model3,model4';
99
+
100
+ const response = await router.getGlobalConfig();
101
+
102
+ const result = response.languageModel?.openai?.serverModelCards;
103
+
104
+ expect(result).toContainEqual({
105
+ displayName: 'model1',
106
+ id: 'model1',
107
+ enabled: true,
108
+ });
109
+ expect(result).toContainEqual({
110
+ displayName: 'model2',
111
+ enabled: true,
112
+ id: 'model2',
113
+ });
114
+ expect(result).toContainEqual({
115
+ displayName: 'model3',
116
+ enabled: true,
117
+ id: 'model3',
118
+ });
119
+ expect(result).toContainEqual({
120
+ displayName: 'model4',
121
+ enabled: true,
122
+ id: 'model4',
123
+ });
124
+
125
+ process.env.OPENAI_MODEL_LIST = '';
126
+ });
127
+ });
128
+
129
+ describe('CUSTOM_MODELS', () => {
130
+ it('custom deletion, addition, and renaming of models', async () => {
131
+ process.env.CUSTOM_MODELS =
132
+ '-all,+llama,+claude-2,-gpt-3.5-turbo,gpt-4-0125-preview=gpt-4-turbo,gpt-4-0125-preview=gpt-4-32k';
133
+
134
+ const response = await router.getGlobalConfig();
135
+
136
+ // Assert
137
+ const result = response.languageModel?.openai?.serverModelCards;
138
+
139
+ expect(result).toMatchSnapshot();
140
+ });
141
+ });
142
+
143
+ describe('OPENROUTER_MODEL_LIST', () => {
144
+ it('custom deletion, addition, and renaming of models', async () => {
145
+ process.env.OPENROUTER_MODEL_LIST =
146
+ '-all,+google/gemma-7b-it,+mistralai/mistral-7b-instruct=Mistral-7B-Instruct';
147
+
148
+ const response = await router.getGlobalConfig();
149
+
150
+ // Assert
151
+ const result = response.languageModel?.openrouter;
152
+
153
+ expect(result).toMatchSnapshot();
154
+
155
+ process.env.OPENROUTER_MODEL_LIST = '';
156
+ });
157
+ });
158
+ });
159
+ });
160
+
161
+ describe('getDefaultAgentConfig', () => {
162
+ it('should return the default agent config', async () => {
163
+ process.env.DEFAULT_AGENT_CONFIG =
164
+ 'plugins=search-engine,lobe-image-designer;enableAutoCreateTopic=true;model=gemini-pro;provider=google;';
165
+
166
+ const response = await router.getDefaultAgentConfig();
167
+
168
+ expect(response).toEqual({
169
+ enableAutoCreateTopic: true,
170
+ model: 'gemini-pro',
171
+ plugins: ['search-engine', 'lobe-image-designer'],
172
+ provider: 'google',
173
+ });
174
+
175
+ process.env.DEFAULT_AGENT_CONFIG = '';
176
+ });
177
+
178
+ it('should return another config', async () => {
179
+ process.env.DEFAULT_AGENT_CONFIG =
180
+ 'model=meta-11ama/11ama-3-70b-instruct:nitro;provider=openrouter;enableAutoCreateTopic=true;params.max_tokens=700';
181
+
182
+ const response = await router.getDefaultAgentConfig();
183
+
184
+ expect(response).toEqual({
185
+ enableAutoCreateTopic: true,
186
+ model: 'meta-11ama/11ama-3-70b-instruct:nitro',
187
+ params: { max_tokens: 700 },
188
+ provider: 'openrouter',
189
+ });
190
+
191
+ process.env.DEFAULT_AGENT_CONFIG = '';
192
+ });
193
+ });
194
+ });
@@ -0,0 +1,121 @@
1
+ import {
2
+ OllamaProviderCard,
3
+ OpenAIProviderCard,
4
+ OpenRouterProviderCard,
5
+ TogetherAIProviderCard,
6
+ } from '@/config/modelProviders';
7
+ import { getServerConfig } from '@/config/server';
8
+ import { publicProcedure, router } from '@/libs/trpc';
9
+ import { parseAgentConfig } from '@/server/routers/config/parseDefaultAgent';
10
+ import { GlobalServerConfig } from '@/types/serverConfig';
11
+ import { extractEnabledModels, transformToChatModelCards } from '@/utils/parseModels';
12
+
13
+ export const configRouter = router({
14
+ getDefaultAgentConfig: publicProcedure.query(async () => {
15
+ const { DEFAULT_AGENT_CONFIG } = getServerConfig();
16
+
17
+ return parseAgentConfig(DEFAULT_AGENT_CONFIG) || {};
18
+ }),
19
+
20
+ getGlobalConfig: publicProcedure.query(async () => {
21
+ const {
22
+ ENABLE_LANGFUSE,
23
+ ENABLE_OAUTH_SSO,
24
+
25
+ DEFAULT_AGENT_CONFIG,
26
+ OPENAI_MODEL_LIST,
27
+
28
+ ENABLED_MOONSHOT,
29
+ ENABLED_ZHIPU,
30
+ ENABLED_AWS_BEDROCK,
31
+ ENABLED_GOOGLE,
32
+ ENABLED_GROQ,
33
+ ENABLED_PERPLEXITY,
34
+ ENABLED_ANTHROPIC,
35
+ ENABLED_MISTRAL,
36
+
37
+ ENABLED_AZURE_OPENAI,
38
+ AZURE_MODEL_LIST,
39
+
40
+ ENABLE_OLLAMA,
41
+ OLLAMA_MODEL_LIST,
42
+ OLLAMA_PROXY_URL,
43
+
44
+ ENABLED_OPENROUTER,
45
+ OPENROUTER_MODEL_LIST,
46
+
47
+ ENABLED_ZEROONE,
48
+ ENABLED_TOGETHERAI,
49
+ TOGETHERAI_MODEL_LIST,
50
+ } = getServerConfig();
51
+
52
+ const config: GlobalServerConfig = {
53
+ defaultAgent: {
54
+ config: parseAgentConfig(DEFAULT_AGENT_CONFIG),
55
+ },
56
+
57
+ enabledOAuthSSO: ENABLE_OAUTH_SSO,
58
+ languageModel: {
59
+ anthropic: {
60
+ enabled: ENABLED_ANTHROPIC,
61
+ },
62
+ azure: {
63
+ enabled: ENABLED_AZURE_OPENAI,
64
+ enabledModels: extractEnabledModels(AZURE_MODEL_LIST, true),
65
+ serverModelCards: transformToChatModelCards({
66
+ defaultChatModels: [],
67
+ modelString: AZURE_MODEL_LIST,
68
+ withDeploymentName: true,
69
+ }),
70
+ },
71
+ bedrock: { enabled: ENABLED_AWS_BEDROCK },
72
+ google: { enabled: ENABLED_GOOGLE },
73
+ groq: { enabled: ENABLED_GROQ },
74
+ mistral: { enabled: ENABLED_MISTRAL },
75
+ moonshot: { enabled: ENABLED_MOONSHOT },
76
+ ollama: {
77
+ enabled: ENABLE_OLLAMA,
78
+ fetchOnClient: !OLLAMA_PROXY_URL,
79
+ serverModelCards: transformToChatModelCards({
80
+ defaultChatModels: OllamaProviderCard.chatModels,
81
+ modelString: OLLAMA_MODEL_LIST,
82
+ }),
83
+ },
84
+ openai: {
85
+ enabledModels: extractEnabledModels(OPENAI_MODEL_LIST),
86
+ serverModelCards: transformToChatModelCards({
87
+ defaultChatModels: OpenAIProviderCard.chatModels,
88
+ modelString: OPENAI_MODEL_LIST,
89
+ }),
90
+ },
91
+
92
+ openrouter: {
93
+ enabled: ENABLED_OPENROUTER,
94
+ enabledModels: extractEnabledModels(OPENROUTER_MODEL_LIST),
95
+ serverModelCards: transformToChatModelCards({
96
+ defaultChatModels: OpenRouterProviderCard.chatModels,
97
+ modelString: OPENROUTER_MODEL_LIST,
98
+ }),
99
+ },
100
+ perplexity: { enabled: ENABLED_PERPLEXITY },
101
+
102
+ togetherai: {
103
+ enabled: ENABLED_TOGETHERAI,
104
+ enabledModels: extractEnabledModels(TOGETHERAI_MODEL_LIST),
105
+ serverModelCards: transformToChatModelCards({
106
+ defaultChatModels: TogetherAIProviderCard.chatModels,
107
+ modelString: TOGETHERAI_MODEL_LIST,
108
+ }),
109
+ },
110
+
111
+ zeroone: { enabled: ENABLED_ZEROONE },
112
+ zhipu: { enabled: ENABLED_ZHIPU },
113
+ },
114
+ telemetry: {
115
+ langfuse: ENABLE_LANGFUSE,
116
+ },
117
+ };
118
+
119
+ return config;
120
+ }),
121
+ });
@@ -3,7 +3,10 @@
3
3
  */
4
4
  import { publicProcedure, router } from '@/libs/trpc';
5
5
 
6
+ import { configRouter } from './config';
7
+
6
8
  export const appRouter = router({
9
+ config: configRouter,
7
10
  healthcheck: publicProcedure.query(() => "i'm live!"),
8
11
  });
9
12
 
@@ -1,5 +1,9 @@
1
1
  import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
2
2
 
3
+ import { trpcClient } from '@/libs/trpc/client';
4
+ import { LobeAgentConfig } from '@/types/agent';
5
+ import { GlobalServerConfig } from '@/types/serverConfig';
6
+
3
7
  import { globalService } from '../global';
4
8
 
5
9
  global.fetch = vi.fn();
@@ -8,6 +12,17 @@ beforeEach(() => {
8
12
  vi.clearAllMocks();
9
13
  });
10
14
 
15
+ vi.mock('@/libs/trpc/client', () => {
16
+ return {
17
+ trpcClient: {
18
+ config: {
19
+ getGlobalConfig: { query: vi.fn() },
20
+ getDefaultAgentConfig: { query: vi.fn() },
21
+ },
22
+ },
23
+ };
24
+ });
25
+
11
26
  describe('GlobalService', () => {
12
27
  describe('getLatestVersion', () => {
13
28
  it('should return the latest version when fetch is successful', async () => {
@@ -60,15 +75,27 @@ describe('GlobalService', () => {
60
75
  describe('ServerConfig', () => {
61
76
  it('should return the serverConfig when fetch is successful', async () => {
62
77
  // Arrange
63
- (fetch as Mock).mockResolvedValue({
64
- json: () => Promise.resolve({ customModelName: 'abc' }),
65
- });
78
+ const mockConfig = { enabledOAuthSSO: true } as GlobalServerConfig;
79
+ vi.spyOn(trpcClient.config.getGlobalConfig, 'query').mockResolvedValue(mockConfig);
66
80
 
67
81
  // Act
68
82
  const config = await globalService.getGlobalConfig();
69
83
 
70
84
  // Assert
71
- expect(config).toEqual({ customModelName: 'abc' });
85
+ expect(config).toEqual({ enabledOAuthSSO: true });
86
+ });
87
+
88
+ it('should return the defaultAgentConfig when fetch is successful', async () => {
89
+ // Arrange
90
+ vi.spyOn(trpcClient.config.getDefaultAgentConfig, 'query').mockResolvedValue({
91
+ model: 'gemini-pro',
92
+ });
93
+
94
+ // Act
95
+ const config = await globalService.getDefaultAgentConfig();
96
+
97
+ // Assert
98
+ expect(config).toEqual({ model: 'gemini-pro' });
72
99
  });
73
100
  });
74
101
  });
@@ -15,7 +15,6 @@ const mapWithBasePath = <T extends object>(apis: T): T => {
15
15
  };
16
16
 
17
17
  export const API_ENDPOINTS = mapWithBasePath({
18
- config: '/api/config',
19
18
  proxy: '/api/proxy',
20
19
  oauth: '/api/auth',
21
20
 
@@ -1,9 +1,11 @@
1
+ import { DeepPartial } from 'utility-types';
2
+
1
3
  import { dataSync } from '@/database/client/core';
4
+ import { trpcClient } from '@/libs/trpc/client';
5
+ import { LobeAgentConfig } from '@/types/agent';
2
6
  import { GlobalServerConfig } from '@/types/serverConfig';
3
7
  import { StartDataSyncParams } from '@/types/sync';
4
8
 
5
- import { API_ENDPOINTS } from './_url';
6
-
7
9
  const VERSION_URL = 'https://registry.npmmirror.com/@lobehub/chat';
8
10
 
9
11
  class GlobalService {
@@ -18,9 +20,11 @@ class GlobalService {
18
20
  };
19
21
 
20
22
  getGlobalConfig = async (): Promise<GlobalServerConfig> => {
21
- const res = await fetch(API_ENDPOINTS.config);
23
+ return trpcClient.config.getGlobalConfig.query();
24
+ };
22
25
 
23
- return res.json();
26
+ getDefaultAgentConfig = async (): Promise<DeepPartial<LobeAgentConfig>> => {
27
+ return trpcClient.config.getDefaultAgentConfig.query();
24
28
  };
25
29
 
26
30
  enabledSync = async (params: StartDataSyncParams) => {
@@ -1,7 +1,7 @@
1
- import { AgentState, initialSessionState } from './slices/chat/initialState';
1
+ import { AgentState, initialAgentChatState } from './slices/chat/initialState';
2
2
 
3
3
  export type SessionStoreState = AgentState;
4
4
 
5
5
  export const initialState: SessionStoreState = {
6
- ...initialSessionState,
6
+ ...initialAgentChatState,
7
7
  };
@@ -1,11 +1,22 @@
1
- import { act, renderHook } from '@testing-library/react';
2
- import * as immer from 'immer';
1
+ import { act, renderHook, waitFor } from '@testing-library/react';
2
+ import { mutate } from 'swr';
3
3
  import { describe, expect, it, vi } from 'vitest';
4
4
 
5
+ import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
6
+ import { globalService } from '@/services/global';
5
7
  import { sessionService } from '@/services/session';
6
8
  import { useAgentStore } from '@/store/agent';
7
9
  import { agentSelectors } from '@/store/agent/selectors';
8
- import { useGlobalStore } from '@/store/global';
10
+ import { useSessionStore } from '@/store/session';
11
+
12
+ vi.mock('zustand/traditional');
13
+ vi.mock('swr', async (importOriginal) => {
14
+ const origin = await importOriginal();
15
+ return {
16
+ ...(origin as any),
17
+ mutate: vi.fn(),
18
+ };
19
+ });
9
20
 
10
21
  describe('AgentSlice', () => {
11
22
  describe('removePlugin', () => {
@@ -135,4 +146,146 @@ describe('AgentSlice', () => {
135
146
  updateSessionConfigMock.mockRestore();
136
147
  });
137
148
  });
149
+
150
+ describe('useFetchAgentConfig', () => {
151
+ it('should update agentConfig and isAgentConfigInit when data changes and isAgentConfigInit is false', async () => {
152
+ const { result } = renderHook(() => useAgentStore());
153
+
154
+ act(() => {
155
+ result.current.isAgentConfigInit = false;
156
+ result.current.agentConfig = { model: 'gpt-3.5-turbo' };
157
+ });
158
+
159
+ vi.spyOn(sessionService, 'getSessionConfig').mockResolvedValueOnce({ model: 'gpt-4' } as any);
160
+
161
+ renderHook(() => result.current.useFetchAgentConfig('test-session-id'));
162
+
163
+ await waitFor(() => {
164
+ expect(result.current.agentConfig).toEqual({ model: 'gpt-4' });
165
+ expect(result.current.isAgentConfigInit).toBe(true);
166
+ });
167
+ });
168
+
169
+ it('should not update state when data is the same and isAgentConfigInit is true', async () => {
170
+ const { result } = renderHook(() => useAgentStore());
171
+
172
+ act(() => {
173
+ useAgentStore.setState({ isAgentConfigInit: true });
174
+ });
175
+
176
+ vi.spyOn(useSessionStore, 'setState');
177
+ vi.spyOn(sessionService, 'getSessionConfig').mockResolvedValueOnce({
178
+ model: 'gpt-3.5-turbo',
179
+ } as any);
180
+
181
+ renderHook(() => result.current.useFetchAgentConfig('test-session-id'));
182
+
183
+ await waitFor(() => {
184
+ expect(result.current.agentConfig).toEqual({ model: 'gpt-3.5-turbo' });
185
+ expect(result.current.isAgentConfigInit).toBe(true);
186
+
187
+ expect(useSessionStore.setState).not.toHaveBeenCalled();
188
+ });
189
+ });
190
+ });
191
+
192
+ describe('useFetchDefaultAgentConfig', () => {
193
+ it('should merge DEFAULT_AGENT_CONFIG and update defaultAgentConfig and isDefaultAgentConfigInit on success', async () => {
194
+ const { result } = renderHook(() => useAgentStore());
195
+ vi.spyOn(globalService, 'getDefaultAgentConfig').mockResolvedValue({ model: 'gemini-pro' });
196
+
197
+ renderHook(() => result.current.useFetchDefaultAgentConfig());
198
+
199
+ await waitFor(async () => {
200
+ expect(result.current.defaultAgentConfig).toEqual({
201
+ ...DEFAULT_AGENT_CONFIG,
202
+ model: 'gemini-pro',
203
+ });
204
+ expect(result.current.isDefaultAgentConfigInit).toBe(true);
205
+ });
206
+ });
207
+
208
+ it('should not modify state on failure', async () => {
209
+ const { result } = renderHook(() => useAgentStore());
210
+
211
+ vi.spyOn(globalService, 'getDefaultAgentConfig').mockRejectedValueOnce(new Error());
212
+
213
+ renderHook(() => result.current.useFetchDefaultAgentConfig());
214
+
215
+ await waitFor(async () => {
216
+ expect(result.current.defaultAgentConfig).toEqual(DEFAULT_AGENT_CONFIG);
217
+ expect(result.current.isDefaultAgentConfigInit).toBe(false);
218
+ });
219
+ });
220
+ });
221
+
222
+ describe('internal_updateAgentConfig', () => {
223
+ it('should call sessionService.updateSessionConfig', async () => {
224
+ const { result } = renderHook(() => useAgentStore());
225
+
226
+ const updateSessionConfigMock = vi.spyOn(sessionService, 'updateSessionConfig');
227
+
228
+ await act(async () => {
229
+ await result.current.internal_updateAgentConfig('test-session-id', { foo: 'bar' } as any);
230
+ });
231
+
232
+ expect(updateSessionConfigMock).toHaveBeenCalledWith('test-session-id', { foo: 'bar' });
233
+ });
234
+
235
+ it('should trigger internal_refreshAgentConfig', async () => {
236
+ const { result } = renderHook(() => useAgentStore());
237
+
238
+ const refreshMock = vi.spyOn(result.current, 'internal_refreshAgentConfig');
239
+
240
+ await act(async () => {
241
+ await result.current.internal_updateAgentConfig('test-session-id', {});
242
+ });
243
+
244
+ expect(refreshMock).toHaveBeenCalledWith('test-session-id');
245
+ });
246
+
247
+ it('should trigger useSessionStore.refreshSessions when model changes', async () => {
248
+ const { result } = renderHook(() => useAgentStore());
249
+
250
+ vi.spyOn(agentSelectors, 'currentAgentModel').mockReturnValueOnce('gpt-3.5-turbo');
251
+
252
+ const refreshSessionsMock = vi.spyOn(useSessionStore.getState(), 'refreshSessions');
253
+
254
+ await act(async () => {
255
+ await result.current.internal_updateAgentConfig('test-session-id', { model: 'gpt-4' });
256
+ });
257
+
258
+ expect(refreshSessionsMock).toHaveBeenCalled();
259
+ });
260
+ });
261
+
262
+ describe('internal_refreshAgentConfig', () => {
263
+ it('should call mutate with correct key', async () => {
264
+ const { result } = renderHook(() => useAgentStore());
265
+
266
+ await act(async () => {
267
+ await result.current.internal_refreshAgentConfig('test-session-id');
268
+ });
269
+
270
+ expect(mutate).toHaveBeenCalledWith(['FETCH_AGENT_CONFIG', 'test-session-id']);
271
+ });
272
+ });
273
+
274
+ describe('edge cases', () => {
275
+ it('should not update config if activeId is null', async () => {
276
+ const { result } = renderHook(() => useAgentStore());
277
+
278
+ act(() => {
279
+ useAgentStore.setState({ activeId: null } as any);
280
+ });
281
+
282
+ const updateMock = vi.spyOn(result.current, 'internal_updateAgentConfig');
283
+
284
+ await act(async () => {
285
+ await result.current.updateAgentConfig({});
286
+ });
287
+
288
+ expect(updateMock).not.toHaveBeenCalled();
289
+ });
290
+ });
138
291
  });
@@ -1,10 +1,12 @@
1
1
  import isEqual from 'fast-deep-equal';
2
2
  import { produce } from 'immer';
3
- import { SWRResponse, mutate } from 'swr';
3
+ import useSWR, { SWRResponse, mutate } from 'swr';
4
4
  import { DeepPartial } from 'utility-types';
5
5
  import { StateCreator } from 'zustand/vanilla';
6
6
 
7
+ import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
7
8
  import { useClientDataSWR } from '@/libs/swr';
9
+ import { globalService } from '@/services/global';
8
10
  import { sessionService } from '@/services/session';
9
11
  import { useSessionStore } from '@/store/session';
10
12
  import { LobeAgentConfig } from '@/types/agent';
@@ -22,6 +24,7 @@ export interface AgentChatAction {
22
24
  updateAgentConfig: (config: Partial<LobeAgentConfig>) => Promise<void>;
23
25
 
24
26
  useFetchAgentConfig: (id: string) => SWRResponse<LobeAgentConfig>;
27
+ useFetchDefaultAgentConfig: () => SWRResponse<DeepPartial<LobeAgentConfig>>;
25
28
 
26
29
  /* eslint-disable typescript-sort-keys/interface */
27
30
 
@@ -73,7 +76,6 @@ export const createChatSlice: StateCreator<
73
76
 
74
77
  await get().internal_updateAgentConfig(activeId, config);
75
78
  },
76
-
77
79
  useFetchAgentConfig: (sessionId) =>
78
80
  useClientDataSWR<LobeAgentConfig>(
79
81
  [FETCH_AGENT_CONFIG_KEY, sessionId],
@@ -86,6 +88,26 @@ export const createChatSlice: StateCreator<
86
88
  },
87
89
  },
88
90
  ),
91
+ useFetchDefaultAgentConfig: () =>
92
+ useSWR<DeepPartial<LobeAgentConfig>>(
93
+ 'fetchDefaultAgentConfig',
94
+ globalService.getDefaultAgentConfig,
95
+ {
96
+ onSuccess: (data) => {
97
+ if (data) {
98
+ set(
99
+ {
100
+ defaultAgentConfig: merge(DEFAULT_AGENT_CONFIG, data),
101
+ isDefaultAgentConfigInit: true,
102
+ },
103
+ false,
104
+ 'fetchDefaultAgentConfig',
105
+ );
106
+ }
107
+ },
108
+ revalidateOnFocus: false,
109
+ },
110
+ ),
89
111
 
90
112
  /* eslint-disable sort-keys-fix/sort-keys-fix */
91
113
 
@@ -1,14 +1,20 @@
1
+ import { DeepPartial } from 'utility-types';
2
+
1
3
  import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
2
4
  import { LobeAgentConfig } from '@/types/agent';
3
5
 
4
6
  export interface AgentState {
5
7
  activeId: string;
6
- agentConfig: LobeAgentConfig;
8
+ agentConfig: DeepPartial<LobeAgentConfig>;
9
+ defaultAgentConfig: LobeAgentConfig;
7
10
  isAgentConfigInit: boolean;
11
+ isDefaultAgentConfigInit: boolean;
8
12
  }
9
13
 
10
- export const initialSessionState: AgentState = {
14
+ export const initialAgentChatState: AgentState = {
11
15
  activeId: 'inbox',
12
- agentConfig: DEFAULT_AGENT_CONFIG,
16
+ agentConfig: {},
17
+ defaultAgentConfig: DEFAULT_AGENT_CONFIG,
13
18
  isAgentConfigInit: false,
19
+ isDefaultAgentConfigInit: false,
14
20
  };
@@ -1,5 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
 
3
+ import { INBOX_SESSION_ID } from '@/const/session';
3
4
  import { DEFAULT_AGENT_CONFIG, DEFAUTT_AGENT_TTS_CONFIG } from '@/const/settings';
4
5
  import { AgentStore } from '@/store/agent';
5
6
 
@@ -76,7 +77,129 @@ describe('agentSelectors', () => {
76
77
  it('should return the appropriate TTS voice based on the service and language', () => {
77
78
  const lang = 'en';
78
79
  const ttsVoice = agentSelectors.currentAgentTTSVoice(lang)(mockSessionStore);
79
- expect(ttsVoice).toBe(mockSessionStore.agentConfig.tts.voice.openai);
80
+ expect(ttsVoice).toBe(mockSessionStore.agentConfig.tts?.voice?.openai);
81
+ });
82
+
83
+ it('should return the default voice for edge TTS service', () => {
84
+ const modifiedStore = {
85
+ ...mockSessionStore,
86
+ agentConfig: {
87
+ ...mockSessionStore.agentConfig,
88
+ tts: {
89
+ ...DEFAUTT_AGENT_TTS_CONFIG,
90
+ ttsService: 'edge',
91
+ },
92
+ },
93
+ } as AgentStore;
94
+ const ttsVoice = agentSelectors.currentAgentTTSVoice('en')(modifiedStore);
95
+ expect(ttsVoice).toBe('ar-SA-HamedNeural');
96
+ });
97
+
98
+ it('should return the default voice for microsoft TTS service', () => {
99
+ const modifiedStore = {
100
+ ...mockSessionStore,
101
+ agentConfig: {
102
+ ...mockSessionStore.agentConfig,
103
+ tts: {
104
+ ...DEFAUTT_AGENT_TTS_CONFIG,
105
+ ttsService: 'microsoft',
106
+ },
107
+ },
108
+ } as AgentStore;
109
+ const ttsVoice = agentSelectors.currentAgentTTSVoice('en')(modifiedStore);
110
+ expect(ttsVoice).toBe('ar-SA-HamedNeural');
111
+ });
112
+
113
+ it('should return the first voice if the specified voice does not exist', () => {
114
+ const lang = 'en';
115
+ const modifiedStore = {
116
+ ...mockSessionStore,
117
+ agentConfig: {
118
+ ...mockSessionStore.agentConfig,
119
+ tts: {
120
+ ...DEFAUTT_AGENT_TTS_CONFIG,
121
+ ttsService: 'avc',
122
+ voice: {
123
+ openai: 'non-existent-voice',
124
+ },
125
+ },
126
+ },
127
+ };
128
+ const ttsVoice = agentSelectors.currentAgentTTSVoice(lang)(modifiedStore as any);
129
+ expect(ttsVoice).toBe('alloy');
130
+ });
131
+ });
132
+
133
+ describe('currentAgentModelProvider', () => {
134
+ it('should return the provider from the agent config', () => {
135
+ const provider = agentSelectors.currentAgentModelProvider(mockSessionStore);
136
+ expect(provider).toBe(mockSessionStore.agentConfig.provider);
137
+ });
138
+
139
+ it('should return undefined if provider is not defined in the agent config', () => {
140
+ const modifiedStore = {
141
+ ...mockSessionStore,
142
+ agentConfig: {
143
+ ...mockSessionStore.agentConfig,
144
+ provider: undefined,
145
+ },
146
+ };
147
+ const provider = agentSelectors.currentAgentModelProvider(modifiedStore);
148
+ expect(provider).toBeUndefined();
149
+ });
150
+ });
151
+
152
+ describe('currentAgentPlugins', () => {
153
+ it('should return the plugins array from the agent config', () => {
154
+ const plugins = agentSelectors.currentAgentPlugins(mockSessionStore);
155
+ expect(plugins).toEqual(mockSessionStore.agentConfig.plugins);
156
+ });
157
+
158
+ it('should return an empty array if plugins are not defined in the agent config', () => {
159
+ const modifiedStore = {
160
+ ...mockSessionStore,
161
+ agentConfig: {
162
+ ...mockSessionStore.agentConfig,
163
+ plugins: undefined,
164
+ },
165
+ };
166
+ const plugins = agentSelectors.currentAgentPlugins(modifiedStore);
167
+ expect(plugins).toEqual([]);
168
+ });
169
+ });
170
+
171
+ describe('currentAgentSystemRole', () => {
172
+ it('should return the system role from the agent config', () => {
173
+ const systemRole = agentSelectors.currentAgentSystemRole(mockSessionStore);
174
+ expect(systemRole).toBe(mockSessionStore.agentConfig.systemRole);
175
+ });
176
+
177
+ it('should return undefined if system role is not defined in the agent config', () => {
178
+ const modifiedStore = {
179
+ ...mockSessionStore,
180
+ agentConfig: {
181
+ ...mockSessionStore.agentConfig,
182
+ systemRole: undefined,
183
+ },
184
+ };
185
+ const systemRole = agentSelectors.currentAgentSystemRole(modifiedStore);
186
+ expect(systemRole).toBeUndefined();
187
+ });
188
+ });
189
+
190
+ describe('isInboxSession', () => {
191
+ it('should return true if activeId is INBOX_SESSION_ID', () => {
192
+ const modifiedStore = {
193
+ ...mockSessionStore,
194
+ activeId: INBOX_SESSION_ID,
195
+ };
196
+ const isInbox = agentSelectors.isInboxSession(modifiedStore);
197
+ expect(isInbox).toBe(true);
198
+ });
199
+
200
+ it('should return false if activeId is not INBOX_SESSION_ID', () => {
201
+ const isInbox = agentSelectors.isInboxSession(mockSessionStore);
202
+ expect(isInbox).toBe(false);
80
203
  });
81
204
  });
82
205
  });
@@ -1,15 +1,16 @@
1
1
  import { VoiceList } from '@lobehub/tts';
2
2
 
3
3
  import { INBOX_SESSION_ID } from '@/const/session';
4
- import { DEFAULT_AGENT_CONFIG, DEFAUTT_AGENT_TTS_CONFIG } from '@/const/settings';
4
+ import { DEFAUTT_AGENT_TTS_CONFIG } from '@/const/settings';
5
5
  import { AgentStore } from '@/store/agent';
6
- import { LobeAgentTTSConfig } from '@/types/agent';
6
+ import { LobeAgentConfig, LobeAgentTTSConfig } from '@/types/agent';
7
7
  import { merge } from '@/utils/merge';
8
8
 
9
9
  const isInboxSession = (s: AgentStore) => s.activeId === INBOX_SESSION_ID;
10
10
 
11
11
  // ========== Config ============== //
12
- const currentAgentConfig = (s: AgentStore) => merge(DEFAULT_AGENT_CONFIG, s.agentConfig);
12
+ const currentAgentConfig = (s: AgentStore): LobeAgentConfig =>
13
+ merge(s.defaultAgentConfig, s.agentConfig);
13
14
 
14
15
  const currentAgentSystemRole = (s: AgentStore) => {
15
16
  return currentAgentConfig(s).systemRole;
@@ -1,162 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
-
3
- import { GlobalServerConfig } from '@/types/serverConfig';
4
-
5
- import { GET } from './route';
6
-
7
- beforeEach(() => {
8
- vi.resetAllMocks();
9
- });
10
-
11
- describe('GET /api/config', () => {
12
- describe('Model Provider env', () => {
13
- describe('OPENAI_MODEL_LIST', () => {
14
- it('custom deletion, addition, and renaming of models', async () => {
15
- process.env.OPENAI_MODEL_LIST =
16
- '-all,+llama,+claude-2,-gpt-3.5-turbo,gpt-4-0125-preview=gpt-4-turbo,gpt-4-0125-preview=gpt-4-32k';
17
-
18
- const response = await GET();
19
-
20
- // Assert
21
- expect(response).toBeInstanceOf(Response);
22
- expect(response.status).toBe(200);
23
-
24
- const jsonResponse: GlobalServerConfig = await response.json();
25
-
26
- const result = jsonResponse.languageModel?.openai;
27
-
28
- expect(result).toMatchSnapshot();
29
- process.env.OPENAI_MODEL_LIST = '';
30
- });
31
-
32
- it('should work correct with gpt-4', async () => {
33
- process.env.OPENAI_MODEL_LIST =
34
- '-all,+gpt-3.5-turbo-1106,+gpt-3.5-turbo,+gpt-3.5-turbo-16k,+gpt-4,+gpt-4-32k,+gpt-4-1106-preview,+gpt-4-vision-preview';
35
-
36
- const response = await GET();
37
- const jsonResponse: GlobalServerConfig = await response.json();
38
-
39
- const result = jsonResponse.languageModel?.openai?.serverModelCards;
40
-
41
- expect(result).toMatchSnapshot();
42
-
43
- process.env.OPENAI_MODEL_LIST = '';
44
- });
45
-
46
- it('duplicate naming model', async () => {
47
- process.env.OPENAI_MODEL_LIST =
48
- 'gpt-4-0125-preview=gpt-4-turbo,gpt-4-0125-preview=gpt-4-32k';
49
-
50
- const response = await GET();
51
- const jsonResponse: GlobalServerConfig = await response.json();
52
-
53
- const result = jsonResponse.languageModel?.openai?.serverModelCards;
54
-
55
- expect(result?.find((s) => s.id === 'gpt-4-0125-preview')?.displayName).toEqual(
56
- 'gpt-4-32k',
57
- );
58
-
59
- process.env.OPENAI_MODEL_LIST = '';
60
- });
61
-
62
- it('should delete model', async () => {
63
- process.env.OPENAI_MODEL_LIST = '-gpt-4';
64
-
65
- const res = await GET();
66
- const data: GlobalServerConfig = await res.json();
67
-
68
- const result = data.languageModel?.openai?.serverModelCards;
69
-
70
- expect(result?.find((r) => r.id === 'gpt-4')).toBeUndefined();
71
-
72
- process.env.OPENAI_MODEL_LIST = '';
73
- });
74
-
75
- it('show the hidden model', async () => {
76
- process.env.OPENAI_MODEL_LIST = '+gpt-4-1106-preview';
77
-
78
- const res = await GET();
79
- const data: GlobalServerConfig = await res.json();
80
-
81
- const result = data.languageModel?.openai?.serverModelCards;
82
-
83
- expect(result?.find((o) => o.id === 'gpt-4-1106-preview')).toEqual({
84
- displayName: 'GPT-4 Turbo Preview (1106)',
85
- functionCall: true,
86
- enabled: true,
87
- id: 'gpt-4-1106-preview',
88
- tokens: 128000,
89
- });
90
-
91
- process.env.OPENAI_MODEL_LIST = '';
92
- });
93
-
94
- it('only add the model', async () => {
95
- process.env.OPENAI_MODEL_LIST = 'model1,model2,model3,model4';
96
-
97
- const res = await GET();
98
- const data: GlobalServerConfig = await res.json();
99
-
100
- const result = data.languageModel?.openai?.serverModelCards;
101
-
102
- expect(result).toContainEqual({
103
- displayName: 'model1',
104
- id: 'model1',
105
- enabled: true,
106
- });
107
- expect(result).toContainEqual({
108
- displayName: 'model2',
109
- enabled: true,
110
- id: 'model2',
111
- });
112
- expect(result).toContainEqual({
113
- displayName: 'model3',
114
- enabled: true,
115
- id: 'model3',
116
- });
117
- expect(result).toContainEqual({
118
- displayName: 'model4',
119
- enabled: true,
120
- id: 'model4',
121
- });
122
-
123
- process.env.OPENAI_MODEL_LIST = '';
124
- });
125
- });
126
-
127
- describe('CUSTOM_MODELS', () => {
128
- it('custom deletion, addition, and renaming of models', async () => {
129
- process.env.CUSTOM_MODELS =
130
- '-all,+llama,+claude-2,-gpt-3.5-turbo,gpt-4-0125-preview=gpt-4-turbo,gpt-4-0125-preview=gpt-4-32k';
131
-
132
- const response = await GET();
133
-
134
- // Assert
135
- expect(response).toBeInstanceOf(Response);
136
- expect(response.status).toBe(200);
137
-
138
- const jsonResponse: GlobalServerConfig = await response.json();
139
-
140
- const result = jsonResponse.languageModel?.openai?.serverModelCards;
141
-
142
- expect(result).toMatchSnapshot();
143
- });
144
- });
145
-
146
- describe('OPENROUTER_MODEL_LIST', () => {
147
- it('custom deletion, addition, and renaming of models', async () => {
148
- process.env.OPENROUTER_MODEL_LIST =
149
- '-all,+google/gemma-7b-it,+mistralai/mistral-7b-instruct=Mistral-7B-Instruct';
150
-
151
- const res = await GET();
152
- const data: GlobalServerConfig = await res.json();
153
-
154
- const result = data.languageModel?.openrouter;
155
-
156
- expect(result).toMatchSnapshot();
157
-
158
- process.env.OPENROUTER_MODEL_LIST = '';
159
- });
160
- });
161
- });
162
- });
@@ -1,118 +0,0 @@
1
- import {
2
- OllamaProviderCard,
3
- OpenAIProviderCard,
4
- OpenRouterProviderCard,
5
- TogetherAIProviderCard,
6
- } from '@/config/modelProviders';
7
- import { getServerConfig } from '@/config/server';
8
- import { GlobalServerConfig } from '@/types/serverConfig';
9
- import { extractEnabledModels, transformToChatModelCards } from '@/utils/parseModels';
10
-
11
- import { parseAgentConfig } from './parseDefaultAgent';
12
-
13
- export const runtime = 'edge';
14
-
15
- /**
16
- * get Server config to client
17
- */
18
- export const GET = async () => {
19
- const {
20
- ENABLE_LANGFUSE,
21
- ENABLE_OAUTH_SSO,
22
-
23
- DEFAULT_AGENT_CONFIG,
24
- OPENAI_MODEL_LIST,
25
-
26
- ENABLED_MOONSHOT,
27
- ENABLED_ZHIPU,
28
- ENABLED_AWS_BEDROCK,
29
- ENABLED_GOOGLE,
30
- ENABLED_GROQ,
31
- ENABLED_PERPLEXITY,
32
- ENABLED_ANTHROPIC,
33
- ENABLED_MISTRAL,
34
-
35
- ENABLED_AZURE_OPENAI,
36
- AZURE_MODEL_LIST,
37
-
38
- ENABLE_OLLAMA,
39
- OLLAMA_MODEL_LIST,
40
- OLLAMA_PROXY_URL,
41
-
42
- ENABLED_OPENROUTER,
43
- OPENROUTER_MODEL_LIST,
44
-
45
- ENABLED_ZEROONE,
46
- ENABLED_TOGETHERAI,
47
- TOGETHERAI_MODEL_LIST,
48
- } = getServerConfig();
49
-
50
- const config: GlobalServerConfig = {
51
- defaultAgent: {
52
- config: parseAgentConfig(DEFAULT_AGENT_CONFIG),
53
- },
54
-
55
- enabledOAuthSSO: ENABLE_OAUTH_SSO,
56
- languageModel: {
57
- anthropic: {
58
- enabled: ENABLED_ANTHROPIC,
59
- },
60
- azure: {
61
- enabled: ENABLED_AZURE_OPENAI,
62
- enabledModels: extractEnabledModels(AZURE_MODEL_LIST, true),
63
- serverModelCards: transformToChatModelCards({
64
- defaultChatModels: [],
65
- modelString: AZURE_MODEL_LIST,
66
- withDeploymentName: true,
67
- }),
68
- },
69
- bedrock: { enabled: ENABLED_AWS_BEDROCK },
70
- google: { enabled: ENABLED_GOOGLE },
71
- groq: { enabled: ENABLED_GROQ },
72
- mistral: { enabled: ENABLED_MISTRAL },
73
- moonshot: { enabled: ENABLED_MOONSHOT },
74
- ollama: {
75
- enabled: ENABLE_OLLAMA,
76
- fetchOnClient: !OLLAMA_PROXY_URL,
77
- serverModelCards: transformToChatModelCards({
78
- defaultChatModels: OllamaProviderCard.chatModels,
79
- modelString: OLLAMA_MODEL_LIST,
80
- }),
81
- },
82
- openai: {
83
- enabledModels: extractEnabledModels(OPENAI_MODEL_LIST),
84
- serverModelCards: transformToChatModelCards({
85
- defaultChatModels: OpenAIProviderCard.chatModels,
86
- modelString: OPENAI_MODEL_LIST,
87
- }),
88
- },
89
-
90
- openrouter: {
91
- enabled: ENABLED_OPENROUTER,
92
- enabledModels: extractEnabledModels(OPENROUTER_MODEL_LIST),
93
- serverModelCards: transformToChatModelCards({
94
- defaultChatModels: OpenRouterProviderCard.chatModels,
95
- modelString: OPENROUTER_MODEL_LIST,
96
- }),
97
- },
98
- perplexity: { enabled: ENABLED_PERPLEXITY },
99
-
100
- togetherai: {
101
- enabled: ENABLED_TOGETHERAI,
102
- enabledModels: extractEnabledModels(TOGETHERAI_MODEL_LIST),
103
- serverModelCards: transformToChatModelCards({
104
- defaultChatModels: TogetherAIProviderCard.chatModels,
105
- modelString: TOGETHERAI_MODEL_LIST,
106
- }),
107
- },
108
-
109
- zeroone: { enabled: ENABLED_ZEROONE },
110
- zhipu: { enabled: ENABLED_ZHIPU },
111
- },
112
- telemetry: {
113
- langfuse: ENABLE_LANGFUSE,
114
- },
115
- };
116
-
117
- return new Response(JSON.stringify(config));
118
- };