@lobehub/lobehub 2.0.0-next.50 → 2.0.0-next.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/apps/desktop/src/main/controllers/ShellCommandCtr.ts +242 -0
- package/apps/desktop/src/main/controllers/__tests__/ShellCommandCtr.test.ts +499 -0
- package/changelog/v1.json +9 -0
- package/locales/ar/chat.json +20 -0
- package/locales/ar/common.json +1 -0
- package/locales/ar/components.json +6 -0
- package/locales/ar/plugin.json +1 -0
- package/locales/bg-BG/chat.json +20 -0
- package/locales/bg-BG/common.json +1 -0
- package/locales/bg-BG/components.json +6 -0
- package/locales/bg-BG/plugin.json +1 -0
- package/locales/de-DE/chat.json +20 -0
- package/locales/de-DE/common.json +1 -0
- package/locales/de-DE/components.json +6 -0
- package/locales/de-DE/plugin.json +1 -0
- package/locales/en-US/chat.json +20 -0
- package/locales/en-US/common.json +1 -0
- package/locales/en-US/components.json +6 -0
- package/locales/en-US/plugin.json +1 -0
- package/locales/es-ES/chat.json +20 -0
- package/locales/es-ES/common.json +1 -0
- package/locales/es-ES/components.json +6 -0
- package/locales/es-ES/plugin.json +1 -0
- package/locales/fa-IR/chat.json +20 -0
- package/locales/fa-IR/common.json +1 -0
- package/locales/fa-IR/components.json +6 -0
- package/locales/fa-IR/plugin.json +1 -0
- package/locales/fr-FR/chat.json +20 -0
- package/locales/fr-FR/common.json +1 -0
- package/locales/fr-FR/components.json +6 -0
- package/locales/fr-FR/plugin.json +1 -0
- package/locales/it-IT/chat.json +20 -0
- package/locales/it-IT/common.json +1 -0
- package/locales/it-IT/components.json +6 -0
- package/locales/it-IT/plugin.json +1 -0
- package/locales/ja-JP/chat.json +20 -0
- package/locales/ja-JP/common.json +1 -0
- package/locales/ja-JP/components.json +6 -0
- package/locales/ja-JP/plugin.json +1 -0
- package/locales/ko-KR/chat.json +20 -0
- package/locales/ko-KR/common.json +1 -0
- package/locales/ko-KR/components.json +6 -0
- package/locales/ko-KR/plugin.json +1 -0
- package/locales/nl-NL/chat.json +20 -0
- package/locales/nl-NL/common.json +1 -0
- package/locales/nl-NL/components.json +6 -0
- package/locales/nl-NL/plugin.json +1 -0
- package/locales/pl-PL/chat.json +20 -0
- package/locales/pl-PL/common.json +1 -0
- package/locales/pl-PL/components.json +6 -0
- package/locales/pl-PL/plugin.json +1 -0
- package/locales/pt-BR/chat.json +20 -0
- package/locales/pt-BR/common.json +1 -0
- package/locales/pt-BR/components.json +6 -0
- package/locales/pt-BR/plugin.json +1 -0
- package/locales/ru-RU/chat.json +20 -0
- package/locales/ru-RU/common.json +1 -0
- package/locales/ru-RU/components.json +6 -0
- package/locales/ru-RU/plugin.json +1 -0
- package/locales/tr-TR/chat.json +20 -0
- package/locales/tr-TR/common.json +1 -0
- package/locales/tr-TR/components.json +6 -0
- package/locales/tr-TR/plugin.json +1 -0
- package/locales/vi-VN/chat.json +20 -0
- package/locales/vi-VN/common.json +1 -0
- package/locales/vi-VN/components.json +6 -0
- package/locales/vi-VN/plugin.json +1 -0
- package/locales/zh-CN/chat.json +20 -0
- package/locales/zh-CN/common.json +1 -0
- package/locales/zh-CN/components.json +6 -0
- package/locales/zh-CN/plugin.json +1 -0
- package/locales/zh-TW/chat.json +20 -0
- package/locales/zh-TW/common.json +1 -0
- package/locales/zh-TW/components.json +6 -0
- package/locales/zh-TW/plugin.json +1 -0
- package/package.json +1 -1
- package/packages/agent-runtime/src/core/InterventionChecker.ts +1 -1
- package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +23 -23
- package/packages/agent-runtime/src/types/state.ts +7 -1
- package/packages/const/src/settings/tool.ts +1 -5
- package/packages/file-loaders/src/loaders/docx/index.ts +1 -1
- package/packages/model-bank/src/aiModels/wenxin.ts +1348 -291
- package/packages/model-runtime/src/providers/wenxin/index.ts +22 -1
- package/packages/model-runtime/src/utils/modelParse.ts +6 -0
- package/packages/types/src/tool/builtin.ts +9 -0
- package/packages/types/src/tool/intervention.ts +32 -2
- package/packages/types/src/user/settings/tool.ts +3 -27
- package/src/config/modelProviders/wenxin.ts +2 -3
- package/src/features/Conversation/MarkdownElements/remarkPlugins/__snapshots__/createRemarkSelfClosingTagPlugin.test.ts.snap +133 -0
- package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.test.ts +48 -0
- package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts +2 -1
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/Fallback.tsx +98 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/ModeSelector.tsx +5 -6
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/index.tsx +40 -36
- package/src/features/Conversation/Messages/Group/Tool/Render/index.tsx +25 -18
- package/src/features/LocalFile/LocalFile.tsx +55 -5
- package/src/locales/default/components.ts +6 -0
- package/src/locales/default/plugin.ts +1 -0
- package/src/services/electron/localFileService.ts +4 -0
- package/src/store/chat/agents/GeneralChatAgent.ts +26 -1
- package/src/store/chat/agents/__tests__/GeneralChatAgent.test.ts +173 -0
- package/src/store/chat/slices/aiChat/actions/conversationControl.ts +8 -40
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +91 -34
- package/src/store/user/selectors.ts +1 -0
- package/src/store/user/slices/settings/action.ts +12 -0
- package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +0 -7
- package/src/store/user/slices/settings/selectors/index.ts +1 -0
- package/src/store/user/slices/settings/selectors/settings.test.ts +0 -37
- package/src/store/user/slices/settings/selectors/settings.ts +0 -5
- package/src/store/user/slices/settings/selectors/toolIntervention.ts +17 -0
- package/src/tools/interventions.ts +8 -0
- package/src/tools/local-system/Intervention/RunCommand/index.tsx +56 -0
- package/src/tools/local-system/Intervention/index.tsx +17 -0
- package/src/tools/local-system/Render/RunCommand/index.tsx +100 -21
- package/src/tools/local-system/Render/index.tsx +2 -0
- package/src/tools/local-system/index.ts +180 -0
- package/src/tools/local-system/systemRole.ts +61 -7
|
@@ -26,6 +26,10 @@ export interface UserSettingsAction {
|
|
|
26
26
|
setSettings: (settings: PartialDeep<UserSettings>) => Promise<void>;
|
|
27
27
|
updateDefaultAgent: (agent: PartialDeep<LobeAgentSettings>) => Promise<void>;
|
|
28
28
|
updateGeneralConfig: (settings: Partial<UserGeneralConfig>) => Promise<void>;
|
|
29
|
+
updateHumanIntervention: (config: {
|
|
30
|
+
allowList?: string[];
|
|
31
|
+
approvalMode?: 'auto-run' | 'allow-list' | 'manual';
|
|
32
|
+
}) => Promise<void>;
|
|
29
33
|
updateKeyVaults: (settings: Partial<UserKeyVaults>) => Promise<void>;
|
|
30
34
|
|
|
31
35
|
updateSystemAgent: (
|
|
@@ -111,6 +115,14 @@ export const createSettingsSlice: StateCreator<
|
|
|
111
115
|
updateGeneralConfig: async (general) => {
|
|
112
116
|
await get().setSettings({ general });
|
|
113
117
|
},
|
|
118
|
+
updateHumanIntervention: async (config) => {
|
|
119
|
+
const current = get().settings.tool?.humanIntervention || {};
|
|
120
|
+
await get().setSettings({
|
|
121
|
+
tool: {
|
|
122
|
+
humanIntervention: { ...current, ...config },
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
},
|
|
114
126
|
updateKeyVaults: async (keyVaults) => {
|
|
115
127
|
await get().setSettings({ keyVaults });
|
|
116
128
|
},
|
|
@@ -95,13 +95,6 @@ exports[`settingsSelectors > currentTTS > should merge DEFAULT_TTS_CONFIG and s.
|
|
|
95
95
|
}
|
|
96
96
|
`;
|
|
97
97
|
|
|
98
|
-
exports[`settingsSelectors > dalleConfig > should return the dalle configuration 1`] = `
|
|
99
|
-
{
|
|
100
|
-
"apiKey": "dalle-api-key",
|
|
101
|
-
"autoGenerate": true,
|
|
102
|
-
}
|
|
103
|
-
`;
|
|
104
|
-
|
|
105
98
|
exports[`settingsSelectors > defaultAgent > should merge DEFAULT_AGENT and s.settings.defaultAgent correctly 1`] = `
|
|
106
99
|
{
|
|
107
100
|
"config": {
|
|
@@ -2,3 +2,4 @@ export { userGeneralSettingsSelectors } from './general';
|
|
|
2
2
|
export { keyVaultsConfigSelectors } from './keyVaults';
|
|
3
3
|
export { settingsSelectors } from './settings';
|
|
4
4
|
export { systemAgentSelectors } from './systemAgent';
|
|
5
|
+
export { toolInterventionSelectors } from './toolIntervention';
|
|
@@ -120,43 +120,6 @@ describe('settingsSelectors', () => {
|
|
|
120
120
|
});
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
describe('dalleConfig', () => {
|
|
124
|
-
it('should return the dalle configuration', () => {
|
|
125
|
-
const s = {
|
|
126
|
-
settings: {
|
|
127
|
-
tool: {
|
|
128
|
-
dalle: {
|
|
129
|
-
apiKey: 'dalle-api-key',
|
|
130
|
-
autoGenerate: true,
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
} as unknown as UserStore;
|
|
135
|
-
|
|
136
|
-
const result = settingsSelectors.dalleConfig(s);
|
|
137
|
-
|
|
138
|
-
expect(result).toMatchSnapshot();
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
describe('isDalleAutoGenerating', () => {
|
|
143
|
-
it('should return the autoGenerate flag from dalle configuration', () => {
|
|
144
|
-
const s = {
|
|
145
|
-
settings: {
|
|
146
|
-
tool: {
|
|
147
|
-
dalle: {
|
|
148
|
-
autoGenerate: true,
|
|
149
|
-
},
|
|
150
|
-
},
|
|
151
|
-
},
|
|
152
|
-
} as unknown as UserStore;
|
|
153
|
-
|
|
154
|
-
const result = settingsSelectors.isDalleAutoGenerating(s);
|
|
155
|
-
|
|
156
|
-
expect(result).toBe(true);
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
|
|
160
123
|
describe('getProviderConfigById', () => {
|
|
161
124
|
it('should return the provider config for a given provider id', () => {
|
|
162
125
|
const providerConfig = {
|
|
@@ -36,9 +36,6 @@ const defaultAgentMeta = (s: UserStore) => merge(DEFAULT_AGENT_META, defaultAgen
|
|
|
36
36
|
|
|
37
37
|
const exportSettings = currentSettings;
|
|
38
38
|
|
|
39
|
-
const dalleConfig = (s: UserStore) => currentSettings(s).tool?.dalle || {};
|
|
40
|
-
const isDalleAutoGenerating = (s: UserStore) => currentSettings(s).tool?.dalle?.autoGenerate;
|
|
41
|
-
|
|
42
39
|
const currentSystemAgent = (s: UserStore) =>
|
|
43
40
|
merge(DEFAULT_SYSTEM_AGENT_CONFIG, currentSettings(s).systemAgent);
|
|
44
41
|
|
|
@@ -50,12 +47,10 @@ export const settingsSelectors = {
|
|
|
50
47
|
currentSettings,
|
|
51
48
|
currentSystemAgent,
|
|
52
49
|
currentTTS,
|
|
53
|
-
dalleConfig,
|
|
54
50
|
defaultAgent,
|
|
55
51
|
defaultAgentConfig,
|
|
56
52
|
defaultAgentMeta,
|
|
57
53
|
exportSettings,
|
|
58
54
|
getHotkeyById,
|
|
59
|
-
isDalleAutoGenerating,
|
|
60
55
|
providerConfig: getProviderConfigById,
|
|
61
56
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { UserStore } from '@/store/user';
|
|
2
|
+
|
|
3
|
+
import { currentSettings } from './settings';
|
|
4
|
+
|
|
5
|
+
const humanInterventionConfig = (s: UserStore) => currentSettings(s).tool?.humanIntervention || {};
|
|
6
|
+
|
|
7
|
+
const interventionApprovalMode = (s: UserStore) =>
|
|
8
|
+
currentSettings(s).tool?.humanIntervention?.approvalMode || 'manual';
|
|
9
|
+
|
|
10
|
+
const interventionAllowList = (s: UserStore) =>
|
|
11
|
+
currentSettings(s).tool?.humanIntervention?.allowList || [];
|
|
12
|
+
|
|
13
|
+
export const toolInterventionSelectors = {
|
|
14
|
+
allowList: interventionAllowList,
|
|
15
|
+
approvalMode: interventionApprovalMode,
|
|
16
|
+
config: humanInterventionConfig,
|
|
17
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BuiltinIntervention } from '@lobechat/types';
|
|
2
|
+
|
|
3
|
+
import { LocalSystemManifest } from './local-system';
|
|
4
|
+
import LocalSystem from './local-system/Intervention';
|
|
5
|
+
|
|
6
|
+
export const BuiltinToolInterventions: Record<string, BuiltinIntervention> = {
|
|
7
|
+
[LocalSystemManifest.identifier]: LocalSystem as BuiltinIntervention,
|
|
8
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { RunCommandParams } from '@lobechat/electron-client-ipc';
|
|
2
|
+
import { Highlighter, Text } from '@lobehub/ui';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
const formatTimeout = (ms?: number) => {
|
|
7
|
+
if (!ms) return null;
|
|
8
|
+
|
|
9
|
+
const seconds = ms / 1000;
|
|
10
|
+
|
|
11
|
+
// >= 60s 显示分钟
|
|
12
|
+
if (seconds >= 60) {
|
|
13
|
+
const minutes = seconds / 60;
|
|
14
|
+
return `${minutes.toFixed(1)}min`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// >= 1s 显示秒
|
|
18
|
+
if (seconds >= 1) {
|
|
19
|
+
return `${seconds.toFixed(1)}s`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// < 1s 显示毫秒
|
|
23
|
+
return `${ms}ms`;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
interface RunCommandProps extends RunCommandParams {
|
|
27
|
+
messageId: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const RunCommand = memo<RunCommandProps>(({ description, command, timeout }) => {
|
|
31
|
+
return (
|
|
32
|
+
<Flexbox gap={8}>
|
|
33
|
+
<Flexbox horizontal justify={'space-between'}>
|
|
34
|
+
{description && <Text>{description}</Text>}
|
|
35
|
+
{timeout && (
|
|
36
|
+
<Text style={{ fontSize: 12 }} type={'secondary'}>
|
|
37
|
+
timeout: {formatTimeout(timeout)}
|
|
38
|
+
</Text>
|
|
39
|
+
)}
|
|
40
|
+
</Flexbox>
|
|
41
|
+
{command && (
|
|
42
|
+
<Highlighter
|
|
43
|
+
language={'sh'}
|
|
44
|
+
showLanguage={false}
|
|
45
|
+
style={{ padding: '4px 8px' }}
|
|
46
|
+
variant={'outlined'}
|
|
47
|
+
wrap
|
|
48
|
+
>
|
|
49
|
+
{command}
|
|
50
|
+
</Highlighter>
|
|
51
|
+
)}
|
|
52
|
+
</Flexbox>
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export default RunCommand;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RunCommandParams } from '@lobechat/electron-client-ipc';
|
|
2
|
+
import { BuiltinInterventionProps } from '@lobechat/types';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
|
|
5
|
+
import RunCommand from './RunCommand';
|
|
6
|
+
|
|
7
|
+
const Intervention = memo<BuiltinInterventionProps<RunCommandParams>>(
|
|
8
|
+
({ apiName, args, messageId }) => {
|
|
9
|
+
if (apiName === 'runCommand') {
|
|
10
|
+
return <RunCommand {...args} messageId={messageId} />;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return null;
|
|
14
|
+
},
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
export default Intervention;
|
|
@@ -1,35 +1,114 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons';
|
|
2
|
+
import { RunCommandParams, RunCommandResult } from '@lobechat/electron-client-ipc';
|
|
2
3
|
import { ChatMessagePluginError } from '@lobechat/types';
|
|
3
|
-
import {
|
|
4
|
-
import '
|
|
5
|
-
import {
|
|
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
|
-
|
|
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
|
+
}
|
|
24
|
+
|
|
25
|
+
&:hover {
|
|
26
|
+
.action-icon {
|
|
27
|
+
opacity: 1;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
`,
|
|
31
|
+
statusIcon: css`
|
|
32
|
+
font-size: 12px;
|
|
33
|
+
`,
|
|
34
|
+
}));
|
|
8
35
|
|
|
9
36
|
interface RunCommandProps {
|
|
10
37
|
args: RunCommandParams;
|
|
11
38
|
messageId: string;
|
|
12
39
|
pluginError: ChatMessagePluginError;
|
|
13
|
-
pluginState:
|
|
40
|
+
pluginState: {
|
|
41
|
+
message: string;
|
|
42
|
+
result: RunCommandResult;
|
|
43
|
+
};
|
|
14
44
|
}
|
|
15
45
|
|
|
16
|
-
const RunCommand = memo<RunCommandProps>(({ args }) => {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const term = new Terminal({ cols: 80, cursorBlink: true, rows: 30 });
|
|
23
|
-
|
|
24
|
-
term.open(terminalRef.current);
|
|
25
|
-
term.write(args.command);
|
|
46
|
+
const RunCommand = memo<RunCommandProps>(({ args, pluginState }) => {
|
|
47
|
+
const { styles, theme } = useStyles();
|
|
48
|
+
const { result, message } = pluginState || {};
|
|
49
|
+
const isSuccess = result?.success;
|
|
50
|
+
const [expanded, setExpanded] = useState(false);
|
|
26
51
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
52
|
+
return (
|
|
53
|
+
<Flexbox className={styles.container} gap={8}>
|
|
54
|
+
{/* Header: Description + Status */}
|
|
55
|
+
<Flexbox align={'center'} className={styles.header} horizontal justify={'space-between'}>
|
|
56
|
+
<Flexbox gap={8} horizontal>
|
|
57
|
+
<Flexbox gap={4} horizontal>
|
|
58
|
+
{!result ? null : isSuccess ? (
|
|
59
|
+
<CheckCircleFilled
|
|
60
|
+
className={styles.statusIcon}
|
|
61
|
+
style={{ color: theme.colorSuccess }}
|
|
62
|
+
/>
|
|
63
|
+
) : (
|
|
64
|
+
<CloseCircleFilled
|
|
65
|
+
className={styles.statusIcon}
|
|
66
|
+
style={{ color: theme.colorError }}
|
|
67
|
+
/>
|
|
68
|
+
)}
|
|
69
|
+
{args.description && <Text className={styles.head}>{args.description}</Text>}
|
|
70
|
+
</Flexbox>
|
|
71
|
+
{message && (
|
|
72
|
+
<Flexbox align={'center'} gap={4} horizontal>
|
|
73
|
+
<Text className={styles.head} type={'secondary'}>
|
|
74
|
+
{message}
|
|
75
|
+
</Text>
|
|
76
|
+
</Flexbox>
|
|
77
|
+
)}
|
|
78
|
+
</Flexbox>
|
|
79
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
80
|
+
<ActionIcon
|
|
81
|
+
className={`action-icon`}
|
|
82
|
+
icon={expanded ? ChevronUp : ChevronDown}
|
|
83
|
+
onClick={() => setExpanded(!expanded)}
|
|
84
|
+
size={'small'}
|
|
85
|
+
style={{ opacity: expanded ? 1 : undefined }}
|
|
86
|
+
title={expanded ? 'Collapse' : 'Expand'}
|
|
87
|
+
/>
|
|
88
|
+
</Flexbox>
|
|
89
|
+
</Flexbox>
|
|
31
90
|
|
|
32
|
-
|
|
91
|
+
{/* Command & Output */}
|
|
92
|
+
{expanded && (
|
|
93
|
+
<Block gap={8} padding={8} variant={'outlined'}>
|
|
94
|
+
<Highlighter
|
|
95
|
+
language={'sh'}
|
|
96
|
+
showLanguage={false}
|
|
97
|
+
style={{ paddingInline: 8 }}
|
|
98
|
+
variant={'borderless'}
|
|
99
|
+
wrap
|
|
100
|
+
>
|
|
101
|
+
{args.command}
|
|
102
|
+
</Highlighter>
|
|
103
|
+
{result?.output && (
|
|
104
|
+
<Highlighter language={'text'} showLanguage={false} variant={'filled'} wrap>
|
|
105
|
+
{result.output}
|
|
106
|
+
</Highlighter>
|
|
107
|
+
)}
|
|
108
|
+
</Block>
|
|
109
|
+
)}
|
|
110
|
+
</Flexbox>
|
|
111
|
+
);
|
|
33
112
|
});
|
|
34
113
|
|
|
35
114
|
export default RunCommand;
|
|
@@ -7,6 +7,7 @@ import { LocalSystemApiName } from '@/tools/local-system';
|
|
|
7
7
|
import ListFiles from './ListFiles';
|
|
8
8
|
import ReadLocalFile from './ReadLocalFile';
|
|
9
9
|
import RenameLocalFile from './RenameLocalFile';
|
|
10
|
+
import RunCommand from './RunCommand';
|
|
10
11
|
import SearchFiles from './SearchFiles';
|
|
11
12
|
import WriteFile from './WriteFile';
|
|
12
13
|
|
|
@@ -16,6 +17,7 @@ const RenderMap = {
|
|
|
16
17
|
[LocalSystemApiName.readLocalFile]: ReadLocalFile,
|
|
17
18
|
[LocalSystemApiName.renameLocalFile]: RenameLocalFile,
|
|
18
19
|
[LocalSystemApiName.writeLocalFile]: WriteFile,
|
|
20
|
+
[LocalSystemApiName.runCommand]: RunCommand,
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
const LocalFilesRender = memo<BuiltinRenderProps<LocalFileItem[]>>(
|
|
@@ -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
|
};
|
|
@@ -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: {
|
|
@@ -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. **
|
|
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
|
|
28
|
-
2. Select the appropriate tool
|
|
29
|
-
|
|
30
|
-
|
|
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 '
|
|
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>
|