@lobehub/lobehub 2.0.0-next.217 → 2.0.0-next.219

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 (35) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/changelog/v1.json +21 -0
  3. package/package.json +2 -2
  4. package/packages/builtin-tool-cloud-sandbox/src/ExecutionRuntime/index.ts +18 -31
  5. package/packages/builtin-tool-cloud-sandbox/src/types.ts +3 -3
  6. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/List/Item/Actions.tsx +1 -1
  7. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/Actions.tsx +1 -1
  8. package/src/app/[variants]/(main)/chat/profile/features/EditorCanvas/TypoBar.tsx +1 -11
  9. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/Actions.tsx +1 -1
  10. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/Actions.tsx +1 -1
  11. package/src/app/[variants]/(main)/group/profile/features/EditorCanvas/TypoBar.tsx +1 -11
  12. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/Item/Actions.tsx +1 -1
  13. package/src/app/[variants]/(main)/home/_layout/Body/Project/List/Actions.tsx +1 -1
  14. package/src/app/[variants]/(main)/home/_layout/Footer/index.tsx +3 -9
  15. package/src/app/[variants]/(main)/home/_layout/Header/components/AddButton.tsx +1 -1
  16. package/src/app/[variants]/(main)/memory/features/EditableModal/index.tsx +8 -101
  17. package/src/app/[variants]/(main)/page/_layout/Body/List/Item/Actions.tsx +1 -1
  18. package/src/app/[variants]/(main)/resource/(home)/_layout/Body/LibraryList/List/Item/Actions.tsx +1 -1
  19. package/src/features/ChatInput/InputEditor/index.tsx +1 -0
  20. package/src/features/ChatInput/TypoBar/index.tsx +0 -11
  21. package/src/features/Conversation/ChatItem/components/MessageContent/index.tsx +11 -12
  22. package/src/features/EditorModal/EditorCanvas.tsx +81 -0
  23. package/src/features/EditorModal/TextareCanvas.tsx +28 -0
  24. package/src/{app/[variants]/(main)/memory/features/EditableModal → features/EditorModal}/Typobar.tsx +0 -11
  25. package/src/features/EditorModal/index.tsx +51 -0
  26. package/src/features/PageEditor/Copilot/TopicSelector/Actions.tsx +1 -1
  27. package/src/features/PageEditor/EditorCanvas/InlineToolbar.tsx +1 -17
  28. package/src/features/ResourceManager/components/Explorer/ItemDropdown/DropdownMenu.tsx +1 -1
  29. package/src/features/User/UserPanel/ThemeButton.tsx +1 -1
  30. package/src/server/routers/tools/market.ts +118 -102
  31. package/src/server/services/discover/index.ts +10 -5
  32. package/src/services/codeInterpreter.ts +12 -20
  33. package/src/store/chat/slices/plugin/actions/pluginTypes.ts +13 -86
  34. package/src/features/Conversation/ChatItem/components/MessageContent/EditableModal.tsx +0 -119
  35. package/src/features/Conversation/ChatItem/components/MessageContent/Typobar.tsx +0 -150
@@ -9,63 +9,20 @@ import { type StateCreator } from 'zustand/vanilla';
9
9
 
10
10
  import { type MCPToolCallResult } from '@/libs/mcp';
11
11
  import { chatService } from '@/services/chat';
12
- import { codeInterpreterService } from '@/services/codeInterpreter';
13
- import { fileService } from '@/services/file';
14
12
  import { mcpService } from '@/services/mcp';
15
13
  import { messageService } from '@/services/message';
16
14
  import { AI_RUNTIME_OPERATION_TYPES } from '@/store/chat/slices/operation';
17
15
  import { type ChatStore } from '@/store/chat/store';
18
16
  import { useToolStore } from '@/store/tool';
19
17
  import { hasExecutor } from '@/store/tool/slices/builtin/executors';
18
+ import { useUserStore } from '@/store/user';
19
+ import { userProfileSelectors } from '@/store/user/slices/auth/selectors';
20
20
  import { safeParseJSON } from '@/utils/safeParseJSON';
21
21
 
22
22
  import { dbMessageSelectors } from '../../message/selectors';
23
23
 
24
24
  const log = debug('lobe-store:plugin-types');
25
25
 
26
- /**
27
- * Get MIME type from filename extension
28
- */
29
- const getMimeTypeFromFilename = (filename: string): string => {
30
- const ext = filename.split('.').pop()?.toLowerCase() || '';
31
- const mimeTypes: Record<string, string> = {
32
- // Images
33
- bmp: 'image/bmp',
34
- gif: 'image/gif',
35
- jpeg: 'image/jpeg',
36
- jpg: 'image/jpeg',
37
- png: 'image/png',
38
- svg: 'image/svg+xml',
39
- webp: 'image/webp',
40
- // Videos
41
- mp4: 'video/mp4',
42
- webm: 'video/webm',
43
- mov: 'video/quicktime',
44
- avi: 'video/x-msvideo',
45
- // Documents
46
- csv: 'text/csv',
47
- doc: 'application/msword',
48
- docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
49
- html: 'text/html',
50
- json: 'application/json',
51
- md: 'text/markdown',
52
- pdf: 'application/pdf',
53
- ppt: 'application/vnd.ms-powerpoint',
54
- pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
55
- rtf: 'application/rtf',
56
- txt: 'text/plain',
57
- xls: 'application/vnd.ms-excel',
58
- xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
59
- xml: 'application/xml',
60
- // Code
61
- css: 'text/css',
62
- js: 'text/javascript',
63
- py: 'text/x-python',
64
- ts: 'text/typescript',
65
- };
66
- return mimeTypes[ext] || 'application/octet-stream';
67
- };
68
-
69
26
  /**
70
27
  * Plugin type-specific implementations
71
28
  * Each method handles a specific type of plugin invocation
@@ -284,10 +241,13 @@ export const pluginTypes: StateCreator<
284
241
  const { CloudSandboxExecutionRuntime } =
285
242
  await import('@lobechat/builtin-tool-cloud-sandbox/executionRuntime');
286
243
 
244
+ // Get userId from user store
245
+ const userId = userProfileSelectors.userId(useUserStore.getState()) || 'anonymous';
246
+
287
247
  // Create runtime with context
288
248
  const runtime = new CloudSandboxExecutionRuntime({
289
249
  topicId: message?.topicId || 'default',
290
- userId: 'current-user', // TODO: Get actual userId from auth context
250
+ userId,
291
251
  });
292
252
 
293
253
  // Parse arguments
@@ -341,58 +301,25 @@ export const pluginTypes: StateCreator<
341
301
  context,
342
302
  );
343
303
 
344
- // Handle exportFile: save exported file and associate with assistant message (parent)
304
+ // Handle exportFile: associate the file (already created by server) with assistant message (parent)
345
305
  if (payload.apiName === 'exportFile' && data.success && data.state) {
346
306
  const exportState = data.state as ExportFileState;
347
- if (exportState.downloadUrl && exportState.filename) {
307
+ // Server now creates the file record and returns fileId in the response
308
+ if (exportState.fileId && exportState.filename) {
348
309
  try {
349
- // Generate a hash from the URL path (without query params) for deduplication
350
- // Extract the path before query params: .../code-interpreter-exports/tpc_xxx/filename.ext
351
- const urlPath = exportState.downloadUrl.split('?')[0];
352
- const hash = `ci-export-${btoa(urlPath).slice(0, 32)}`;
353
-
354
- // Use mimeType from state if available, otherwise infer from filename
355
- const mimeType = exportState.mimeType || getMimeTypeFromFilename(exportState.filename);
356
-
357
- // 1. Create file record in database
358
- const fileResult = await fileService.createFile({
359
- fileType: mimeType,
360
- hash,
361
- name: exportState.filename,
362
- size: exportState.size || 0,
363
- source: 'code-interpreter',
364
- url: exportState.downloadUrl,
365
- });
366
-
367
- // 2. If there's text content, save it to documents table for retrieval
368
- if (exportState.content) {
369
- await codeInterpreterService.saveExportedFileContent({
370
- content: exportState.content,
371
- fileId: fileResult.id,
372
- fileType: mimeType,
373
- filename: exportState.filename,
374
- url: exportState.downloadUrl,
375
- });
376
-
377
- log(
378
- '[invokeCloudCodeInterpreterTool] Saved file content to document: fileId=%s',
379
- fileResult.id,
380
- );
381
- }
382
-
383
- // 3. Associate file with the assistant message (parent of tool message)
310
+ // Associate file with the assistant message (parent of tool message)
384
311
  // The current message (id) is the tool message, we need to attach to its parent
385
312
  const targetMessageId = message?.parentId || id;
386
313
 
387
- await messageService.addFilesToMessage(targetMessageId, [fileResult.id], {
314
+ await messageService.addFilesToMessage(targetMessageId, [exportState.fileId], {
388
315
  agentId: message?.agentId,
389
316
  topicId: message?.topicId,
390
317
  });
391
318
 
392
319
  log(
393
- '[invokeCloudCodeInterpreterTool] Saved exported file: targetMessageId=%s, fileId=%s, filename=%s',
320
+ '[invokeCloudCodeInterpreterTool] Associated exported file with message: targetMessageId=%s, fileId=%s, filename=%s',
394
321
  targetMessageId,
395
- fileResult.id,
322
+ exportState.fileId,
396
323
  exportState.filename,
397
324
  );
398
325
  } catch (error) {
@@ -1,119 +0,0 @@
1
- import {
2
- ReactCodePlugin,
3
- ReactCodemirrorPlugin,
4
- ReactHRPlugin,
5
- ReactLinkHighlightPlugin,
6
- ReactListPlugin,
7
- ReactMathPlugin,
8
- ReactTablePlugin,
9
- } from '@lobehub/editor';
10
- import { Editor, useEditor } from '@lobehub/editor/react';
11
- import { Flexbox, Modal } from '@lobehub/ui';
12
- import { memo, useMemo } from 'react';
13
- import { useTranslation } from 'react-i18next';
14
-
15
- import { useUserStore } from '@/store/user';
16
- import { labPreferSelectors } from '@/store/user/slices/preference/selectors';
17
-
18
- import TypoBar from './Typobar';
19
-
20
- interface EditableMessageProps {
21
- editing?: boolean;
22
- onChange?: (value: string) => void;
23
- onEditingChange?: (editing: boolean) => void;
24
- value?: string;
25
- }
26
-
27
- const EditableMessage = memo<EditableMessageProps>(
28
- ({ editing, onEditingChange, onChange, value }) => {
29
- const { t } = useTranslation('common');
30
- const editor = useEditor();
31
-
32
- const enableRichRender = useUserStore(labPreferSelectors.enableInputMarkdown);
33
-
34
- const richRenderProps = useMemo(
35
- () =>
36
- !enableRichRender
37
- ? {
38
- enablePasteMarkdown: false,
39
- markdownOption: {
40
- bold: false,
41
- code: false,
42
- header: false,
43
- italic: false,
44
- quote: false,
45
- strikethrough: false,
46
- underline: false,
47
- underlineStrikethrough: false,
48
- },
49
- }
50
- : {
51
- plugins: [
52
- ReactListPlugin,
53
- ReactCodePlugin,
54
- ReactCodemirrorPlugin,
55
- ReactHRPlugin,
56
- ReactLinkHighlightPlugin,
57
- ReactTablePlugin,
58
- ReactMathPlugin,
59
- ],
60
- },
61
- [enableRichRender],
62
- );
63
-
64
- return (
65
- <Modal
66
- cancelText={t('cancel')}
67
- closable={false}
68
- destroyOnHidden
69
- okText={t('ok')}
70
- onCancel={() => onEditingChange?.(false)}
71
- onOk={() => {
72
- if (!editor) return;
73
- const newValue = editor.getDocument('markdown') as unknown as string;
74
- onChange?.(newValue);
75
- onEditingChange?.(false);
76
- }}
77
- open={editing}
78
- styles={{
79
- body: {
80
- overflow: 'hidden',
81
- padding: 0,
82
- },
83
- }}
84
- title={null}
85
- width={'min(90vw, 960px)'}
86
- >
87
- <TypoBar editor={editor} />
88
- <Flexbox
89
- onClick={() => {
90
- editor.focus();
91
- }}
92
- paddingBlock={16}
93
- paddingInline={48}
94
- style={{ cursor: 'text', maxHeight: '80vh', minHeight: '50vh', overflowY: 'auto' }}
95
- >
96
- <Editor
97
- autoFocus
98
- content={''}
99
- editor={editor}
100
- onInit={(editor) => {
101
- if (!editor) return;
102
- try {
103
- editor?.setDocument('markdown', value);
104
- } catch {}
105
- }}
106
- style={{
107
- paddingBottom: 120,
108
- }}
109
- type={'text'}
110
- variant={'chat'}
111
- {...richRenderProps}
112
- />
113
- </Flexbox>
114
- </Modal>
115
- );
116
- },
117
- );
118
-
119
- export default EditableMessage;
@@ -1,150 +0,0 @@
1
- import { HotkeyEnum, type IEditor, getHotkeyById } from '@lobehub/editor';
2
- import { useEditorState } from '@lobehub/editor/react';
3
- import {
4
- ChatInputActionBar,
5
- ChatInputActions,
6
- type ChatInputActionsProps,
7
- CodeLanguageSelect,
8
- } from '@lobehub/editor/react';
9
- import { cssVar } from 'antd-style';
10
- import {
11
- BoldIcon,
12
- CodeXmlIcon,
13
- ItalicIcon,
14
- ListIcon,
15
- ListOrderedIcon,
16
- ListTodoIcon,
17
- MessageSquareQuote,
18
- SigmaIcon,
19
- SquareDashedBottomCodeIcon,
20
- StrikethroughIcon,
21
- UnderlineIcon,
22
- } from 'lucide-react';
23
- import { memo, useMemo } from 'react';
24
- import { useTranslation } from 'react-i18next';
25
-
26
- const TypoBar = memo<{ editor?: IEditor }>(({ editor }) => {
27
- const { t } = useTranslation('editor');
28
- const editorState = useEditorState(editor);
29
-
30
- const items: ChatInputActionsProps['items'] = useMemo(
31
- () =>
32
- [
33
- {
34
- active: editorState.isBold,
35
- icon: BoldIcon,
36
- key: 'bold',
37
- label: t('typobar.bold'),
38
- onClick: editorState.bold,
39
- tooltipProps: { hotkey: getHotkeyById(HotkeyEnum.Bold).keys },
40
- },
41
- {
42
- active: editorState.isItalic,
43
- icon: ItalicIcon,
44
- key: 'italic',
45
- label: t('typobar.italic'),
46
- onClick: editorState.italic,
47
- tooltipProps: { hotkey: getHotkeyById(HotkeyEnum.Italic).keys },
48
- },
49
- {
50
- active: editorState.isUnderline,
51
- icon: UnderlineIcon,
52
- key: 'underline',
53
- label: t('typobar.underline'),
54
- onClick: editorState.underline,
55
- tooltipProps: { hotkey: getHotkeyById(HotkeyEnum.Underline).keys },
56
- },
57
- {
58
- active: editorState.isStrikethrough,
59
- icon: StrikethroughIcon,
60
- key: 'strikethrough',
61
- label: t('typobar.strikethrough'),
62
- onClick: editorState.strikethrough,
63
- tooltipProps: { hotkey: getHotkeyById(HotkeyEnum.Strikethrough).keys },
64
- },
65
- {
66
- type: 'divider',
67
- },
68
-
69
- {
70
- icon: ListIcon,
71
- key: 'bulletList',
72
- label: t('typobar.bulletList'),
73
- onClick: editorState.bulletList,
74
- tooltipProps: { hotkey: getHotkeyById(HotkeyEnum.BulletList).keys },
75
- },
76
- {
77
- icon: ListOrderedIcon,
78
- key: 'numberlist',
79
- label: t('typobar.numberList'),
80
- onClick: editorState.numberList,
81
- tooltipProps: { hotkey: getHotkeyById(HotkeyEnum.NumberList).keys },
82
- },
83
- {
84
- icon: ListTodoIcon,
85
- key: 'tasklist',
86
- label: t('typobar.taskList'),
87
- onClick: editorState.checkList,
88
- },
89
- {
90
- type: 'divider',
91
- },
92
- {
93
- active: editorState.isBlockquote,
94
- icon: MessageSquareQuote,
95
- key: 'blockquote',
96
- label: t('typobar.blockquote'),
97
- onClick: editorState.blockquote,
98
- },
99
- {
100
- type: 'divider',
101
- },
102
- {
103
- icon: SigmaIcon,
104
- key: 'math',
105
- label: t('typobar.tex'),
106
- onClick: editorState.insertMath,
107
- },
108
- {
109
- active: editorState.isCode,
110
- icon: CodeXmlIcon,
111
- key: 'code',
112
- label: t('typobar.code'),
113
- onClick: editorState.code,
114
- tooltipProps: { hotkey: getHotkeyById(HotkeyEnum.CodeInline).keys },
115
- },
116
- {
117
- icon: SquareDashedBottomCodeIcon,
118
- key: 'codeblock',
119
- label: t('typobar.codeblock'),
120
- onClick: editorState.codeblock,
121
- },
122
- editorState.isCodeblock && {
123
- children: (
124
- <CodeLanguageSelect
125
- onSelect={(value) => editorState.updateCodeblockLang(value)}
126
- value={editorState.codeblockLang}
127
- />
128
- ),
129
- disabled: !editorState.isCodeblock,
130
- key: 'codeblockLang',
131
- },
132
- ].filter(Boolean) as ChatInputActionsProps['items'],
133
- [editorState],
134
- );
135
-
136
- return (
137
- <ChatInputActionBar
138
- left={<ChatInputActions items={items} />}
139
- style={{
140
- background: cssVar.colorFillQuaternary,
141
- borderTopLeftRadius: 8,
142
- borderTopRightRadius: 8,
143
- }}
144
- />
145
- );
146
- });
147
-
148
- TypoBar.displayName = 'TypoBar';
149
-
150
- export default TypoBar;