@lobehub/lobehub 2.0.0-next.50 → 2.0.0-next.52

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 (171) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/apps/desktop/src/main/controllers/LocalFileCtr.ts +25 -5
  3. package/apps/desktop/src/main/controllers/ShellCommandCtr.ts +242 -0
  4. package/apps/desktop/src/main/controllers/__tests__/LocalFileCtr.test.ts +4 -1
  5. package/apps/desktop/src/main/controllers/__tests__/ShellCommandCtr.test.ts +499 -0
  6. package/apps/desktop/src/main/modules/fileSearch/__tests__/macOS.integration.test.ts +357 -0
  7. package/apps/desktop/src/main/modules/fileSearch/impl/macOS.ts +30 -22
  8. package/changelog/v1.json +18 -0
  9. package/locales/ar/chat.json +20 -0
  10. package/locales/ar/common.json +1 -0
  11. package/locales/ar/components.json +6 -0
  12. package/locales/ar/models.json +119 -126
  13. package/locales/ar/plugin.json +2 -1
  14. package/locales/bg-BG/chat.json +20 -0
  15. package/locales/bg-BG/common.json +1 -0
  16. package/locales/bg-BG/components.json +6 -0
  17. package/locales/bg-BG/models.json +104 -132
  18. package/locales/bg-BG/plugin.json +2 -1
  19. package/locales/de-DE/chat.json +20 -0
  20. package/locales/de-DE/common.json +1 -0
  21. package/locales/de-DE/components.json +6 -0
  22. package/locales/de-DE/models.json +119 -126
  23. package/locales/de-DE/plugin.json +2 -1
  24. package/locales/en-US/chat.json +20 -0
  25. package/locales/en-US/common.json +1 -0
  26. package/locales/en-US/components.json +6 -0
  27. package/locales/en-US/models.json +167 -126
  28. package/locales/en-US/plugin.json +2 -1
  29. package/locales/es-ES/chat.json +20 -0
  30. package/locales/es-ES/common.json +1 -0
  31. package/locales/es-ES/components.json +6 -0
  32. package/locales/es-ES/models.json +119 -126
  33. package/locales/es-ES/plugin.json +2 -1
  34. package/locales/fa-IR/chat.json +20 -0
  35. package/locales/fa-IR/common.json +1 -0
  36. package/locales/fa-IR/components.json +6 -0
  37. package/locales/fa-IR/models.json +119 -126
  38. package/locales/fa-IR/plugin.json +2 -1
  39. package/locales/fr-FR/chat.json +20 -0
  40. package/locales/fr-FR/common.json +1 -0
  41. package/locales/fr-FR/components.json +6 -0
  42. package/locales/fr-FR/models.json +119 -126
  43. package/locales/fr-FR/plugin.json +2 -1
  44. package/locales/it-IT/chat.json +20 -0
  45. package/locales/it-IT/common.json +1 -0
  46. package/locales/it-IT/components.json +6 -0
  47. package/locales/it-IT/models.json +119 -126
  48. package/locales/it-IT/plugin.json +2 -1
  49. package/locales/ja-JP/chat.json +20 -0
  50. package/locales/ja-JP/common.json +1 -0
  51. package/locales/ja-JP/components.json +6 -0
  52. package/locales/ja-JP/models.json +119 -126
  53. package/locales/ja-JP/plugin.json +2 -1
  54. package/locales/ko-KR/chat.json +20 -0
  55. package/locales/ko-KR/common.json +1 -0
  56. package/locales/ko-KR/components.json +6 -0
  57. package/locales/ko-KR/models.json +119 -126
  58. package/locales/ko-KR/plugin.json +2 -1
  59. package/locales/nl-NL/chat.json +20 -0
  60. package/locales/nl-NL/common.json +1 -0
  61. package/locales/nl-NL/components.json +6 -0
  62. package/locales/nl-NL/models.json +119 -126
  63. package/locales/nl-NL/plugin.json +2 -1
  64. package/locales/pl-PL/chat.json +20 -0
  65. package/locales/pl-PL/common.json +1 -0
  66. package/locales/pl-PL/components.json +6 -0
  67. package/locales/pl-PL/models.json +119 -126
  68. package/locales/pl-PL/plugin.json +2 -1
  69. package/locales/pt-BR/chat.json +20 -0
  70. package/locales/pt-BR/common.json +1 -0
  71. package/locales/pt-BR/components.json +6 -0
  72. package/locales/pt-BR/models.json +119 -126
  73. package/locales/pt-BR/plugin.json +2 -1
  74. package/locales/ru-RU/chat.json +20 -0
  75. package/locales/ru-RU/common.json +1 -0
  76. package/locales/ru-RU/components.json +6 -0
  77. package/locales/ru-RU/models.json +119 -126
  78. package/locales/ru-RU/plugin.json +2 -1
  79. package/locales/tr-TR/chat.json +20 -0
  80. package/locales/tr-TR/common.json +1 -0
  81. package/locales/tr-TR/components.json +6 -0
  82. package/locales/tr-TR/models.json +119 -126
  83. package/locales/tr-TR/plugin.json +2 -1
  84. package/locales/vi-VN/chat.json +20 -0
  85. package/locales/vi-VN/common.json +1 -0
  86. package/locales/vi-VN/components.json +6 -0
  87. package/locales/vi-VN/models.json +119 -126
  88. package/locales/vi-VN/plugin.json +2 -1
  89. package/locales/zh-CN/chat.json +20 -0
  90. package/locales/zh-CN/common.json +1 -0
  91. package/locales/zh-CN/components.json +6 -0
  92. package/locales/zh-CN/models.json +173 -80
  93. package/locales/zh-CN/plugin.json +2 -1
  94. package/locales/zh-TW/chat.json +20 -0
  95. package/locales/zh-TW/common.json +1 -0
  96. package/locales/zh-TW/components.json +6 -0
  97. package/locales/zh-TW/models.json +119 -126
  98. package/locales/zh-TW/plugin.json +2 -1
  99. package/package.json +1 -1
  100. package/packages/agent-runtime/src/core/InterventionChecker.ts +1 -1
  101. package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +23 -23
  102. package/packages/agent-runtime/src/types/state.ts +7 -1
  103. package/packages/const/src/settings/tool.ts +1 -5
  104. package/packages/electron-client-ipc/src/types/localSystem.ts +26 -2
  105. package/packages/file-loaders/src/loaders/docx/index.ts +1 -1
  106. package/packages/model-bank/src/aiModels/wenxin.ts +1348 -291
  107. package/packages/model-runtime/src/core/contextBuilders/openai.test.ts +58 -0
  108. package/packages/model-runtime/src/core/contextBuilders/openai.ts +24 -10
  109. package/packages/model-runtime/src/core/openaiCompatibleFactory/index.ts +3 -2
  110. package/packages/model-runtime/src/providers/openai/index.test.ts +44 -0
  111. package/packages/model-runtime/src/providers/wenxin/index.ts +22 -1
  112. package/packages/model-runtime/src/utils/modelParse.ts +6 -0
  113. package/packages/types/src/tool/builtin.ts +15 -4
  114. package/packages/types/src/tool/intervention.ts +32 -2
  115. package/packages/types/src/user/settings/tool.ts +3 -27
  116. package/src/config/modelProviders/wenxin.ts +2 -3
  117. package/src/features/Conversation/MarkdownElements/remarkPlugins/__snapshots__/createRemarkSelfClosingTagPlugin.test.ts.snap +133 -0
  118. package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.test.ts +48 -0
  119. package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts +2 -1
  120. package/src/features/Conversation/Messages/Assistant/Tool/Render/LoadingPlaceholder/index.tsx +3 -3
  121. package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/Fallback.tsx +98 -0
  122. package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/ModeSelector.tsx +5 -6
  123. package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/index.tsx +40 -36
  124. package/src/features/Conversation/Messages/Group/Tool/Render/LoadingPlaceholder/index.tsx +3 -3
  125. package/src/features/Conversation/Messages/Group/Tool/Render/index.tsx +25 -18
  126. package/src/features/LocalFile/LocalFile.tsx +55 -5
  127. package/src/features/PluginsUI/Render/BuiltinType/index.test.tsx +10 -4
  128. package/src/features/PluginsUI/Render/BuiltinType/index.tsx +2 -2
  129. package/src/locales/default/components.ts +6 -0
  130. package/src/locales/default/plugin.ts +2 -1
  131. package/src/services/chat/chat.test.ts +1 -0
  132. package/src/services/electron/localFileService.ts +4 -0
  133. package/src/store/aiInfra/slices/aiProvider/__tests__/selectors.test.ts +62 -0
  134. package/src/store/aiInfra/slices/aiProvider/selectors.ts +1 -1
  135. package/src/store/chat/agents/GeneralChatAgent.ts +26 -1
  136. package/src/store/chat/agents/__tests__/GeneralChatAgent.test.ts +173 -0
  137. package/src/store/chat/slices/aiChat/actions/conversationControl.ts +8 -40
  138. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +91 -34
  139. package/src/store/user/selectors.ts +1 -0
  140. package/src/store/user/slices/settings/action.ts +12 -0
  141. package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +0 -7
  142. package/src/store/user/slices/settings/selectors/index.ts +1 -0
  143. package/src/store/user/slices/settings/selectors/settings.test.ts +0 -37
  144. package/src/store/user/slices/settings/selectors/settings.ts +0 -5
  145. package/src/store/user/slices/settings/selectors/toolIntervention.ts +17 -0
  146. package/src/tools/code-interpreter/Render/index.tsx +1 -1
  147. package/src/tools/interventions.ts +32 -0
  148. package/src/tools/local-system/Intervention/RunCommand/index.tsx +56 -0
  149. package/src/tools/local-system/Placeholder/ListFiles.tsx +3 -5
  150. package/src/tools/local-system/Placeholder/SearchFiles.tsx +2 -5
  151. package/src/tools/local-system/Render/ListFiles/index.tsx +16 -21
  152. package/src/tools/local-system/Render/RenameLocalFile/index.tsx +15 -20
  153. package/src/tools/local-system/Render/RunCommand/index.tsx +103 -27
  154. package/src/tools/local-system/Render/SearchFiles/SearchQuery/index.tsx +0 -1
  155. package/src/tools/local-system/Render/SearchFiles/index.tsx +15 -20
  156. package/src/tools/local-system/Render/WriteFile/index.tsx +2 -8
  157. package/src/tools/local-system/index.ts +184 -4
  158. package/src/tools/local-system/systemRole.ts +62 -8
  159. package/src/tools/placeholders.ts +39 -8
  160. package/src/tools/renders.ts +56 -9
  161. package/src/tools/web-browsing/Placeholder/{PageContent.tsx → CrawlMultiPages.tsx} +4 -1
  162. package/src/tools/web-browsing/Placeholder/CrawlSinglePage.tsx +12 -0
  163. package/src/tools/web-browsing/Placeholder/Search.tsx +4 -4
  164. package/src/tools/web-browsing/Render/CrawlMultiPages.tsx +15 -0
  165. package/src/tools/web-browsing/Render/CrawlSinglePage.tsx +15 -0
  166. package/src/tools/web-browsing/Render/Search/index.tsx +39 -44
  167. package/packages/database/migrations/0044_add_tool_intervention.sql +0 -1
  168. package/src/tools/local-system/Placeholder/index.tsx +0 -25
  169. package/src/tools/local-system/Render/index.tsx +0 -40
  170. package/src/tools/web-browsing/Placeholder/index.tsx +0 -40
  171. package/src/tools/web-browsing/Render/index.tsx +0 -57
@@ -1,4 +1,5 @@
1
1
  import { LocalSearchFilesParams } from '@lobechat/electron-client-ipc';
2
+ import { BuiltinPlaceholderProps } from '@lobechat/types';
2
3
  import { Icon } from '@lobehub/ui';
3
4
  import { Skeleton } from 'antd';
4
5
  import { createStyles } from 'antd-style';
@@ -21,11 +22,7 @@ const useStyles = createStyles(({ css, token, cx }) => ({
21
22
  `),
22
23
  }));
23
24
 
24
- interface SearchFilesProps {
25
- args: LocalSearchFilesParams;
26
- }
27
-
28
- const SearchFiles = memo<SearchFilesProps>(({ args }) => {
25
+ const SearchFiles = memo<BuiltinPlaceholderProps<LocalSearchFilesParams>>(({ args = {} }) => {
29
26
  const { styles } = useStyles();
30
27
 
31
28
  return (
@@ -1,31 +1,26 @@
1
1
  import { ListLocalFileParams } from '@lobechat/electron-client-ipc';
2
- import { ChatMessagePluginError } from '@lobechat/types';
2
+ import { BuiltinRenderProps } from '@lobechat/types';
3
3
  import React, { memo } from 'react';
4
4
 
5
5
  import { LocalFolder } from '@/features/LocalFile';
6
- import { LocalFileListState } from '@/tools/local-system/type';
7
6
 
7
+ import { LocalFileListState } from '../../type';
8
8
  import SearchResult from './Result';
9
9
 
10
- interface ListFilesProps {
11
- args: ListLocalFileParams;
12
- messageId: string;
13
- pluginError: ChatMessagePluginError;
14
- pluginState?: LocalFileListState;
15
- }
16
-
17
- const ListFiles = memo<ListFilesProps>(({ messageId, pluginError, args, pluginState }) => {
18
- return (
19
- <>
20
- <LocalFolder path={args.path} />
21
- <SearchResult
22
- listResults={pluginState?.listResults}
23
- messageId={messageId}
24
- pluginError={pluginError}
25
- />
26
- </>
27
- );
28
- });
10
+ const ListFiles = memo<BuiltinRenderProps<ListLocalFileParams, LocalFileListState>>(
11
+ ({ messageId, pluginError, args, pluginState }) => {
12
+ return (
13
+ <>
14
+ <LocalFolder path={args.path} />
15
+ <SearchResult
16
+ listResults={pluginState?.listResults}
17
+ messageId={messageId}
18
+ pluginError={pluginError}
19
+ />
20
+ </>
21
+ );
22
+ },
23
+ );
29
24
 
30
25
  ListFiles.displayName = 'ListFiles';
31
26
 
@@ -1,5 +1,5 @@
1
1
  import { RenameLocalFileParams } from '@lobechat/electron-client-ipc';
2
- import { ChatMessagePluginError } from '@lobechat/types';
2
+ import { BuiltinRenderProps } from '@lobechat/types';
3
3
  import { Icon } from '@lobehub/ui';
4
4
  import { createStyles } from 'antd-style';
5
5
  import { ArrowRightIcon } from 'lucide-react';
@@ -19,27 +19,22 @@ const useStyles = createStyles(({ css, token }) => ({
19
19
  `,
20
20
  }));
21
21
 
22
- interface RenameLocalFileProps {
23
- args: RenameLocalFileParams;
24
- messageId: string;
25
- pluginError: ChatMessagePluginError;
26
- pluginState: LocalReadFileState;
27
- }
22
+ const RenameLocalFile = memo<BuiltinRenderProps<RenameLocalFileParams, LocalReadFileState>>(
23
+ ({ args }) => {
24
+ const { styles } = useStyles();
28
25
 
29
- const RenameLocalFile = memo<RenameLocalFileProps>(({ args }) => {
30
- const { styles } = useStyles();
26
+ const { base: oldFileName, dir } = path.parse(args.path);
31
27
 
32
- const { base: oldFileName, dir } = path.parse(args.path);
33
-
34
- return (
35
- <Flexbox align={'center'} className={styles.container} gap={8} horizontal paddingInline={12}>
36
- <Flexbox>{oldFileName}</Flexbox>
37
- <Flexbox>
38
- <Icon icon={ArrowRightIcon} />
28
+ return (
29
+ <Flexbox align={'center'} className={styles.container} gap={8} horizontal paddingInline={12}>
30
+ <Flexbox>{oldFileName}</Flexbox>
31
+ <Flexbox>
32
+ <Icon icon={ArrowRightIcon} />
33
+ </Flexbox>
34
+ <LocalFile name={args.newName} path={path.join(dir, args.newName)} />
39
35
  </Flexbox>
40
- <LocalFile name={args.newName} path={path.join(dir, args.newName)} />
41
- </Flexbox>
42
- );
43
- });
36
+ );
37
+ },
38
+ );
44
39
 
45
40
  export default RenameLocalFile;
@@ -1,35 +1,111 @@
1
- import { RunCommandParams } from '@lobechat/electron-client-ipc';
2
- import { ChatMessagePluginError } from '@lobechat/types';
3
- import { Terminal } from '@xterm/xterm';
4
- import '@xterm/xterm/css/xterm.css';
5
- import { memo, useEffect, useRef } from 'react';
1
+ import { CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons';
2
+ import { RunCommandParams, RunCommandResult } from '@lobechat/electron-client-ipc';
3
+ import { BuiltinRenderProps } from '@lobechat/types';
4
+ import { ActionIcon, Block, Highlighter, Text } from '@lobehub/ui';
5
+ import { createStyles } from 'antd-style';
6
+ import { ChevronDown, ChevronUp } from 'lucide-react';
7
+ import { memo, useState } from 'react';
8
+ import { Flexbox } from 'react-layout-kit';
6
9
 
7
- import { LocalReadFileState } from '@/tools/local-system/type';
10
+ const useStyles = createStyles(({ css, token }) => ({
11
+ container: css`
12
+ overflow: hidden;
13
+ padding-inline: 8px 0;
14
+ `,
15
+ head: css`
16
+ font-family: ${token.fontFamilyCode};
17
+ font-size: 12px;
18
+ `,
19
+ header: css`
20
+ .action-icon {
21
+ opacity: 0;
22
+ transition: opacity 0.2s ease;
23
+ }
8
24
 
9
- interface RunCommandProps {
10
- args: RunCommandParams;
11
- messageId: string;
12
- pluginError: ChatMessagePluginError;
13
- pluginState: LocalReadFileState;
14
- }
15
-
16
- const RunCommand = memo<RunCommandProps>(({ args }) => {
17
- const terminalRef = useRef(null);
25
+ &:hover {
26
+ .action-icon {
27
+ opacity: 1;
28
+ }
29
+ }
30
+ `,
31
+ statusIcon: css`
32
+ font-size: 12px;
33
+ `,
34
+ }));
18
35
 
19
- useEffect(() => {
20
- if (!terminalRef.current) return;
21
-
22
- const term = new Terminal({ cols: 80, cursorBlink: true, rows: 30 });
36
+ interface RunCommandState {
37
+ message: string;
38
+ result: RunCommandResult;
39
+ }
23
40
 
24
- term.open(terminalRef.current);
25
- term.write(args.command);
41
+ const RunCommand = memo<BuiltinRenderProps<RunCommandParams, RunCommandState>>(
42
+ ({ args, pluginState }) => {
43
+ const { styles, theme } = useStyles();
44
+ const { result, message } = pluginState || {};
45
+ const isSuccess = result?.success;
46
+ const [expanded, setExpanded] = useState(false);
26
47
 
27
- return () => {
28
- term.dispose();
29
- };
30
- }, []);
48
+ return (
49
+ <Flexbox className={styles.container} gap={8}>
50
+ {/* Header: Description + Status */}
51
+ <Flexbox align={'center'} className={styles.header} horizontal justify={'space-between'}>
52
+ <Flexbox gap={8} horizontal>
53
+ <Flexbox gap={4} horizontal>
54
+ {!result ? null : isSuccess ? (
55
+ <CheckCircleFilled
56
+ className={styles.statusIcon}
57
+ style={{ color: theme.colorSuccess }}
58
+ />
59
+ ) : (
60
+ <CloseCircleFilled
61
+ className={styles.statusIcon}
62
+ style={{ color: theme.colorError }}
63
+ />
64
+ )}
65
+ {args.description && <Text className={styles.head}>{args.description}</Text>}
66
+ </Flexbox>
67
+ {message && (
68
+ <Flexbox align={'center'} gap={4} horizontal>
69
+ <Text className={styles.head} type={'secondary'}>
70
+ {message}
71
+ </Text>
72
+ </Flexbox>
73
+ )}
74
+ </Flexbox>
75
+ <Flexbox align={'center'} gap={8} horizontal>
76
+ <ActionIcon
77
+ className={`action-icon`}
78
+ icon={expanded ? ChevronUp : ChevronDown}
79
+ onClick={() => setExpanded(!expanded)}
80
+ size={'small'}
81
+ style={{ opacity: expanded ? 1 : undefined }}
82
+ title={expanded ? 'Collapse' : 'Expand'}
83
+ />
84
+ </Flexbox>
85
+ </Flexbox>
31
86
 
32
- return <div ref={terminalRef} />;
33
- });
87
+ {/* Command & Output */}
88
+ {expanded && (
89
+ <Block gap={8} padding={8} variant={'outlined'}>
90
+ <Highlighter
91
+ language={'sh'}
92
+ showLanguage={false}
93
+ style={{ paddingInline: 8 }}
94
+ variant={'borderless'}
95
+ wrap
96
+ >
97
+ {args.command}
98
+ </Highlighter>
99
+ {result?.output && (
100
+ <Highlighter language={'text'} showLanguage={false} variant={'filled'} wrap>
101
+ {result.output}
102
+ </Highlighter>
103
+ )}
104
+ </Block>
105
+ )}
106
+ </Flexbox>
107
+ );
108
+ },
109
+ );
34
110
 
35
111
  export default RunCommand;
@@ -13,7 +13,6 @@ import SearchView from './SearchView';
13
13
 
14
14
  interface SearchQueryViewProps {
15
15
  args: LocalSearchFilesParams;
16
-
17
16
  messageId: string;
18
17
  pluginState?: LocalFileSearchState;
19
18
  }
@@ -1,5 +1,5 @@
1
1
  import { LocalSearchFilesParams } from '@lobechat/electron-client-ipc';
2
- import { ChatMessagePluginError } from '@lobechat/types';
2
+ import { BuiltinRenderProps } from '@lobechat/types';
3
3
  import { memo } from 'react';
4
4
  import { Flexbox } from 'react-layout-kit';
5
5
 
@@ -8,25 +8,20 @@ import { LocalFileSearchState } from '@/tools/local-system/type';
8
8
  import SearchResult from './Result';
9
9
  import SearchQuery from './SearchQuery';
10
10
 
11
- interface SearchFilesProps {
12
- args: LocalSearchFilesParams;
13
- messageId: string;
14
- pluginError: ChatMessagePluginError;
15
- pluginState?: LocalFileSearchState;
16
- }
17
-
18
- const SearchFiles = memo<SearchFilesProps>(({ messageId, pluginError, args, pluginState }) => {
19
- return (
20
- <Flexbox gap={4}>
21
- <SearchQuery args={args} messageId={messageId} pluginState={pluginState} />
22
- <SearchResult
23
- messageId={messageId}
24
- pluginError={pluginError}
25
- searchResults={pluginState?.searchResults}
26
- />
27
- </Flexbox>
28
- );
29
- });
11
+ const SearchFiles = memo<BuiltinRenderProps<LocalSearchFilesParams, LocalFileSearchState>>(
12
+ ({ messageId, pluginError, args, pluginState }) => {
13
+ return (
14
+ <Flexbox gap={4}>
15
+ <SearchQuery args={args} messageId={messageId} pluginState={pluginState} />
16
+ <SearchResult
17
+ messageId={messageId}
18
+ pluginError={pluginError}
19
+ searchResults={pluginState?.searchResults}
20
+ />
21
+ </Flexbox>
22
+ );
23
+ },
24
+ );
30
25
 
31
26
  SearchFiles.displayName = 'SearchFiles';
32
27
 
@@ -1,5 +1,5 @@
1
1
  import { WriteLocalFileParams } from '@lobechat/electron-client-ipc';
2
- import { ChatMessagePluginError } from '@lobechat/types';
2
+ import { BuiltinRenderProps } from '@lobechat/types';
3
3
  import { Icon } from '@lobehub/ui';
4
4
  import { Skeleton } from 'antd';
5
5
  import { ChevronRight } from 'lucide-react';
@@ -9,13 +9,7 @@ import { Flexbox } from 'react-layout-kit';
9
9
 
10
10
  import { LocalFile, LocalFolder } from '@/features/LocalFile';
11
11
 
12
- interface WriteFileProps {
13
- args: WriteLocalFileParams;
14
- messageId: string;
15
- pluginError: ChatMessagePluginError;
16
- }
17
-
18
- const WriteFile = memo<WriteFileProps>(({ args }) => {
12
+ const WriteFile = memo<BuiltinRenderProps<WriteLocalFileParams>>(({ args }) => {
19
13
  if (!args) return <Skeleton active />;
20
14
 
21
15
  const { base, dir } = path.parse(args.path);
@@ -3,10 +3,16 @@ import { BuiltinToolManifest } from '@lobechat/types';
3
3
  import { systemPrompt } from './systemRole';
4
4
 
5
5
  export const LocalSystemApiName = {
6
+ editLocalFile: 'editLocalFile',
7
+ getCommandOutput: 'getCommandOutput',
8
+ globLocalFiles: 'globLocalFiles',
9
+ grepContent: 'grepContent',
10
+ killCommand: 'killCommand',
6
11
  listLocalFiles: 'listLocalFiles',
7
12
  moveLocalFiles: 'moveLocalFiles',
8
13
  readLocalFile: 'readLocalFile',
9
14
  renameLocalFile: 'renameLocalFile',
15
+ runCommand: 'runCommand',
10
16
  searchLocalFiles: 'searchLocalFiles',
11
17
  writeLocalFile: 'writeLocalFile',
12
18
  };
@@ -72,6 +78,10 @@ export const LocalSystemManifest: BuiltinToolManifest = {
72
78
  format: 'date-time',
73
79
  type: 'string',
74
80
  },
81
+ directory: {
82
+ description: 'Limit the search to this specific directory path',
83
+ type: 'string',
84
+ },
75
85
  exclude: {
76
86
  description: 'Array of file or directory paths to exclude',
77
87
  items: {
@@ -108,10 +118,6 @@ export const LocalSystemManifest: BuiltinToolManifest = {
108
118
  format: 'date-time',
109
119
  type: 'string',
110
120
  },
111
- onlyIn: {
112
- description: 'Limit the search to this specific directory path',
113
- type: 'string',
114
- },
115
121
  sortBy: {
116
122
  description: 'Sort results by',
117
123
  enum: ['name', 'date', 'size'],
@@ -130,6 +136,7 @@ export const LocalSystemManifest: BuiltinToolManifest = {
130
136
  {
131
137
  description:
132
138
  'Moves or renames multiple files/directories. Input is an array of objects, each containing an oldPath and a newPath.',
139
+ humanIntervention: 'required',
133
140
  name: LocalSystemApiName.moveLocalFiles,
134
141
  parameters: {
135
142
  properties: {
@@ -195,6 +202,179 @@ export const LocalSystemManifest: BuiltinToolManifest = {
195
202
  type: 'object',
196
203
  },
197
204
  },
205
+ {
206
+ description:
207
+ 'Execute a shell command and return its output. Supports both synchronous and background execution with timeout control.',
208
+ humanIntervention: 'required',
209
+ name: LocalSystemApiName.runCommand,
210
+ parameters: {
211
+ properties: {
212
+ command: {
213
+ description: 'The shell command to execute',
214
+ type: 'string',
215
+ },
216
+ description: {
217
+ description:
218
+ 'Clear description of what this command does (5-10 words, in active voice). Use the same language as the user input.',
219
+ type: 'string',
220
+ },
221
+ run_in_background: {
222
+ description: 'Set to true to run command in background and return shell_id',
223
+ type: 'boolean',
224
+ },
225
+ timeout: {
226
+ description: 'Timeout in milliseconds (default: 120000ms, max: 600000ms)',
227
+ type: 'number',
228
+ },
229
+ },
230
+ required: ['command'],
231
+ type: 'object',
232
+ },
233
+ },
234
+ {
235
+ description:
236
+ 'Retrieve output from a running or completed background shell command. Returns only new output since the last check.',
237
+ name: LocalSystemApiName.getCommandOutput,
238
+ parameters: {
239
+ properties: {
240
+ filter: {
241
+ description:
242
+ 'Optional regex pattern to filter output lines. Only matching lines are returned.',
243
+ type: 'string',
244
+ },
245
+ shell_id: {
246
+ description: 'The ID of the background shell to retrieve output from',
247
+ type: 'string',
248
+ },
249
+ },
250
+ required: ['shell_id'],
251
+ type: 'object',
252
+ },
253
+ },
254
+ {
255
+ description: 'Kill a running background shell command by its ID.',
256
+ name: LocalSystemApiName.killCommand,
257
+ parameters: {
258
+ properties: {
259
+ shell_id: {
260
+ description: 'The ID of the background shell to kill',
261
+ type: 'string',
262
+ },
263
+ },
264
+ required: ['shell_id'],
265
+ type: 'object',
266
+ },
267
+ },
268
+ {
269
+ description:
270
+ 'Search for content within files using regex patterns. Supports various output modes and filtering options.',
271
+ name: LocalSystemApiName.grepContent,
272
+ parameters: {
273
+ properties: {
274
+ '-A': {
275
+ description:
276
+ 'Number of lines to show after each match (requires output_mode: "content")',
277
+ type: 'number',
278
+ },
279
+ '-B': {
280
+ description:
281
+ 'Number of lines to show before each match (requires output_mode: "content")',
282
+ type: 'number',
283
+ },
284
+ '-C': {
285
+ description:
286
+ 'Number of lines to show before and after each match (requires output_mode: "content")',
287
+ type: 'number',
288
+ },
289
+ '-i': {
290
+ description: 'Case insensitive search',
291
+ type: 'boolean',
292
+ },
293
+ '-n': {
294
+ description: 'Show line numbers in output (requires output_mode: "content")',
295
+ type: 'boolean',
296
+ },
297
+ 'glob': {
298
+ description: 'Glob pattern to filter files (e.g. "*.js", "*.{ts,tsx}")',
299
+ type: 'string',
300
+ },
301
+ 'head_limit': {
302
+ description: 'Limit output to first N results',
303
+ type: 'number',
304
+ },
305
+ 'multiline': {
306
+ description: 'Enable multiline mode where . matches newlines',
307
+ type: 'boolean',
308
+ },
309
+ 'output_mode': {
310
+ description:
311
+ 'Output mode: "content" (matching lines), "files_with_matches" (file paths), "count" (match counts)',
312
+ enum: ['content', 'files_with_matches', 'count'],
313
+ type: 'string',
314
+ },
315
+ 'path': {
316
+ description: 'File or directory to search in (defaults to current working directory)',
317
+ type: 'string',
318
+ },
319
+ 'pattern': {
320
+ description: 'The regular expression pattern to search for',
321
+ type: 'string',
322
+ },
323
+ 'type': {
324
+ description: 'File type to search (e.g. "js", "py", "rust")',
325
+ type: 'string',
326
+ },
327
+ },
328
+ required: ['pattern'],
329
+ type: 'object',
330
+ },
331
+ },
332
+ {
333
+ description:
334
+ 'Find files matching glob patterns. Supports standard glob syntax like "**/*.js" or "src/**/*.ts".',
335
+ name: LocalSystemApiName.globLocalFiles,
336
+ parameters: {
337
+ properties: {
338
+ path: {
339
+ description: 'The directory to search in (defaults to current working directory)',
340
+ type: 'string',
341
+ },
342
+ pattern: {
343
+ description: 'The glob pattern to match files against (e.g. "**/*.js", "*.{ts,tsx}")',
344
+ type: 'string',
345
+ },
346
+ },
347
+ required: ['pattern'],
348
+ type: 'object',
349
+ },
350
+ },
351
+ {
352
+ description:
353
+ 'Perform exact string replacements in files. Must read the file first before editing.',
354
+ name: LocalSystemApiName.editLocalFile,
355
+ parameters: {
356
+ properties: {
357
+ file_path: {
358
+ description: 'The absolute path to the file to modify',
359
+ type: 'string',
360
+ },
361
+ new_string: {
362
+ description: 'The text to replace with (must differ from old_string)',
363
+ type: 'string',
364
+ },
365
+ old_string: {
366
+ description: 'The exact text to replace',
367
+ type: 'string',
368
+ },
369
+ replace_all: {
370
+ description: 'Replace all occurrences of old_string (default: false)',
371
+ type: 'boolean',
372
+ },
373
+ },
374
+ required: ['file_path', 'old_string', 'new_string'],
375
+ type: 'object',
376
+ },
377
+ },
198
378
  ],
199
379
  identifier: 'lobe-local-system',
200
380
  meta: {
@@ -1,4 +1,4 @@
1
- export const systemPrompt = `You have a Local System tool with capabilities to interact with the user's local file system. You can list directories, read file contents, search for files, move, and rename files/directories.
1
+ export const systemPrompt = `You have a Local System tool with capabilities to interact with the user's local system. You can list directories, read file contents, search for files, move, and rename files/directories.
2
2
 
3
3
  <user_context>
4
4
  Here are some known locations and system details on the user's system. User is using the Operating System: {{platform}}({{arch}}). Use these paths when the user refers to these common locations by name (e.g., "my desktop", "downloads folder").
@@ -15,19 +15,33 @@ Here are some known locations and system details on the user's system. User is u
15
15
  <core_capabilities>
16
16
  You have access to a set of tools to interact with the user's local file system:
17
17
 
18
+ **File Operations:**
18
19
  1. **listLocalFiles**: Lists files and directories in a specified path.
19
20
  2. **readLocalFile**: Reads the content of a specified file, optionally within a line range. You can read file types such as Word, Excel, PowerPoint, PDF, and plain text files.
20
- 3. **writeFile**: Write content to a specific file, only support plain text file like \`.text\` or \`.md\`
21
- 4. **searchLocalFiles**: Searches for files based on keywords and other criteria. Use this tool to find files if the user is unsure about the exact path.
21
+ 3. **writeLocalFile**: Write content to a specific file, only support plain text file like \`.text\` or \`.md\`
22
+ 4. **searchLocalFiles**: Searches for files based on keywords and other criteria using Spotlight (macOS) or native search. Use this tool to find files if the user is unsure about the exact path.
22
23
  5. **renameLocalFile**: Renames a single file or directory in its current location.
23
24
  6. **moveLocalFiles**: Moves multiple files or directories. Can be used for renaming during the move.
25
+ 7. **editLocalFile**: Performs exact string replacements in files. Must read the file first before editing.
26
+
27
+ **Shell Commands:**
28
+ 8. **runCommand**: Execute shell commands with timeout control. Supports both synchronous and background execution. When providing a description, always use the same language as the user's input.
29
+ 9. **getCommandOutput**: Retrieve output from running background commands. Returns only new output since last check.
30
+ 10. **killCommand**: Terminate a running background shell command by its ID.
31
+
32
+ **Search & Find:**
33
+ 11. **grepContent**: Search for content within files using regex patterns. Supports various output modes, filtering, and context lines.
34
+ 12. **globLocalFiles**: Find files matching glob patterns (e.g., "**/*.js", "*.{ts,tsx}").
24
35
  </core_capabilities>
25
36
 
26
37
  <workflow>
27
- 1. Understand the user's request regarding local files (listing, reading, searching, renaming, moving, writing).
28
- 2. Select the appropriate tool (listFiles, readFile, searchFiles, renameFile, moveLocalFiles, writeFile).
29
- 3. Execute the file operation. **If the user mentions a common location (like Desktop, Documents, Downloads, etc.) without providing a full path, use the corresponding path from the <user_context> section.**
30
- 4. Present the results (directory listing, file content, search results) or confirmation of the rename or move operation.
38
+ 1. Understand the user's request regarding local operations (files, commands, searches).
39
+ 2. Select the appropriate tool:
40
+ - File operations: listLocalFiles, readLocalFile, writeLocalFile, editLocalFile, searchLocalFiles, renameLocalFile, moveLocalFiles
41
+ - Shell commands: runCommand, getCommandOutput, killCommand
42
+ - Search/Find: grepContent, globLocalFiles
43
+ 3. Execute the operation. **If the user mentions a common location (like Desktop, Documents, Downloads, etc.) without providing a full path, use the corresponding path from the <user_context> section.**
44
+ 4. Present the results or confirmation.
31
45
  </workflow>
32
46
 
33
47
  <tool_usage_guidelines>
@@ -54,7 +68,37 @@ You have access to a set of tools to interact with the user's local file system:
54
68
  - 'oldPath': The current absolute path of the file/directory to move or rename.
55
69
  - 'newPath': The target absolute path for the file/directory (can include a new name).
56
70
  Example: items: [{ oldPath: "/path/to/file1.txt", newPath: "/new/path/to/fileA.txt" }, { oldPath: "/path/to/folderB", newPath: "/archive/folderB_renamed" }]
57
- - For writing to a file: Use 'writeFile' with the file path and the content to be written. Be cautious as this might overwrite existing files.
71
+ - For writing to a file: Use 'writeLocalFile' with the file path and the content to be written. Be cautious as this might overwrite existing files.
72
+ - For editing a file: Use 'editLocalFile'. Provide the following parameters:
73
+ - 'file_path': The absolute path to the file to modify.
74
+ - 'old_string': The exact text to replace.
75
+ - 'new_string': The text to replace with.
76
+ - 'replace_all' (Optional): Set to true to replace all occurrences (default: false, replaces only first occurrence).
77
+ Note: You MUST read the file first using 'readLocalFile' before editing to verify the content.
78
+ - For executing shell commands: Use 'runCommand'. Provide the following parameters:
79
+ - 'command': The shell command to execute.
80
+ - 'description' (Optional but recommended): A clear, concise description of what the command does (5-10 words, in active voice). **IMPORTANT: Always use the same language as the user's input.** If the user speaks Chinese, write the description in Chinese; if English, use English, etc.
81
+ - 'run_in_background' (Optional): Set to true to run in background and get a shell_id for later checking output.
82
+ - 'timeout' (Optional): Timeout in milliseconds (default: 120000ms, max: 600000ms).
83
+ The command runs in cmd.exe on Windows or /bin/sh on macOS/Linux.
84
+ - For retrieving output from background commands: Use 'getCommandOutput'. Provide:
85
+ - 'shell_id': The ID returned from runCommand when run_in_background was true.
86
+ - 'filter' (Optional): A regex pattern to filter output lines.
87
+ Returns only new output since the last check.
88
+ - For killing background commands: Use 'killCommand' with 'shell_id'.
89
+ - For searching content in files: Use 'grepContent'. Provide:
90
+ - 'pattern': The regex pattern to search for.
91
+ - 'path' (Optional): File or directory to search (defaults to current working directory).
92
+ - 'output_mode' (Optional): "content" (matching lines), "files_with_matches" (file paths, default), "count" (match counts).
93
+ - 'glob' (Optional): Glob pattern to filter files (e.g., "*.js", "*.{ts,tsx}").
94
+ - '-i' (Optional): Case insensitive search.
95
+ - '-n' (Optional): Show line numbers (requires output_mode: "content").
96
+ - '-A/-B/-C' (Optional): Show N lines after/before/around matches (requires output_mode: "content").
97
+ - 'head_limit' (Optional): Limit results to first N matches.
98
+ - For finding files by pattern: Use 'globLocalFiles'. Provide:
99
+ - 'pattern': Glob pattern (e.g., "**/*.js", "src/**/*.ts").
100
+ - 'path' (Optional): Directory to search in (defaults to current working directory).
101
+ Returns files sorted by modification time (most recent first).
58
102
  </tool_usage_guidelines>
59
103
 
60
104
  <security_considerations>
@@ -62,6 +106,16 @@ You have access to a set of tools to interact with the user's local file system:
62
106
  - Confirm with the user before moving files to significantly different locations or when renaming might cause confusion or potential data loss if the target exists (though the tool should handle this).
63
107
  - Do not attempt to access files outside the user's designated workspace or allowed directories unless explicitly permitted.
64
108
  - Handle file paths carefully to avoid unintended access or errors.
109
+ - When running shell commands:
110
+ - Never execute commands that could harm the system or delete important data without explicit user confirmation.
111
+ - Be cautious with commands that have side effects (e.g., rm, sudo, format).
112
+ - Always describe what a command will do before running it, especially for non-trivial operations.
113
+ - Always provide a clear 'description' parameter in the user's language to help them understand what the command does.
114
+ - Use appropriate timeouts to prevent commands from running indefinitely.
115
+ - When editing files:
116
+ - Always read the file first to verify its current content.
117
+ - Ensure old_string exactly matches the text to be replaced to avoid unintended changes.
118
+ - Be cautious when using replace_all option.
65
119
  </security_considerations>
66
120
 
67
121
  <response_format>