@lobehub/lobehub 2.0.0-next.186 → 2.0.0-next.188

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 (140) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/ar/models.json +89 -5
  4. package/locales/ar/plugin.json +5 -0
  5. package/locales/ar/providers.json +1 -0
  6. package/locales/bg-BG/models.json +68 -0
  7. package/locales/bg-BG/plugin.json +5 -0
  8. package/locales/bg-BG/providers.json +1 -0
  9. package/locales/de-DE/models.json +85 -0
  10. package/locales/de-DE/plugin.json +5 -0
  11. package/locales/de-DE/providers.json +1 -0
  12. package/locales/en-US/models.json +11 -10
  13. package/locales/en-US/plugin.json +5 -0
  14. package/locales/en-US/providers.json +1 -0
  15. package/locales/es-ES/models.json +72 -0
  16. package/locales/es-ES/plugin.json +5 -0
  17. package/locales/es-ES/providers.json +1 -0
  18. package/locales/fa-IR/models.json +86 -0
  19. package/locales/fa-IR/plugin.json +5 -0
  20. package/locales/fa-IR/providers.json +1 -0
  21. package/locales/fr-FR/models.json +49 -0
  22. package/locales/fr-FR/plugin.json +5 -0
  23. package/locales/fr-FR/providers.json +1 -0
  24. package/locales/it-IT/models.json +82 -0
  25. package/locales/it-IT/plugin.json +5 -0
  26. package/locales/it-IT/providers.json +1 -0
  27. package/locales/ja-JP/models.json +42 -5
  28. package/locales/ja-JP/plugin.json +5 -0
  29. package/locales/ja-JP/providers.json +1 -0
  30. package/locales/ko-KR/models.json +54 -0
  31. package/locales/ko-KR/plugin.json +5 -0
  32. package/locales/ko-KR/providers.json +1 -0
  33. package/locales/nl-NL/models.json +12 -1
  34. package/locales/nl-NL/plugin.json +5 -0
  35. package/locales/nl-NL/providers.json +1 -0
  36. package/locales/pl-PL/models.json +46 -0
  37. package/locales/pl-PL/plugin.json +5 -0
  38. package/locales/pl-PL/providers.json +1 -0
  39. package/locales/pt-BR/models.json +59 -0
  40. package/locales/pt-BR/plugin.json +5 -0
  41. package/locales/pt-BR/providers.json +1 -0
  42. package/locales/ru-RU/models.json +85 -0
  43. package/locales/ru-RU/plugin.json +5 -0
  44. package/locales/ru-RU/providers.json +1 -0
  45. package/locales/tr-TR/models.json +81 -0
  46. package/locales/tr-TR/plugin.json +5 -0
  47. package/locales/tr-TR/providers.json +1 -0
  48. package/locales/vi-VN/models.json +54 -0
  49. package/locales/vi-VN/plugin.json +5 -0
  50. package/locales/vi-VN/providers.json +1 -0
  51. package/locales/zh-CN/models.json +42 -5
  52. package/locales/zh-CN/plugin.json +5 -0
  53. package/locales/zh-CN/providers.json +1 -0
  54. package/locales/zh-TW/models.json +85 -0
  55. package/locales/zh-TW/plugin.json +5 -0
  56. package/locales/zh-TW/providers.json +1 -0
  57. package/package.json +1 -1
  58. package/packages/builtin-tool-gtd/src/manifest.ts +13 -8
  59. package/packages/builtin-tool-gtd/src/systemRole.ts +54 -19
  60. package/packages/builtin-tool-knowledge-base/package.json +1 -0
  61. package/packages/builtin-tool-knowledge-base/src/client/Inspector/ReadKnowledge/index.tsx +97 -0
  62. package/packages/builtin-tool-knowledge-base/src/client/Inspector/SearchKnowledgeBase/index.tsx +75 -0
  63. package/packages/builtin-tool-knowledge-base/src/client/Inspector/index.ts +11 -0
  64. package/packages/builtin-tool-knowledge-base/src/client/Render/ReadKnowledge/FileCard.tsx +12 -12
  65. package/packages/builtin-tool-knowledge-base/src/client/Render/ReadKnowledge/index.tsx +16 -25
  66. package/packages/builtin-tool-knowledge-base/src/client/Render/SearchKnowledgeBase/Item/index.tsx +21 -47
  67. package/packages/builtin-tool-knowledge-base/src/client/Render/SearchKnowledgeBase/index.tsx +19 -31
  68. package/packages/builtin-tool-knowledge-base/src/client/Render/index.ts +0 -5
  69. package/packages/builtin-tool-knowledge-base/src/client/index.ts +5 -1
  70. package/packages/builtin-tool-knowledge-base/src/executor/index.ts +119 -0
  71. package/packages/builtin-tool-local-system/package.json +1 -0
  72. package/packages/builtin-tool-local-system/src/client/Inspector/EditLocalFile/index.tsx +44 -29
  73. package/packages/builtin-tool-local-system/src/client/Inspector/GrepContent/index.tsx +20 -18
  74. package/packages/builtin-tool-local-system/src/client/Inspector/ListLocalFiles/index.tsx +76 -0
  75. package/packages/builtin-tool-local-system/src/client/Inspector/ReadLocalFile/index.tsx +8 -32
  76. package/packages/builtin-tool-local-system/src/client/Inspector/RenameLocalFile/index.tsx +62 -0
  77. package/packages/builtin-tool-local-system/src/client/Inspector/SearchLocalFiles/index.tsx +17 -11
  78. package/packages/builtin-tool-local-system/src/client/Inspector/WriteLocalFile/index.tsx +61 -0
  79. package/packages/builtin-tool-local-system/src/client/Inspector/index.ts +6 -0
  80. package/packages/builtin-tool-local-system/src/client/Render/EditLocalFile/index.tsx +6 -1
  81. package/packages/builtin-tool-local-system/src/client/Render/SearchFiles/SearchQuery/SearchView.tsx +19 -31
  82. package/packages/builtin-tool-local-system/src/client/Render/SearchFiles/SearchQuery/index.tsx +2 -42
  83. package/packages/builtin-tool-local-system/src/client/Render/index.ts +0 -2
  84. package/packages/builtin-tool-local-system/src/client/components/FilePathDisplay.tsx +56 -0
  85. package/packages/builtin-tool-local-system/src/client/components/index.ts +2 -0
  86. package/packages/builtin-tool-local-system/src/executor/index.ts +435 -0
  87. package/packages/builtin-tool-web-browsing/src/client/Inspector/Search/index.tsx +32 -5
  88. package/packages/fetch-sse/src/__tests__/request.test.ts +608 -0
  89. package/packages/model-bank/src/aiModels/aihubmix.ts +44 -8
  90. package/packages/model-bank/src/aiModels/google.ts +49 -17
  91. package/packages/model-bank/src/aiModels/hunyuan.ts +20 -0
  92. package/packages/model-bank/src/aiModels/infiniai.ts +48 -7
  93. package/packages/model-bank/src/aiModels/lobehub.ts +13 -11
  94. package/packages/model-bank/src/aiModels/minimax.ts +46 -2
  95. package/packages/model-bank/src/aiModels/ollamacloud.ts +40 -5
  96. package/packages/model-bank/src/aiModels/openai.ts +6 -3
  97. package/packages/model-bank/src/aiModels/qwen.ts +1 -1
  98. package/packages/model-bank/src/aiModels/siliconcloud.ts +60 -0
  99. package/packages/model-bank/src/aiModels/vertexai.ts +77 -44
  100. package/packages/model-bank/src/aiModels/volcengine.ts +111 -2
  101. package/packages/model-bank/src/aiModels/zenmux.ts +19 -13
  102. package/packages/model-bank/src/aiModels/zhipu.ts +64 -2
  103. package/packages/model-bank/src/types/aiModel.ts +3 -0
  104. package/packages/model-runtime/src/core/contextBuilders/google.test.ts +84 -0
  105. package/packages/model-runtime/src/core/contextBuilders/google.ts +37 -1
  106. package/packages/model-runtime/src/providers/volcengine/index.ts +2 -1
  107. package/packages/model-runtime/src/providers/zhipu/index.test.ts +0 -27
  108. package/packages/model-runtime/src/providers/zhipu/index.ts +1 -1
  109. package/packages/model-runtime/src/utils/modelParse.ts +26 -21
  110. package/packages/types/src/agent/chatConfig.ts +6 -2
  111. package/src/features/ChatInput/ActionBar/Model/ControlsForm.tsx +40 -1
  112. package/src/features/ChatInput/ActionBar/Model/GPT52ProReasoningEffortSlider.tsx +59 -0
  113. package/src/features/ChatInput/ActionBar/Model/GPT52ReasoningEffortSlider.tsx +61 -0
  114. package/src/features/ChatInput/ActionBar/Model/TextVerbositySlider.tsx +1 -1
  115. package/src/features/ChatInput/ActionBar/Model/ThinkingLevel2Slider.tsx +58 -0
  116. package/src/features/ChatInput/ActionBar/Model/ThinkingLevelSlider.tsx +10 -8
  117. package/src/helpers/toolEngineering/index.ts +1 -1
  118. package/src/locales/default/plugin.ts +6 -0
  119. package/src/server/modules/Mecha/AgentToolsEngine/__tests__/index.test.ts +1 -1
  120. package/src/server/modules/Mecha/AgentToolsEngine/index.ts +1 -1
  121. package/src/services/chat/mecha/modelParamsResolver.ts +11 -0
  122. package/src/store/chat/slices/builtinTool/actions/index.ts +1 -11
  123. package/src/store/tool/slices/builtin/executors/index.ts +4 -0
  124. package/src/styles/text.ts +1 -1
  125. package/src/tools/executionRuntimes.ts +3 -8
  126. package/src/tools/identifiers.ts +1 -1
  127. package/src/tools/index.ts +1 -1
  128. package/src/tools/inspectors.ts +5 -0
  129. package/src/tools/renders.ts +6 -12
  130. package/packages/builtin-tool-local-system/src/client/Render/RenameLocalFile/index.tsx +0 -37
  131. package/src/store/chat/slices/builtinTool/actions/__tests__/localSystem.test.ts +0 -201
  132. package/src/store/chat/slices/builtinTool/actions/knowledgeBase.ts +0 -163
  133. package/src/store/chat/slices/builtinTool/actions/localSystem.ts +0 -241
  134. package/src/tools/knowledge-base/ExecutionRuntime/index.ts +0 -25
  135. package/src/tools/knowledge-base/Render/ReadKnowledge/index.tsx +0 -29
  136. package/src/tools/knowledge-base/Render/SearchKnowledgeBase/index.tsx +0 -29
  137. package/src/tools/knowledge-base/Render/index.ts +0 -7
  138. package/src/tools/knowledge-base/index.ts +0 -12
  139. package/src/tools/local-system/ExecutionRuntime/index.ts +0 -9
  140. package/src/tools/local-system/systemRole.ts +0 -1
@@ -0,0 +1,75 @@
1
+ 'use client';
2
+
3
+ import { type BuiltinInspectorProps } from '@lobechat/types';
4
+ import { Text } from '@lobehub/ui';
5
+ import { createStaticStyles, cssVar, cx } from 'antd-style';
6
+ import { memo } from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+
9
+ import { highlightTextStyles, shinyTextStyles } from '@/styles';
10
+
11
+ import { type SearchKnowledgeBaseArgs, type SearchKnowledgeBaseState } from '../../..';
12
+
13
+ const styles = createStaticStyles(({ css, cssVar }) => ({
14
+ root: css`
15
+ overflow: hidden;
16
+ display: -webkit-box;
17
+ -webkit-box-orient: vertical;
18
+ -webkit-line-clamp: 1;
19
+
20
+ color: ${cssVar.colorTextSecondary};
21
+ `,
22
+ }));
23
+
24
+ export const SearchKnowledgeBaseInspector = memo<
25
+ BuiltinInspectorProps<SearchKnowledgeBaseArgs, SearchKnowledgeBaseState>
26
+ >(({ args, partialArgs, isArgumentsStreaming, isLoading, pluginState }) => {
27
+ const { t } = useTranslation('plugin');
28
+
29
+ const query = args?.query || partialArgs?.query || '';
30
+ // Use fileResults length for display (aggregated by file)
31
+ const resultCount = pluginState?.fileResults?.length ?? 0;
32
+ const hasResults = resultCount > 0;
33
+
34
+ // During argument streaming
35
+ if (isArgumentsStreaming) {
36
+ if (!query)
37
+ return (
38
+ <div className={cx(styles.root, shinyTextStyles.shinyText)}>
39
+ <span>{t('builtins.lobe-knowledge-base.apiName.searchKnowledgeBase')}</span>
40
+ </div>
41
+ );
42
+
43
+ return (
44
+ <div className={cx(styles.root, shinyTextStyles.shinyText)}>
45
+ <span>{t('builtins.lobe-knowledge-base.apiName.searchKnowledgeBase')}: </span>
46
+ <span className={highlightTextStyles.gold}>{query}</span>
47
+ </div>
48
+ );
49
+ }
50
+
51
+ return (
52
+ <div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
53
+ <span style={{ marginInlineStart: 2 }}>
54
+ <span>{t('builtins.lobe-knowledge-base.apiName.searchKnowledgeBase')}: </span>
55
+ {query && <span className={highlightTextStyles.gold}>{query}</span>}
56
+ {!isLoading &&
57
+ pluginState?.fileResults &&
58
+ (hasResults ? (
59
+ <span style={{ marginInlineStart: 4 }}>({resultCount})</span>
60
+ ) : (
61
+ <Text
62
+ as={'span'}
63
+ color={cssVar.colorTextDescription}
64
+ fontSize={12}
65
+ style={{ marginInlineStart: 4 }}
66
+ >
67
+ ({t('builtins.lobe-knowledge-base.inspector.noResults')})
68
+ </Text>
69
+ ))}
70
+ </span>
71
+ </div>
72
+ );
73
+ });
74
+
75
+ SearchKnowledgeBaseInspector.displayName = 'SearchKnowledgeBaseInspector';
@@ -0,0 +1,11 @@
1
+ import { KnowledgeBaseApiName } from '../../types';
2
+ import { ReadKnowledgeInspector } from './ReadKnowledge';
3
+ import { SearchKnowledgeBaseInspector } from './SearchKnowledgeBase';
4
+
5
+ /**
6
+ * Knowledge Base Inspector Components Registry
7
+ */
8
+ export const KnowledgeBaseInspectors = {
9
+ [KnowledgeBaseApiName.readKnowledge]: ReadKnowledgeInspector,
10
+ [KnowledgeBaseApiName.searchKnowledgeBase]: SearchKnowledgeBaseInspector,
11
+ };
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
 
3
- import { Alert, Flexbox, Text } from '@lobehub/ui';
3
+ import { Alert, Flexbox, MaterialFileTypeIcon, Text } from '@lobehub/ui';
4
4
  import { Descriptions } from 'antd';
5
5
  import { createStaticStyles } from 'antd-style';
6
- import { ComponentType, memo } from 'react';
6
+ import { memo } from 'react';
7
7
 
8
8
  import { FileContentDetail } from '../../../types';
9
9
 
@@ -63,21 +63,21 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
63
63
  }));
64
64
 
65
65
  interface FileCardProps {
66
- FileIcon: ComponentType<{ fileName: string; size: number }>;
67
66
  file: FileContentDetail;
68
- labels: {
69
- chars: string;
70
- lines: string;
71
- };
72
67
  }
73
68
 
74
- const FileCard = memo<FileCardProps>(({ file, FileIcon, labels }) => {
69
+ const FileCard = memo<FileCardProps>(({ file }) => {
75
70
  if (file.error) {
76
71
  return (
77
72
  <Flexbox className={styles.container} gap={8}>
78
73
  <Flexbox className={styles.cardBody} gap={8}>
79
74
  <Flexbox align={'center'} className={styles.titleRow} gap={8} horizontal>
80
- <FileIcon fileName={file.filename} size={16} />
75
+ <MaterialFileTypeIcon
76
+ filename={file.filename}
77
+ size={16}
78
+ type={'file'}
79
+ variant={'raw'}
80
+ />
81
81
  <div className={styles.title}>{file.filename}</div>
82
82
  </Flexbox>
83
83
  </Flexbox>
@@ -92,7 +92,7 @@ const FileCard = memo<FileCardProps>(({ file, FileIcon, labels }) => {
92
92
  <Flexbox className={styles.container} justify={'space-between'}>
93
93
  <Flexbox className={styles.cardBody} gap={8}>
94
94
  <Flexbox align={'center'} className={styles.titleRow} gap={8} horizontal>
95
- <FileIcon fileName={file.filename} size={16} />
95
+ <MaterialFileTypeIcon filename={file.filename} size={16} type={'file'} variant={'raw'} />
96
96
  <div className={styles.title}>{file.filename}</div>
97
97
  </Flexbox>
98
98
  {file.preview && (
@@ -118,11 +118,11 @@ const FileCard = memo<FileCardProps>(({ file, FileIcon, labels }) => {
118
118
  items={[
119
119
  {
120
120
  children: file.totalCharCount?.toLocaleString(),
121
- label: labels.chars,
121
+ label: 'Chars',
122
122
  },
123
123
  {
124
124
  children: file.totalLineCount?.toLocaleString(),
125
- label: labels.lines,
125
+ label: 'Lines',
126
126
  },
127
127
  ]}
128
128
  size="small"
@@ -2,36 +2,27 @@
2
2
 
3
3
  import { BuiltinRenderProps } from '@lobechat/types';
4
4
  import { Flexbox } from '@lobehub/ui';
5
- import { ComponentType, memo } from 'react';
5
+ import { memo } from 'react';
6
6
 
7
7
  import { ReadKnowledgeArgs, ReadKnowledgeState } from '../../../types';
8
8
  import FileCard from './FileCard';
9
9
 
10
- export interface ReadKnowledgeRenderProps extends Pick<
11
- BuiltinRenderProps<ReadKnowledgeArgs, ReadKnowledgeState>,
12
- 'pluginState'
13
- > {
14
- FileIcon: ComponentType<{ fileName: string; size: number }>;
15
- labels: {
16
- chars: string;
17
- lines: string;
18
- };
19
- }
10
+ const ReadKnowledge = memo<BuiltinRenderProps<ReadKnowledgeArgs, ReadKnowledgeState>>(
11
+ ({ pluginState }) => {
12
+ const { files } = pluginState || {};
20
13
 
21
- const ReadKnowledge = memo<ReadKnowledgeRenderProps>(({ pluginState, FileIcon, labels }) => {
22
- const { files } = pluginState || {};
14
+ if (!files || files.length === 0) {
15
+ return null;
16
+ }
23
17
 
24
- if (!files || files.length === 0) {
25
- return null;
26
- }
27
-
28
- return (
29
- <Flexbox gap={12} horizontal style={{ flexWrap: 'wrap' }}>
30
- {files.map((file) => (
31
- <FileCard FileIcon={FileIcon} file={file} key={file.fileId} labels={labels} />
32
- ))}
33
- </Flexbox>
34
- );
35
- });
18
+ return (
19
+ <Flexbox gap={12} horizontal style={{ flexWrap: 'wrap' }}>
20
+ {files.map((file) => (
21
+ <FileCard file={file} key={file.fileId} />
22
+ ))}
23
+ </Flexbox>
24
+ );
25
+ },
26
+ );
36
27
 
37
28
  export default ReadKnowledge;
@@ -1,62 +1,36 @@
1
1
  'use client';
2
2
 
3
3
  import { FileSearchResult } from '@lobechat/types';
4
- import { Center, Flexbox, Text, Tooltip } from '@lobehub/ui';
4
+ import { Center, Flexbox, MaterialFileTypeIcon, Text, Tooltip } from '@lobehub/ui';
5
5
  import { cx, useThemeMode } from 'antd-style';
6
- import { ComponentType, memo } from 'react';
6
+ import { memo } from 'react';
7
7
 
8
8
  import { styles } from './style';
9
9
 
10
10
  export interface FileItemProps extends FileSearchResult {
11
- FileIcon: ComponentType<{
12
- fileName: string;
13
- size: number;
14
- variant?: 'raw' | 'file' | 'folder';
15
- }>;
16
11
  index: number;
17
- isMobile?: boolean;
18
- onFileClick?: (params: { chunkId: string; chunkText: string; fileId: string }) => void;
19
12
  }
20
13
 
21
- const FileItem = memo<FileItemProps>(
22
- ({ fileId, fileName, relevanceScore, topChunks, FileIcon, isMobile, onFileClick }) => {
23
- const { isDarkMode } = useThemeMode();
14
+ const FileItem = memo<FileItemProps>(({ fileId, fileName, relevanceScore }) => {
15
+ const { isDarkMode } = useThemeMode();
24
16
 
25
- // Use the first chunk for preview
26
- const firstChunk = topChunks[0];
27
-
28
- return (
29
- <Flexbox
30
- align={'center'}
31
- className={cx(
32
- styles.container,
33
- isDarkMode ? styles.containerDark : styles.containerLight,
34
- isMobile && styles.mobile,
35
- )}
36
- gap={4}
37
- horizontal
38
- key={fileId}
39
- onClick={(e) => {
40
- e.stopPropagation();
41
- if (firstChunk && onFileClick) {
42
- onFileClick({
43
- chunkId: firstChunk.id,
44
- chunkText: firstChunk.text,
45
- fileId,
46
- });
47
- }
48
- }}
49
- >
50
- <FileIcon fileName={fileName} size={20} variant={'raw'} />
51
- <Flexbox gap={12} horizontal justify={'space-between'} style={{ maxWidth: 200 }}>
52
- <Text ellipsis>{fileName}</Text>
53
- <Tooltip title={`Relevance: ${(relevanceScore * 100).toFixed(1)}%`}>
54
- <Center className={styles.badge}>{relevanceScore.toFixed(2)}</Center>
55
- </Tooltip>
56
- </Flexbox>
17
+ return (
18
+ <Flexbox
19
+ align={'center'}
20
+ className={cx(styles.container, isDarkMode ? styles.containerDark : styles.containerLight)}
21
+ gap={4}
22
+ horizontal
23
+ key={fileId}
24
+ >
25
+ <MaterialFileTypeIcon filename={fileName} size={20} type={'file'} variant={'raw'} />
26
+ <Flexbox gap={12} horizontal justify={'space-between'} style={{ maxWidth: 200 }}>
27
+ <Text ellipsis>{fileName}</Text>
28
+ <Tooltip title={`Relevance: ${(relevanceScore * 100).toFixed(1)}%`}>
29
+ <Center className={styles.badge}>{relevanceScore.toFixed(2)}</Center>
30
+ </Tooltip>
57
31
  </Flexbox>
58
- );
59
- },
60
- );
32
+ </Flexbox>
33
+ );
34
+ });
61
35
 
62
36
  export default FileItem;
@@ -1,42 +1,30 @@
1
1
  'use client';
2
2
 
3
3
  import { BuiltinRenderProps } from '@lobechat/types';
4
- import { Flexbox } from '@lobehub/ui';
5
- import { ComponentType, memo } from 'react';
4
+ import { Empty, Flexbox } from '@lobehub/ui';
5
+ import { memo } from 'react';
6
+ import { useTranslation } from 'react-i18next';
6
7
 
7
8
  import { SearchKnowledgeBaseArgs, SearchKnowledgeBaseState } from '../../../types';
8
9
  import FileItem from './Item';
9
10
 
10
- export interface SearchKnowledgeBaseRenderProps extends Pick<
11
- BuiltinRenderProps<SearchKnowledgeBaseArgs, SearchKnowledgeBaseState>,
12
- 'pluginState'
13
- > {
14
- FileIcon: ComponentType<{ fileName: string; size: number; variant?: 'raw' | 'file' | 'folder' }>;
15
- isMobile?: boolean;
16
- onFileClick?: (params: { chunkId: string; chunkText: string; fileId: string }) => void;
17
- }
11
+ const SearchKnowledgeBase = memo<
12
+ BuiltinRenderProps<SearchKnowledgeBaseArgs, SearchKnowledgeBaseState>
13
+ >(({ pluginState }) => {
14
+ const { t } = useTranslation('plugin');
15
+ const { fileResults } = pluginState || {};
18
16
 
19
- const SearchKnowledgeBase = memo<SearchKnowledgeBaseRenderProps>(
20
- ({ pluginState, FileIcon, isMobile, onFileClick }) => {
21
- const { fileResults } = pluginState || {};
17
+ if (!fileResults || fileResults.length === 0) {
18
+ return <Empty description={t('builtins.lobe-knowledge-base.inspector.noResults')} />;
19
+ }
22
20
 
23
- return (
24
- <Flexbox gap={8} horizontal wrap={'wrap'}>
25
- {fileResults?.map((file, index) => {
26
- return (
27
- <FileItem
28
- FileIcon={FileIcon}
29
- index={index}
30
- isMobile={isMobile}
31
- key={file.fileId}
32
- onFileClick={onFileClick}
33
- {...file}
34
- />
35
- );
36
- })}
37
- </Flexbox>
38
- );
39
- },
40
- );
21
+ return (
22
+ <Flexbox gap={8} horizontal wrap={'wrap'}>
23
+ {fileResults.map((file, index) => {
24
+ return <FileItem index={index} key={file.fileId} {...file} />;
25
+ })}
26
+ </Flexbox>
27
+ );
28
+ });
41
29
 
42
30
  export default SearchKnowledgeBase;
@@ -5,8 +5,3 @@ export const KnowledgeBaseRenders = {
5
5
  readKnowledge: ReadKnowledge,
6
6
  searchKnowledgeBase: SearchKnowledgeBase,
7
7
  };
8
-
9
-
10
-
11
- export {default as ReadKnowledge} from './ReadKnowledge';
12
- export {default as SearchKnowledgeBase} from './SearchKnowledgeBase';
@@ -1,4 +1,8 @@
1
- export { KnowledgeBaseRenders, ReadKnowledge, SearchKnowledgeBase } from './Render';
1
+ // Inspector components (customized tool call headers)
2
+ export { KnowledgeBaseInspectors } from './Inspector';
3
+
4
+ // Render components (read-only snapshots)
5
+ export { KnowledgeBaseRenders } from './Render';
2
6
 
3
7
  // Re-export types and manifest for convenience
4
8
  export { KnowledgeBaseManifest } from '../manifest';
@@ -0,0 +1,119 @@
1
+ import { formatSearchResults, promptFileContents, promptNoSearchResults } from '@lobechat/prompts';
2
+ import { BaseExecutor, type BuiltinToolContext, type BuiltinToolResult } from '@lobechat/types';
3
+
4
+ import { ragService } from '@/services/rag';
5
+ import { agentSelectors } from '@/store/agent/selectors';
6
+ import { getAgentStoreState } from '@/store/agent/store';
7
+
8
+ import {
9
+ type FileContentDetail,
10
+ KnowledgeBaseIdentifier,
11
+ type ReadKnowledgeArgs,
12
+ type ReadKnowledgeState,
13
+ type SearchKnowledgeBaseArgs,
14
+ type SearchKnowledgeBaseState,
15
+ } from '../types';
16
+
17
+ /**
18
+ * Knowledge Base Tool Executor
19
+ *
20
+ * Handles knowledge base search and retrieval operations.
21
+ */
22
+ class KnowledgeBaseExecutor extends BaseExecutor<{
23
+ readKnowledge: 'readKnowledge';
24
+ searchKnowledgeBase: 'searchKnowledgeBase';
25
+ }> {
26
+ readonly identifier = KnowledgeBaseIdentifier;
27
+ protected readonly apiEnum = {
28
+ readKnowledge: 'readKnowledge' as const,
29
+ searchKnowledgeBase: 'searchKnowledgeBase' as const,
30
+ };
31
+
32
+ /**
33
+ * Search knowledge base and return file summaries with relevant chunks
34
+ */
35
+ searchKnowledgeBase = async (
36
+ params: SearchKnowledgeBaseArgs,
37
+ ctx: BuiltinToolContext,
38
+ ): Promise<BuiltinToolResult> => {
39
+ try {
40
+ const { query, topK = 20 } = params;
41
+
42
+ // Get knowledge base IDs from agent store
43
+ const agentState = getAgentStoreState();
44
+ const knowledgeIds = agentSelectors.currentKnowledgeIds(agentState);
45
+
46
+ // Only search in knowledge bases, not agent files
47
+ // Agent files will be injected as full content in context-engine
48
+ const knowledgeBaseIds = knowledgeIds.knowledgeBaseIds;
49
+
50
+ const { chunks, fileResults } = await ragService.semanticSearchForChat(
51
+ { knowledgeIds: knowledgeBaseIds, query, topK },
52
+ ctx.signal,
53
+ );
54
+
55
+ if (chunks.length === 0) {
56
+ const state: SearchKnowledgeBaseState = { chunks: [], fileResults: [], totalResults: 0 };
57
+
58
+ return { content: promptNoSearchResults(query), state, success: true };
59
+ }
60
+
61
+ // Format search results for AI
62
+ const formattedContent = formatSearchResults(fileResults, query);
63
+
64
+ const state: SearchKnowledgeBaseState = { chunks, fileResults, totalResults: chunks.length };
65
+
66
+ return { content: formattedContent, state, success: true };
67
+ } catch (e) {
68
+ return {
69
+ content: `Error searching knowledge base: ${(e as Error).message}`,
70
+ error: { body: e, message: (e as Error).message, type: 'PluginServerError' },
71
+ success: false,
72
+ };
73
+ }
74
+ };
75
+
76
+ /**
77
+ * Read full content of specific files from knowledge base
78
+ */
79
+ readKnowledge = async (params: ReadKnowledgeArgs): Promise<BuiltinToolResult> => {
80
+ try {
81
+ const { fileIds } = params;
82
+
83
+ if (!fileIds || fileIds.length === 0) {
84
+ return {
85
+ content: 'Error: No file IDs provided',
86
+ success: false,
87
+ };
88
+ }
89
+
90
+ const fileContents = await ragService.getFileContents(fileIds);
91
+
92
+ const formattedContent = promptFileContents(fileContents);
93
+
94
+ const state: ReadKnowledgeState = {
95
+ files: fileContents.map(
96
+ (file): FileContentDetail => ({
97
+ error: file.error,
98
+ fileId: file.fileId,
99
+ filename: file.filename,
100
+ preview: file.preview,
101
+ totalCharCount: file.totalCharCount,
102
+ totalLineCount: file.totalLineCount,
103
+ }),
104
+ ),
105
+ };
106
+
107
+ return { content: formattedContent, state, success: true };
108
+ } catch (e) {
109
+ return {
110
+ content: `Error reading knowledge: ${(e as Error).message}`,
111
+ error: { body: e, message: (e as Error).message, type: 'PluginServerError' },
112
+ success: false,
113
+ };
114
+ }
115
+ };
116
+ }
117
+
118
+ // Export the executor instance for registration
119
+ export const knowledgeBaseExecutor = new KnowledgeBaseExecutor();
@@ -5,6 +5,7 @@
5
5
  "exports": {
6
6
  ".": "./src/index.ts",
7
7
  "./client": "./src/client/index.ts",
8
+ "./executor": "./src/executor/index.ts",
8
9
  "./executionRuntime": "./src/ExecutionRuntime/index.ts"
9
10
  },
10
11
  "main": "./src/index.ts",
@@ -2,15 +2,16 @@
2
2
 
3
3
  import { type EditLocalFileParams } from '@lobechat/electron-client-ipc';
4
4
  import { type BuiltinInspectorProps } from '@lobechat/types';
5
+ import { Icon, Text } from '@lobehub/ui';
5
6
  import { createStaticStyles, cssVar, cx } from 'antd-style';
6
- import { Check, X } from 'lucide-react';
7
- import path from 'path-browserify-esm';
8
- import { memo } from 'react';
7
+ import { Minus, Plus } from 'lucide-react';
8
+ import { type ReactNode, memo } from 'react';
9
9
  import { useTranslation } from 'react-i18next';
10
10
 
11
- import { highlightTextStyles, shinyTextStyles } from '@/styles';
11
+ import { shinyTextStyles } from '@/styles';
12
12
 
13
13
  import { type EditLocalFileState } from '../../../types';
14
+ import { FilePathDisplay } from '../../components/FilePathDisplay';
14
15
 
15
16
  const styles = createStaticStyles(({ css, cssVar }) => ({
16
17
  root: css`
@@ -21,9 +22,9 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
21
22
 
22
23
  color: ${cssVar.colorTextSecondary};
23
24
  `,
24
- statusIcon: css`
25
- margin-block-end: -2px;
26
- margin-inline-start: 4px;
25
+ separator: css`
26
+ margin-inline: 2px;
27
+ color: ${cssVar.colorTextQuaternary};
27
28
  `,
28
29
  }));
29
30
 
@@ -32,18 +33,11 @@ export const EditLocalFileInspector = memo<
32
33
  >(({ args, partialArgs, isArgumentsStreaming, pluginState, isLoading }) => {
33
34
  const { t } = useTranslation('plugin');
34
35
 
35
- // Show filename with parent directory for context
36
36
  const filePath = args?.file_path || partialArgs?.file_path || '';
37
- let displayPath = '';
38
- if (filePath) {
39
- const { base, dir } = path.parse(filePath);
40
- const parentDir = path.basename(dir);
41
- displayPath = parentDir ? `${parentDir}/${base}` : base;
42
- }
43
37
 
44
38
  // During argument streaming
45
39
  if (isArgumentsStreaming) {
46
- if (!displayPath)
40
+ if (!filePath)
47
41
  return (
48
42
  <div className={cx(styles.root, shinyTextStyles.shinyText)}>
49
43
  <span>{t('builtins.lobe-local-system.apiName.editLocalFile')}</span>
@@ -53,27 +47,48 @@ export const EditLocalFileInspector = memo<
53
47
  return (
54
48
  <div className={cx(styles.root, shinyTextStyles.shinyText)}>
55
49
  <span>{t('builtins.lobe-local-system.apiName.editLocalFile')}: </span>
56
- <span className={highlightTextStyles.primary}>{displayPath}</span>
50
+ <FilePathDisplay filePath={filePath} />
57
51
  </div>
58
52
  );
59
53
  }
60
54
 
61
- // Check if edit was successful (has replacements count)
62
- const isSuccess = pluginState?.replacements !== undefined && pluginState.replacements >= 0;
55
+ // Build stats parts with colors and icons
56
+ const linesAdded = pluginState?.linesAdded ?? 0;
57
+ const linesDeleted = pluginState?.linesDeleted ?? 0;
58
+
59
+ const statsParts: ReactNode[] = [];
60
+ if (linesAdded > 0) {
61
+ statsParts.push(
62
+ <Text as={'span'} code color={cssVar.colorSuccess} fontSize={12} key="added">
63
+ <Icon icon={Plus} size={12} />
64
+ {linesAdded}
65
+ </Text>,
66
+ );
67
+ }
68
+ if (linesDeleted > 0) {
69
+ statsParts.push(
70
+ <Text as={'span'} code color={cssVar.colorError} fontSize={12} key="deleted">
71
+ <Icon icon={Minus} size={12} />
72
+ {linesDeleted}
73
+ </Text>,
74
+ );
75
+ }
63
76
 
64
77
  return (
65
78
  <div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
66
- <span style={{ marginInlineStart: 2 }}>
67
- <span>{t('builtins.lobe-local-system.apiName.editLocalFile')}: </span>
68
- {displayPath && <span className={highlightTextStyles.primary}>{displayPath}</span>}
69
- {isLoading ? null : pluginState ? (
70
- isSuccess ? (
71
- <Check className={styles.statusIcon} color={cssVar.colorSuccess} size={14} />
72
- ) : (
73
- <X className={styles.statusIcon} color={cssVar.colorError} size={14} />
74
- )
75
- ) : null}
76
- </span>
79
+ <span>{t('builtins.lobe-local-system.apiName.editLocalFile')}: </span>
80
+ <FilePathDisplay filePath={filePath} />
81
+ {!isLoading && statsParts.length > 0 && (
82
+ <>
83
+ {' '}
84
+ {statsParts.map((part, index) => (
85
+ <span key={index}>
86
+ {index > 0 && <span className={styles.separator}> / </span>}
87
+ {part}
88
+ </span>
89
+ ))}
90
+ </>
91
+ )}
77
92
  </div>
78
93
  );
79
94
  });