@lobehub/lobehub 2.0.0-next.231 → 2.0.0-next.233

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.
Files changed (37) hide show
  1. package/.github/workflows/bundle-analyzer.yml +1 -1
  2. package/.github/workflows/e2e.yml +67 -52
  3. package/.github/workflows/manual-build-desktop.yml +5 -5
  4. package/.github/workflows/pr-build-desktop.yml +4 -4
  5. package/.github/workflows/pr-build-docker.yml +2 -2
  6. package/.github/workflows/release-desktop-beta.yml +4 -4
  7. package/.github/workflows/release-docker.yml +2 -2
  8. package/.github/workflows/test.yml +44 -7
  9. package/CHANGELOG.md +50 -0
  10. package/changelog/v1.json +14 -0
  11. package/docs/self-hosting/environment-variables/auth.mdx +7 -0
  12. package/docs/self-hosting/environment-variables/auth.zh-CN.mdx +7 -0
  13. package/package.json +1 -1
  14. package/packages/business/config/src/llm.ts +6 -1
  15. package/packages/const/src/settings/image.ts +1 -1
  16. package/packages/model-bank/src/aiModels/azure.ts +2 -2
  17. package/packages/model-bank/src/aiModels/google.ts +1 -0
  18. package/packages/model-bank/src/aiModels/lobehub.ts +33 -13
  19. package/packages/model-bank/src/aiModels/openai.ts +21 -4
  20. package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.ts +4 -1
  21. package/packages/model-runtime/src/providers/openai/__snapshots__/index.test.ts.snap +1 -1
  22. package/packages/ssrf-safe-fetch/index.test.ts +5 -34
  23. package/packages/ssrf-safe-fetch/index.ts +12 -2
  24. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/MultiImagesUpload/index.tsx +3 -3
  25. package/src/app/[variants]/(main)/image/features/GenerationFeed/index.tsx +3 -10
  26. package/src/app/[variants]/(main)/image/index.tsx +1 -1
  27. package/src/components/Loading/BrandTextLoading/index.module.css +81 -0
  28. package/src/components/Loading/BrandTextLoading/index.tsx +24 -17
  29. package/src/envs/auth.ts +15 -0
  30. package/src/hooks/useFetchAiImageConfig.ts +54 -10
  31. package/src/libs/redis/manager.ts +63 -0
  32. package/src/libs/trpc/utils/internalJwt.ts +2 -2
  33. package/src/server/services/agent/index.test.ts +15 -8
  34. package/src/server/services/agent/index.ts +11 -4
  35. package/src/store/image/slices/generationConfig/initialState.ts +5 -5
  36. package/src/store/image/slices/generationConfig/selectors.test.ts +11 -4
  37. package/vitest.config.mts +10 -6
@@ -3,17 +3,20 @@ import { DEFAULT_AGENT_CONFIG } from '@lobechat/const';
3
3
  import { type LobeChatDatabase } from '@lobechat/database';
4
4
  import { type AgentItem, type LobeAgentConfig } from '@lobechat/types';
5
5
  import { cleanObject, merge } from '@lobechat/utils';
6
+ import debug from 'debug';
6
7
  import type { PartialDeep } from 'type-fest';
7
8
 
8
9
  import { AgentModel } from '@/database/models/agent';
9
10
  import { SessionModel } from '@/database/models/session';
10
11
  import { UserModel } from '@/database/models/user';
11
12
  import { getRedisConfig } from '@/envs/redis';
12
- import { RedisKeyNamespace, RedisKeys, createRedisWithPrefix } from '@/libs/redis';
13
+ import { RedisKeyNamespace, RedisKeys, initializeRedisWithPrefix, isRedisEnabled } from '@/libs/redis';
13
14
  import { getServerDefaultAgentConfig } from '@/server/globalConfig';
14
15
 
15
16
  import { type UpdateAgentResult } from './type';
16
17
 
18
+ const log = debug('lobe-agent:service');
19
+
17
20
  interface AgentWelcomeData {
18
21
  openQuestions: string[];
19
22
  welcomeMessage: string;
@@ -113,7 +116,10 @@ export class AgentService {
113
116
  */
114
117
  private async getAgentWelcomeFromRedis(agentId: string): Promise<AgentWelcomeData | null> {
115
118
  try {
116
- const redis = await createRedisWithPrefix(getRedisConfig(), RedisKeyNamespace.AI_GENERATION);
119
+ const redisConfig = getRedisConfig();
120
+ if (!isRedisEnabled(redisConfig)) return null;
121
+
122
+ const redis = await initializeRedisWithPrefix(redisConfig, RedisKeyNamespace.AI_GENERATION);
117
123
  if (!redis) return null;
118
124
 
119
125
  const key = RedisKeys.aiGeneration.agentWelcome(agentId);
@@ -121,8 +127,9 @@ export class AgentService {
121
127
  if (!value) return null;
122
128
 
123
129
  return JSON.parse(value) as AgentWelcomeData;
124
- } catch {
125
- // Silently fail - Redis errors shouldn't break agent retrieval
130
+ } catch (error) {
131
+ // Log error for observability but don't break agent retrieval
132
+ log('Failed to get agent welcome from Redis for agent %s: %O', agentId, error);
126
133
  return null;
127
134
  }
128
135
  }
@@ -4,13 +4,13 @@ import {
4
4
  ModelProvider,
5
5
  type RuntimeImageGenParams,
6
6
  extractDefaultValues,
7
- gptImage1ParamsSchema,
8
7
  } from 'model-bank';
8
+ import { nanoBananaProParameters } from 'model-bank/google';
9
9
 
10
10
  import { DEFAULT_IMAGE_CONFIG } from '@/const/settings';
11
11
 
12
- export const DEFAULT_AI_IMAGE_PROVIDER = ModelProvider.OpenAI;
13
- export const DEFAULT_AI_IMAGE_MODEL = 'gpt-image-1';
12
+ export const DEFAULT_AI_IMAGE_PROVIDER = ModelProvider.Google;
13
+ export const DEFAULT_AI_IMAGE_MODEL = 'gemini-3-pro-image-preview:image';
14
14
 
15
15
  export interface GenerationConfigState {
16
16
  parameters: RuntimeImageGenParams;
@@ -30,14 +30,14 @@ export interface GenerationConfigState {
30
30
  }
31
31
 
32
32
  export const DEFAULT_IMAGE_GENERATION_PARAMETERS: RuntimeImageGenParams =
33
- extractDefaultValues(gptImage1ParamsSchema);
33
+ extractDefaultValues(nanoBananaProParameters);
34
34
 
35
35
  export const initialGenerationConfigState: GenerationConfigState = {
36
36
  model: DEFAULT_AI_IMAGE_MODEL,
37
37
  provider: DEFAULT_AI_IMAGE_PROVIDER,
38
38
  imageNum: DEFAULT_IMAGE_CONFIG.defaultImageNum,
39
39
  parameters: DEFAULT_IMAGE_GENERATION_PARAMETERS,
40
- parametersSchema: gptImage1ParamsSchema,
40
+ parametersSchema: nanoBananaProParameters,
41
41
  isAspectRatioLocked: false,
42
42
  activeAspectRatio: null,
43
43
  isInit: false,
@@ -6,6 +6,7 @@ import { ImageStore } from '@/store/image';
6
6
  import { initialState } from '@/store/image/initialState';
7
7
  import { merge } from '@/utils/merge';
8
8
 
9
+ import { DEFAULT_AI_IMAGE_MODEL, DEFAULT_AI_IMAGE_PROVIDER } from './initialState';
9
10
  import { imageGenerationConfigSelectors } from './selectors';
10
11
 
11
12
  // Mock external dependencies
@@ -57,7 +58,7 @@ describe('imageGenerationConfigSelectors', () => {
57
58
 
58
59
  it('should return the default model from initial state', () => {
59
60
  const result = imageGenerationConfigSelectors.model(initialStore);
60
- expect(result).toBe('gpt-image-1'); // Default model from initialState
61
+ expect(result).toBe(DEFAULT_AI_IMAGE_MODEL);
61
62
  });
62
63
  });
63
64
 
@@ -70,7 +71,7 @@ describe('imageGenerationConfigSelectors', () => {
70
71
 
71
72
  it('should return the default provider from initial state', () => {
72
73
  const result = imageGenerationConfigSelectors.provider(initialStore);
73
- expect(result).toBe('openai'); // Default provider from initialState
74
+ expect(result).toBe(DEFAULT_AI_IMAGE_PROVIDER);
74
75
  });
75
76
  });
76
77
 
@@ -98,7 +99,10 @@ describe('imageGenerationConfigSelectors', () => {
98
99
  it('should return the current parameters', () => {
99
100
  const state = merge(initialStore, { parameters: testParameters });
100
101
  const result = imageGenerationConfigSelectors.parameters(state);
101
- expect(result).toEqual(testParameters);
102
+ // merge does deep merge, so result contains both default and test values
103
+ expect(result.prompt).toBe(testParameters.prompt);
104
+ expect(result.size).toBe(testParameters.size);
105
+ expect(result.imageUrls).toEqual(testParameters.imageUrls);
102
106
  });
103
107
 
104
108
  it('should return the default parameters from initial state', () => {
@@ -120,7 +124,10 @@ describe('imageGenerationConfigSelectors', () => {
120
124
  it('should return the current parametersSchema', () => {
121
125
  const state = merge(initialStore, { parametersSchema: testModelSchema });
122
126
  const result = imageGenerationConfigSelectors.parametersSchema(state);
123
- expect(result).toEqual(testModelSchema);
127
+ // merge does deep merge, so result contains both default and test values
128
+ expect(result.prompt).toEqual(testModelSchema.prompt);
129
+ expect(result.size).toEqual(testModelSchema.size);
130
+ expect(result.imageUrls).toEqual(testModelSchema.imageUrls);
124
131
  });
125
132
 
126
133
  it('should return default parametersSchema when not explicitly overridden', () => {
package/vitest.config.mts CHANGED
@@ -2,6 +2,10 @@ import { dirname, join, resolve } from 'node:path';
2
2
  import { coverageConfigDefaults, defineConfig } from 'vitest/config';
3
3
 
4
4
  export default defineConfig({
5
+ optimizeDeps: {
6
+ exclude: ['crypto', 'util', 'tty'],
7
+ include: ['@lobehub/tts'],
8
+ },
5
9
  plugins: [
6
10
  /**
7
11
  * @lobehub/fluent-emoji@4.0.0 ships `es/FluentEmoji/style.js` but its `es/FluentEmoji/index.js`
@@ -27,16 +31,13 @@ export default defineConfig({
27
31
  id.endsWith('/FluentEmoji/style/index.js') ||
28
32
  id.endsWith('/FluentEmoji/style/index.js?');
29
33
 
30
- if (isFluentEmojiEntry && isMissingStyleIndex) return resolve(dirname(importer), 'style.js');
34
+ if (isFluentEmojiEntry && isMissingStyleIndex)
35
+ return resolve(dirname(importer), 'style.js');
31
36
 
32
37
  return null;
33
38
  },
34
39
  },
35
40
  ],
36
- optimizeDeps: {
37
- exclude: ['crypto', 'util', 'tty'],
38
- include: ['@lobehub/tts'],
39
- },
40
41
  test: {
41
42
  alias: {
42
43
  /* eslint-disable sort-keys-fix/sort-keys-fix */
@@ -77,11 +78,14 @@ export default defineConfig({
77
78
  environment: 'happy-dom',
78
79
  exclude: [
79
80
  '**/node_modules/**',
81
+ '**/.*/**',
80
82
  '**/dist/**',
81
83
  '**/build/**',
82
84
  '**/tmp/**',
83
85
  '**/temp/**',
84
- '**/.temp/**',
86
+ '**/docs/**',
87
+ '**/locales/**',
88
+ '**/public/**',
85
89
  '**/apps/desktop/**',
86
90
  '**/apps/mobile/**',
87
91
  '**/packages/**',