@lobehub/chat 1.140.0 → 1.141.1

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 (125) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/changelog/v1.json +24 -0
  3. package/locales/ar/chat.json +13 -0
  4. package/locales/ar/common.json +1 -0
  5. package/locales/ar/components.json +4 -0
  6. package/locales/ar/file.json +2 -2
  7. package/locales/bg-BG/chat.json +13 -0
  8. package/locales/bg-BG/common.json +1 -0
  9. package/locales/bg-BG/components.json +4 -0
  10. package/locales/bg-BG/file.json +2 -2
  11. package/locales/de-DE/chat.json +13 -0
  12. package/locales/de-DE/common.json +1 -0
  13. package/locales/de-DE/components.json +4 -0
  14. package/locales/de-DE/file.json +2 -2
  15. package/locales/en-US/chat.json +13 -0
  16. package/locales/en-US/common.json +1 -0
  17. package/locales/en-US/components.json +4 -0
  18. package/locales/en-US/file.json +2 -2
  19. package/locales/es-ES/chat.json +13 -0
  20. package/locales/es-ES/common.json +1 -0
  21. package/locales/es-ES/components.json +4 -0
  22. package/locales/es-ES/file.json +2 -2
  23. package/locales/fa-IR/chat.json +13 -0
  24. package/locales/fa-IR/common.json +1 -0
  25. package/locales/fa-IR/components.json +4 -0
  26. package/locales/fa-IR/file.json +2 -2
  27. package/locales/fr-FR/chat.json +13 -0
  28. package/locales/fr-FR/common.json +1 -0
  29. package/locales/fr-FR/components.json +4 -0
  30. package/locales/fr-FR/file.json +2 -2
  31. package/locales/it-IT/chat.json +13 -0
  32. package/locales/it-IT/common.json +1 -0
  33. package/locales/it-IT/components.json +4 -0
  34. package/locales/it-IT/file.json +2 -2
  35. package/locales/ja-JP/chat.json +13 -0
  36. package/locales/ja-JP/common.json +1 -0
  37. package/locales/ja-JP/components.json +4 -0
  38. package/locales/ja-JP/file.json +2 -2
  39. package/locales/ko-KR/chat.json +13 -0
  40. package/locales/ko-KR/common.json +1 -0
  41. package/locales/ko-KR/components.json +4 -0
  42. package/locales/ko-KR/file.json +2 -2
  43. package/locales/nl-NL/chat.json +13 -0
  44. package/locales/nl-NL/common.json +1 -0
  45. package/locales/nl-NL/components.json +4 -0
  46. package/locales/nl-NL/file.json +2 -2
  47. package/locales/pl-PL/chat.json +13 -0
  48. package/locales/pl-PL/common.json +1 -0
  49. package/locales/pl-PL/components.json +4 -0
  50. package/locales/pl-PL/file.json +2 -2
  51. package/locales/pt-BR/chat.json +13 -0
  52. package/locales/pt-BR/common.json +1 -0
  53. package/locales/pt-BR/components.json +4 -0
  54. package/locales/pt-BR/file.json +2 -2
  55. package/locales/ru-RU/chat.json +13 -0
  56. package/locales/ru-RU/common.json +1 -0
  57. package/locales/ru-RU/components.json +4 -0
  58. package/locales/ru-RU/file.json +2 -2
  59. package/locales/tr-TR/chat.json +13 -0
  60. package/locales/tr-TR/common.json +1 -0
  61. package/locales/tr-TR/components.json +4 -0
  62. package/locales/tr-TR/file.json +2 -2
  63. package/locales/vi-VN/chat.json +13 -0
  64. package/locales/vi-VN/common.json +1 -0
  65. package/locales/vi-VN/components.json +4 -0
  66. package/locales/vi-VN/file.json +2 -2
  67. package/locales/zh-CN/chat.json +13 -0
  68. package/locales/zh-CN/common.json +1 -0
  69. package/locales/zh-CN/components.json +4 -0
  70. package/locales/zh-CN/file.json +2 -2
  71. package/locales/zh-TW/chat.json +13 -0
  72. package/locales/zh-TW/common.json +1 -0
  73. package/locales/zh-TW/components.json +4 -0
  74. package/locales/zh-TW/file.json +2 -2
  75. package/next.config.ts +5 -6
  76. package/package.json +8 -2
  77. package/packages/context-engine/src/__tests__/pipeline.test.ts +7 -27
  78. package/packages/context-engine/src/pipeline.ts +5 -21
  79. package/packages/context-engine/src/types.ts +2 -2
  80. package/packages/database/src/models/__tests__/message.test.ts +200 -2
  81. package/packages/database/src/models/message.ts +13 -0
  82. package/packages/model-runtime/src/core/openaiCompatibleFactory/index.test.ts +313 -0
  83. package/packages/model-runtime/src/core/openaiCompatibleFactory/index.ts +21 -5
  84. package/packages/model-runtime/src/providers/azureai/index.test.ts +12 -2
  85. package/packages/model-runtime/src/providers/groq/index.test.ts +449 -0
  86. package/packages/model-runtime/src/providers/groq/index.ts +46 -0
  87. package/src/app/[variants]/(main)/_layout/Desktop/SideBar/TopActions.tsx +3 -2
  88. package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/Tags/index.tsx +1 -1
  89. package/src/app/[variants]/(main)/files/(content)/@menu/features/KnowledgeBase/Item/index.tsx +10 -2
  90. package/src/features/ChatInput/InputEditor/index.tsx +2 -0
  91. package/src/features/Conversation/Messages/User/index.tsx +7 -17
  92. package/src/features/Conversation/components/ChatItem/ShareMessageModal/SharePdf/PdfPreview.tsx +361 -0
  93. package/src/features/Conversation/components/ChatItem/ShareMessageModal/SharePdf/index.tsx +119 -0
  94. package/src/features/Conversation/components/ChatItem/ShareMessageModal/SharePdf/style.ts +63 -0
  95. package/src/features/Conversation/components/ChatItem/ShareMessageModal/SharePdf/template.ts +24 -0
  96. package/src/features/Conversation/components/ChatItem/ShareMessageModal/SharePdf/usePdfGeneration.ts +93 -0
  97. package/src/features/Conversation/components/ShareMessageModal/ShareImage/Preview.tsx +1 -1
  98. package/src/features/Conversation/components/ShareMessageModal/index.tsx +39 -14
  99. package/src/features/FileManager/FileList/MasonryFileItem/MasonryItemWrapper.tsx +44 -0
  100. package/src/features/FileManager/FileList/MasonryFileItem/index.tsx +553 -0
  101. package/src/features/FileManager/FileList/MasonrySkeleton.tsx +57 -0
  102. package/src/features/FileManager/FileList/ToolBar/ViewSwitcher.tsx +45 -0
  103. package/src/features/FileManager/FileList/ToolBar/index.tsx +9 -1
  104. package/src/features/FileManager/FileList/index.tsx +83 -13
  105. package/src/features/FileManager/Header/FilesSearchBar.tsx +7 -2
  106. package/src/features/ShareModal/ShareImage/Preview.tsx +1 -1
  107. package/src/features/ShareModal/SharePdf/PdfPreview.tsx +361 -0
  108. package/src/features/ShareModal/SharePdf/index.tsx +194 -0
  109. package/src/features/ShareModal/SharePdf/usePdfGeneration.ts +90 -0
  110. package/src/features/ShareModal/index.tsx +40 -14
  111. package/src/features/ShareModal/style.ts +8 -5
  112. package/src/helpers/toolEngineering/index.ts +7 -1
  113. package/src/helpers/toolFilters.ts +35 -0
  114. package/src/libs/trpc/client/lambda.ts +7 -1
  115. package/src/locales/default/chat.ts +13 -0
  116. package/src/locales/default/common.ts +1 -0
  117. package/src/locales/default/components.ts +4 -0
  118. package/src/locales/default/file.ts +2 -2
  119. package/src/server/globalConfig/parseSystemAgent.ts +4 -2
  120. package/src/server/routers/lambda/exporter.ts +173 -3
  121. package/src/server/routers/lambda/message.ts +11 -0
  122. package/src/services/chat/contextEngineering.ts +1 -9
  123. package/src/store/agent/slices/chat/selectors/agent.ts +16 -6
  124. package/src/store/global/initialState.ts +2 -0
  125. package/src/store/tool/slices/builtin/selectors.ts +15 -5
@@ -1,4 +1,10 @@
1
+ import { marked } from 'marked';
2
+ import PDFDocument from 'pdfkit';
3
+ import { z } from 'zod';
4
+
1
5
  import { DrizzleMigrationModel } from '@/database/models/drizzleMigration';
6
+ import { MessageModel } from '@/database/models/message';
7
+ import { SessionModel } from '@/database/models/session';
2
8
  import { DataExporterRepos } from '@/database/repositories/dataExporter';
3
9
  import { authedProcedure, router } from '@/libs/trpc/lambda';
4
10
  import { serverDatabase } from '@/libs/trpc/lambda/middleware';
@@ -8,18 +14,182 @@ const exportProcedure = authedProcedure.use(serverDatabase).use(async (opts) =>
8
14
  const { ctx } = opts;
9
15
  const dataExporterRepos = new DataExporterRepos(ctx.serverDB, ctx.userId);
10
16
  const drizzleMigration = new DrizzleMigrationModel(ctx.serverDB);
17
+ const messageModel = new MessageModel(ctx.serverDB, ctx.userId);
18
+ const sessionModel = new SessionModel(ctx.serverDB, ctx.userId);
11
19
 
12
20
  return opts.next({
13
- ctx: { dataExporterRepos, drizzleMigration },
21
+ ctx: { dataExporterRepos, drizzleMigration, messageModel, sessionModel },
14
22
  });
15
23
  });
16
24
 
25
+
26
+ const REGULAR_FONT_URL =
27
+ 'https://cdn.jsdelivr.net/gh/adobe-fonts/source-han-sans@2.004R/OTF/SimplifiedChinese/SourceHanSansSC-Regular.otf';
28
+
29
+ let regularFontCache: Buffer | null = null;
30
+
31
+ const loadRegularFont = async (): Promise<Buffer> => {
32
+ if (regularFontCache) return regularFontCache;
33
+
34
+ const response = await fetch(REGULAR_FONT_URL);
35
+ if (!response.ok) {
36
+ throw new Error(`Failed to fetch font from CDN: ${response.status} ${response.statusText}`);
37
+ }
38
+
39
+ const fontBuffer = Buffer.from(await response.arrayBuffer());
40
+ regularFontCache = fontBuffer;
41
+
42
+ return fontBuffer;
43
+ };
44
+
45
+ const generatePdfFromMarkdown = async (
46
+ markdownContent: string,
47
+ title?: string,
48
+ ): Promise<Buffer> => {
49
+ const regularFont = await loadRegularFont();
50
+
51
+ return new Promise((resolve, reject) => {
52
+ try {
53
+ const tokens = marked.lexer(markdownContent);
54
+
55
+ const doc = new PDFDocument({
56
+ bufferPages: true,
57
+ margins: {
58
+ bottom: 50,
59
+ left: 50,
60
+ right: 50,
61
+ top: 50,
62
+ },
63
+ size: 'A4',
64
+ });
65
+
66
+ const chunks: Buffer[] = [];
67
+
68
+ doc.registerFont('Regular', regularFont);
69
+ doc.font('Regular');
70
+
71
+ doc.on('data', (chunk: Buffer) => chunks.push(chunk));
72
+ doc.on('end', () => {
73
+ const pdfBuffer = Buffer.concat(chunks);
74
+ resolve(pdfBuffer);
75
+ });
76
+ doc.on('error', reject);
77
+
78
+ if (title) {
79
+ doc.fontSize(20).text(title, { align: 'center' });
80
+ }
81
+ doc.moveDown(2);
82
+
83
+ let currentY = doc.y;
84
+
85
+ for (const token of tokens) {
86
+ if (currentY > 700) {
87
+ doc.addPage();
88
+ currentY = 50;
89
+ }
90
+
91
+ switch (token.type) {
92
+ case 'heading': {
93
+ const headingSize = Math.max(16 - (token.depth - 1) * 2, 12);
94
+ doc.fontSize(headingSize).fillColor('#222').text(token.text, { continued: false });
95
+ doc.moveDown(0.5);
96
+ break;
97
+ }
98
+
99
+ case 'paragraph': {
100
+ doc.fontSize(12).fillColor('#333').text(token.text, { align: 'left', lineGap: 2 });
101
+ doc.moveDown(1);
102
+ break;
103
+ }
104
+
105
+ case 'list': {
106
+ for (const item of token.items) {
107
+ doc.fontSize(12).fillColor('#333').text(`• ${item.text}`, { indent: 20, lineGap: 2 });
108
+ }
109
+ doc.moveDown(1);
110
+ break;
111
+ }
112
+
113
+ case 'blockquote': {
114
+ doc.fontSize(12).fillColor('#666').text(token.text, { indent: 20, lineGap: 2 });
115
+ doc.moveDown(1);
116
+ break;
117
+ }
118
+
119
+ case 'code': {
120
+ doc.fontSize(10).fillColor('#333').text(token.text, {
121
+ continued: false,
122
+ indent: 20,
123
+ lineGap: 1,
124
+ });
125
+ doc.moveDown(1);
126
+ break;
127
+ }
128
+
129
+ case 'hr': {
130
+ doc.moveTo(50, doc.y).lineTo(545, doc.y).stroke();
131
+ doc.moveDown(1);
132
+ break;
133
+ }
134
+
135
+ default: {
136
+ if ('text' in token && token.text) {
137
+ doc.fontSize(12).fillColor('#333').text(token.text, { align: 'left', lineGap: 2 });
138
+ doc.moveDown(1);
139
+ }
140
+ break;
141
+ }
142
+ }
143
+
144
+ currentY = doc.y;
145
+ }
146
+
147
+ const pages = doc.bufferedPageRange();
148
+ for (let i = 0; i < pages.count; i++) {
149
+ doc.switchToPage(i);
150
+ doc
151
+ .fontSize(8)
152
+ .fillColor('#666')
153
+ .text(`Page ${i + 1} of ${pages.count}`, 50, 750, {
154
+ align: 'center',
155
+ width: 495,
156
+ });
157
+ }
158
+
159
+ // 完成文档
160
+ doc.end();
161
+ } catch (error) {
162
+ reject(
163
+ new Error(
164
+ `PDFKit PDF generation failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
165
+ ),
166
+ );
167
+ }
168
+ });
169
+ };
170
+
17
171
  export const exporterRouter = router({
18
172
  exportData: exportProcedure.mutation(async ({ ctx }): Promise<ExportDatabaseData> => {
19
173
  const data = await ctx.dataExporterRepos.export(5);
20
-
21
174
  const schemaHash = await ctx.drizzleMigration.getLatestMigrationHash();
22
-
23
175
  return { data, schemaHash };
24
176
  }),
177
+
178
+ exportPdf: exportProcedure
179
+ .input(
180
+ z.object({
181
+ content: z.string(),
182
+ sessionId: z.string(),
183
+ title: z.string().optional(),
184
+ topicId: z.string().optional(),
185
+ }),
186
+ )
187
+ .mutation(async ({ input }) => {
188
+ const { content, title } = input;
189
+ const pdfBuffer = await generatePdfFromMarkdown(content, title);
190
+ return {
191
+ filename: `${title}.pdf`,
192
+ pdf: pdfBuffer.toString('base64'),
193
+ };
194
+ }),
25
195
  });
@@ -198,6 +198,17 @@ export const messageRouter = router({
198
198
  await ctx.messageModel.updateMessageRAG(input.id, input.value);
199
199
  }),
200
200
 
201
+ updateMetadata: messageProcedure
202
+ .input(
203
+ z.object({
204
+ id: z.string(),
205
+ value: z.object({}).passthrough(),
206
+ }),
207
+ )
208
+ .mutation(async ({ input, ctx }) => {
209
+ return ctx.messageModel.updateMetadata(input.id, input.value);
210
+ }),
211
+
201
212
  updatePluginError: messageProcedure
202
213
  .input(
203
214
  z.object({
@@ -1,6 +1,5 @@
1
1
  import { INBOX_GUIDE_SYSTEMROLE, INBOX_SESSION_ID, isDesktop, isServerMode } from '@lobechat/const';
2
2
  import {
3
- type AgentState,
4
3
  ContextEngine,
5
4
  HistorySummaryProvider,
6
5
  HistoryTruncateProcessor,
@@ -122,14 +121,7 @@ export const contextEngineering = async ({
122
121
  ],
123
122
  });
124
123
 
125
- const initialState: AgentState = { messages, model, provider, systemRole, tools };
126
-
127
- const result = await pipeline.process({
128
- initialState,
129
- maxTokens: 10_000_000,
130
- messages,
131
- model,
132
- });
124
+ const result = await pipeline.process({ messages });
133
125
 
134
126
  return result.messages;
135
127
  };
@@ -1,16 +1,16 @@
1
- import { VoiceList } from '@lobehub/tts';
2
-
3
- import { INBOX_SESSION_ID } from '@/const/session';
4
1
  import {
5
2
  DEFAULT_AGENT_CONFIG,
6
3
  DEFAULT_MODEL,
7
4
  DEFAULT_PROVIDER,
8
5
  DEFAUTT_AGENT_TTS_CONFIG,
9
- } from '@/const/settings';
6
+ INBOX_SESSION_ID,
7
+ } from '@lobechat/const';
8
+ import { KnowledgeItem, KnowledgeType, LobeAgentConfig, LobeAgentTTSConfig } from '@lobechat/types';
9
+ import { VoiceList } from '@lobehub/tts';
10
+
10
11
  import { DEFAULT_OPENING_QUESTIONS } from '@/features/AgentSetting/store/selectors';
12
+ import { filterToolIds } from '@/helpers/toolFilters';
11
13
  import { AgentStoreState } from '@/store/agent/initialState';
12
- import { LobeAgentConfig, LobeAgentTTSConfig } from '@/types/agent';
13
- import { KnowledgeItem, KnowledgeType } from '@/types/knowledgeBase';
14
14
  import { merge } from '@/utils/merge';
15
15
 
16
16
  const isInboxSession = (s: AgentStoreState) => s.activeId === INBOX_SESSION_ID;
@@ -68,6 +68,15 @@ const currentAgentPlugins = (s: AgentStoreState) => {
68
68
  return config?.plugins || [];
69
69
  };
70
70
 
71
+ /**
72
+ * Get displayable agent plugins by filtering out platform-specific tools
73
+ * that shouldn't be shown in the current environment
74
+ */
75
+ const displayableAgentPlugins = (s: AgentStoreState) => {
76
+ const plugins = currentAgentPlugins(s);
77
+ return filterToolIds(plugins);
78
+ };
79
+
71
80
  const currentAgentKnowledgeBases = (s: AgentStoreState) => {
72
81
  const config = currentAgentConfig(s);
73
82
 
@@ -172,6 +181,7 @@ export const agentSelectors = {
172
181
  currentAgentTTSVoice,
173
182
  currentEnabledKnowledge,
174
183
  currentKnowledgeIds,
184
+ displayableAgentPlugins,
175
185
  getAgentConfigByAgentId,
176
186
  getAgentConfigById,
177
187
  hasEnabledKnowledge,
@@ -57,6 +57,7 @@ export interface SystemStatus {
57
57
  expandInputActionbar?: boolean;
58
58
  // which sessionGroup should expand
59
59
  expandSessionGroupKeys: string[];
60
+ fileManagerViewMode?: 'list' | 'masonry';
60
61
  filePanelWidth: number;
61
62
  hideGemini2_5FlashImagePreviewChineseWarning?: boolean;
62
63
  hidePWAInstaller?: boolean;
@@ -125,6 +126,7 @@ export const INITIAL_STATUS = {
125
126
  chatInputHeight: 64,
126
127
  expandInputActionbar: true,
127
128
  expandSessionGroupKeys: [SessionDefaultGroup.Pinned, SessionDefaultGroup.Default],
129
+ fileManagerViewMode: 'list' as const,
128
130
  filePanelWidth: 320,
129
131
  hideGemini2_5FlashImagePreviewChineseWarning: false,
130
132
  hidePWAInstaller: false,
@@ -1,5 +1,7 @@
1
+ import { LobeToolMeta } from '@lobechat/types';
2
+
3
+ import { shouldEnableTool } from '@/helpers/toolFilters';
1
4
  import { DalleManifest } from '@/tools/dalle';
2
- import { LobeToolMeta } from '@/types/tool/tool';
3
5
 
4
6
  import type { ToolStoreState } from '../../initialState';
5
7
 
@@ -7,10 +9,18 @@ const metaList =
7
9
  (showDalle?: boolean) =>
8
10
  (s: ToolStoreState): LobeToolMeta[] =>
9
11
  s.builtinTools
10
- .filter(
11
- (item) =>
12
- !item.hidden && (!showDalle ? item.identifier !== DalleManifest.identifier : true),
13
- )
12
+ .filter((item) => {
13
+ // Filter hidden tools
14
+ if (item.hidden) return false;
15
+
16
+ // Filter Dalle if not enabled
17
+ if (!showDalle && item.identifier === DalleManifest.identifier) return false;
18
+
19
+ // Filter platform-specific tools (e.g., LocalSystem desktop-only)
20
+ if (!shouldEnableTool(item.identifier)) return false;
21
+
22
+ return true;
23
+ })
14
24
  .map((t) => ({
15
25
  author: 'LobeHub',
16
26
  identifier: t.identifier,