@lobehub/lobehub 2.0.0-next.344 → 2.0.0-next.346

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 (185) hide show
  1. package/.cursor/rules/i18n.mdc +1 -1
  2. package/.cursor/rules/modal-imperative.mdc +162 -0
  3. package/.cursor/rules/rules-index.mdc +1 -0
  4. package/.env.example +0 -14
  5. package/.eslintrc.js +8 -1
  6. package/CHANGELOG.md +66 -0
  7. package/CLAUDE.md +4 -2
  8. package/Dockerfile +3 -13
  9. package/README.md +3 -5
  10. package/README.zh-CN.md +3 -5
  11. package/changelog/v1.json +20 -0
  12. package/docs/self-hosting/advanced/auth/clerk-to-betterauth.mdx +11 -42
  13. package/docs/self-hosting/advanced/auth/clerk-to-betterauth.zh-CN.mdx +10 -41
  14. package/e2e/src/support/webServer.ts +2 -0
  15. package/locales/ar/error.json +0 -4
  16. package/locales/bg-BG/error.json +0 -4
  17. package/locales/de-DE/error.json +0 -4
  18. package/locales/en-US/error.json +0 -4
  19. package/locales/es-ES/error.json +0 -4
  20. package/locales/fa-IR/error.json +0 -4
  21. package/locales/fr-FR/error.json +0 -4
  22. package/locales/it-IT/error.json +0 -4
  23. package/locales/ja-JP/error.json +0 -4
  24. package/locales/ko-KR/error.json +0 -4
  25. package/locales/nl-NL/error.json +0 -4
  26. package/locales/pl-PL/error.json +0 -4
  27. package/locales/pt-BR/error.json +0 -4
  28. package/locales/ru-RU/error.json +0 -4
  29. package/locales/tr-TR/error.json +0 -4
  30. package/locales/vi-VN/error.json +0 -4
  31. package/locales/zh-CN/error.json +0 -4
  32. package/locales/zh-TW/error.json +0 -4
  33. package/package.json +12 -12
  34. package/packages/builtin-agents/package.json +2 -0
  35. package/packages/builtin-agents/src/agents/agent-builder/index.ts +4 -2
  36. package/packages/builtin-agents/src/agents/group-agent-builder/index.ts +4 -2
  37. package/packages/builtin-agents/src/agents/page-agent/index.ts +5 -2
  38. package/packages/context-engine/src/engine/messages/MessagesEngine.ts +9 -9
  39. package/packages/context-engine/src/providers/GroupContextInjector.ts +19 -33
  40. package/packages/context-engine/src/providers/__tests__/GroupContextInjector.test.ts +79 -43
  41. package/packages/context-engine/src/providers/__tests__/__snapshots__/GroupContextInjector.test.ts.snap +5 -15
  42. package/packages/database/src/repositories/userMemory/__tests__/UserMemoryTopicRepository.test.ts +24 -3
  43. package/packages/file-loaders/package.json +1 -1
  44. package/packages/file-loaders/src/loadFile.ts +10 -15
  45. package/packages/file-loaders/src/loaders/index.ts +68 -19
  46. package/packages/file-loaders/src/loaders/pdf/__snapshots__/index.test.ts.snap +1 -1
  47. package/packages/file-loaders/test/__snapshots__/loaders.test.ts.snap +1 -1
  48. package/packages/model-bank/src/modelProviders/comfyui.ts +0 -1
  49. package/packages/model-bank/src/modelProviders/fal.ts +0 -1
  50. package/packages/types/src/fetch.ts +1 -2
  51. package/packages/utils/src/server/__tests__/auth.test.ts +0 -47
  52. package/packages/utils/src/server/auth.ts +1 -9
  53. package/pnpm-workspace.yaml +1 -0
  54. package/scripts/_shared/checkDeprecatedClerkEnv.js +42 -0
  55. package/scripts/changelogWorkflow/buildStaticChangelog.ts +2 -1
  56. package/scripts/clerk-to-betterauth/_internal/types.ts +53 -20
  57. package/scripts/clerk-to-betterauth/export-clerk-users-with-api.ts +43 -36
  58. package/scripts/countEnWord.ts +1 -1
  59. package/scripts/electronWorkflow/modifiers/appCode.mts +2 -131
  60. package/scripts/i18nWorkflow/protectedPatterns.ts +1 -2
  61. package/scripts/prebuild.mts +10 -8
  62. package/scripts/serverLauncher/startServer.js +23 -5
  63. package/src/app/(backend)/middleware/auth/index.test.ts +8 -4
  64. package/src/app/(backend)/middleware/auth/index.ts +0 -15
  65. package/src/app/(backend)/middleware/auth/utils.test.ts +0 -28
  66. package/src/app/(backend)/middleware/auth/utils.ts +2 -17
  67. package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +3 -51
  68. package/src/app/(backend)/webapi/models/[provider]/route.test.ts +8 -4
  69. package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +7 -6
  70. package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -16
  71. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/index.tsx +1 -1
  72. package/src/app/[variants]/(main)/home/features/InputArea/SkillInstallBanner.tsx +13 -13
  73. package/src/app/[variants]/(main)/home/features/RecentPage/Item.tsx +2 -2
  74. package/src/app/[variants]/(main)/resource/features/store/action.ts +2 -2
  75. package/src/app/[variants]/(main)/resource/features/store/initialState.ts +2 -2
  76. package/src/app/[variants]/(main)/resource/store/action.ts +2 -2
  77. package/src/app/[variants]/(main)/resource/store/initialState.ts +2 -2
  78. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +3 -21
  79. package/src/app/[variants]/(main)/settings/profile/features/AvatarRow.tsx +1 -2
  80. package/src/app/[variants]/(main)/settings/security/index.tsx +1 -22
  81. package/src/app/[variants]/(main)/settings/skill/features/KlavisSkillItem.tsx +12 -14
  82. package/src/app/[variants]/(main)/settings/skill/features/LobehubSkillItem.tsx +8 -14
  83. package/src/app/[variants]/(main)/settings/skill/index.tsx +7 -5
  84. package/src/app/[variants]/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +2 -35
  85. package/src/app/[variants]/(mobile)/me/(home)/__tests__/useCategory.test.tsx +0 -20
  86. package/src/app/[variants]/(mobile)/me/(home)/features/UserBanner.tsx +1 -2
  87. package/src/app/[variants]/(mobile)/me/profile/features/Category.tsx +3 -13
  88. package/src/app/[variants]/(mobile)/settings/_layout/Header.tsx +2 -3
  89. package/src/app/[variants]/share/t/[id]/_layout/index.tsx +1 -1
  90. package/src/app/[variants]/share/t/[id]/index.tsx +1 -1
  91. package/src/app/robots.tsx +1 -1
  92. package/src/envs/auth.ts +2 -27
  93. package/src/envs/llm.ts +2 -2
  94. package/src/features/AgentSetting/AgentPlugin/index.tsx +9 -12
  95. package/src/features/ChatInput/ActionBar/Tools/index.tsx +7 -5
  96. package/src/features/ChatMiniMap/utils.ts +1 -1
  97. package/src/features/CommandMenu/SearchResults.tsx +1 -1
  98. package/src/features/Conversation/ChatList/components/AutoScroll/DebugInspector.tsx +166 -0
  99. package/src/features/Conversation/ChatList/components/AutoScroll/index.tsx +86 -0
  100. package/src/features/Conversation/ChatList/components/VirtualizedList.tsx +11 -17
  101. package/src/features/Conversation/Messages/AgentCouncil/components/AutoScrollShadow.tsx +25 -14
  102. package/src/features/Conversation/Messages/AgentCouncil/components/CouncilMember.tsx +1 -1
  103. package/src/features/FileViewer/Renderer/PDF/index.tsx +5 -8
  104. package/src/features/IntegrationDetailModal/IntegrationDetailContent.tsx +305 -0
  105. package/src/features/IntegrationDetailModal/index.tsx +21 -283
  106. package/src/features/MCPPluginDetail/Deployment/index.tsx +1 -1
  107. package/src/features/MCPPluginDetail/Schema/Prompts.tsx +1 -1
  108. package/src/features/MCPPluginDetail/Schema/Tools.tsx +1 -1
  109. package/src/features/ProfileEditor/AgentTool.tsx +14 -20
  110. package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +0 -8
  111. package/src/features/ResourceManager/components/Explorer/MasonryView/MasonryFileItem/NoteFileItem.tsx +1 -1
  112. package/src/features/ResourceManager/index.tsx +1 -1
  113. package/src/features/ShareModal/SharePdf/PdfPreview.tsx +4 -4
  114. package/src/features/SkillStore/LobeHubList/index.tsx +50 -87
  115. package/src/features/SkillStore/Search/index.tsx +1 -1
  116. package/src/features/SkillStore/{Content.tsx → SkillStoreContent.tsx} +3 -8
  117. package/src/features/SkillStore/index.tsx +15 -33
  118. package/src/features/User/UserPanel/PanelContent.tsx +0 -8
  119. package/src/features/User/__tests__/PanelContent.test.tsx +1 -35
  120. package/src/features/User/__tests__/UserAvatar.test.tsx +30 -57
  121. package/src/features/User/__tests__/useMenu.test.tsx +2 -43
  122. package/src/layout/AuthProvider/index.tsx +0 -5
  123. package/src/libs/next/config/define-config.ts +20 -15
  124. package/src/libs/next/proxy/createRouteMatcher.test.ts +121 -0
  125. package/src/libs/next/proxy/createRouteMatcher.ts +18 -0
  126. package/src/libs/next/proxy/define-config.ts +4 -53
  127. package/src/libs/next-auth/adapter/index.ts +1 -2
  128. package/src/libs/oidc-provider/provider.test.ts +5 -316
  129. package/src/libs/pdfjs/pdf.worker.ts +1 -0
  130. package/src/libs/pdfjs/worker.ts +12 -0
  131. package/src/libs/trpc/lambda/context.test.ts +0 -13
  132. package/src/libs/trpc/lambda/context.ts +3 -22
  133. package/src/libs/trpc/middleware/userAuth.ts +2 -4
  134. package/src/libs/trusted-client/getSessionUser.ts +2 -17
  135. package/src/locales/default/error.ts +0 -6
  136. package/src/locales/default/index.ts +0 -2
  137. package/src/proxy.ts +0 -1
  138. package/src/server/routers/lambda/__tests__/user.test.ts +0 -71
  139. package/src/server/routers/lambda/user.ts +6 -63
  140. package/src/server/services/changelog/index.test.ts +3 -2
  141. package/src/server/services/changelog/index.ts +1 -1
  142. package/src/server/services/user/index.ts +0 -83
  143. package/src/services/chat/index.ts +1 -2
  144. package/src/services/chat/mecha/agentConfigResolver.test.ts +43 -0
  145. package/src/services/chat/mecha/agentConfigResolver.ts +3 -1
  146. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +58 -14
  147. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +10 -2
  148. package/src/store/user/slices/auth/action.test.ts +1 -81
  149. package/src/store/user/slices/auth/action.ts +3 -28
  150. package/src/store/user/slices/auth/initialState.ts +1 -18
  151. package/src/store/user/slices/auth/selectors.test.ts +2 -127
  152. package/src/store/user/slices/auth/selectors.ts +1 -21
  153. package/src/utils/errorResponse.ts +1 -4
  154. package/src/utils/markdownToTxt.ts +20 -0
  155. package/locales/ar/clerk.json +0 -545
  156. package/locales/bg-BG/clerk.json +0 -545
  157. package/locales/de-DE/clerk.json +0 -545
  158. package/locales/en-US/clerk.json +0 -545
  159. package/locales/es-ES/clerk.json +0 -545
  160. package/locales/fa-IR/clerk.json +0 -545
  161. package/locales/fr-FR/clerk.json +0 -545
  162. package/locales/it-IT/clerk.json +0 -545
  163. package/locales/ja-JP/clerk.json +0 -545
  164. package/locales/ko-KR/clerk.json +0 -545
  165. package/locales/nl-NL/clerk.json +0 -545
  166. package/locales/pl-PL/clerk.json +0 -545
  167. package/locales/pt-BR/clerk.json +0 -545
  168. package/locales/ru-RU/clerk.json +0 -545
  169. package/locales/tr-TR/clerk.json +0 -545
  170. package/locales/vi-VN/clerk.json +0 -545
  171. package/locales/zh-CN/clerk.json +0 -545
  172. package/locales/zh-TW/clerk.json +0 -545
  173. package/src/app/(backend)/api/webhooks/clerk/__tests__/fixtures/createUser.json +0 -73
  174. package/src/app/(backend)/api/webhooks/clerk/route.ts +0 -95
  175. package/src/app/(backend)/api/webhooks/clerk/validateRequest.ts +0 -22
  176. package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +0 -27
  177. package/src/app/[variants]/(main)/settings/security/features/ClerkProfile.tsx +0 -67
  178. package/src/features/Conversation/ChatList/components/AutoScroll.tsx +0 -25
  179. package/src/layout/AuthProvider/Clerk/UserUpdater.tsx +0 -40
  180. package/src/layout/AuthProvider/Clerk/index.tsx +0 -54
  181. package/src/layout/AuthProvider/Clerk/useAppearance.ts +0 -133
  182. package/src/libs/clerk-auth/index.test.ts +0 -216
  183. package/src/libs/clerk-auth/index.ts +0 -80
  184. package/src/locales/default/clerk.ts +0 -677
  185. 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 into system message', async () => {
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
- const systemContent = result.messages[0].content;
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
- // Original content should be preserved
41
- expect(systemContent).toContain('You are a helpful editor.');
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(systemContent).toContain('You are "Editor"');
45
- expect(systemContent).toContain('acting as a participant');
46
- expect(systemContent).toContain('"Writing Team"');
47
- expect(systemContent).toContain('agt_editor');
48
- expect(systemContent).not.toContain('<agent_identity>');
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(systemContent).toContain('<group_context>');
52
- expect(systemContent).toContain('A team for collaborative writing');
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(systemContent).toContain('<group_participants>');
56
- expect(systemContent).toContain('<member name="Supervisor" id="agt_supervisor" />');
57
- expect(systemContent).toContain('<member name="Writer" id="agt_writer" />');
58
- expect(systemContent).toContain('<member name="Editor" id="agt_editor" you="true" />');
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(systemContent).toContain('<identity_rules>');
62
- expect(systemContent).toContain('NEVER expose or display agent IDs');
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[] = [{ role: 'system', content: 'You are a helpful editor.' }];
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 system message exists', async () => {
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[0].content).toBe('Hello');
102
- expect(result.messages[1].content).toBe('Hi there!');
103
- expect(result.metadata.groupContextInjected).toBeUndefined();
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[] = [{ content: 'You are an editor.', role: 'system' }];
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
- expect(result.messages[0].content).toMatchSnapshot();
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[] = [{ content: 'System prompt.', role: 'system' }];
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
- expect(result.messages[0].content).toMatchSnapshot();
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[] = [{ content: 'Base prompt.', role: 'system' }];
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
- expect(result.messages[0].content).toMatchSnapshot();
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[] = [{ role: 'system', content: 'Base prompt.' }];
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
- const systemContent = result.messages[0].content;
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(systemContent).toMatchSnapshot();
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[] = [{ content: 'Prompt.', role: 'system' }];
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
- expect(result.messages[0].content).toMatchSnapshot();
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
- // Only system message should be modified
208
- expect(result.messages[0].content).toContain('<group_context>');
209
- expect(result.messages[1].content).toBe('User message.');
210
- expect(result.messages[2].content).toBe('Assistant response.');
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
- "Prompt.
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
- "Base prompt.
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
- "System prompt.
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
- "You are an editor.
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
- "Base prompt.
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
 
@@ -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
- { id: 'msg-1', content: 'Hello', role: 'user', topicId, userId },
54
- { id: 'msg-2', content: 'Hi there!', role: 'assistant', topicId, userId },
55
- { id: 'msg-3', content: 'How are you?', role: 'user', topicId, userId },
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);
@@ -30,7 +30,7 @@
30
30
  "debug": "^4.4.3",
31
31
  "mammoth": "^1.11.0",
32
32
  "officeparser": "5.1.1",
33
- "pdfjs-dist": "4.10.38",
33
+ "pdfjs-dist": "5.4.530",
34
34
  "word-extractor": "^1.0.4",
35
35
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
36
36
  "yauzl": "^3.2.0"
@@ -2,10 +2,8 @@ import debug from 'debug';
2
2
  import { stat } from 'node:fs/promises';
3
3
  import * as path from 'node:path';
4
4
 
5
- import { fileLoaders } from './loaders';
6
- import { TextLoader } from './loaders/text';
7
- import { FileDocument, FileMetadata, SupportedFileType } from './types';
8
- import type { DocumentPage, FileLoaderInterface } from './types';
5
+ import { getFileLoader } from './loaders';
6
+ import type { DocumentPage, FileDocument, FileMetadata, SupportedFileType } from './types';
9
7
  import { isTextReadableFile } from './utils/isTextReadableFile';
10
8
 
11
9
  const log = debug('file-loaders:loadFile');
@@ -64,9 +62,6 @@ const getFileType = (filePath: string): SupportedFileType | undefined => {
64
62
  }
65
63
  };
66
64
 
67
- // Default fallback loader class
68
- const DefaultLoader = TextLoader;
69
-
70
65
  /**
71
66
  * Loads a file from the specified path, automatically detecting the file type
72
67
  * and using the appropriate loader class.
@@ -113,18 +108,18 @@ export const loadFile = async (
113
108
  source,
114
109
  });
115
110
 
116
- const paserType = getFileType(filePath);
117
- log('Parser type determined as:', paserType);
111
+ const parserType = getFileType(filePath);
112
+ log('Parser type determined as:', parserType);
118
113
 
119
- // Select the loader CLASS based on the determined fileType, fallback to DefaultLoader
120
- const LoaderClass: new () => FileLoaderInterface = paserType
121
- ? fileLoaders[paserType]
122
- : DefaultLoader;
114
+ // Use lazy loading to get the loader class - this prevents heavy dependencies
115
+ // like pdfjs-dist from being loaded until they're actually needed
116
+ const loaderType = parserType ?? 'txt';
117
+ const LoaderClass = await getFileLoader(loaderType);
123
118
  log('Selected loader class:', LoaderClass.name);
124
119
 
125
- if (!paserType) {
120
+ if (!parserType) {
126
121
  console.warn(
127
- `No specific loader found for file type '${fileType}'. Using default loader (${DefaultLoader.name}) as fallback.`,
122
+ `No specific loader found for file type '${fileType}'. Using default loader (TextLoader) as fallback.`,
128
123
  );
129
124
  }
130
125
 
@@ -1,21 +1,70 @@
1
- import { FileLoaderInterface, SupportedFileType } from '../types';
2
- import { DocLoader } from './doc';
3
- import { DocxLoader } from './docx';
4
- // import { EpubLoader } from './epub';
5
- import { ExcelLoader } from './excel';
6
- import { PdfLoader } from './pdf';
7
- import { PptxLoader } from './pptx';
8
- import { TextLoader } from './text';
1
+ import type { FileLoaderInterface, SupportedFileType } from '../types';
9
2
 
10
- // Loader configuration map
11
- // Key: file extension (lowercase, without leading dot) or specific type name
12
- // Value: Loader Class implementing FileLoaderInterface
13
- export const fileLoaders: Record<SupportedFileType, new () => FileLoaderInterface> = {
14
- doc: DocLoader,
15
- docx: DocxLoader,
16
- // epub: EpubLoader,
17
- excel: ExcelLoader,
18
- pdf: PdfLoader,
19
- pptx: PptxLoader,
20
- txt: TextLoader,
3
+ // Lazy loader factory type - returns a Promise that resolves to the loader class
4
+ type LazyLoaderFactory = () => Promise<new () => FileLoaderInterface>;
5
+
6
+ // Loader configuration map using lazy imports
7
+ // This prevents pdfjs-dist from being loaded at module initialization
8
+ // and only loads it when PDF files need to be processed
9
+ const lazyFileLoaders: Record<SupportedFileType, LazyLoaderFactory> = {
10
+ doc: async () => {
11
+ const { DocLoader } = await import('./doc');
12
+ return DocLoader;
13
+ },
14
+ docx: async () => {
15
+ const { DocxLoader } = await import('./docx');
16
+ return DocxLoader;
17
+ },
18
+ excel: async () => {
19
+ const { ExcelLoader } = await import('./excel');
20
+ return ExcelLoader;
21
+ },
22
+ pdf: async () => {
23
+ // Polyfill DOMMatrix for Node.js environment before importing pdfjs-dist
24
+ // pdfjs-dist 5.x uses DOMMatrix at module initialization which doesn't exist in Node.js
25
+ if (typeof globalThis.DOMMatrix === 'undefined') {
26
+ try {
27
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
28
+ const canvas = require('@napi-rs/canvas');
29
+ globalThis.DOMMatrix = canvas.DOMMatrix;
30
+ globalThis.DOMPoint = canvas.DOMPoint;
31
+ globalThis.DOMRect = canvas.DOMRect;
32
+ globalThis.Path2D = canvas.Path2D;
33
+ } catch {
34
+ // @napi-rs/canvas not available, pdfjs-dist may fail if DOMMatrix is needed
35
+ }
36
+ }
37
+ const { PdfLoader } = await import('./pdf');
38
+ return PdfLoader;
39
+ },
40
+ pptx: async () => {
41
+ const { PptxLoader } = await import('./pptx');
42
+ return PptxLoader;
43
+ },
44
+ txt: async () => {
45
+ const { TextLoader } = await import('./text');
46
+ return TextLoader;
47
+ },
48
+ };
49
+
50
+ /**
51
+ * Get a file loader class for the specified file type.
52
+ * Uses dynamic imports to avoid loading heavy dependencies (like pdfjs-dist) until needed.
53
+ * Falls back to TextLoader if no specific loader is found.
54
+ */
55
+ export const getFileLoader = async (
56
+ fileType: SupportedFileType | string,
57
+ ): Promise<new () => FileLoaderInterface> => {
58
+ const loaderFactory = lazyFileLoaders[fileType as SupportedFileType];
59
+ if (!loaderFactory) {
60
+ // Fallback to TextLoader for unsupported file types
61
+ const { TextLoader } = await import('./text');
62
+ return TextLoader;
63
+ }
64
+ return loaderFactory();
21
65
  };
66
+
67
+ // For backward compatibility - but prefer using getFileLoader for lazy loading
68
+ // This is kept to avoid breaking existing imports, but it will trigger immediate loading
69
+ // of all loaders. Consider migrating to getFileLoader.
70
+ export { lazyFileLoaders as fileLoaderFactories };
@@ -52,7 +52,7 @@ exports[`PdfLoader > should attach document metadata correctly 1`] = `
52
52
  "Title": "test",
53
53
  },
54
54
  "pdfMetadata": null,
55
- "pdfVersion": "4.10.38",
55
+ "pdfVersion": "5.4.530",
56
56
  }
57
57
  `;
58
58
 
@@ -25,7 +25,7 @@ exports[`loadFile Integration Tests > PDF Handling > should load content from a
25
25
  "Title": "test",
26
26
  },
27
27
  "pdfMetadata": null,
28
- "pdfVersion": "4.10.38",
28
+ "pdfVersion": "5.4.530",
29
29
  },
30
30
  },
31
31
  "pages": [
@@ -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: {
@@ -6,7 +6,6 @@ import { type ModelProviderCard } from '@/types/llm';
6
6
  const Fal: ModelProviderCard = {
7
7
  chatModels: [],
8
8
  description: 'A generative media platform built for developers.',
9
- enabled: true,
10
9
  id: 'fal',
11
10
  name: 'Fal',
12
11
  settings: {
@@ -5,8 +5,7 @@ export const ChatErrorType = {
5
5
  // ******* Business Error Semantics ******* //
6
6
 
7
7
  InvalidAccessCode: 'InvalidAccessCode', // is in valid password
8
- InvalidClerkUser: 'InvalidClerkUser', // is not Clerk User
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, enableClerk, enableNextAuth } from '@/envs/auth';
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
 
@@ -13,6 +13,7 @@ overrides:
13
13
  '@swagger-api/apidom-reference': 1.1.0
14
14
  jose: ^6.1.3
15
15
  stylelint-config-clean-order: 7.0.0
16
+ pdfjs-dist: 5.4.530
16
17
 
17
18
  patchedDependencies:
18
19
  '@swagger-api/apidom-reference': patches/@swagger-api__apidom-reference.patch