@lobehub/chat 0.150.3 → 0.150.5

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.5](https://github.com/lobehub/lobe-chat/compare/v0.150.4...v0.150.5)
6
+
7
+ <sup>Released on **2024-04-27**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Fix the plugin string env and search error.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Fix the plugin string env and search error, closes [#2239](https://github.com/lobehub/lobe-chat/issues/2239) ([74b1ae0](https://github.com/lobehub/lobe-chat/commit/74b1ae0))
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.4](https://github.com/lobehub/lobe-chat/compare/v0.150.3...v0.150.4)
31
+
32
+ <sup>Released on **2024-04-27**</sup>
33
+
34
+ #### 💄 Styles
35
+
36
+ - **misc**: Hide default model tag and show ollama provider by default.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Styles
44
+
45
+ - **misc**: Hide default model tag and show ollama provider by default, closes [#2238](https://github.com/lobehub/lobe-chat/issues/2238) ([baa4780](https://github.com/lobehub/lobe-chat/commit/baa4780))
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.3](https://github.com/lobehub/lobe-chat/compare/v0.150.2...v0.150.3)
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.3",
3
+ "version": "0.150.5",
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",
@@ -3,6 +3,7 @@ import { Flexbox } from 'react-layout-kit';
3
3
  import { shallow } from 'zustand/shallow';
4
4
 
5
5
  import ModelTag from '@/components/ModelTag';
6
+ import { useAgentStore } from '@/store/agent';
6
7
  import { useChatStore } from '@/store/chat';
7
8
  import { useSessionStore } from '@/store/session';
8
9
  import { sessionHelpers } from '@/store/session/helpers';
@@ -19,6 +20,7 @@ interface SessionItemProps {
19
20
  const SessionItem = memo<SessionItemProps>(({ id }) => {
20
21
  const [open, setOpen] = useState(false);
21
22
  const [createGroupModalOpen, setCreateGroupModalOpen] = useState(false);
23
+ const [defaultModel] = useAgentStore((s) => [s.defaultAgentConfig.model]);
22
24
 
23
25
  const [active] = useSessionStore((s) => [s.activeId === id]);
24
26
  const [loading] = useChatStore((s) => [!!s.chatLoadingId && id === s.activeId]);
@@ -40,6 +42,8 @@ const SessionItem = memo<SessionItemProps>(({ id }) => {
40
42
  ];
41
43
  });
42
44
 
45
+ const showModel = model !== defaultModel;
46
+
43
47
  const actions = useMemo(
44
48
  () => (
45
49
  <Actions
@@ -54,12 +58,12 @@ const SessionItem = memo<SessionItemProps>(({ id }) => {
54
58
 
55
59
  const addon = useMemo(
56
60
  () =>
57
- model && (
61
+ !showModel ? undefined : (
58
62
  <Flexbox gap={4} horizontal style={{ flexWrap: 'wrap' }}>
59
63
  <ModelTag model={model} />
60
64
  </Flexbox>
61
65
  ),
62
- [model],
66
+ [showModel, model],
63
67
  );
64
68
 
65
69
  return (
@@ -8,9 +8,10 @@ import { useSessionStore } from '@/store/session';
8
8
  const SessionSearchBar = memo<{ mobile?: boolean }>(({ mobile: controlledMobile }) => {
9
9
  const { t } = useTranslation('chat');
10
10
 
11
- const [keywords, useSearchSessions] = useSessionStore((s) => [
11
+ const [keywords, useSearchSessions, updateSearchKeywords] = useSessionStore((s) => [
12
12
  s.sessionSearchKeywords,
13
13
  s.useSearchSessions,
14
+ s.updateSearchKeywords,
14
15
  ]);
15
16
 
16
17
  const { isValidating } = useSearchSessions(keywords);
@@ -24,12 +25,7 @@ const SessionSearchBar = memo<{ mobile?: boolean }>(({ mobile: controlledMobile
24
25
  enableShortKey={!mobile}
25
26
  loading={isValidating}
26
27
  onChange={(e) => {
27
- const newKeywords = e.target.value;
28
-
29
- useSessionStore.setState({
30
- isSearching: !!newKeywords,
31
- sessionSearchKeywords: newKeywords,
32
- });
28
+ updateSearchKeywords(e.target.value);
33
29
  }}
34
30
  placeholder={t('searchAgentPlaceholder')}
35
31
  shortKey={'k'}
@@ -3,11 +3,13 @@ import { memo } from 'react';
3
3
 
4
4
  import { INBOX_SESSION_ID } from '@/const/session';
5
5
  import AgentSetting from '@/features/AgentSetting';
6
+ import { useAgentStore } from '@/store/agent';
7
+ import { agentSelectors } from '@/store/agent/selectors';
6
8
  import { useGlobalStore } from '@/store/global';
7
9
  import { settingsSelectors } from '@/store/global/selectors';
8
10
 
9
11
  const Agent = memo(() => {
10
- const config = useGlobalStore(settingsSelectors.defaultAgentConfig, isEqual);
12
+ const config = useAgentStore(agentSelectors.defaultAgentConfig, isEqual);
11
13
  const meta = useGlobalStore(settingsSelectors.defaultAgentMeta, isEqual);
12
14
  const [updateAgent] = useGlobalStore((s) => [s.updateDefaultAgent]);
13
15
 
@@ -13,6 +13,7 @@ const OpenAIProvider = memo(() => {
13
13
  modelList={{ showModelFetcher: true }}
14
14
  provider={'openai'}
15
15
  showApiKey={showOpenAIApiKey}
16
+ showBrowserRequest
16
17
  showEndpoint={showOpenAIProxyUrl}
17
18
  title={<OpenAI.Combine size={24} />}
18
19
  />
@@ -30,8 +30,8 @@ export default memo(() => {
30
30
  <>
31
31
  <PageTitle title={t('tab.llm')} />
32
32
  <OpenAI />
33
- <Azure />
34
33
  <Ollama />
34
+ <Azure />
35
35
  <Google />
36
36
  <Anthropic />
37
37
  <Bedrock />
@@ -71,8 +71,8 @@ declare global {
71
71
  AWS_SECRET_ACCESS_KEY?: string;
72
72
 
73
73
  // Ollama Provider;
74
+ ENABLE_OLLAMA?: string;
74
75
  OLLAMA_PROXY_URL?: string;
75
-
76
76
  OLLAMA_MODEL_LIST?: string;
77
77
 
78
78
  /**
@@ -119,8 +119,6 @@ export const getProviderConfig = () => {
119
119
 
120
120
  const TOGETHERAI_API_KEY = process.env.TOGETHERAI_API_KEY || '';
121
121
 
122
- const OLLAMA_PROXY_URL = process.env.OLLAMA_PROXY_URL || '';
123
-
124
122
  // region format: iad1,sfo1
125
123
  let regions: string[] = [];
126
124
  if (process.env.OPENAI_FUNCTION_REGIONS) {
@@ -200,8 +198,8 @@ export const getProviderConfig = () => {
200
198
  AWS_ACCESS_KEY_ID: AWS_ACCESS_KEY_ID,
201
199
  AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || '',
202
200
 
203
- ENABLE_OLLAMA: !!OLLAMA_PROXY_URL,
204
- OLLAMA_PROXY_URL: OLLAMA_PROXY_URL,
201
+ ENABLE_OLLAMA: process.env.ENABLE_OLLAMA as unknown as boolean,
202
+ OLLAMA_PROXY_URL: process.env.OLLAMA_PROXY_URL || '',
205
203
  OLLAMA_MODEL_LIST: process.env.OLLAMA_MODEL_LIST || process.env.OLLAMA_CUSTOM_MODELS,
206
204
  };
207
205
  };
@@ -101,7 +101,7 @@ export const DEFAULT_LLM_CONFIG: GlobalLLMConfig = {
101
101
  enabledModels: filterEnabledModels(MoonshotProviderCard),
102
102
  },
103
103
  ollama: {
104
- enabled: false,
104
+ enabled: true,
105
105
  enabledModels: filterEnabledModels(OllamaProviderCard),
106
106
  endpoint: '',
107
107
  fetchOnClient: true,
@@ -81,15 +81,15 @@ class _SessionModel extends BaseModel {
81
81
  async queryByKeyword(keyword: string): Promise<LobeSessions> {
82
82
  if (!keyword) return [];
83
83
 
84
- console.time('queryByKeyword');
84
+ const startTime = Date.now();
85
85
  const keywordLowerCase = keyword.toLowerCase();
86
86
 
87
87
  // First, filter sessions by title and description
88
88
  const matchingSessionsPromise = this.table
89
89
  .filter((session) => {
90
90
  return (
91
- session.meta.title.toLowerCase().includes(keywordLowerCase) ||
92
- session.meta.description.toLowerCase().includes(keywordLowerCase)
91
+ session.meta.title?.toLowerCase().includes(keywordLowerCase) ||
92
+ session.meta.description?.toLowerCase().includes(keywordLowerCase)
93
93
  );
94
94
  })
95
95
  .toArray();
@@ -112,7 +112,7 @@ class _SessionModel extends BaseModel {
112
112
  // match topics
113
113
  const matchingTopicsPromise = this.db.topics
114
114
  .filter((topic) => {
115
- return topic.title.toLowerCase().includes(keywordLowerCase);
115
+ return topic.title?.toLowerCase().includes(keywordLowerCase);
116
116
  })
117
117
  .toArray();
118
118
 
@@ -139,7 +139,7 @@ class _SessionModel extends BaseModel {
139
139
  .anyOf([...combinedSessionIds])
140
140
  .toArray();
141
141
 
142
- console.timeEnd('queryByKeyword');
142
+ console.log(`检索到 ${items.length} 项,耗时 ${Date.now() - startTime}ms`);
143
143
  return this.mapToAgentSessions(items);
144
144
  }
145
145
 
@@ -110,6 +110,20 @@ describe('parseAgentConfig', () => {
110
110
  };
111
111
  expect(parseAgentConfig(envStr)).toEqual(expected);
112
112
  });
113
+
114
+ it('should parsers plugins correctly', () => {
115
+ const envStr =
116
+ 'enableAutoCreateTopic=true;model=gemini-pro;provider=google;plugins=lobe-image-designer';
117
+
118
+ const expected = {
119
+ enableAutoCreateTopic: true,
120
+ model: 'gemini-pro',
121
+ plugins: ['lobe-image-designer'],
122
+ provider: 'google',
123
+ };
124
+
125
+ expect(parseAgentConfig(envStr)).toEqual(expected);
126
+ });
113
127
  });
114
128
 
115
129
  describe('Error Boundary', () => {
@@ -35,6 +35,11 @@ export const parseAgentConfig = (envStr: string) => {
35
35
  finalValue = array.map((item) => (isNaN(item as any) ? item : Number(item)));
36
36
  }
37
37
 
38
+ // handle plugins if it's a string
39
+ if (key === 'plugins') {
40
+ finalValue = typeof finalValue === 'string' ? [finalValue] : finalValue;
41
+ }
42
+
38
43
  set(config, key, finalValue);
39
44
  }
40
45
 
@@ -0,0 +1,28 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`agentSelectors > defaultAgentConfig > should merge DEFAULT_AGENT_CONFIG and defaultAgent(s).config correctly 1`] = `
4
+ {
5
+ "autoCreateTopicThreshold": 2,
6
+ "displayMode": "chat",
7
+ "enableAutoCreateTopic": true,
8
+ "historyCount": 1,
9
+ "model": "gpt-3.5-turbo",
10
+ "params": {
11
+ "frequency_penalty": 0,
12
+ "presence_penalty": 0,
13
+ "temperature": 0.7,
14
+ "top_p": 1,
15
+ },
16
+ "plugins": [],
17
+ "provider": "openai",
18
+ "systemRole": "user",
19
+ "tts": {
20
+ "showAllLocaleVoice": false,
21
+ "sttLocale": "auto",
22
+ "ttsService": "openai",
23
+ "voice": {
24
+ "openai": "alloy",
25
+ },
26
+ },
27
+ }
28
+ `;
@@ -3,6 +3,9 @@ import { describe, expect, it } from 'vitest';
3
3
  import { INBOX_SESSION_ID } from '@/const/session';
4
4
  import { DEFAULT_AGENT_CONFIG, DEFAUTT_AGENT_TTS_CONFIG } from '@/const/settings';
5
5
  import { AgentStore } from '@/store/agent';
6
+ import { GlobalStore } from '@/store/global';
7
+ import { settingsSelectors } from '@/store/global/slices/settings/selectors';
8
+ import { LobeAgentConfig } from '@/types/agent';
6
9
 
7
10
  import { agentSelectors } from './selectors';
8
11
 
@@ -16,6 +19,24 @@ const mockSessionStore = {
16
19
  } as AgentStore;
17
20
 
18
21
  describe('agentSelectors', () => {
22
+ describe('defaultAgentConfig', () => {
23
+ it('should merge DEFAULT_AGENT_CONFIG and defaultAgent(s).config correctly', () => {
24
+ const s = {
25
+ defaultAgentConfig: {
26
+ systemRole: 'user',
27
+ model: 'gpt-3.5-turbo',
28
+ params: {
29
+ temperature: 0.7,
30
+ },
31
+ },
32
+ } as unknown as AgentStore;
33
+
34
+ const result = agentSelectors.defaultAgentConfig(s);
35
+
36
+ expect(result).toMatchSnapshot();
37
+ });
38
+ });
39
+
19
40
  describe('currentAgentConfig', () => {
20
41
  it('should return the merged default and session-specific agent config', () => {
21
42
  const config = agentSelectors.currentAgentConfig(mockSessionStore);
@@ -1,7 +1,7 @@
1
1
  import { VoiceList } from '@lobehub/tts';
2
2
 
3
3
  import { INBOX_SESSION_ID } from '@/const/session';
4
- import { DEFAUTT_AGENT_TTS_CONFIG } from '@/const/settings';
4
+ import { DEFAULT_AGENT_CONFIG, DEFAUTT_AGENT_TTS_CONFIG } from '@/const/settings';
5
5
  import { AgentStore } from '@/store/agent';
6
6
  import { LobeAgentConfig, LobeAgentTTSConfig } from '@/types/agent';
7
7
  import { merge } from '@/utils/merge';
@@ -9,6 +9,9 @@ import { merge } from '@/utils/merge';
9
9
  const isInboxSession = (s: AgentStore) => s.activeId === INBOX_SESSION_ID;
10
10
 
11
11
  // ========== Config ============== //
12
+
13
+ const defaultAgentConfig = (s: AgentStore) => merge(DEFAULT_AGENT_CONFIG, s.defaultAgentConfig);
14
+
12
15
  const currentAgentConfig = (s: AgentStore): LobeAgentConfig =>
13
16
  merge(s.defaultAgentConfig, s.agentConfig);
14
17
 
@@ -77,6 +80,7 @@ export const agentSelectors = {
77
80
  currentAgentSystemRole,
78
81
  currentAgentTTS,
79
82
  currentAgentTTSVoice,
83
+ defaultAgentConfig,
80
84
  hasSystemRole,
81
85
  isInboxSession,
82
86
  };
@@ -138,8 +138,8 @@ describe('LLMSettingsSliceAction', () => {
138
138
  const enabledProviders = modelProviderSelectors.modelProviderListForModelSelect(
139
139
  result.current,
140
140
  );
141
- expect(enabledProviders).toHaveLength(2);
142
- expect(enabledProviders[1].id).toBe('perplexity');
141
+ expect(enabledProviders).toHaveLength(3);
142
+ expect(enabledProviders.at(-1)!.id).toBe('perplexity');
143
143
  });
144
144
  });
145
145
  });
@@ -99,33 +99,6 @@ exports[`settingsSelectors > defaultAgent > should merge DEFAULT_AGENT and s.set
99
99
  }
100
100
  `;
101
101
 
102
- exports[`settingsSelectors > defaultAgentConfig > should merge DEFAULT_AGENT_CONFIG and defaultAgent(s).config correctly 1`] = `
103
- {
104
- "autoCreateTopicThreshold": 2,
105
- "displayMode": "chat",
106
- "enableAutoCreateTopic": true,
107
- "historyCount": 1,
108
- "model": "gpt-3.5-turbo",
109
- "params": {
110
- "frequency_penalty": 0,
111
- "presence_penalty": 0,
112
- "temperature": 0.7,
113
- "top_p": 1,
114
- },
115
- "plugins": [],
116
- "provider": "openai",
117
- "systemRole": "user",
118
- "tts": {
119
- "showAllLocaleVoice": false,
120
- "sttLocale": "auto",
121
- "ttsService": "openai",
122
- "voice": {
123
- "openai": "alloy",
124
- },
125
- },
126
- }
127
- `;
128
-
129
102
  exports[`settingsSelectors > defaultAgentMeta > should merge DEFAULT_AGENT_META and defaultAgent(s).meta correctly 1`] = `
130
103
  {
131
104
  "avatar": "agent-avatar.jpg",
@@ -79,28 +79,6 @@ describe('settingsSelectors', () => {
79
79
  });
80
80
  });
81
81
 
82
- describe('defaultAgentConfig', () => {
83
- it('should merge DEFAULT_AGENT_CONFIG and defaultAgent(s).config correctly', () => {
84
- const s = {
85
- settings: {
86
- defaultAgent: {
87
- config: {
88
- systemRole: 'user',
89
- model: 'gpt-3.5-turbo',
90
- params: {
91
- temperature: 0.7,
92
- },
93
- },
94
- },
95
- },
96
- } as unknown as GlobalStore;
97
-
98
- const result = settingsSelectors.defaultAgentConfig(s);
99
-
100
- expect(result).toMatchSnapshot();
101
- });
102
- });
103
-
104
82
  describe('defaultAgentMeta', () => {
105
83
  it('should merge DEFAULT_AGENT_META and defaultAgent(s).meta correctly', () => {
106
84
  const s = {
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_LANG } from '@/const/locale';
2
2
  import { DEFAULT_AGENT_META } from '@/const/meta';
3
- import { DEFAULT_AGENT, DEFAULT_AGENT_CONFIG, DEFAULT_TTS_CONFIG } from '@/const/settings';
3
+ import { DEFAULT_AGENT, DEFAULT_TTS_CONFIG } from '@/const/settings';
4
4
  import { Locales } from '@/locales/resources';
5
5
  import { GeneralModelProviderConfig, GlobalLLMProviderKey, GlobalSettings } from '@/types/settings';
6
6
  import { isOnServerSide } from '@/utils/env';
@@ -22,8 +22,6 @@ const currentTTS = (s: GlobalStore) => merge(DEFAULT_TTS_CONFIG, currentSettings
22
22
 
23
23
  const defaultAgent = (s: GlobalStore) => merge(DEFAULT_AGENT, currentSettings(s).defaultAgent);
24
24
 
25
- const defaultAgentConfig = (s: GlobalStore) => merge(DEFAULT_AGENT_CONFIG, defaultAgent(s).config);
26
-
27
25
  const defaultAgentMeta = (s: GlobalStore) => merge(DEFAULT_AGENT_META, defaultAgent(s).meta);
28
26
 
29
27
  // TODO: Maybe we can also export settings difference
@@ -55,7 +53,6 @@ export const settingsSelectors = {
55
53
  currentTTS,
56
54
  dalleConfig,
57
55
  defaultAgent,
58
- defaultAgentConfig,
59
56
  defaultAgentMeta,
60
57
  exportSettings,
61
58
  isDalleAutoGenerating,
@@ -70,6 +70,8 @@ export interface SessionAction {
70
70
  */
71
71
  removeSession: (id: string) => Promise<void>;
72
72
 
73
+ updateSearchKeywords: (keywords: string) => void;
74
+
73
75
  useFetchSessions: () => SWRResponse<ChatSessionList>;
74
76
  useSearchSessions: (keyword?: string) => SWRResponse<any>;
75
77
 
@@ -169,6 +171,13 @@ export const createSessionSlice: StateCreator<
169
171
  }
170
172
  },
171
173
 
174
+ updateSearchKeywords: (keywords) => {
175
+ set(
176
+ { isSearching: !!keywords, sessionSearchKeywords: keywords },
177
+ false,
178
+ n('updateSearchKeywords'),
179
+ );
180
+ },
172
181
  updateSessionGroupId: async (sessionId, group) => {
173
182
  await get().internal_updateSession(sessionId, { group });
174
183
  },