@lobehub/lobehub 2.0.0-next.344 → 2.0.0-next.345
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/.cursor/rules/i18n.mdc +1 -1
- package/.cursor/rules/modal-imperative.mdc +162 -0
- package/.cursor/rules/rules-index.mdc +1 -0
- package/.env.example +0 -14
- package/.eslintrc.js +8 -1
- package/CHANGELOG.md +41 -0
- package/Dockerfile +3 -13
- package/README.md +3 -5
- package/README.zh-CN.md +3 -5
- package/changelog/v1.json +15 -0
- package/docs/self-hosting/advanced/auth/clerk-to-betterauth.mdx +11 -42
- package/docs/self-hosting/advanced/auth/clerk-to-betterauth.zh-CN.mdx +10 -41
- package/e2e/src/support/webServer.ts +2 -0
- package/locales/ar/error.json +0 -4
- package/locales/bg-BG/error.json +0 -4
- package/locales/de-DE/error.json +0 -4
- package/locales/en-US/error.json +0 -4
- package/locales/es-ES/error.json +0 -4
- package/locales/fa-IR/error.json +0 -4
- package/locales/fr-FR/error.json +0 -4
- package/locales/it-IT/error.json +0 -4
- package/locales/ja-JP/error.json +0 -4
- package/locales/ko-KR/error.json +0 -4
- package/locales/nl-NL/error.json +0 -4
- package/locales/pl-PL/error.json +0 -4
- package/locales/pt-BR/error.json +0 -4
- package/locales/ru-RU/error.json +0 -4
- package/locales/tr-TR/error.json +0 -4
- package/locales/vi-VN/error.json +0 -4
- package/locales/zh-CN/error.json +0 -4
- package/locales/zh-TW/error.json +0 -4
- package/package.json +7 -9
- package/packages/builtin-agents/package.json +2 -0
- package/packages/builtin-agents/src/agents/agent-builder/index.ts +4 -2
- package/packages/builtin-agents/src/agents/group-agent-builder/index.ts +4 -2
- package/packages/builtin-agents/src/agents/page-agent/index.ts +5 -2
- package/packages/context-engine/src/engine/messages/MessagesEngine.ts +9 -9
- package/packages/context-engine/src/providers/GroupContextInjector.ts +19 -33
- package/packages/context-engine/src/providers/__tests__/GroupContextInjector.test.ts +79 -43
- package/packages/context-engine/src/providers/__tests__/__snapshots__/GroupContextInjector.test.ts.snap +5 -15
- package/packages/database/src/repositories/userMemory/__tests__/UserMemoryTopicRepository.test.ts +24 -3
- package/packages/model-bank/src/modelProviders/comfyui.ts +0 -1
- package/packages/model-bank/src/modelProviders/fal.ts +0 -1
- package/packages/types/src/fetch.ts +1 -2
- package/packages/utils/src/server/__tests__/auth.test.ts +0 -47
- package/packages/utils/src/server/auth.ts +1 -9
- package/scripts/_shared/checkDeprecatedClerkEnv.js +42 -0
- package/scripts/changelogWorkflow/buildStaticChangelog.ts +2 -1
- package/scripts/clerk-to-betterauth/_internal/types.ts +53 -20
- package/scripts/clerk-to-betterauth/export-clerk-users-with-api.ts +43 -36
- package/scripts/countEnWord.ts +1 -1
- package/scripts/electronWorkflow/modifiers/appCode.mts +2 -131
- package/scripts/i18nWorkflow/protectedPatterns.ts +1 -2
- package/scripts/prebuild.mts +10 -8
- package/scripts/serverLauncher/startServer.js +23 -5
- package/src/app/(backend)/middleware/auth/index.test.ts +8 -4
- package/src/app/(backend)/middleware/auth/index.ts +0 -15
- package/src/app/(backend)/middleware/auth/utils.test.ts +0 -28
- package/src/app/(backend)/middleware/auth/utils.ts +2 -17
- package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +3 -51
- package/src/app/(backend)/webapi/models/[provider]/route.test.ts +8 -4
- package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +7 -6
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -16
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/index.tsx +1 -1
- package/src/app/[variants]/(main)/home/features/InputArea/SkillInstallBanner.tsx +13 -13
- package/src/app/[variants]/(main)/home/features/RecentPage/Item.tsx +2 -2
- package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +3 -21
- package/src/app/[variants]/(main)/settings/profile/features/AvatarRow.tsx +1 -2
- package/src/app/[variants]/(main)/settings/security/index.tsx +1 -22
- package/src/app/[variants]/(main)/settings/skill/features/KlavisSkillItem.tsx +12 -14
- package/src/app/[variants]/(main)/settings/skill/features/LobehubSkillItem.tsx +8 -14
- package/src/app/[variants]/(main)/settings/skill/index.tsx +7 -5
- package/src/app/[variants]/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +2 -35
- package/src/app/[variants]/(mobile)/me/(home)/__tests__/useCategory.test.tsx +0 -20
- package/src/app/[variants]/(mobile)/me/(home)/features/UserBanner.tsx +1 -2
- package/src/app/[variants]/(mobile)/me/profile/features/Category.tsx +3 -13
- package/src/app/[variants]/(mobile)/settings/_layout/Header.tsx +2 -3
- package/src/app/[variants]/share/t/[id]/_layout/index.tsx +1 -1
- package/src/app/[variants]/share/t/[id]/index.tsx +1 -1
- package/src/app/robots.tsx +1 -1
- package/src/envs/auth.ts +2 -27
- package/src/envs/llm.ts +2 -2
- package/src/features/AgentSetting/AgentPlugin/index.tsx +9 -12
- package/src/features/ChatInput/ActionBar/Tools/index.tsx +7 -5
- package/src/features/ChatMiniMap/utils.ts +1 -1
- package/src/features/CommandMenu/SearchResults.tsx +1 -1
- package/src/features/Conversation/ChatList/components/AutoScroll/DebugInspector.tsx +166 -0
- package/src/features/Conversation/ChatList/components/AutoScroll/index.tsx +86 -0
- package/src/features/Conversation/ChatList/components/VirtualizedList.tsx +11 -17
- package/src/features/Conversation/Messages/AgentCouncil/components/AutoScrollShadow.tsx +25 -14
- package/src/features/Conversation/Messages/AgentCouncil/components/CouncilMember.tsx +1 -1
- package/src/features/IntegrationDetailModal/IntegrationDetailContent.tsx +305 -0
- package/src/features/IntegrationDetailModal/index.tsx +21 -283
- package/src/features/MCPPluginDetail/Deployment/index.tsx +1 -1
- package/src/features/MCPPluginDetail/Schema/Prompts.tsx +1 -1
- package/src/features/MCPPluginDetail/Schema/Tools.tsx +1 -1
- package/src/features/ProfileEditor/AgentTool.tsx +14 -20
- package/src/features/ResourceManager/components/Explorer/MasonryView/MasonryFileItem/NoteFileItem.tsx +1 -1
- package/src/features/SkillStore/LobeHubList/index.tsx +50 -87
- package/src/features/SkillStore/Search/index.tsx +1 -1
- package/src/features/SkillStore/{Content.tsx → SkillStoreContent.tsx} +3 -8
- package/src/features/SkillStore/index.tsx +15 -33
- package/src/features/User/UserPanel/PanelContent.tsx +0 -8
- package/src/features/User/__tests__/PanelContent.test.tsx +1 -35
- package/src/features/User/__tests__/UserAvatar.test.tsx +30 -57
- package/src/features/User/__tests__/useMenu.test.tsx +2 -43
- package/src/layout/AuthProvider/index.tsx +0 -5
- package/src/libs/next/config/define-config.ts +6 -0
- package/src/libs/next/proxy/createRouteMatcher.test.ts +121 -0
- package/src/libs/next/proxy/createRouteMatcher.ts +18 -0
- package/src/libs/next/proxy/define-config.ts +4 -53
- package/src/libs/next-auth/adapter/index.ts +1 -2
- package/src/libs/oidc-provider/provider.test.ts +5 -316
- package/src/libs/trpc/lambda/context.test.ts +0 -13
- package/src/libs/trpc/lambda/context.ts +3 -22
- package/src/libs/trpc/middleware/userAuth.ts +2 -4
- package/src/libs/trusted-client/getSessionUser.ts +2 -17
- package/src/locales/default/error.ts +0 -6
- package/src/locales/default/index.ts +0 -2
- package/src/proxy.ts +0 -1
- package/src/server/routers/lambda/__tests__/user.test.ts +0 -71
- package/src/server/routers/lambda/user.ts +6 -63
- package/src/server/services/changelog/index.test.ts +3 -2
- package/src/server/services/changelog/index.ts +1 -1
- package/src/server/services/user/index.ts +0 -83
- package/src/services/chat/index.ts +1 -2
- package/src/services/chat/mecha/agentConfigResolver.test.ts +43 -0
- package/src/services/chat/mecha/agentConfigResolver.ts +3 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +58 -14
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +10 -2
- package/src/store/user/slices/auth/action.test.ts +1 -81
- package/src/store/user/slices/auth/action.ts +3 -28
- package/src/store/user/slices/auth/initialState.ts +1 -18
- package/src/store/user/slices/auth/selectors.test.ts +2 -127
- package/src/store/user/slices/auth/selectors.ts +1 -21
- package/src/utils/errorResponse.ts +1 -4
- package/src/utils/markdownToTxt.ts +20 -0
- package/locales/ar/clerk.json +0 -545
- package/locales/bg-BG/clerk.json +0 -545
- package/locales/de-DE/clerk.json +0 -545
- package/locales/en-US/clerk.json +0 -545
- package/locales/es-ES/clerk.json +0 -545
- package/locales/fa-IR/clerk.json +0 -545
- package/locales/fr-FR/clerk.json +0 -545
- package/locales/it-IT/clerk.json +0 -545
- package/locales/ja-JP/clerk.json +0 -545
- package/locales/ko-KR/clerk.json +0 -545
- package/locales/nl-NL/clerk.json +0 -545
- package/locales/pl-PL/clerk.json +0 -545
- package/locales/pt-BR/clerk.json +0 -545
- package/locales/ru-RU/clerk.json +0 -545
- package/locales/tr-TR/clerk.json +0 -545
- package/locales/vi-VN/clerk.json +0 -545
- package/locales/zh-CN/clerk.json +0 -545
- package/locales/zh-TW/clerk.json +0 -545
- package/src/app/(backend)/api/webhooks/clerk/__tests__/fixtures/createUser.json +0 -73
- package/src/app/(backend)/api/webhooks/clerk/route.ts +0 -95
- package/src/app/(backend)/api/webhooks/clerk/validateRequest.ts +0 -22
- package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +0 -27
- package/src/app/[variants]/(main)/settings/security/features/ClerkProfile.tsx +0 -67
- package/src/features/Conversation/ChatList/components/AutoScroll.tsx +0 -25
- package/src/layout/AuthProvider/Clerk/UserUpdater.tsx +0 -40
- package/src/layout/AuthProvider/Clerk/index.tsx +0 -54
- package/src/layout/AuthProvider/Clerk/useAppearance.ts +0 -133
- package/src/libs/clerk-auth/index.test.ts +0 -216
- package/src/libs/clerk-auth/index.ts +0 -80
- package/src/locales/default/clerk.ts +0 -677
- package/src/server/services/user/index.test.ts +0 -220
|
@@ -12,7 +12,7 @@ describe('GroupContextInjector', () => {
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
describe('Basic Scenarios', () => {
|
|
15
|
-
it('should inject group context
|
|
15
|
+
it('should inject group context before first user message', async () => {
|
|
16
16
|
const injector = new GroupContextInjector({
|
|
17
17
|
currentAgentId: 'agt_editor',
|
|
18
18
|
currentAgentName: 'Editor',
|
|
@@ -35,31 +35,39 @@ describe('GroupContextInjector', () => {
|
|
|
35
35
|
const context = createContext(input);
|
|
36
36
|
const result = await injector.process(context);
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
// System message should be unchanged
|
|
39
|
+
expect(result.messages[0].content).toBe('You are a helpful editor.');
|
|
40
|
+
|
|
41
|
+
// Should have 3 messages now (system, injected, user)
|
|
42
|
+
expect(result.messages).toHaveLength(3);
|
|
39
43
|
|
|
40
|
-
//
|
|
41
|
-
|
|
44
|
+
// Check injected message (second message)
|
|
45
|
+
const injectedContent = result.messages[1].content;
|
|
46
|
+
expect(result.messages[1].role).toBe('user');
|
|
42
47
|
|
|
43
48
|
// Agent identity (plain text, no wrapper)
|
|
44
|
-
expect(
|
|
45
|
-
expect(
|
|
46
|
-
expect(
|
|
47
|
-
expect(
|
|
48
|
-
expect(
|
|
49
|
+
expect(injectedContent).toContain('You are "Editor"');
|
|
50
|
+
expect(injectedContent).toContain('acting as a participant');
|
|
51
|
+
expect(injectedContent).toContain('"Writing Team"');
|
|
52
|
+
expect(injectedContent).toContain('agt_editor');
|
|
53
|
+
expect(injectedContent).not.toContain('<agent_identity>');
|
|
49
54
|
|
|
50
55
|
// Group context section with system prompt
|
|
51
|
-
expect(
|
|
52
|
-
expect(
|
|
56
|
+
expect(injectedContent).toContain('<group_context>');
|
|
57
|
+
expect(injectedContent).toContain('A team for collaborative writing');
|
|
53
58
|
|
|
54
59
|
// Participants section with XML format
|
|
55
|
-
expect(
|
|
56
|
-
expect(
|
|
57
|
-
expect(
|
|
58
|
-
expect(
|
|
60
|
+
expect(injectedContent).toContain('<group_participants>');
|
|
61
|
+
expect(injectedContent).toContain('<member name="Supervisor" id="agt_supervisor" />');
|
|
62
|
+
expect(injectedContent).toContain('<member name="Writer" id="agt_writer" />');
|
|
63
|
+
expect(injectedContent).toContain('<member name="Editor" id="agt_editor" you="true" />');
|
|
59
64
|
|
|
60
65
|
// Identity rules
|
|
61
|
-
expect(
|
|
62
|
-
expect(
|
|
66
|
+
expect(injectedContent).toContain('<identity_rules>');
|
|
67
|
+
expect(injectedContent).toContain('NEVER expose or display agent IDs');
|
|
68
|
+
|
|
69
|
+
// Original user message should be third
|
|
70
|
+
expect(result.messages[2].content).toBe('Please review this.');
|
|
63
71
|
|
|
64
72
|
// Metadata should be updated
|
|
65
73
|
expect(result.metadata.groupContextInjected).toBe(true);
|
|
@@ -72,35 +80,37 @@ describe('GroupContextInjector', () => {
|
|
|
72
80
|
enabled: false, // Disabled
|
|
73
81
|
});
|
|
74
82
|
|
|
75
|
-
const input: any[] = [
|
|
83
|
+
const input: any[] = [
|
|
84
|
+
{ role: 'system', content: 'You are a helpful editor.' },
|
|
85
|
+
{ role: 'user', content: 'Hello' },
|
|
86
|
+
];
|
|
76
87
|
|
|
77
88
|
const context = createContext(input);
|
|
78
89
|
const result = await injector.process(context);
|
|
79
90
|
|
|
80
|
-
// Should be unchanged
|
|
91
|
+
// Should be unchanged - no injection
|
|
92
|
+
expect(result.messages).toHaveLength(2);
|
|
81
93
|
expect(result.messages[0].content).toBe('You are a helpful editor.');
|
|
94
|
+
expect(result.messages[1].content).toBe('Hello');
|
|
82
95
|
expect(result.metadata.groupContextInjected).toBeUndefined();
|
|
83
96
|
});
|
|
84
97
|
|
|
85
|
-
it('should skip injection when no
|
|
98
|
+
it('should skip injection when no user message exists', async () => {
|
|
86
99
|
const injector = new GroupContextInjector({
|
|
87
100
|
currentAgentId: 'agt_editor',
|
|
88
101
|
currentAgentName: 'Editor',
|
|
89
102
|
enabled: true,
|
|
90
103
|
});
|
|
91
104
|
|
|
92
|
-
const input: any[] = [
|
|
93
|
-
{ role: 'user', content: 'Hello' },
|
|
94
|
-
{ role: 'assistant', content: 'Hi there!' },
|
|
95
|
-
];
|
|
105
|
+
const input: any[] = [{ role: 'system', content: 'You are a helpful editor.' }];
|
|
96
106
|
|
|
97
107
|
const context = createContext(input);
|
|
98
108
|
const result = await injector.process(context);
|
|
99
109
|
|
|
100
|
-
// Messages should be unchanged
|
|
101
|
-
expect(result.messages
|
|
102
|
-
expect(result.messages[
|
|
103
|
-
expect(result.metadata.groupContextInjected).
|
|
110
|
+
// Messages should be unchanged - no user message to inject before
|
|
111
|
+
expect(result.messages).toHaveLength(1);
|
|
112
|
+
expect(result.messages[0].content).toBe('You are a helpful editor.');
|
|
113
|
+
expect(result.metadata.groupContextInjected).toBe(true);
|
|
104
114
|
});
|
|
105
115
|
});
|
|
106
116
|
|
|
@@ -113,12 +123,16 @@ describe('GroupContextInjector', () => {
|
|
|
113
123
|
enabled: true,
|
|
114
124
|
});
|
|
115
125
|
|
|
116
|
-
const input: any[] = [
|
|
126
|
+
const input: any[] = [
|
|
127
|
+
{ content: 'You are an editor.', role: 'system' },
|
|
128
|
+
{ content: 'Hello', role: 'user' },
|
|
129
|
+
];
|
|
117
130
|
|
|
118
131
|
const context = createContext(input);
|
|
119
132
|
const result = await injector.process(context);
|
|
120
133
|
|
|
121
|
-
|
|
134
|
+
// Check injected message content
|
|
135
|
+
expect(result.messages[1].content).toMatchSnapshot();
|
|
122
136
|
});
|
|
123
137
|
|
|
124
138
|
it('should handle config with only group info', async () => {
|
|
@@ -129,12 +143,16 @@ describe('GroupContextInjector', () => {
|
|
|
129
143
|
systemPrompt: 'Test group description',
|
|
130
144
|
});
|
|
131
145
|
|
|
132
|
-
const input: any[] = [
|
|
146
|
+
const input: any[] = [
|
|
147
|
+
{ content: 'System prompt.', role: 'system' },
|
|
148
|
+
{ content: 'Hello', role: 'user' },
|
|
149
|
+
];
|
|
133
150
|
|
|
134
151
|
const context = createContext(input);
|
|
135
152
|
const result = await injector.process(context);
|
|
136
153
|
|
|
137
|
-
|
|
154
|
+
// Check injected message content
|
|
155
|
+
expect(result.messages[1].content).toMatchSnapshot();
|
|
138
156
|
});
|
|
139
157
|
|
|
140
158
|
it('should handle empty config', async () => {
|
|
@@ -142,12 +160,16 @@ describe('GroupContextInjector', () => {
|
|
|
142
160
|
enabled: true,
|
|
143
161
|
});
|
|
144
162
|
|
|
145
|
-
const input: any[] = [
|
|
163
|
+
const input: any[] = [
|
|
164
|
+
{ content: 'Base prompt.', role: 'system' },
|
|
165
|
+
{ content: 'Hello', role: 'user' },
|
|
166
|
+
];
|
|
146
167
|
|
|
147
168
|
const context = createContext(input);
|
|
148
169
|
const result = await injector.process(context);
|
|
149
170
|
|
|
150
|
-
|
|
171
|
+
// Check injected message content
|
|
172
|
+
expect(result.messages[1].content).toMatchSnapshot();
|
|
151
173
|
});
|
|
152
174
|
});
|
|
153
175
|
|
|
@@ -158,15 +180,19 @@ describe('GroupContextInjector', () => {
|
|
|
158
180
|
// Minimal config
|
|
159
181
|
});
|
|
160
182
|
|
|
161
|
-
const input: any[] = [
|
|
183
|
+
const input: any[] = [
|
|
184
|
+
{ role: 'system', content: 'Base prompt.' },
|
|
185
|
+
{ role: 'user', content: 'Hello' },
|
|
186
|
+
];
|
|
162
187
|
|
|
163
188
|
const context = createContext(input);
|
|
164
189
|
const result = await injector.process(context);
|
|
165
190
|
|
|
166
|
-
|
|
191
|
+
// Check injected message content
|
|
192
|
+
const injectedContent = result.messages[1].content;
|
|
167
193
|
|
|
168
194
|
// Even with minimal config, identity rules should be present
|
|
169
|
-
expect(
|
|
195
|
+
expect(injectedContent).toMatchSnapshot();
|
|
170
196
|
});
|
|
171
197
|
});
|
|
172
198
|
|
|
@@ -179,12 +205,16 @@ describe('GroupContextInjector', () => {
|
|
|
179
205
|
systemPrompt: 'Empty group description',
|
|
180
206
|
});
|
|
181
207
|
|
|
182
|
-
const input: any[] = [
|
|
208
|
+
const input: any[] = [
|
|
209
|
+
{ content: 'Prompt.', role: 'system' },
|
|
210
|
+
{ content: 'Hello', role: 'user' },
|
|
211
|
+
];
|
|
183
212
|
|
|
184
213
|
const context = createContext(input);
|
|
185
214
|
const result = await injector.process(context);
|
|
186
215
|
|
|
187
|
-
|
|
216
|
+
// Check injected message content
|
|
217
|
+
expect(result.messages[1].content).toMatchSnapshot();
|
|
188
218
|
});
|
|
189
219
|
|
|
190
220
|
it('should preserve other messages unchanged', async () => {
|
|
@@ -204,10 +234,16 @@ describe('GroupContextInjector', () => {
|
|
|
204
234
|
const context = createContext(input);
|
|
205
235
|
const result = await injector.process(context);
|
|
206
236
|
|
|
207
|
-
//
|
|
208
|
-
expect(result.messages[0].content).
|
|
209
|
-
|
|
210
|
-
|
|
237
|
+
// System message should be unchanged
|
|
238
|
+
expect(result.messages[0].content).toBe('System prompt.');
|
|
239
|
+
|
|
240
|
+
// Injected message should be second
|
|
241
|
+
expect(result.messages[1].role).toBe('user');
|
|
242
|
+
expect(result.messages[1].content).toContain('<group_context>');
|
|
243
|
+
|
|
244
|
+
// Original messages should be preserved
|
|
245
|
+
expect(result.messages[2].content).toBe('User message.');
|
|
246
|
+
expect(result.messages[3].content).toBe('Assistant response.');
|
|
211
247
|
});
|
|
212
248
|
});
|
|
213
249
|
});
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
3
|
exports[`GroupContextInjector > Edge Cases > should handle empty members array 1`] = `
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
<group_context>
|
|
4
|
+
"<group_context>
|
|
7
5
|
You are "", acting as a in the multi-agent group "Empty Group".
|
|
8
6
|
Your internal agent ID is (for system use only, never expose to users).
|
|
9
7
|
|
|
@@ -24,9 +22,7 @@ Empty group description
|
|
|
24
22
|
`;
|
|
25
23
|
|
|
26
24
|
exports[`GroupContextInjector > Identity Rules Section > should always include identity rules 1`] = `
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
<group_context>
|
|
25
|
+
"<group_context>
|
|
30
26
|
You are "", acting as a in the multi-agent group "".
|
|
31
27
|
Your internal agent ID is (for system use only, never expose to users).
|
|
32
28
|
|
|
@@ -47,9 +43,7 @@ Your internal agent ID is (for system use only, never expose to users).
|
|
|
47
43
|
`;
|
|
48
44
|
|
|
49
45
|
exports[`GroupContextInjector > Variable Replacement > should handle config with only group info 1`] = `
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
<group_context>
|
|
46
|
+
"<group_context>
|
|
53
47
|
You are "", acting as a in the multi-agent group "Test Group".
|
|
54
48
|
Your internal agent ID is (for system use only, never expose to users).
|
|
55
49
|
|
|
@@ -70,9 +64,7 @@ Test group description
|
|
|
70
64
|
`;
|
|
71
65
|
|
|
72
66
|
exports[`GroupContextInjector > Variable Replacement > should handle config with only identity info 1`] = `
|
|
73
|
-
"
|
|
74
|
-
|
|
75
|
-
<group_context>
|
|
67
|
+
"<group_context>
|
|
76
68
|
You are "Editor", acting as a participant in the multi-agent group "".
|
|
77
69
|
Your internal agent ID is agt_editor (for system use only, never expose to users).
|
|
78
70
|
|
|
@@ -93,9 +85,7 @@ Your internal agent ID is agt_editor (for system use only, never expose to users
|
|
|
93
85
|
`;
|
|
94
86
|
|
|
95
87
|
exports[`GroupContextInjector > Variable Replacement > should handle empty config 1`] = `
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
<group_context>
|
|
88
|
+
"<group_context>
|
|
99
89
|
You are "", acting as a in the multi-agent group "".
|
|
100
90
|
Your internal agent ID is (for system use only, never expose to users).
|
|
101
91
|
|
package/packages/database/src/repositories/userMemory/__tests__/UserMemoryTopicRepository.test.ts
CHANGED
|
@@ -50,9 +50,30 @@ describe('UserMemoryTopicRepository', () => {
|
|
|
50
50
|
|
|
51
51
|
it('should return concatenated user message content', async () => {
|
|
52
52
|
await serverDB.insert(messages).values([
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
{
|
|
54
|
+
id: 'msg-1',
|
|
55
|
+
content: 'Hello',
|
|
56
|
+
role: 'user',
|
|
57
|
+
topicId,
|
|
58
|
+
userId,
|
|
59
|
+
createdAt: new Date('2024-01-01'),
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 'msg-2',
|
|
63
|
+
content: 'Hi there!',
|
|
64
|
+
role: 'assistant',
|
|
65
|
+
topicId,
|
|
66
|
+
userId,
|
|
67
|
+
createdAt: new Date('2024-01-02'),
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 'msg-3',
|
|
71
|
+
content: 'How are you?',
|
|
72
|
+
role: 'user',
|
|
73
|
+
topicId,
|
|
74
|
+
userId,
|
|
75
|
+
createdAt: new Date('2024-01-03'),
|
|
76
|
+
},
|
|
56
77
|
]);
|
|
57
78
|
|
|
58
79
|
const result = await repo.getUserMessagesQueryForTopic(topicId);
|
|
@@ -12,7 +12,6 @@ const ComfyUI: ModelProviderCard = {
|
|
|
12
12
|
chatModels: [],
|
|
13
13
|
description:
|
|
14
14
|
'A powerful open-source workflow engine for image, video, and audio generation, supporting models like SD, FLUX, Qwen, Hunyuan, and WAN with node-based editing and private deployment.',
|
|
15
|
-
enabled: true,
|
|
16
15
|
id: 'comfyui',
|
|
17
16
|
name: 'ComfyUI',
|
|
18
17
|
settings: {
|
|
@@ -5,8 +5,7 @@ export const ChatErrorType = {
|
|
|
5
5
|
// ******* Business Error Semantics ******* //
|
|
6
6
|
|
|
7
7
|
InvalidAccessCode: 'InvalidAccessCode', // is in valid password
|
|
8
|
-
|
|
9
|
-
FreePlanLimit: 'FreePlanLimit', // is not Clerk User
|
|
8
|
+
FreePlanLimit: 'FreePlanLimit', // Free plan usage limit
|
|
10
9
|
SubscriptionPlanLimit: 'SubscriptionPlanLimit', // Subscription user limit exceeded
|
|
11
10
|
SubscriptionKeyMismatch: 'SubscriptionKeyMismatch', // Subscription key mismatch
|
|
12
11
|
|
|
@@ -4,34 +4,17 @@ import { extractBearerToken, getUserAuth } from '../auth';
|
|
|
4
4
|
|
|
5
5
|
// Mock auth constants
|
|
6
6
|
let mockEnableBetterAuth = false;
|
|
7
|
-
let mockEnableClerk = false;
|
|
8
7
|
let mockEnableNextAuth = false;
|
|
9
8
|
|
|
10
9
|
vi.mock('@/envs/auth', () => ({
|
|
11
10
|
get enableBetterAuth() {
|
|
12
11
|
return mockEnableBetterAuth;
|
|
13
12
|
},
|
|
14
|
-
get enableClerk() {
|
|
15
|
-
return mockEnableClerk;
|
|
16
|
-
},
|
|
17
13
|
get enableNextAuth() {
|
|
18
14
|
return mockEnableNextAuth;
|
|
19
15
|
},
|
|
20
16
|
}));
|
|
21
17
|
|
|
22
|
-
vi.mock('@/libs/clerk-auth', () => ({
|
|
23
|
-
ClerkAuth: class {
|
|
24
|
-
async getAuth() {
|
|
25
|
-
return {
|
|
26
|
-
clerkAuth: {
|
|
27
|
-
redirectToSignIn: vi.fn(),
|
|
28
|
-
},
|
|
29
|
-
userId: 'clerk-user-id',
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
}));
|
|
34
|
-
|
|
35
18
|
vi.mock('@/libs/next-auth', () => ({
|
|
36
19
|
default: {
|
|
37
20
|
auth: vi.fn().mockResolvedValue({
|
|
@@ -62,7 +45,6 @@ describe('getUserAuth', () => {
|
|
|
62
45
|
beforeEach(() => {
|
|
63
46
|
vi.clearAllMocks();
|
|
64
47
|
mockEnableBetterAuth = false;
|
|
65
|
-
mockEnableClerk = false;
|
|
66
48
|
mockEnableNextAuth = false;
|
|
67
49
|
});
|
|
68
50
|
|
|
@@ -70,22 +52,7 @@ describe('getUserAuth', () => {
|
|
|
70
52
|
await expect(getUserAuth()).rejects.toThrow('Auth method is not enabled');
|
|
71
53
|
});
|
|
72
54
|
|
|
73
|
-
it('should return clerk auth when clerk is enabled', async () => {
|
|
74
|
-
mockEnableClerk = true;
|
|
75
|
-
mockEnableNextAuth = false;
|
|
76
|
-
|
|
77
|
-
const auth = await getUserAuth();
|
|
78
|
-
|
|
79
|
-
expect(auth).toEqual({
|
|
80
|
-
clerkAuth: {
|
|
81
|
-
redirectToSignIn: expect.any(Function),
|
|
82
|
-
},
|
|
83
|
-
userId: 'clerk-user-id',
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
55
|
it('should return next auth when next auth is enabled', async () => {
|
|
88
|
-
mockEnableClerk = false;
|
|
89
56
|
mockEnableNextAuth = true;
|
|
90
57
|
|
|
91
58
|
const auth = await getUserAuth();
|
|
@@ -100,20 +67,6 @@ describe('getUserAuth', () => {
|
|
|
100
67
|
});
|
|
101
68
|
});
|
|
102
69
|
|
|
103
|
-
it('should prioritize clerk auth over next auth when both are enabled', async () => {
|
|
104
|
-
mockEnableClerk = true;
|
|
105
|
-
mockEnableNextAuth = true;
|
|
106
|
-
|
|
107
|
-
const auth = await getUserAuth();
|
|
108
|
-
|
|
109
|
-
expect(auth).toEqual({
|
|
110
|
-
clerkAuth: {
|
|
111
|
-
redirectToSignIn: expect.any(Function),
|
|
112
|
-
},
|
|
113
|
-
userId: 'clerk-user-id',
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
70
|
it('should return better auth when better auth is enabled', async () => {
|
|
118
71
|
mockEnableBetterAuth = true;
|
|
119
72
|
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
import { headers } from 'next/headers';
|
|
2
2
|
|
|
3
|
-
import { enableBetterAuth,
|
|
3
|
+
import { enableBetterAuth, enableNextAuth } from '@/envs/auth';
|
|
4
4
|
|
|
5
5
|
export const getUserAuth = async () => {
|
|
6
|
-
if (enableClerk) {
|
|
7
|
-
const { ClerkAuth } = await import('@/libs/clerk-auth');
|
|
8
|
-
|
|
9
|
-
const clerkAuth = new ClerkAuth();
|
|
10
|
-
|
|
11
|
-
return await clerkAuth.getAuth();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
6
|
if (enableBetterAuth) {
|
|
15
7
|
const { auth: betterAuth } = await import('@/auth');
|
|
16
8
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utility to check for deprecated Clerk environment variables.
|
|
3
|
+
* Used by both prebuild.mts (build time) and startServer.js (Docker runtime).
|
|
4
|
+
*
|
|
5
|
+
* IMPORTANT: Keep this file as CommonJS (.js) for compatibility with startServer.js
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const CLERK_MIGRATION_DOC_URL =
|
|
9
|
+
'https://lobehub.com/docs/self-hosting/advanced/auth/clerk-to-betterauth';
|
|
10
|
+
|
|
11
|
+
const CLERK_ENV_VARS = [
|
|
12
|
+
'NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY',
|
|
13
|
+
'CLERK_SECRET_KEY',
|
|
14
|
+
'CLERK_WEBHOOK_SECRET',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check for deprecated Clerk environment variables and exit if found
|
|
19
|
+
* @param {object} options
|
|
20
|
+
* @param {string} [options.action='redeploy'] - Action hint in error message ('redeploy' or 'restart')
|
|
21
|
+
*/
|
|
22
|
+
function checkDeprecatedClerkEnv(options = {}) {
|
|
23
|
+
const { action = 'redeploy' } = options;
|
|
24
|
+
const foundClerkEnvVars = CLERK_ENV_VARS.filter((envVar) => process.env[envVar]);
|
|
25
|
+
|
|
26
|
+
if (foundClerkEnvVars.length > 0) {
|
|
27
|
+
console.error('\n' + '═'.repeat(70));
|
|
28
|
+
console.error('❌ ERROR: Clerk authentication is no longer supported!');
|
|
29
|
+
console.error('═'.repeat(70));
|
|
30
|
+
console.error('\nDetected deprecated Clerk environment variables:');
|
|
31
|
+
for (const envVar of foundClerkEnvVars) {
|
|
32
|
+
console.error(` • ${envVar}`);
|
|
33
|
+
}
|
|
34
|
+
console.error('\nClerk has been removed from LobeChat. Please migrate to Better Auth.');
|
|
35
|
+
console.error(`\n📖 Migration guide: ${CLERK_MIGRATION_DOC_URL}`);
|
|
36
|
+
console.error(`\nAfter migration, remove the Clerk environment variables and ${action}.`);
|
|
37
|
+
console.error('═'.repeat(70) + '\n');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { checkDeprecatedClerkEnv };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { consola } from 'consola';
|
|
2
2
|
import { readJsonSync, writeJSONSync } from 'fs-extra';
|
|
3
|
-
import { markdownToTxt } from 'markdown-to-txt';
|
|
4
3
|
import { existsSync, readFileSync } from 'node:fs';
|
|
5
4
|
import { resolve } from 'node:path';
|
|
6
5
|
import semver from 'semver';
|
|
7
6
|
|
|
7
|
+
import { markdownToTxt } from '@/utils/markdownToTxt';
|
|
8
|
+
|
|
8
9
|
import { CHANGELOG_DIR, CHANGELOG_FILE } from './const';
|
|
9
10
|
|
|
10
11
|
export interface ChangelogStaticItem {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { ExternalAccountJSON, UserJSON } from '@clerk/backend';
|
|
2
|
-
|
|
3
1
|
export type ClerkToBetterAuthMode = 'test' | 'prod';
|
|
4
2
|
export type DatabaseDriver = 'neon' | 'node';
|
|
5
3
|
|
|
@@ -19,27 +17,62 @@ export type CSVUserRow = {
|
|
|
19
17
|
verified_phone_numbers: string;
|
|
20
18
|
};
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
// Clerk API response types (no SDK dependency)
|
|
21
|
+
export interface ClerkApiExternalAccount {
|
|
22
|
+
approved_scopes: string;
|
|
23
|
+
created_at?: number;
|
|
24
|
+
id: string;
|
|
25
|
+
provider: string;
|
|
26
|
+
provider_user_id: string;
|
|
27
|
+
updated_at?: number;
|
|
28
|
+
verification?: { status: string };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ClerkApiEmailAddress {
|
|
32
|
+
email_address: string;
|
|
33
|
+
id: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ClerkApiUser {
|
|
37
|
+
banned: boolean;
|
|
38
|
+
created_at: number;
|
|
39
|
+
email_addresses?: ClerkApiEmailAddress[];
|
|
40
|
+
external_accounts?: ClerkApiExternalAccount[];
|
|
41
|
+
id: string;
|
|
42
|
+
image_url: string;
|
|
43
|
+
lockout_expires_in_seconds: number | null;
|
|
44
|
+
password_enabled: boolean;
|
|
45
|
+
password_last_updated_at: number | null;
|
|
46
|
+
primary_email_address_id: string | null;
|
|
47
|
+
two_factor_enabled: boolean;
|
|
48
|
+
updated_at: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface ClerkApiUserListResponse {
|
|
52
|
+
data: ClerkApiUser[];
|
|
53
|
+
total_count: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ClerkExternalAccount {
|
|
57
|
+
approved_scopes: string;
|
|
26
58
|
created_at?: number;
|
|
59
|
+
id: string;
|
|
60
|
+
provider: string;
|
|
61
|
+
provider_user_id: string;
|
|
27
62
|
updated_at?: number;
|
|
28
63
|
verificationStatus?: boolean;
|
|
29
|
-
}
|
|
64
|
+
}
|
|
30
65
|
|
|
31
|
-
export
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
| 'image_url'
|
|
35
|
-
| 'created_at'
|
|
36
|
-
| 'updated_at'
|
|
37
|
-
| 'password_last_updated_at'
|
|
38
|
-
| 'password_enabled'
|
|
39
|
-
| 'banned'
|
|
40
|
-
| 'two_factor_enabled'
|
|
41
|
-
| 'lockout_expires_in_seconds'
|
|
42
|
-
> & {
|
|
66
|
+
export interface ClerkUser {
|
|
67
|
+
banned: boolean;
|
|
68
|
+
created_at: number;
|
|
43
69
|
external_accounts: ClerkExternalAccount[];
|
|
70
|
+
id: string;
|
|
71
|
+
image_url: string;
|
|
72
|
+
lockout_expires_in_seconds: number | null;
|
|
73
|
+
password_enabled: boolean;
|
|
74
|
+
password_last_updated_at: number | null;
|
|
44
75
|
primaryEmail?: string;
|
|
45
|
-
|
|
76
|
+
two_factor_enabled: boolean;
|
|
77
|
+
updated_at: number;
|
|
78
|
+
}
|