@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
@@ -2,8 +2,8 @@
2
2
 
3
3
  import { type GrepContentParams } from '@lobechat/electron-client-ipc';
4
4
  import { type BuiltinInspectorProps } from '@lobechat/types';
5
+ import { Text } from '@lobehub/ui';
5
6
  import { createStaticStyles, cssVar, cx } from 'antd-style';
6
- import { Check, X } from 'lucide-react';
7
7
  import { memo } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
9
 
@@ -20,10 +20,6 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
20
20
 
21
21
  color: ${cssVar.colorTextSecondary};
22
22
  `,
23
- statusIcon: css`
24
- margin-block-end: -2px;
25
- margin-inline-start: 4px;
26
- `,
27
23
  }));
28
24
 
29
25
  export const GrepContentInspector = memo<
@@ -50,22 +46,28 @@ export const GrepContentInspector = memo<
50
46
  );
51
47
  }
52
48
 
53
- // Check if grep was successful
54
- const isSuccess = pluginState?.result?.success;
49
+ // Check result count
50
+ const resultCount = pluginState?.result?.total_matches ?? 0;
51
+ const hasResults = resultCount > 0;
55
52
 
56
53
  return (
57
54
  <div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
58
- <span style={{ marginInlineStart: 2 }}>
59
- <span>{t('builtins.lobe-local-system.apiName.grepContent')}: </span>
60
- {pattern && <span className={highlightTextStyles.primary}>{pattern}</span>}
61
- {isLoading ? null : pluginState?.result ? (
62
- isSuccess ? (
63
- <Check className={styles.statusIcon} color={cssVar.colorSuccess} size={14} />
64
- ) : (
65
- <X className={styles.statusIcon} color={cssVar.colorError} size={14} />
66
- )
67
- ) : null}
68
- </span>
55
+ <span>{t('builtins.lobe-local-system.apiName.grepContent')}: </span>
56
+ {pattern && <span className={highlightTextStyles.primary}>{pattern}</span>}
57
+ {!isLoading &&
58
+ pluginState?.result &&
59
+ (hasResults ? (
60
+ <span style={{ marginInlineStart: 4 }}>({resultCount})</span>
61
+ ) : (
62
+ <Text
63
+ as={'span'}
64
+ color={cssVar.colorTextDescription}
65
+ fontSize={12}
66
+ style={{ marginInlineStart: 4 }}
67
+ >
68
+ ({t('builtins.lobe-local-system.inspector.noResults')})
69
+ </Text>
70
+ ))}
69
71
  </div>
70
72
  );
71
73
  });
@@ -0,0 +1,76 @@
1
+ 'use client';
2
+
3
+ import { type ListLocalFileParams } from '@lobechat/electron-client-ipc';
4
+ import { type BuiltinInspectorProps } from '@lobechat/types';
5
+ import { Text } from '@lobehub/ui';
6
+ import { createStaticStyles, cssVar, cx } from 'antd-style';
7
+ import { memo } from 'react';
8
+ import { useTranslation } from 'react-i18next';
9
+
10
+ import { shinyTextStyles } from '@/styles';
11
+
12
+ import { type LocalFileListState } from '../../..';
13
+ import { FilePathDisplay } from '../../components/FilePathDisplay';
14
+
15
+ const styles = createStaticStyles(({ css, cssVar }) => ({
16
+ root: css`
17
+ overflow: hidden;
18
+ display: -webkit-box;
19
+ -webkit-box-orient: vertical;
20
+ -webkit-line-clamp: 1;
21
+
22
+ color: ${cssVar.colorTextSecondary};
23
+ `,
24
+ }));
25
+
26
+ export const ListLocalFilesInspector = memo<
27
+ BuiltinInspectorProps<ListLocalFileParams, LocalFileListState>
28
+ >(({ args, partialArgs, isArgumentsStreaming, pluginState, isLoading }) => {
29
+ const { t } = useTranslation('plugin');
30
+
31
+ const path = args?.path || partialArgs?.path || '';
32
+
33
+ // During argument streaming
34
+ if (isArgumentsStreaming) {
35
+ if (!path)
36
+ return (
37
+ <div className={cx(styles.root, shinyTextStyles.shinyText)}>
38
+ <span>{t('builtins.lobe-local-system.apiName.listLocalFiles')}</span>
39
+ </div>
40
+ );
41
+
42
+ return (
43
+ <div className={cx(styles.root, shinyTextStyles.shinyText)}>
44
+ <span>{t('builtins.lobe-local-system.apiName.listLocalFiles')}: </span>
45
+ <FilePathDisplay filePath={path} isDirectory />
46
+ </div>
47
+ );
48
+ }
49
+
50
+ // Show result count if available
51
+ const resultCount = pluginState?.listResults?.length ?? 0;
52
+ const hasResults = resultCount > 0;
53
+
54
+ return (
55
+ <div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
56
+ <span>{t('builtins.lobe-local-system.apiName.listLocalFiles')}: </span>
57
+ <FilePathDisplay filePath={path} isDirectory />
58
+ {!isLoading &&
59
+ pluginState?.listResults &&
60
+ (hasResults ? (
61
+ <span style={{ marginInlineStart: 4 }}>({resultCount})</span>
62
+ ) : (
63
+ <Text
64
+ as={'span'}
65
+ color={cssVar.colorTextDescription}
66
+ fontSize={12}
67
+ style={{ marginInlineStart: 4 }}
68
+ >
69
+ ({t('builtins.lobe-local-system.inspector.noResults')})
70
+ </Text>
71
+ ))}
72
+ </div>
73
+ );
74
+ });
75
+
76
+ ListLocalFilesInspector.displayName = 'ListLocalFilesInspector';
@@ -2,15 +2,14 @@
2
2
 
3
3
  import { type LocalReadFileParams } from '@lobechat/electron-client-ipc';
4
4
  import { type BuiltinInspectorProps } from '@lobechat/types';
5
- import { createStaticStyles, cssVar, cx } from 'antd-style';
6
- import { Check, X } from 'lucide-react';
7
- import path from 'path-browserify-esm';
5
+ import { createStaticStyles, cx } from 'antd-style';
8
6
  import { memo } from 'react';
9
7
  import { useTranslation } from 'react-i18next';
10
8
 
11
- import { highlightTextStyles, shinyTextStyles } from '@/styles';
9
+ import { shinyTextStyles } from '@/styles';
12
10
 
13
11
  import { type LocalReadFileState } from '../../..';
12
+ import { FilePathDisplay } from '../../components/FilePathDisplay';
14
13
 
15
14
  const styles = createStaticStyles(({ css, cssVar }) => ({
16
15
  root: css`
@@ -21,29 +20,18 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
21
20
 
22
21
  color: ${cssVar.colorTextSecondary};
23
22
  `,
24
- statusIcon: css`
25
- margin-block-end: -2px;
26
- margin-inline-start: 4px;
27
- `,
28
23
  }));
29
24
 
30
25
  export const ReadLocalFileInspector = memo<
31
26
  BuiltinInspectorProps<LocalReadFileParams, LocalReadFileState>
32
- >(({ args, partialArgs, isArgumentsStreaming, pluginState, isLoading }) => {
27
+ >(({ args, partialArgs, isArgumentsStreaming, isLoading }) => {
33
28
  const { t } = useTranslation('plugin');
34
29
 
35
- // Show filename with parent directory for context
36
30
  const filePath = args?.path || partialArgs?.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
31
 
44
32
  // During argument streaming
45
33
  if (isArgumentsStreaming) {
46
- if (!displayPath)
34
+ if (!filePath)
47
35
  return (
48
36
  <div className={cx(styles.root, shinyTextStyles.shinyText)}>
49
37
  <span>{t('builtins.lobe-local-system.apiName.readLocalFile')}</span>
@@ -53,27 +41,15 @@ export const ReadLocalFileInspector = memo<
53
41
  return (
54
42
  <div className={cx(styles.root, shinyTextStyles.shinyText)}>
55
43
  <span>{t('builtins.lobe-local-system.apiName.readLocalFile')}: </span>
56
- <span className={highlightTextStyles.primary}>{displayPath}</span>
44
+ <FilePathDisplay filePath={filePath} />
57
45
  </div>
58
46
  );
59
47
  }
60
48
 
61
- // Check if file was read successfully (has content)
62
- const hasContent = !!pluginState?.fileContent;
63
-
64
49
  return (
65
50
  <div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
66
- <span style={{ marginInlineStart: 2 }}>
67
- <span>{t('builtins.lobe-local-system.apiName.readLocalFile')}: </span>
68
- {displayPath && <span className={highlightTextStyles.primary}>{displayPath}</span>}
69
- {isLoading ? null : pluginState ? (
70
- hasContent ? (
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>
51
+ <span>{t('builtins.lobe-local-system.apiName.readLocalFile')}: </span>
52
+ <FilePathDisplay filePath={filePath} />
77
53
  </div>
78
54
  );
79
55
  });
@@ -0,0 +1,62 @@
1
+ 'use client';
2
+
3
+ import { type RenameLocalFileParams } from '@lobechat/electron-client-ipc';
4
+ import { type BuiltinInspectorProps } from '@lobechat/types';
5
+ import { MaterialFileTypeIcon } from '@lobehub/ui';
6
+ import { createStaticStyles, cx } from 'antd-style';
7
+ import path from 'path-browserify-esm';
8
+ import { memo } from 'react';
9
+ import { useTranslation } from 'react-i18next';
10
+
11
+ import { highlightTextStyles, shinyTextStyles } from '@/styles';
12
+
13
+ import { type LocalRenameFileState } from '../../..';
14
+
15
+ const styles = createStaticStyles(({ css, cssVar }) => ({
16
+ icon: css`
17
+ flex-shrink: 0;
18
+ margin-inline-end: 4px;
19
+ `,
20
+ root: css`
21
+ overflow: hidden;
22
+ display: -webkit-box;
23
+ -webkit-box-orient: vertical;
24
+ -webkit-line-clamp: 1;
25
+
26
+ color: ${cssVar.colorTextSecondary};
27
+ `,
28
+ }));
29
+
30
+ export const RenameLocalFileInspector = memo<
31
+ BuiltinInspectorProps<RenameLocalFileParams, LocalRenameFileState>
32
+ >(({ args, partialArgs, isArgumentsStreaming }) => {
33
+ const { t } = useTranslation('plugin');
34
+
35
+ const filePath = args?.path || partialArgs?.path || '';
36
+ const newName = args?.newName || partialArgs?.newName || '';
37
+
38
+ // Get the old filename from path
39
+ const oldName = filePath ? path.basename(filePath) : '';
40
+
41
+ return (
42
+ <div className={cx(styles.root, isArgumentsStreaming && shinyTextStyles.shinyText)}>
43
+ {oldName && newName ? (
44
+ <>
45
+ {t('builtins.lobe-local-system.apiName.renameLocalFile')} {oldName} →{' '}
46
+ <MaterialFileTypeIcon
47
+ className={styles.icon}
48
+ filename={newName}
49
+ size={16}
50
+ type={'file'}
51
+ variant={'raw'}
52
+ />
53
+ <span className={highlightTextStyles.primary}>{newName}</span>
54
+ </>
55
+ ) : (
56
+ <span>{t('builtins.lobe-local-system.apiName.renameLocalFile')}</span>
57
+ )}
58
+ </div>
59
+ );
60
+ });
61
+
62
+ RenameLocalFileInspector.displayName = 'RenameLocalFileInspector';
@@ -2,8 +2,8 @@
2
2
 
3
3
  import { type LocalSearchFilesParams } from '@lobechat/electron-client-ipc';
4
4
  import { type BuiltinInspectorProps } from '@lobechat/types';
5
+ import { Text } from '@lobehub/ui';
5
6
  import { createStaticStyles, cssVar, cx } from 'antd-style';
6
- import { Check } from 'lucide-react';
7
7
  import { memo } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
9
 
@@ -20,10 +20,6 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
20
20
 
21
21
  color: ${cssVar.colorTextSecondary};
22
22
  `,
23
- statusIcon: css`
24
- margin-block-end: -2px;
25
- margin-inline-start: 4px;
26
- `,
27
23
  }));
28
24
 
29
25
  export const SearchLocalFilesInspector = memo<
@@ -51,18 +47,28 @@ export const SearchLocalFilesInspector = memo<
51
47
  }
52
48
 
53
49
  // Check if search returned results
54
- const hasResults = pluginState?.searchResults && pluginState.searchResults.length >= 0;
50
+ const resultCount = pluginState?.searchResults?.length ?? 0;
51
+ const hasResults = resultCount > 0;
55
52
 
56
53
  return (
57
54
  <div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
58
55
  <span style={{ marginInlineStart: 2 }}>
59
56
  <span>{t('builtins.lobe-local-system.apiName.searchLocalFiles')}: </span>
60
57
  {keywords && <span className={highlightTextStyles.primary}>{keywords}</span>}
61
- {isLoading ? null : pluginState?.searchResults ? (
62
- hasResults ? (
63
- <Check className={styles.statusIcon} color={cssVar.colorSuccess} size={14} />
64
- ) : null
65
- ) : null}
58
+ {!isLoading &&
59
+ pluginState?.searchResults &&
60
+ (hasResults ? (
61
+ <span style={{ marginInlineStart: 4 }}>({resultCount})</span>
62
+ ) : (
63
+ <Text
64
+ as={'span'}
65
+ color={cssVar.colorTextDescription}
66
+ fontSize={12}
67
+ style={{ marginInlineStart: 4 }}
68
+ >
69
+ ({t('builtins.lobe-local-system.inspector.noResults')})
70
+ </Text>
71
+ ))}
66
72
  </span>
67
73
  </div>
68
74
  );
@@ -0,0 +1,61 @@
1
+ 'use client';
2
+
3
+ import { type WriteLocalFileParams } from '@lobechat/electron-client-ipc';
4
+ import { type BuiltinInspectorProps } from '@lobechat/types';
5
+ import { Icon, Text } from '@lobehub/ui';
6
+ import { createStaticStyles, cssVar, cx } from 'antd-style';
7
+ import { Plus } from 'lucide-react';
8
+ import { memo } from 'react';
9
+ import { useTranslation } from 'react-i18next';
10
+
11
+ import { shinyTextStyles } from '@/styles';
12
+
13
+ import { FilePathDisplay } from '../../components/FilePathDisplay';
14
+
15
+ const styles = createStaticStyles(({ css, cssVar }) => ({
16
+ root: css`
17
+ overflow: hidden;
18
+ display: -webkit-box;
19
+ -webkit-box-orient: vertical;
20
+ -webkit-line-clamp: 1;
21
+
22
+ color: ${cssVar.colorTextSecondary};
23
+ `,
24
+ }));
25
+
26
+ export const WriteLocalFileInspector = memo<BuiltinInspectorProps<WriteLocalFileParams>>(
27
+ ({ args, partialArgs, isArgumentsStreaming }) => {
28
+ const { t } = useTranslation('plugin');
29
+
30
+ const filePath = args?.path || partialArgs?.path || '';
31
+ const content = args?.content || partialArgs?.content || '';
32
+
33
+ // Calculate lines from content
34
+ const lines = content ? content.split('\n').length : 0;
35
+
36
+ // During argument streaming without path
37
+ if (isArgumentsStreaming && !filePath) {
38
+ return (
39
+ <div className={cx(styles.root, shinyTextStyles.shinyText)}>
40
+ <span>{t('builtins.lobe-local-system.apiName.writeLocalFile')}</span>
41
+ </div>
42
+ );
43
+ }
44
+
45
+ return (
46
+ <div className={cx(styles.root, isArgumentsStreaming && shinyTextStyles.shinyText)}>
47
+ <span>{t('builtins.lobe-local-system.apiName.writeLocalFile')}: </span>
48
+ <FilePathDisplay filePath={filePath} />
49
+ {lines > 0 && (
50
+ <Text as={'span'} code color={cssVar.colorSuccess} fontSize={12}>
51
+ {' '}
52
+ <Icon icon={Plus} size={12} />
53
+ {lines}
54
+ </Text>
55
+ )}
56
+ </div>
57
+ );
58
+ },
59
+ );
60
+
61
+ WriteLocalFileInspector.displayName = 'WriteLocalFileInspector';
@@ -2,9 +2,12 @@ import { LocalSystemApiName } from '../..';
2
2
  import { EditLocalFileInspector } from './EditLocalFile';
3
3
  import { GlobLocalFilesInspector } from './GlobLocalFiles';
4
4
  import { GrepContentInspector } from './GrepContent';
5
+ import { ListLocalFilesInspector } from './ListLocalFiles';
5
6
  import { ReadLocalFileInspector } from './ReadLocalFile';
7
+ import { RenameLocalFileInspector } from './RenameLocalFile';
6
8
  import { RunCommandInspector } from './RunCommand';
7
9
  import { SearchLocalFilesInspector } from './SearchLocalFiles';
10
+ import { WriteLocalFileInspector } from './WriteLocalFile';
8
11
 
9
12
  /**
10
13
  * Local System Inspector Components Registry
@@ -13,7 +16,10 @@ export const LocalSystemInspectors = {
13
16
  [LocalSystemApiName.editLocalFile]: EditLocalFileInspector,
14
17
  [LocalSystemApiName.globLocalFiles]: GlobLocalFilesInspector,
15
18
  [LocalSystemApiName.grepContent]: GrepContentInspector,
19
+ [LocalSystemApiName.listLocalFiles]: ListLocalFilesInspector,
16
20
  [LocalSystemApiName.readLocalFile]: ReadLocalFileInspector,
21
+ [LocalSystemApiName.renameLocalFile]: RenameLocalFileInspector,
17
22
  [LocalSystemApiName.runCommand]: RunCommandInspector,
18
23
  [LocalSystemApiName.searchLocalFiles]: SearchLocalFilesInspector,
24
+ [LocalSystemApiName.writeLocalFile]: WriteLocalFileInspector,
19
25
  };
@@ -50,7 +50,12 @@ const EditLocalFile = memo<BuiltinRenderProps<EditLocalFileParams, EditLocalFile
50
50
  <Flexbox data-theme={isDarkMode ? 'dark' : 'light'} gap={12}>
51
51
  {files.map((file, index) => (
52
52
  <div key={`${file.oldPath}-${index}`} style={{ fontSize: '12px' }}>
53
- <Diff diffType={file.type} gutterType="default" hunks={file.hunks} viewType="split">
53
+ <Diff
54
+ diffType={file.type}
55
+ gutterType="default"
56
+ hunks={file.hunks}
57
+ viewType="unified"
58
+ >
54
59
  {(hunks) => hunks.map((hunk) => <Hunk hunk={hunk} key={hunk.content} />)}
55
60
  </Diff>
56
61
  </div>
@@ -12,52 +12,40 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
12
12
  color: ${cssVar.colorTextTertiary};
13
13
  `,
14
14
  query: css`
15
- cursor: pointer;
16
-
17
15
  padding-block: 4px;
18
16
  padding-inline: 8px;
19
17
  border-radius: 8px;
20
18
 
21
19
  font-size: 12px;
22
20
  color: ${cssVar.colorTextSecondary};
23
-
24
- &:hover {
25
- background: ${cssVar.colorFillTertiary};
26
- }
27
21
  `,
28
22
  }));
29
23
 
30
24
  interface SearchBarProps {
31
25
  defaultQuery: string;
32
- onEditingChange: (editing: boolean) => void;
33
26
  resultsNumber: number;
34
27
  searching?: boolean;
35
28
  }
36
29
 
37
- const SearchBar = memo<SearchBarProps>(
38
- ({ defaultQuery, resultsNumber, onEditingChange, searching }) => {
39
- const { t } = useTranslation('tool');
40
- return (
41
- <Flexbox align={'center'} distribution={'space-between'} gap={40} height={26} horizontal>
42
- <Flexbox
43
- align={'center'}
44
- className={cx(styles.query, searching && shinyTextStyles.shinyText)}
45
- gap={8}
46
- horizontal
47
- onClick={() => {
48
- onEditingChange(true);
49
- }}
50
- >
51
- <Icon icon={SearchIcon} />
52
- {defaultQuery}
53
- </Flexbox>
30
+ const SearchBar = memo<SearchBarProps>(({ defaultQuery, resultsNumber, searching }) => {
31
+ const { t } = useTranslation('tool');
32
+ return (
33
+ <Flexbox align={'center'} distribution={'space-between'} gap={40} height={26} horizontal>
34
+ <Flexbox
35
+ align={'center'}
36
+ className={cx(styles.query, searching && shinyTextStyles.shinyText)}
37
+ gap={8}
38
+ horizontal
39
+ >
40
+ <Icon icon={SearchIcon} />
41
+ {defaultQuery}
42
+ </Flexbox>
54
43
 
55
- <Flexbox align={'center'} className={styles.font} horizontal>
56
- <div>{t('search.searchResult')}</div>
57
- {resultsNumber}
58
- </Flexbox>
44
+ <Flexbox align={'center'} className={styles.font} horizontal>
45
+ <div>{t('search.searchResult')}</div>
46
+ {resultsNumber}
59
47
  </Flexbox>
60
- );
61
- },
62
- );
48
+ </Flexbox>
49
+ );
50
+ });
63
51
  export default SearchBar;
@@ -1,9 +1,6 @@
1
1
  import type { LocalFileSearchState } from '@lobechat/builtin-tool-local-system';
2
2
  import { type LocalSearchFilesParams } from '@lobechat/electron-client-ipc';
3
- import { ActionIcon, Button, Flexbox, Icon, SearchBar } from '@lobehub/ui';
4
- import { SearchIcon, XIcon } from 'lucide-react';
5
- import { memo, useState } from 'react';
6
- import { useTranslation } from 'react-i18next';
3
+ import { memo } from 'react';
7
4
 
8
5
  import { useChatStore } from '@/store/chat';
9
6
  import { chatToolSelectors } from '@/store/chat/selectors';
@@ -17,49 +14,12 @@ interface SearchQueryViewProps {
17
14
  }
18
15
 
19
16
  const SearchQueryView = memo<SearchQueryViewProps>(({ messageId, args, pluginState }) => {
20
- const { t } = useTranslation('tool');
21
17
  const loading = useChatStore(chatToolSelectors.isSearchingLocalFiles(messageId));
22
- const reSearchLocalFiles = useChatStore((s) => s.reSearchLocalFiles);
23
18
  const searchResults = pluginState?.searchResults || [];
24
19
 
25
- const [editing, setEditing] = useState(false);
26
- const [query, setQuery] = useState(args.keywords);
27
-
28
- const updateAndSearch = async () => {
29
- const data: LocalSearchFilesParams = { keywords: query };
30
-
31
- await reSearchLocalFiles(messageId, data);
32
- };
33
-
34
- return editing ? (
35
- <Flexbox align={'center'} flex={1} gap={8} height={32} horizontal>
36
- <Flexbox gap={8}>
37
- <SearchBar
38
- autoFocus
39
- onChange={(e) => {
40
- setQuery(e.target.value);
41
- }}
42
- onSearch={updateAndSearch}
43
- placeholder={t('search.searchBar.placeholder')}
44
- style={{ minWidth: 400 }}
45
- value={query}
46
- variant={'filled'}
47
- />
48
- <Button
49
- icon={<Icon icon={SearchIcon} />}
50
- loading={loading}
51
- onClick={updateAndSearch}
52
- type={'primary'}
53
- >
54
- {t('search.searchBar.button')}
55
- </Button>
56
- </Flexbox>
57
- <ActionIcon icon={XIcon} onClick={() => setEditing(false)} />
58
- </Flexbox>
59
- ) : (
20
+ return (
60
21
  <SearchView
61
22
  defaultQuery={args?.keywords}
62
- onEditingChange={setEditing}
63
23
  resultsNumber={searchResults.length}
64
24
  searching={loading || !pluginState}
65
25
  />
@@ -3,7 +3,6 @@ import EditLocalFile from './EditLocalFile';
3
3
  import ListFiles from './ListFiles';
4
4
  import MoveLocalFiles from './MoveLocalFiles';
5
5
  import ReadLocalFile from './ReadLocalFile';
6
- import RenameLocalFile from './RenameLocalFile';
7
6
  import RunCommand from './RunCommand';
8
7
  import SearchFiles from './SearchFiles';
9
8
  import WriteFile from './WriteFile';
@@ -16,7 +15,6 @@ export const LocalSystemRenders = {
16
15
  [LocalSystemApiName.listLocalFiles]: ListFiles,
17
16
  [LocalSystemApiName.moveLocalFiles]: MoveLocalFiles,
18
17
  [LocalSystemApiName.readLocalFile]: ReadLocalFile,
19
- [LocalSystemApiName.renameLocalFile]: RenameLocalFile,
20
18
  [LocalSystemApiName.runCommand]: RunCommand,
21
19
  [LocalSystemApiName.searchLocalFiles]: SearchFiles,
22
20
  [LocalSystemApiName.writeLocalFile]: WriteFile,
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+
3
+ import { MaterialFileTypeIcon } from '@lobehub/ui';
4
+ import { createStaticStyles, cssVar } from 'antd-style';
5
+ import path from 'path-browserify-esm';
6
+ import { memo, useMemo } from 'react';
7
+
8
+ const styles = createStaticStyles(({ css }) => ({
9
+ icon: css`
10
+ flex-shrink: 0;
11
+ margin-inline-end: 4px;
12
+ `,
13
+ text: css`
14
+ color: ${cssVar.colorText};
15
+ `,
16
+ }));
17
+
18
+ interface FilePathDisplayProps {
19
+ filePath: string;
20
+ isDirectory?: boolean;
21
+ }
22
+
23
+ /**
24
+ * Reusable component for displaying file/folder icon + path in LocalSystem inspectors
25
+ * Used by Read, Write, Edit, Delete, Rename, List inspectors
26
+ */
27
+ export const FilePathDisplay = memo<FilePathDisplayProps>(({ filePath, isDirectory }) => {
28
+ const { displayPath, name } = useMemo(() => {
29
+ if (!filePath) return { displayPath: '', name: '' };
30
+ const { base, dir } = path.parse(filePath);
31
+ const parentDir = path.basename(dir);
32
+ return {
33
+ displayPath: parentDir ? `${parentDir}/${base}` : base,
34
+ name: base,
35
+ };
36
+ }, [filePath]);
37
+
38
+ if (!filePath) return null;
39
+
40
+ return (
41
+ <>
42
+ {name && (
43
+ <MaterialFileTypeIcon
44
+ className={styles.icon}
45
+ filename={name}
46
+ size={16}
47
+ type={isDirectory ? 'folder' : 'file'}
48
+ variant={'raw'}
49
+ />
50
+ )}
51
+ {displayPath && <span className={styles.text}>{displayPath}</span>}
52
+ </>
53
+ );
54
+ });
55
+
56
+ FilePathDisplay.displayName = 'FilePathDisplay';
@@ -0,0 +1,2 @@
1
+ export { default as FileItem } from './FileItem';
2
+ export { FilePathDisplay } from './FilePathDisplay';