@lobehub/lobehub 2.0.0-next.345 → 2.0.0-next.347
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/CHANGELOG.md +58 -0
- package/CLAUDE.md +4 -2
- package/changelog/v1.json +17 -0
- package/package.json +6 -4
- package/packages/file-loaders/package.json +1 -1
- package/packages/file-loaders/src/loadFile.ts +10 -15
- package/packages/file-loaders/src/loaders/index.ts +68 -19
- package/packages/file-loaders/src/loaders/pdf/__snapshots__/index.test.ts.snap +1 -1
- package/packages/file-loaders/test/__snapshots__/loaders.test.ts.snap +1 -1
- package/pnpm-workspace.yaml +1 -0
- package/src/app/[variants]/(main)/agent/profile/features/AgentSettings/Content.tsx +133 -0
- package/src/app/[variants]/(main)/agent/profile/features/AgentSettings/index.tsx +35 -0
- package/src/app/[variants]/(main)/agent/profile/features/ProfileEditor/index.tsx +16 -2
- package/src/app/[variants]/(main)/group/profile/features/AgentSettings/Content.tsx +140 -0
- package/src/app/[variants]/(main)/group/profile/features/AgentSettings/index.tsx +36 -0
- package/src/app/[variants]/(main)/group/profile/features/GroupProfile/index.tsx +17 -2
- package/src/app/[variants]/(main)/resource/features/store/action.ts +2 -2
- package/src/app/[variants]/(main)/resource/features/store/initialState.ts +2 -2
- package/src/app/[variants]/(main)/resource/store/action.ts +2 -2
- package/src/app/[variants]/(main)/resource/store/initialState.ts +2 -2
- package/src/features/AgentSetting/AgentOpening/OpeningQuestions.tsx +4 -3
- package/src/features/AgentSetting/AgentOpening/index.tsx +0 -3
- package/src/features/FileViewer/Renderer/PDF/index.tsx +5 -8
- package/src/features/ProfileEditor/AgentTool.tsx +20 -29
- package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +0 -8
- package/src/features/ResourceManager/index.tsx +1 -1
- package/src/features/ShareModal/SharePdf/PdfPreview.tsx +4 -4
- package/src/libs/next/config/define-config.ts +14 -15
- package/src/libs/pdfjs/pdf.worker.ts +1 -0
- package/src/libs/pdfjs/worker.ts +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.347](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.346...v2.0.0-next.347)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-01-23**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Add advace config back in agent/group profiles.
|
|
12
|
+
|
|
13
|
+
#### 💄 Styles
|
|
14
|
+
|
|
15
|
+
- **misc**: Move plugin store button outside scroll container.
|
|
16
|
+
|
|
17
|
+
<br/>
|
|
18
|
+
|
|
19
|
+
<details>
|
|
20
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
21
|
+
|
|
22
|
+
#### What's fixed
|
|
23
|
+
|
|
24
|
+
- **misc**: Add advace config back in agent/group profiles, closes [#11727](https://github.com/lobehub/lobe-chat/issues/11727) ([403175f](https://github.com/lobehub/lobe-chat/commit/403175f))
|
|
25
|
+
|
|
26
|
+
#### Styles
|
|
27
|
+
|
|
28
|
+
- **misc**: Move plugin store button outside scroll container, closes [#11728](https://github.com/lobehub/lobe-chat/issues/11728) ([c484d1a](https://github.com/lobehub/lobe-chat/commit/c484d1a))
|
|
29
|
+
|
|
30
|
+
</details>
|
|
31
|
+
|
|
32
|
+
<div align="right">
|
|
33
|
+
|
|
34
|
+
[](#readme-top)
|
|
35
|
+
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
## [Version 2.0.0-next.346](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.345...v2.0.0-next.346)
|
|
39
|
+
|
|
40
|
+
<sup>Released on **2026-01-23**</sup>
|
|
41
|
+
|
|
42
|
+
#### 🐛 Bug Fixes
|
|
43
|
+
|
|
44
|
+
- **pdf**: Upgrade pdfjs-dist and react-pdf to v5.x.
|
|
45
|
+
|
|
46
|
+
<br/>
|
|
47
|
+
|
|
48
|
+
<details>
|
|
49
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
50
|
+
|
|
51
|
+
#### What's fixed
|
|
52
|
+
|
|
53
|
+
- **pdf**: Upgrade pdfjs-dist and react-pdf to v5.x, closes [#11686](https://github.com/lobehub/lobe-chat/issues/11686) ([2b620df](https://github.com/lobehub/lobe-chat/commit/2b620df))
|
|
54
|
+
|
|
55
|
+
</details>
|
|
56
|
+
|
|
57
|
+
<div align="right">
|
|
58
|
+
|
|
59
|
+
[](#readme-top)
|
|
60
|
+
|
|
61
|
+
</div>
|
|
62
|
+
|
|
5
63
|
## [Version 2.0.0-next.345](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.344...v2.0.0-next.345)
|
|
6
64
|
|
|
7
65
|
<sup>Released on **2026-01-23**</sup>
|
package/CLAUDE.md
CHANGED
|
@@ -61,9 +61,11 @@ see @.cursor/rules/typescript.mdc
|
|
|
61
61
|
- **Dev**: Translate `locales/zh-CN/namespace.json` and `locales/en-US/namespace.json` locales file only for dev preview
|
|
62
62
|
- DON'T run `pnpm i18n`, let CI auto handle it
|
|
63
63
|
|
|
64
|
-
## Linear Issue Management(ignore if not installed
|
|
64
|
+
## Linear Issue Management (search tools first; ignore if not installed)
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
ClaudeCode may not inject MCP tools until they are discovered/used.\
|
|
67
|
+
Before applying Linear workflows, **use tool search** to confirm `linear-server` exists (e.g. search `linear` / `mcp__linear-server__`). If not found, treat it as not installed.\
|
|
68
|
+
Then read `@.cursor/rules/linear.mdc` when working with Linear issues.
|
|
67
69
|
|
|
68
70
|
## Rules Index
|
|
69
71
|
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"fixes": [
|
|
5
|
+
"Add advace config back in agent/group profiles."
|
|
6
|
+
],
|
|
7
|
+
"improvements": [
|
|
8
|
+
"Move plugin store button outside scroll container."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"date": "2026-01-23",
|
|
12
|
+
"version": "2.0.0-next.347"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"children": {},
|
|
16
|
+
"date": "2026-01-23",
|
|
17
|
+
"version": "2.0.0-next.346"
|
|
18
|
+
},
|
|
2
19
|
{
|
|
3
20
|
"children": {
|
|
4
21
|
"features": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.347",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
]
|
|
134
134
|
},
|
|
135
135
|
"overrides": {
|
|
136
|
+
"pdfjs-dist": "5.4.530",
|
|
136
137
|
"stylelint-config-clean-order": "7.0.0"
|
|
137
138
|
},
|
|
138
139
|
"dependencies": {
|
|
@@ -206,11 +207,12 @@
|
|
|
206
207
|
"@lobehub/tts": "^4.0.2",
|
|
207
208
|
"@lobehub/ui": "^4.27.4",
|
|
208
209
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
210
|
+
"@napi-rs/canvas": "^0.1.88",
|
|
209
211
|
"@neondatabase/serverless": "^1.0.2",
|
|
210
212
|
"@next/third-parties": "^16.1.1",
|
|
211
213
|
"@opentelemetry/exporter-jaeger": "^2.2.0",
|
|
212
214
|
"@opentelemetry/winston-transport": "^0.19.0",
|
|
213
|
-
"@react-pdf/renderer": "^4.3.
|
|
215
|
+
"@react-pdf/renderer": "^4.3.2",
|
|
214
216
|
"@react-three/drei": "^10.7.7",
|
|
215
217
|
"@react-three/fiber": "^9.4.2",
|
|
216
218
|
"@saintno/comfyui-sdk": "^0.2.49",
|
|
@@ -296,7 +298,7 @@
|
|
|
296
298
|
"path-browserify-esm": "^1.0.6",
|
|
297
299
|
"pathe": "^2.0.3",
|
|
298
300
|
"pdf-parse": "^1.1.4",
|
|
299
|
-
"pdfjs-dist": "4.
|
|
301
|
+
"pdfjs-dist": "5.4.530",
|
|
300
302
|
"pdfkit": "^0.17.2",
|
|
301
303
|
"pg": "^8.16.3",
|
|
302
304
|
"pino": "^10.1.0",
|
|
@@ -316,7 +318,7 @@
|
|
|
316
318
|
"react-hotkeys-hook": "^5.2.1",
|
|
317
319
|
"react-i18next": "^16.5.0",
|
|
318
320
|
"react-lazy-load": "^4.0.1",
|
|
319
|
-
"react-pdf": "^
|
|
321
|
+
"react-pdf": "^10.3.0",
|
|
320
322
|
"react-responsive": "^10.0.1",
|
|
321
323
|
"react-rnd": "^10.5.2",
|
|
322
324
|
"react-router-dom": "^7.11.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 {
|
|
6
|
-
import {
|
|
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
|
|
117
|
-
log('Parser type determined as:',
|
|
111
|
+
const parserType = getFileType(filePath);
|
|
112
|
+
log('Parser type determined as:', parserType);
|
|
118
113
|
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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 (!
|
|
120
|
+
if (!parserType) {
|
|
126
121
|
console.warn(
|
|
127
|
-
`No specific loader found for file type '${fileType}'. Using default loader (
|
|
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
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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 };
|
package/pnpm-workspace.yaml
CHANGED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Avatar, Block, Flexbox, Icon, Text } from '@lobehub/ui';
|
|
4
|
+
import { useTheme } from 'antd-style';
|
|
5
|
+
import type { ItemType } from 'antd/es/menu/interface';
|
|
6
|
+
import isEqual from 'fast-deep-equal';
|
|
7
|
+
import { BrainIcon, MessageSquareHeartIcon, Settings2Icon } from 'lucide-react';
|
|
8
|
+
import { memo, useMemo, useState } from 'react';
|
|
9
|
+
import { useTranslation } from 'react-i18next';
|
|
10
|
+
|
|
11
|
+
import Menu from '@/components/Menu';
|
|
12
|
+
import { DEFAULT_AVATAR, DEFAULT_INBOX_AVATAR } from '@/const/meta';
|
|
13
|
+
import { AgentSettings as Settings } from '@/features/AgentSetting';
|
|
14
|
+
import { useAgentStore } from '@/store/agent';
|
|
15
|
+
import { agentSelectors, builtinAgentSelectors } from '@/store/agent/selectors';
|
|
16
|
+
import { ChatSettingsTabs } from '@/store/global/initialState';
|
|
17
|
+
|
|
18
|
+
const Content = memo(() => {
|
|
19
|
+
const { t } = useTranslation('setting');
|
|
20
|
+
const theme = useTheme();
|
|
21
|
+
const [agentId, isInbox] = useAgentStore((s) => [
|
|
22
|
+
s.activeAgentId,
|
|
23
|
+
builtinAgentSelectors.isInboxAgent(s),
|
|
24
|
+
]);
|
|
25
|
+
const config = useAgentStore(agentSelectors.currentAgentConfig, isEqual);
|
|
26
|
+
const meta = useAgentStore(agentSelectors.currentAgentMeta, isEqual);
|
|
27
|
+
const [tab, setTab] = useState(ChatSettingsTabs.Chat);
|
|
28
|
+
|
|
29
|
+
const updateAgentConfig = async (config: any) => {
|
|
30
|
+
if (!agentId) return;
|
|
31
|
+
await useAgentStore.getState().optimisticUpdateAgentConfig(agentId, config);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const updateAgentMeta = async (meta: any) => {
|
|
35
|
+
if (!agentId) return;
|
|
36
|
+
await useAgentStore.getState().optimisticUpdateAgentMeta(agentId, meta);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const menuItems: ItemType[] = useMemo(
|
|
40
|
+
() =>
|
|
41
|
+
[
|
|
42
|
+
{
|
|
43
|
+
icon: <Icon icon={Settings2Icon} />,
|
|
44
|
+
key: ChatSettingsTabs.Chat,
|
|
45
|
+
label: t('agentTab.chat'),
|
|
46
|
+
},
|
|
47
|
+
!isInbox
|
|
48
|
+
? {
|
|
49
|
+
icon: <Icon icon={MessageSquareHeartIcon} />,
|
|
50
|
+
key: ChatSettingsTabs.Opening,
|
|
51
|
+
label: t('agentTab.opening'),
|
|
52
|
+
}
|
|
53
|
+
: null,
|
|
54
|
+
{
|
|
55
|
+
icon: <Icon icon={BrainIcon} />,
|
|
56
|
+
key: ChatSettingsTabs.Modal,
|
|
57
|
+
label: t('agentTab.modal'),
|
|
58
|
+
},
|
|
59
|
+
].filter(Boolean) as ItemType[],
|
|
60
|
+
[t, isInbox],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const displayTitle = isInbox ? 'Lobe AI' : meta.title || t('defaultSession', { ns: 'common' });
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<Flexbox
|
|
67
|
+
direction="horizontal"
|
|
68
|
+
height="100%"
|
|
69
|
+
style={{
|
|
70
|
+
padding: 0,
|
|
71
|
+
position: 'relative',
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
<Flexbox
|
|
75
|
+
height={'100%'}
|
|
76
|
+
paddingBlock={24}
|
|
77
|
+
paddingInline={8}
|
|
78
|
+
style={{
|
|
79
|
+
background: theme.colorBgLayout,
|
|
80
|
+
borderRight: `1px solid ${theme.colorBorderSecondary}`,
|
|
81
|
+
}}
|
|
82
|
+
width={200}
|
|
83
|
+
>
|
|
84
|
+
<Block
|
|
85
|
+
align={'center'}
|
|
86
|
+
gap={8}
|
|
87
|
+
horizontal
|
|
88
|
+
paddingBlock={'14px 16px'}
|
|
89
|
+
paddingInline={4}
|
|
90
|
+
style={{
|
|
91
|
+
overflow: 'hidden',
|
|
92
|
+
}}
|
|
93
|
+
variant={'borderless'}
|
|
94
|
+
>
|
|
95
|
+
<Avatar
|
|
96
|
+
avatar={isInbox ? DEFAULT_INBOX_AVATAR : meta.avatar || DEFAULT_AVATAR}
|
|
97
|
+
background={meta.backgroundColor || undefined}
|
|
98
|
+
shape={'square'}
|
|
99
|
+
size={28}
|
|
100
|
+
/>
|
|
101
|
+
<Text ellipsis weight={500}>
|
|
102
|
+
{displayTitle}
|
|
103
|
+
</Text>
|
|
104
|
+
</Block>
|
|
105
|
+
<Menu
|
|
106
|
+
items={menuItems}
|
|
107
|
+
onClick={({ key }) => setTab(key as ChatSettingsTabs)}
|
|
108
|
+
selectable
|
|
109
|
+
selectedKeys={[tab]}
|
|
110
|
+
style={{ width: '100%' }}
|
|
111
|
+
/>
|
|
112
|
+
</Flexbox>
|
|
113
|
+
<Flexbox
|
|
114
|
+
flex={1}
|
|
115
|
+
paddingBlock={24}
|
|
116
|
+
paddingInline={64}
|
|
117
|
+
style={{ overflow: 'scroll', width: '100%' }}
|
|
118
|
+
>
|
|
119
|
+
<Settings
|
|
120
|
+
config={config}
|
|
121
|
+
id={agentId}
|
|
122
|
+
loading={false}
|
|
123
|
+
meta={meta}
|
|
124
|
+
onConfigChange={updateAgentConfig}
|
|
125
|
+
onMetaChange={updateAgentMeta}
|
|
126
|
+
tab={tab}
|
|
127
|
+
/>
|
|
128
|
+
</Flexbox>
|
|
129
|
+
</Flexbox>
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
export default Content;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Modal } from '@lobehub/ui';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
|
|
6
|
+
import { useAgentStore } from '@/store/agent';
|
|
7
|
+
|
|
8
|
+
import Content from './Content';
|
|
9
|
+
|
|
10
|
+
const AgentSettings = memo(() => {
|
|
11
|
+
const showAgentSetting = useAgentStore((s) => s.showAgentSetting);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Modal
|
|
15
|
+
centered
|
|
16
|
+
footer={null}
|
|
17
|
+
onCancel={() => useAgentStore.setState({ showAgentSetting: false })}
|
|
18
|
+
open={showAgentSetting}
|
|
19
|
+
styles={{
|
|
20
|
+
body: {
|
|
21
|
+
height: '60vh',
|
|
22
|
+
overflow: 'scroll',
|
|
23
|
+
padding: 0,
|
|
24
|
+
position: 'relative',
|
|
25
|
+
},
|
|
26
|
+
}}
|
|
27
|
+
title={null}
|
|
28
|
+
width={960}
|
|
29
|
+
>
|
|
30
|
+
<Content />
|
|
31
|
+
</Modal>
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default AgentSettings;
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
import { ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
|
|
4
4
|
import { Button, Flexbox } from '@lobehub/ui';
|
|
5
5
|
import { Divider } from 'antd';
|
|
6
|
+
import { useTheme } from 'antd-style';
|
|
6
7
|
import isEqual from 'fast-deep-equal';
|
|
7
|
-
import { Clock, PlayIcon } from 'lucide-react';
|
|
8
|
+
import { Clock, PlayIcon, Settings2Icon } from 'lucide-react';
|
|
8
9
|
import React, { memo, useCallback } from 'react';
|
|
9
10
|
import { useTranslation } from 'react-i18next';
|
|
10
11
|
import urlJoin from 'url-join';
|
|
@@ -16,6 +17,7 @@ import { agentSelectors } from '@/store/agent/selectors';
|
|
|
16
17
|
import { useChatStore } from '@/store/chat';
|
|
17
18
|
|
|
18
19
|
import AgentCronJobs from '../AgentCronJobs';
|
|
20
|
+
import AgentSettings from '../AgentSettings';
|
|
19
21
|
import EditorCanvas from '../EditorCanvas';
|
|
20
22
|
import AgentPublishButton from '../Header/AgentPublishButton';
|
|
21
23
|
import AgentHeader from './AgentHeader';
|
|
@@ -23,6 +25,7 @@ import AgentTool from './AgentTool';
|
|
|
23
25
|
|
|
24
26
|
const ProfileEditor = memo(() => {
|
|
25
27
|
const { t } = useTranslation('setting');
|
|
28
|
+
const theme = useTheme();
|
|
26
29
|
const config = useAgentStore(agentSelectors.currentAgentConfig, isEqual);
|
|
27
30
|
const updateConfig = useAgentStore((s) => s.updateAgentConfig);
|
|
28
31
|
const agentId = useAgentStore((s) => s.activeAgentId);
|
|
@@ -44,7 +47,7 @@ const ProfileEditor = memo(() => {
|
|
|
44
47
|
>
|
|
45
48
|
{/* Header: Avatar + Name + Description */}
|
|
46
49
|
<AgentHeader />
|
|
47
|
-
{/* Config Bar: Model Selector */}
|
|
50
|
+
{/* Config Bar: Model Selector + Settings Button */}
|
|
48
51
|
<Flexbox
|
|
49
52
|
align={'center'}
|
|
50
53
|
gap={8}
|
|
@@ -59,6 +62,15 @@ const ProfileEditor = memo(() => {
|
|
|
59
62
|
provider: config.provider,
|
|
60
63
|
}}
|
|
61
64
|
/>
|
|
65
|
+
<Button
|
|
66
|
+
icon={Settings2Icon}
|
|
67
|
+
onClick={() => useAgentStore.setState({ showAgentSetting: true })}
|
|
68
|
+
size={'small'}
|
|
69
|
+
style={{ color: theme.colorTextSecondary }}
|
|
70
|
+
type={'text'}
|
|
71
|
+
>
|
|
72
|
+
{t('advancedSettings')}
|
|
73
|
+
</Button>
|
|
62
74
|
</Flexbox>
|
|
63
75
|
<AgentTool />
|
|
64
76
|
<Flexbox
|
|
@@ -93,6 +105,8 @@ const ProfileEditor = memo(() => {
|
|
|
93
105
|
<EditorCanvas />
|
|
94
106
|
{/* Agent Cron Jobs Display (only show if jobs exist) */}
|
|
95
107
|
{ENABLE_BUSINESS_FEATURES && <AgentCronJobs />}
|
|
108
|
+
{/* Advanced Settings Modal */}
|
|
109
|
+
<AgentSettings />
|
|
96
110
|
</>
|
|
97
111
|
);
|
|
98
112
|
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Avatar, Block, Flexbox, Icon, Text } from '@lobehub/ui';
|
|
4
|
+
import { useTheme } from 'antd-style';
|
|
5
|
+
import type { ItemType } from 'antd/es/menu/interface';
|
|
6
|
+
import { MessageSquareHeartIcon } from 'lucide-react';
|
|
7
|
+
import { memo, useMemo, useState } from 'react';
|
|
8
|
+
import { useTranslation } from 'react-i18next';
|
|
9
|
+
|
|
10
|
+
import Menu from '@/components/Menu';
|
|
11
|
+
import { DEFAULT_AVATAR } from '@/const/meta';
|
|
12
|
+
import { AgentSettings as Settings } from '@/features/AgentSetting';
|
|
13
|
+
import { useAgentGroupStore } from '@/store/agentGroup';
|
|
14
|
+
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
|
15
|
+
import { ChatSettingsTabs } from '@/store/global/initialState';
|
|
16
|
+
|
|
17
|
+
const Content = memo(() => {
|
|
18
|
+
const { t } = useTranslation('setting');
|
|
19
|
+
const theme = useTheme();
|
|
20
|
+
const groupId = useAgentGroupStore(agentGroupSelectors.activeGroupId);
|
|
21
|
+
const currentGroup = useAgentGroupStore(agentGroupSelectors.currentGroup);
|
|
22
|
+
const [tab] = useState(ChatSettingsTabs.Opening);
|
|
23
|
+
|
|
24
|
+
const updateGroupConfig = async (config: any) => {
|
|
25
|
+
if (!groupId) return;
|
|
26
|
+
// Only update openingMessage and openingQuestions
|
|
27
|
+
const groupConfig = {
|
|
28
|
+
openingMessage: config.openingMessage,
|
|
29
|
+
openingQuestions: config.openingQuestions,
|
|
30
|
+
};
|
|
31
|
+
await useAgentGroupStore.getState().updateGroupConfig(groupConfig);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const updateGroupMeta = async (meta: any) => {
|
|
35
|
+
if (!groupId) return;
|
|
36
|
+
await useAgentGroupStore.getState().updateGroup(groupId, meta);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Convert group config to agent config format for AgentSettings component
|
|
40
|
+
const agentConfig = useMemo(
|
|
41
|
+
() =>
|
|
42
|
+
({
|
|
43
|
+
chatConfig: {},
|
|
44
|
+
model: '',
|
|
45
|
+
openingMessage: currentGroup?.config?.openingMessage,
|
|
46
|
+
openingQuestions: currentGroup?.config?.openingQuestions,
|
|
47
|
+
params: {},
|
|
48
|
+
systemRole: '',
|
|
49
|
+
tts: {},
|
|
50
|
+
}) as any,
|
|
51
|
+
[currentGroup?.config],
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const agentMeta = useMemo(
|
|
55
|
+
() => ({
|
|
56
|
+
avatar: currentGroup?.avatar || undefined,
|
|
57
|
+
backgroundColor: currentGroup?.backgroundColor || undefined,
|
|
58
|
+
description: currentGroup?.description || undefined,
|
|
59
|
+
tags: [] as string[],
|
|
60
|
+
title: currentGroup?.title || undefined,
|
|
61
|
+
}),
|
|
62
|
+
[currentGroup],
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const menuItems: ItemType[] = useMemo(
|
|
66
|
+
() => [
|
|
67
|
+
{
|
|
68
|
+
icon: <Icon icon={MessageSquareHeartIcon} />,
|
|
69
|
+
key: ChatSettingsTabs.Opening,
|
|
70
|
+
label: t('agentTab.opening'),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
[t],
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const displayTitle = currentGroup?.title || t('defaultSession', { ns: 'common' });
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Flexbox
|
|
80
|
+
direction="horizontal"
|
|
81
|
+
height="100%"
|
|
82
|
+
style={{
|
|
83
|
+
padding: 0,
|
|
84
|
+
position: 'relative',
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
<Flexbox
|
|
88
|
+
height={'100%'}
|
|
89
|
+
paddingBlock={24}
|
|
90
|
+
paddingInline={8}
|
|
91
|
+
style={{
|
|
92
|
+
background: theme.colorBgLayout,
|
|
93
|
+
borderRight: `1px solid ${theme.colorBorderSecondary}`,
|
|
94
|
+
}}
|
|
95
|
+
width={200}
|
|
96
|
+
>
|
|
97
|
+
<Block
|
|
98
|
+
align={'center'}
|
|
99
|
+
gap={8}
|
|
100
|
+
horizontal
|
|
101
|
+
paddingBlock={'14px 16px'}
|
|
102
|
+
paddingInline={4}
|
|
103
|
+
style={{
|
|
104
|
+
overflow: 'hidden',
|
|
105
|
+
}}
|
|
106
|
+
variant={'borderless'}
|
|
107
|
+
>
|
|
108
|
+
<Avatar
|
|
109
|
+
avatar={currentGroup?.avatar || DEFAULT_AVATAR}
|
|
110
|
+
background={currentGroup?.backgroundColor || undefined}
|
|
111
|
+
shape={'square'}
|
|
112
|
+
size={28}
|
|
113
|
+
/>
|
|
114
|
+
<Text ellipsis weight={500}>
|
|
115
|
+
{displayTitle}
|
|
116
|
+
</Text>
|
|
117
|
+
</Block>
|
|
118
|
+
<Menu items={menuItems} selectable selectedKeys={[tab]} style={{ width: '100%' }} />
|
|
119
|
+
</Flexbox>
|
|
120
|
+
<Flexbox
|
|
121
|
+
flex={1}
|
|
122
|
+
paddingBlock={24}
|
|
123
|
+
paddingInline={64}
|
|
124
|
+
style={{ overflow: 'scroll', width: '100%' }}
|
|
125
|
+
>
|
|
126
|
+
<Settings
|
|
127
|
+
config={agentConfig}
|
|
128
|
+
id={groupId}
|
|
129
|
+
loading={false}
|
|
130
|
+
meta={agentMeta}
|
|
131
|
+
onConfigChange={updateGroupConfig}
|
|
132
|
+
onMetaChange={updateGroupMeta}
|
|
133
|
+
tab={tab}
|
|
134
|
+
/>
|
|
135
|
+
</Flexbox>
|
|
136
|
+
</Flexbox>
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
export default Content;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Modal } from '@lobehub/ui';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
|
|
6
|
+
import Content from './Content';
|
|
7
|
+
|
|
8
|
+
interface AgentSettingsProps {
|
|
9
|
+
onCancel: () => void;
|
|
10
|
+
open: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const AgentSettings = memo<AgentSettingsProps>(({ open, onCancel }) => {
|
|
14
|
+
return (
|
|
15
|
+
<Modal
|
|
16
|
+
centered
|
|
17
|
+
footer={null}
|
|
18
|
+
onCancel={onCancel}
|
|
19
|
+
open={open}
|
|
20
|
+
styles={{
|
|
21
|
+
body: {
|
|
22
|
+
height: '60vh',
|
|
23
|
+
overflow: 'scroll',
|
|
24
|
+
padding: 0,
|
|
25
|
+
position: 'relative',
|
|
26
|
+
},
|
|
27
|
+
}}
|
|
28
|
+
title={null}
|
|
29
|
+
width={960}
|
|
30
|
+
>
|
|
31
|
+
<Content />
|
|
32
|
+
</Modal>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export default AgentSettings;
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { Button, Flexbox } from '@lobehub/ui';
|
|
4
4
|
import { Divider } from 'antd';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { useTheme } from 'antd-style';
|
|
6
|
+
import { PlayIcon, Settings2Icon } from 'lucide-react';
|
|
7
|
+
import { memo, useCallback, useMemo, useState } from 'react';
|
|
7
8
|
import { useTranslation } from 'react-i18next';
|
|
8
9
|
import urlJoin from 'url-join';
|
|
9
10
|
|
|
@@ -13,12 +14,15 @@ import { useAgentGroupStore } from '@/store/agentGroup';
|
|
|
13
14
|
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
|
14
15
|
import { useGroupProfileStore } from '@/store/groupProfile';
|
|
15
16
|
|
|
17
|
+
import AgentSettings from '../AgentSettings';
|
|
16
18
|
import AutoSaveHint from '../Header/AutoSaveHint';
|
|
17
19
|
import GroupPublishButton from '../Header/GroupPublishButton';
|
|
18
20
|
import GroupHeader from './GroupHeader';
|
|
19
21
|
|
|
20
22
|
const GroupProfile = memo(() => {
|
|
21
23
|
const { t } = useTranslation(['setting', 'chat']);
|
|
24
|
+
const theme = useTheme();
|
|
25
|
+
const [showAgentSetting, setShowAgentSetting] = useState(false);
|
|
22
26
|
const groupId = useAgentGroupStore(agentGroupSelectors.activeGroupId);
|
|
23
27
|
const currentGroup = useAgentGroupStore(agentGroupSelectors.currentGroup);
|
|
24
28
|
const updateGroup = useAgentGroupStore((s) => s.updateGroup);
|
|
@@ -86,6 +90,15 @@ const GroupProfile = memo(() => {
|
|
|
86
90
|
{t('startConversation')}
|
|
87
91
|
</Button>
|
|
88
92
|
<GroupPublishButton />
|
|
93
|
+
<Button
|
|
94
|
+
icon={Settings2Icon}
|
|
95
|
+
onClick={() => setShowAgentSetting(true)}
|
|
96
|
+
size={'small'}
|
|
97
|
+
style={{ color: theme.colorTextSecondary }}
|
|
98
|
+
type={'text'}
|
|
99
|
+
>
|
|
100
|
+
{t('advancedSettings')}
|
|
101
|
+
</Button>
|
|
89
102
|
</Flexbox>
|
|
90
103
|
</Flexbox>
|
|
91
104
|
<Divider />
|
|
@@ -97,6 +110,8 @@ const GroupProfile = memo(() => {
|
|
|
97
110
|
onContentChange={onContentChange}
|
|
98
111
|
placeholder={t('group.profile.contentPlaceholder', { ns: 'chat' })}
|
|
99
112
|
/>
|
|
113
|
+
{/* Advanced Settings Modal */}
|
|
114
|
+
<AgentSettings onCancel={() => setShowAgentSetting(false)} open={showAgentSetting} />
|
|
100
115
|
</>
|
|
101
116
|
);
|
|
102
117
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type StateCreator } from 'zustand/vanilla';
|
|
2
2
|
|
|
3
|
-
import { type
|
|
3
|
+
import { type ResourceManagerMode } from '@/features/ResourceManager';
|
|
4
4
|
import { type FilesTabs, SortType } from '@/types/files';
|
|
5
5
|
|
|
6
6
|
import { type State, type ViewMode, initialState } from './initialState';
|
|
@@ -67,7 +67,7 @@ export interface Action {
|
|
|
67
67
|
/**
|
|
68
68
|
* Set the view mode
|
|
69
69
|
*/
|
|
70
|
-
setMode: (mode:
|
|
70
|
+
setMode: (mode: ResourceManagerMode) => void;
|
|
71
71
|
/**
|
|
72
72
|
* Set the pending rename item ID
|
|
73
73
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ResourceManagerMode } from '@/features/ResourceManager';
|
|
2
2
|
import { FilesTabs, SortType } from '@/types/files';
|
|
3
3
|
|
|
4
4
|
export type ViewMode = 'list' | 'masonry';
|
|
@@ -39,7 +39,7 @@ export interface State {
|
|
|
39
39
|
/**
|
|
40
40
|
* View mode for displaying resources
|
|
41
41
|
*/
|
|
42
|
-
mode:
|
|
42
|
+
mode: ResourceManagerMode;
|
|
43
43
|
/**
|
|
44
44
|
* ID of item currently being renamed (for inline editing)
|
|
45
45
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type StateCreator } from 'zustand/vanilla';
|
|
2
2
|
|
|
3
|
-
import { type
|
|
3
|
+
import { type ResourceManagerMode } from '@/features/ResourceManager';
|
|
4
4
|
|
|
5
5
|
import { type State, initialState } from './initialState';
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ export interface Action {
|
|
|
12
12
|
/**
|
|
13
13
|
* Set the view mode
|
|
14
14
|
*/
|
|
15
|
-
setMode: (mode:
|
|
15
|
+
setMode: (mode: ResourceManagerMode) => void;
|
|
16
16
|
/**
|
|
17
17
|
* Set selected file IDs
|
|
18
18
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ResourceManagerMode } from '@/features/ResourceManager';
|
|
2
2
|
|
|
3
3
|
export interface State {
|
|
4
4
|
currentViewItemId?: string;
|
|
5
|
-
mode:
|
|
5
|
+
mode: ResourceManagerMode;
|
|
6
6
|
selectedFileIds: string[];
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -86,13 +86,14 @@ const OpeningQuestions = memo(() => {
|
|
|
86
86
|
const isRepeat = openingQuestions.includes(questionInput.trim());
|
|
87
87
|
|
|
88
88
|
return (
|
|
89
|
-
<Flexbox gap={8}>
|
|
90
|
-
<Flexbox gap={4}>
|
|
91
|
-
<Space.Compact>
|
|
89
|
+
<Flexbox gap={8} width={'100%'}>
|
|
90
|
+
<Flexbox gap={4} width={'100%'}>
|
|
91
|
+
<Space.Compact style={{ width: '100%' }}>
|
|
92
92
|
<Input
|
|
93
93
|
onChange={(e) => setQuestionInput(e.target.value)}
|
|
94
94
|
onPressEnter={addQuestion}
|
|
95
95
|
placeholder={t('settingOpening.openingQuestions.placeholder')}
|
|
96
|
+
style={{ flex: 1 }}
|
|
96
97
|
value={questionInput}
|
|
97
98
|
/>
|
|
98
99
|
<Button
|
|
@@ -4,8 +4,6 @@ import { Form } from '@lobehub/ui';
|
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
|
-
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
8
|
-
|
|
9
7
|
import OpeningMessage from './OpeningMessage';
|
|
10
8
|
import OpeningQuestions from './OpeningQuestions';
|
|
11
9
|
|
|
@@ -44,7 +42,6 @@ const AgentOpening = memo(() => {
|
|
|
44
42
|
]}
|
|
45
43
|
itemsType={'group'}
|
|
46
44
|
variant={'borderless'}
|
|
47
|
-
{...FORM_STYLE}
|
|
48
45
|
/>
|
|
49
46
|
);
|
|
50
47
|
});
|
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Flexbox } from '@lobehub/ui';
|
|
4
|
-
import type { PDFDocumentProxy } from 'pdfjs-dist';
|
|
5
4
|
import { Fragment, memo, useCallback, useState } from 'react';
|
|
6
5
|
import { Document, Page, pdfjs } from 'react-pdf';
|
|
7
|
-
import 'react-pdf/dist/
|
|
8
|
-
import 'react-pdf/dist/
|
|
6
|
+
import 'react-pdf/dist/Page/AnnotationLayer.css';
|
|
7
|
+
import 'react-pdf/dist/Page/TextLayer.css';
|
|
9
8
|
|
|
10
9
|
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
|
10
|
+
import '@/libs/pdfjs/worker';
|
|
11
11
|
import { lambdaQuery } from '@/libs/trpc/client';
|
|
12
12
|
|
|
13
13
|
import HighlightLayer from './HighlightLayer';
|
|
14
14
|
import { styles } from './style';
|
|
15
15
|
import useResizeObserver from './useResizeObserver';
|
|
16
16
|
|
|
17
|
-
// 如果海外的地址: https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs
|
|
18
|
-
pdfjs.GlobalWorkerOptions.workerSrc = `https://registry.npmmirror.com/pdfjs-dist/${pdfjs.version}/files/build/pdf.worker.min.mjs`;
|
|
19
|
-
|
|
20
17
|
const options = {
|
|
21
18
|
cMapUrl: `https://registry.npmmirror.com/pdfjs-dist/${pdfjs.version}/files/cmaps/`,
|
|
22
19
|
standardFontDataUrl: `https://registry.npmmirror.com/pdfjs-dist/${pdfjs.version}/files/standard_fonts/`,
|
|
@@ -46,8 +43,8 @@ const PDFViewer = memo<PDFViewerProps>(({ url, fileId }) => {
|
|
|
46
43
|
|
|
47
44
|
useResizeObserver(containerRef, onResize);
|
|
48
45
|
|
|
49
|
-
const onDocumentLoadSuccess = (
|
|
50
|
-
setNumPages(
|
|
46
|
+
const onDocumentLoadSuccess = (document: unknown) => {
|
|
47
|
+
setNumPages((document as { numPages: number }).numPages);
|
|
51
48
|
setIsLoaded(true);
|
|
52
49
|
};
|
|
53
50
|
|
|
@@ -35,6 +35,7 @@ import { type LobeToolMetaWithAvailability } from '@/store/tool/slices/builtin/s
|
|
|
35
35
|
|
|
36
36
|
import PluginTag from './PluginTag';
|
|
37
37
|
|
|
38
|
+
|
|
38
39
|
const WEB_BROWSING_IDENTIFIER = 'lobe-web-browsing';
|
|
39
40
|
|
|
40
41
|
type TabType = 'all' | 'installed';
|
|
@@ -44,13 +45,7 @@ const prefixCls = 'ant';
|
|
|
44
45
|
const styles = createStaticStyles(({ css }) => ({
|
|
45
46
|
dropdown: css`
|
|
46
47
|
overflow: hidden;
|
|
47
|
-
|
|
48
48
|
width: 100%;
|
|
49
|
-
border: 1px solid ${cssVar.colorBorderSecondary};
|
|
50
|
-
border-radius: ${cssVar.borderRadiusLG};
|
|
51
|
-
|
|
52
|
-
background: ${cssVar.colorBgElevated};
|
|
53
|
-
box-shadow: ${cssVar.boxShadowSecondary};
|
|
54
49
|
|
|
55
50
|
.${prefixCls}-dropdown-menu {
|
|
56
51
|
border-radius: 0 !important;
|
|
@@ -339,7 +334,7 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
339
334
|
() => [
|
|
340
335
|
// 原有的 builtin 工具
|
|
341
336
|
...filteredBuiltinList.map((item) => ({
|
|
342
|
-
icon: <Avatar avatar={item.meta.avatar} size={20} style={{ flex: 'none' }} />,
|
|
337
|
+
icon: <Avatar avatar={item.meta.avatar} size={20} style={{ flex: 'none', marginRight: 0 }} />,
|
|
343
338
|
key: item.identifier,
|
|
344
339
|
label: (
|
|
345
340
|
<ToolItem
|
|
@@ -412,18 +407,6 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
412
407
|
),
|
|
413
408
|
type: 'group',
|
|
414
409
|
},
|
|
415
|
-
{
|
|
416
|
-
type: 'divider',
|
|
417
|
-
},
|
|
418
|
-
{
|
|
419
|
-
extra: <Icon icon={ArrowRight} />,
|
|
420
|
-
icon: Store,
|
|
421
|
-
key: 'plugin-store',
|
|
422
|
-
label: t('tools.plugins.store'),
|
|
423
|
-
onClick: () => {
|
|
424
|
-
createSkillStoreModal();
|
|
425
|
-
},
|
|
426
|
-
},
|
|
427
410
|
],
|
|
428
411
|
[builtinItems, pluginItems, enablePluginCount, t],
|
|
429
412
|
);
|
|
@@ -557,7 +540,6 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
557
540
|
{/* Plugin Selector Dropdown - Using Action component pattern */}
|
|
558
541
|
<Suspense fallback={button}>
|
|
559
542
|
<ActionDropdown
|
|
560
|
-
maxHeight={500}
|
|
561
543
|
maxWidth={400}
|
|
562
544
|
menu={{
|
|
563
545
|
items: currentItems,
|
|
@@ -567,11 +549,10 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
567
549
|
overflowY: 'visible',
|
|
568
550
|
},
|
|
569
551
|
}}
|
|
570
|
-
minHeight={isKlavisEnabledInEnv || isLobehubSkillEnabled ? 500 : undefined}
|
|
571
552
|
minWidth={400}
|
|
572
553
|
placement={'bottomLeft'}
|
|
573
554
|
popupRender={(menu) => (
|
|
574
|
-
<
|
|
555
|
+
<Flexbox className={styles.dropdown} style={{ maxHeight: 500 }}>
|
|
575
556
|
{/* stopPropagation prevents dropdown's onClick from calling preventDefault on Segmented */}
|
|
576
557
|
<div className={styles.header} onClick={(e) => e.stopPropagation()}>
|
|
577
558
|
<Segmented
|
|
@@ -591,16 +572,26 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
591
572
|
value={effectiveTab}
|
|
592
573
|
/>
|
|
593
574
|
</div>
|
|
594
|
-
<div
|
|
595
|
-
|
|
575
|
+
<div className={styles.scroller} style={{ flex: 1 }}>
|
|
576
|
+
{menu}
|
|
577
|
+
</div>
|
|
578
|
+
<Flexbox
|
|
579
|
+
align="center"
|
|
580
|
+
gap={8}
|
|
581
|
+
horizontal
|
|
582
|
+
onClick={() => createSkillStoreModal()}
|
|
596
583
|
style={{
|
|
597
|
-
|
|
598
|
-
|
|
584
|
+
borderBlockStart: `1px solid ${cssVar.colorBorderSecondary}`,
|
|
585
|
+
cursor: 'pointer',
|
|
586
|
+
flex: 'none',
|
|
587
|
+
padding: cssVar.paddingSM,
|
|
599
588
|
}}
|
|
600
589
|
>
|
|
601
|
-
{
|
|
602
|
-
|
|
603
|
-
|
|
590
|
+
<Icon icon={Store} />
|
|
591
|
+
<span style={{ flex: 1 }}>{t('tools.plugins.store')}</span>
|
|
592
|
+
<Icon icon={ArrowRight} />
|
|
593
|
+
</Flexbox>
|
|
594
|
+
</Flexbox>
|
|
604
595
|
)}
|
|
605
596
|
trigger={'click'}
|
|
606
597
|
>
|
|
@@ -41,7 +41,6 @@ const styles = createStaticStyles(({ css }) => {
|
|
|
41
41
|
cursor: pointer;
|
|
42
42
|
min-width: 800px;
|
|
43
43
|
|
|
44
|
-
/* Hover effect for individual rows */
|
|
45
44
|
&:hover {
|
|
46
45
|
background: ${cssVar.colorFillTertiary};
|
|
47
46
|
}
|
|
@@ -194,7 +193,6 @@ const FileListItem = memo<FileListItemProps>(
|
|
|
194
193
|
const [isDragging, setIsDragging] = useState(false);
|
|
195
194
|
const [isOver, setIsOver] = useState(false);
|
|
196
195
|
|
|
197
|
-
// Memoize computed values that don't change
|
|
198
196
|
const computedValues = useMemo(() => {
|
|
199
197
|
const isPDF = fileType?.toLowerCase() === 'pdf' || name?.toLowerCase().endsWith('.pdf');
|
|
200
198
|
return {
|
|
@@ -208,7 +206,6 @@ const FileListItem = memo<FileListItemProps>(
|
|
|
208
206
|
|
|
209
207
|
const { isSupportedForChunking, isPage, isFolder, emoji } = computedValues;
|
|
210
208
|
|
|
211
|
-
// Memoize drag data to prevent recreation
|
|
212
209
|
const dragData = useMemo(
|
|
213
210
|
() => ({
|
|
214
211
|
fileType,
|
|
@@ -219,7 +216,6 @@ const FileListItem = memo<FileListItemProps>(
|
|
|
219
216
|
[fileType, isFolder, name, sourceType],
|
|
220
217
|
);
|
|
221
218
|
|
|
222
|
-
// Native HTML5 drag event handlers
|
|
223
219
|
const handleDragStart = useCallback(
|
|
224
220
|
(e: DragEvent) => {
|
|
225
221
|
if (!resourceManagerState.libraryId) {
|
|
@@ -264,7 +260,6 @@ const FileListItem = memo<FileListItemProps>(
|
|
|
264
260
|
}, []);
|
|
265
261
|
|
|
266
262
|
const handleDrop = useCallback(() => {
|
|
267
|
-
// Clear the highlight after drop
|
|
268
263
|
setIsOver(false);
|
|
269
264
|
}, []);
|
|
270
265
|
|
|
@@ -359,7 +354,6 @@ const FileListItem = memo<FileListItemProps>(
|
|
|
359
354
|
{ replace: true },
|
|
360
355
|
);
|
|
361
356
|
} else {
|
|
362
|
-
// Set mode to file and store the file ID
|
|
363
357
|
resourceManagerState.setCurrentViewItemId(id);
|
|
364
358
|
resourceManagerState.setMode('editor');
|
|
365
359
|
// Also update URL query parameter for shareable links
|
|
@@ -378,7 +372,6 @@ const FileListItem = memo<FileListItemProps>(
|
|
|
378
372
|
useEffect(() => {
|
|
379
373
|
if (pendingRenameItemId === id && isFolder && !isRenaming) {
|
|
380
374
|
handleRenameStart();
|
|
381
|
-
// Clear the pending rename item after triggering
|
|
382
375
|
resourceManagerState.setPendingRenameItemId(null);
|
|
383
376
|
}
|
|
384
377
|
}, [pendingRenameItemId, id, isFolder, resourceManagerState]);
|
|
@@ -575,7 +568,6 @@ const FileListItem = memo<FileListItemProps>(
|
|
|
575
568
|
},
|
|
576
569
|
// Custom comparison function to prevent unnecessary re-renders
|
|
577
570
|
(prevProps, nextProps) => {
|
|
578
|
-
// Only re-render if these critical props change
|
|
579
571
|
return (
|
|
580
572
|
prevProps.id === nextProps.id &&
|
|
581
573
|
prevProps.name === nextProps.name &&
|
|
@@ -48,7 +48,7 @@ const styles = createStaticStyles(({ css, cssVar }) => {
|
|
|
48
48
|
};
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
export type
|
|
51
|
+
export type ResourceManagerMode = 'editor' | 'explorer' | 'page';
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
54
|
* Manage resources. Can be from a certian library.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
1
3
|
import { LoadingOutlined } from '@ant-design/icons';
|
|
2
4
|
import { Button, Flexbox } from '@lobehub/ui';
|
|
3
5
|
import { Input, Modal, Spin } from 'antd';
|
|
@@ -5,15 +7,13 @@ import { createStaticStyles, cx } from 'antd-style';
|
|
|
5
7
|
import { ChevronLeft, ChevronRight, Expand, FileText } from 'lucide-react';
|
|
6
8
|
import { memo, useState } from 'react';
|
|
7
9
|
import { useTranslation } from 'react-i18next';
|
|
8
|
-
import { Document, Page
|
|
10
|
+
import { Document, Page } from 'react-pdf';
|
|
9
11
|
|
|
10
12
|
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
13
|
+
import '@/libs/pdfjs/worker';
|
|
11
14
|
|
|
12
15
|
import { containerStyles } from '../style';
|
|
13
16
|
|
|
14
|
-
// Set PDF.js worker
|
|
15
|
-
pdfjs.GlobalWorkerOptions.workerSrc = `https://registry.npmmirror.com/pdfjs-dist/${pdfjs.version}/files/build/pdf.worker.min.mjs`;
|
|
16
|
-
|
|
17
17
|
const styles = createStaticStyles(({ css }) => ({
|
|
18
18
|
containerWrapper: css`
|
|
19
19
|
position: relative;
|
|
@@ -17,16 +17,14 @@ interface CustomNextConfig {
|
|
|
17
17
|
export function defineConfig(config: CustomNextConfig) {
|
|
18
18
|
const isProd = process.env.NODE_ENV === 'production';
|
|
19
19
|
const buildWithDocker = process.env.DOCKER === 'true';
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
const enableReactScan = !!process.env.REACT_SCAN_MONITOR_API_KEY;
|
|
22
22
|
const shouldUseCSP = process.env.ENABLED_CSP === '1';
|
|
23
23
|
|
|
24
24
|
const isTest =
|
|
25
25
|
process.env.NODE_ENV === 'test' || process.env.TEST === '1' || process.env.E2E === '1';
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const isStandaloneMode = buildWithDocker || isDesktop;
|
|
27
|
+
const isStandaloneMode = buildWithDocker || process.env.NEXT_BUILD_STANDALONE === '1';
|
|
30
28
|
|
|
31
29
|
const standaloneConfig: NextConfig = {
|
|
32
30
|
output: 'standalone',
|
|
@@ -38,6 +36,7 @@ export function defineConfig(config: CustomNextConfig) {
|
|
|
38
36
|
const nextConfig: NextConfig = {
|
|
39
37
|
...(isStandaloneMode ? standaloneConfig : {}),
|
|
40
38
|
assetPrefix,
|
|
39
|
+
|
|
41
40
|
compiler: {
|
|
42
41
|
emotion: true,
|
|
43
42
|
},
|
|
@@ -321,13 +320,14 @@ export function defineConfig(config: CustomNextConfig) {
|
|
|
321
320
|
},
|
|
322
321
|
...(config.redirects ?? []),
|
|
323
322
|
],
|
|
324
|
-
|
|
325
323
|
// when external packages in dev mode with turbopack, this config will lead to bundle error
|
|
324
|
+
// @napi-rs/canvas is a native module that can't be bundled by Turbopack
|
|
325
|
+
// pdfjs-dist uses @napi-rs/canvas for DOMMatrix polyfill in Node.js environment
|
|
326
326
|
serverExternalPackages: config.serverExternalPackages
|
|
327
327
|
? config.serverExternalPackages
|
|
328
|
-
: ['pdfkit'],
|
|
328
|
+
: ['pdfkit', '@napi-rs/canvas', 'pdfjs-dist'],
|
|
329
329
|
|
|
330
|
-
transpilePackages: ['
|
|
330
|
+
transpilePackages: ['mermaid', 'better-auth-harmony'],
|
|
331
331
|
turbopack: {
|
|
332
332
|
rules: isTest
|
|
333
333
|
? void 0
|
|
@@ -406,14 +406,13 @@ export function defineConfig(config: CustomNextConfig) {
|
|
|
406
406
|
|
|
407
407
|
const withBundleAnalyzer = process.env.ANALYZE === 'true' ? analyzer() : noWrapper;
|
|
408
408
|
|
|
409
|
-
const withPWA =
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
: noWrapper;
|
|
409
|
+
const withPWA = isProd
|
|
410
|
+
? withSerwistInit({
|
|
411
|
+
register: false,
|
|
412
|
+
swDest: 'public/sw.js',
|
|
413
|
+
swSrc: 'src/app/sw.ts',
|
|
414
|
+
})
|
|
415
|
+
: noWrapper;
|
|
417
416
|
|
|
418
417
|
return withBundleAnalyzer(withPWA(nextConfig as NextConfig));
|
|
419
418
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'pdfjs-dist/build/pdf.worker.min.mjs';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { pdfjs } from 'react-pdf';
|
|
4
|
+
|
|
5
|
+
pdfjs.GlobalWorkerOptions.workerSrc = `https://registry.npmmirror.com/pdfjs-dist/${pdfjs.version}/files/build/pdf.worker.min.mjs`;
|
|
6
|
+
|
|
7
|
+
// TODO: Re-enable module worker when fully on Turbopack.
|
|
8
|
+
// if (typeof Worker !== 'undefined' && !pdfjs.GlobalWorkerOptions.workerPort) {
|
|
9
|
+
// pdfjs.GlobalWorkerOptions.workerPort = new Worker(new URL('./pdf.worker.ts', import.meta.url), {
|
|
10
|
+
// type: 'module',
|
|
11
|
+
// });
|
|
12
|
+
// }
|