mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-14 03:30:19 +00:00
💄 style: improve loading and local-system render (#11087)
* 💄 style: improve loading * ♻️ refactor: move local-system to builtin-tool-local-system package * update * remove focusThrottleInterval
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
"private": true,
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./client": "./src/client/index.ts",
|
||||
"./executionRuntime": "./src/ExecutionRuntime/index.ts"
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
@@ -12,5 +13,14 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lobechat/types": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@lobehub/ui": "^4",
|
||||
"antd": "^6",
|
||||
"antd-style": "*",
|
||||
"lucide-react": "*",
|
||||
"path-browserify-esm": "*",
|
||||
"react": "*",
|
||||
"react-i18next": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
'use client';
|
||||
|
||||
import { type EditLocalFileParams } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
||||
import { Check, X } from 'lucide-react';
|
||||
import path from 'path-browserify-esm';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { highlightTextStyles, shinyTextStyles } from '@/styles';
|
||||
|
||||
import { type EditLocalFileState } from '../../../types';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
statusIcon: css`
|
||||
margin-block-end: -2px;
|
||||
margin-inline-start: 4px;
|
||||
`,
|
||||
}));
|
||||
|
||||
export const EditLocalFileInspector = memo<
|
||||
BuiltinInspectorProps<EditLocalFileParams, EditLocalFileState>
|
||||
>(({ args, partialArgs, isArgumentsStreaming, pluginState, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
// Show filename with parent directory for context
|
||||
const filePath = args?.file_path || partialArgs?.file_path || '';
|
||||
let displayPath = '';
|
||||
if (filePath) {
|
||||
const { base, dir } = path.parse(filePath);
|
||||
const parentDir = path.basename(dir);
|
||||
displayPath = parentDir ? `${parentDir}/${base}` : base;
|
||||
}
|
||||
|
||||
// During argument streaming
|
||||
if (isArgumentsStreaming) {
|
||||
if (!displayPath)
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.editLocalFile')}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.editLocalFile')}: </span>
|
||||
<span className={highlightTextStyles.primary}>{displayPath}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Check if edit was successful (has replacements count)
|
||||
const isSuccess = pluginState?.replacements !== undefined && pluginState.replacements >= 0;
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
|
||||
<span style={{ marginInlineStart: 2 }}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.editLocalFile')}: </span>
|
||||
{displayPath && <span className={highlightTextStyles.primary}>{displayPath}</span>}
|
||||
{isLoading ? null : pluginState ? (
|
||||
isSuccess ? (
|
||||
<Check className={styles.statusIcon} color={cssVar.colorSuccess} size={14} />
|
||||
) : (
|
||||
<X className={styles.statusIcon} color={cssVar.colorError} size={14} />
|
||||
)
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
EditLocalFileInspector.displayName = 'EditLocalFileInspector';
|
||||
@@ -0,0 +1,73 @@
|
||||
'use client';
|
||||
|
||||
import { type GlobFilesParams } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
||||
import { Check, X } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { highlightTextStyles, shinyTextStyles } from '@/styles';
|
||||
|
||||
import { type GlobFilesState } from '../../..';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
statusIcon: css`
|
||||
margin-block-end: -2px;
|
||||
margin-inline-start: 4px;
|
||||
`,
|
||||
}));
|
||||
|
||||
export const GlobLocalFilesInspector = memo<BuiltinInspectorProps<GlobFilesParams, GlobFilesState>>(
|
||||
({ args, partialArgs, isArgumentsStreaming, pluginState, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
const pattern = args?.pattern || partialArgs?.pattern || '';
|
||||
|
||||
// During argument streaming
|
||||
if (isArgumentsStreaming) {
|
||||
if (!pattern)
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.globLocalFiles')}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.globLocalFiles')}: </span>
|
||||
<span className={highlightTextStyles.primary}>{pattern}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Check if glob was successful
|
||||
const isSuccess = pluginState?.result?.success;
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
|
||||
<span style={{ marginInlineStart: 2 }}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.globLocalFiles')}: </span>
|
||||
{pattern && <span className={highlightTextStyles.primary}>{pattern}</span>}
|
||||
{isLoading ? null : pluginState?.result ? (
|
||||
isSuccess ? (
|
||||
<Check className={styles.statusIcon} color={cssVar.colorSuccess} size={14} />
|
||||
) : (
|
||||
<X className={styles.statusIcon} color={cssVar.colorError} size={14} />
|
||||
)
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
GlobLocalFilesInspector.displayName = 'GlobLocalFilesInspector';
|
||||
@@ -0,0 +1,73 @@
|
||||
'use client';
|
||||
|
||||
import { type GrepContentParams } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
||||
import { Check, X } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { highlightTextStyles, shinyTextStyles } from '@/styles';
|
||||
|
||||
import { type GrepContentState } from '../../..';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
statusIcon: css`
|
||||
margin-block-end: -2px;
|
||||
margin-inline-start: 4px;
|
||||
`,
|
||||
}));
|
||||
|
||||
export const GrepContentInspector = memo<
|
||||
BuiltinInspectorProps<GrepContentParams, GrepContentState>
|
||||
>(({ args, partialArgs, isArgumentsStreaming, pluginState, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
const pattern = args?.pattern || partialArgs?.pattern || '';
|
||||
|
||||
// During argument streaming
|
||||
if (isArgumentsStreaming) {
|
||||
if (!pattern)
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.grepContent')}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.grepContent')}: </span>
|
||||
<span className={highlightTextStyles.primary}>{pattern}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Check if grep was successful
|
||||
const isSuccess = pluginState?.result?.success;
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
|
||||
<span style={{ marginInlineStart: 2 }}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.grepContent')}: </span>
|
||||
{pattern && <span className={highlightTextStyles.primary}>{pattern}</span>}
|
||||
{isLoading ? null : pluginState?.result ? (
|
||||
isSuccess ? (
|
||||
<Check className={styles.statusIcon} color={cssVar.colorSuccess} size={14} />
|
||||
) : (
|
||||
<X className={styles.statusIcon} color={cssVar.colorError} size={14} />
|
||||
)
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
GrepContentInspector.displayName = 'GrepContentInspector';
|
||||
@@ -0,0 +1,81 @@
|
||||
'use client';
|
||||
|
||||
import { type LocalReadFileParams } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
||||
import { Check, X } from 'lucide-react';
|
||||
import path from 'path-browserify-esm';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { highlightTextStyles, shinyTextStyles } from '@/styles';
|
||||
|
||||
import { type LocalReadFileState } from '../../..';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
statusIcon: css`
|
||||
margin-block-end: -2px;
|
||||
margin-inline-start: 4px;
|
||||
`,
|
||||
}));
|
||||
|
||||
export const ReadLocalFileInspector = memo<
|
||||
BuiltinInspectorProps<LocalReadFileParams, LocalReadFileState>
|
||||
>(({ args, partialArgs, isArgumentsStreaming, pluginState, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
// Show filename with parent directory for context
|
||||
const filePath = args?.path || partialArgs?.path || '';
|
||||
let displayPath = '';
|
||||
if (filePath) {
|
||||
const { base, dir } = path.parse(filePath);
|
||||
const parentDir = path.basename(dir);
|
||||
displayPath = parentDir ? `${parentDir}/${base}` : base;
|
||||
}
|
||||
|
||||
// During argument streaming
|
||||
if (isArgumentsStreaming) {
|
||||
if (!displayPath)
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.readLocalFile')}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.readLocalFile')}: </span>
|
||||
<span className={highlightTextStyles.primary}>{displayPath}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Check if file was read successfully (has content)
|
||||
const hasContent = !!pluginState?.fileContent;
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
|
||||
<span style={{ marginInlineStart: 2 }}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.readLocalFile')}: </span>
|
||||
{displayPath && <span className={highlightTextStyles.primary}>{displayPath}</span>}
|
||||
{isLoading ? null : pluginState ? (
|
||||
hasContent ? (
|
||||
<Check className={styles.statusIcon} color={cssVar.colorSuccess} size={14} />
|
||||
) : (
|
||||
<X className={styles.statusIcon} color={cssVar.colorError} size={14} />
|
||||
)
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
ReadLocalFileInspector.displayName = 'ReadLocalFileInspector';
|
||||
@@ -0,0 +1,80 @@
|
||||
'use client';
|
||||
|
||||
import { type RunCommandParams, type RunCommandResult } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
||||
import { Check, X } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { highlightTextStyles, shinyTextStyles } from '@/styles';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
statusIcon: css`
|
||||
margin-block-end: -2px;
|
||||
margin-inline-start: 4px;
|
||||
`,
|
||||
}));
|
||||
|
||||
interface RunCommandState {
|
||||
message: string;
|
||||
result: RunCommandResult;
|
||||
}
|
||||
|
||||
export const RunCommandInspector = memo<BuiltinInspectorProps<RunCommandParams, RunCommandState>>(
|
||||
({ args, partialArgs, isArgumentsStreaming, pluginState, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
// Show description if available, otherwise show command
|
||||
const description = args?.description || partialArgs?.description || args?.command || '';
|
||||
|
||||
// During argument streaming
|
||||
if (isArgumentsStreaming) {
|
||||
if (!description)
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.runCommand')}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.runCommand')}: </span>
|
||||
<span className={highlightTextStyles.primary}>{description}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Get execution result from pluginState
|
||||
const result = pluginState?.result;
|
||||
const isSuccess = result?.success && result?.exit_code === 0;
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
|
||||
<span style={{ marginInlineStart: 2 }}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.runCommand')}: </span>
|
||||
{description && <span className={highlightTextStyles.primary}>{description}</span>}
|
||||
{isLoading ? null : result?.success !== undefined ? (
|
||||
isSuccess ? (
|
||||
<Check className={styles.statusIcon} color={cssVar.colorSuccess} size={14} />
|
||||
) : (
|
||||
<X className={styles.statusIcon} color={cssVar.colorError} size={14} />
|
||||
)
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
RunCommandInspector.displayName = 'RunCommandInspector';
|
||||
|
||||
export default RunCommandInspector;
|
||||
@@ -0,0 +1,71 @@
|
||||
'use client';
|
||||
|
||||
import { type LocalSearchFilesParams } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
||||
import { Check } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { highlightTextStyles, shinyTextStyles } from '@/styles';
|
||||
|
||||
import { type LocalFileSearchState } from '../../..';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
statusIcon: css`
|
||||
margin-block-end: -2px;
|
||||
margin-inline-start: 4px;
|
||||
`,
|
||||
}));
|
||||
|
||||
export const SearchLocalFilesInspector = memo<
|
||||
BuiltinInspectorProps<LocalSearchFilesParams, LocalFileSearchState>
|
||||
>(({ args, partialArgs, isArgumentsStreaming, pluginState, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
const keywords = args?.keywords || partialArgs?.keywords || '';
|
||||
|
||||
// During argument streaming
|
||||
if (isArgumentsStreaming) {
|
||||
if (!keywords)
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.searchLocalFiles')}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.searchLocalFiles')}: </span>
|
||||
<span className={highlightTextStyles.primary}>{keywords}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Check if search returned results
|
||||
const hasResults = pluginState?.searchResults && pluginState.searchResults.length >= 0;
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
|
||||
<span style={{ marginInlineStart: 2 }}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.searchLocalFiles')}: </span>
|
||||
{keywords && <span className={highlightTextStyles.primary}>{keywords}</span>}
|
||||
{isLoading ? null : pluginState?.searchResults ? (
|
||||
hasResults ? (
|
||||
<Check className={styles.statusIcon} color={cssVar.colorSuccess} size={14} />
|
||||
) : null
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
SearchLocalFilesInspector.displayName = 'SearchLocalFilesInspector';
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
import { LocalSystemApiName } from '@lobechat/builtin-tool-local-system';
|
||||
|
||||
import { LocalSystemApiName } from '../..';
|
||||
import { EditLocalFileInspector } from './EditLocalFile';
|
||||
import { GlobLocalFilesInspector } from './GlobLocalFiles';
|
||||
import { GrepContentInspector } from './GrepContent';
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
import { LocalSystemApiName } from '@lobechat/builtin-tool-local-system';
|
||||
|
||||
import { LocalSystemApiName } from '../..';
|
||||
import EditLocalFile from './EditLocalFile';
|
||||
import MoveLocalFiles from './MoveLocalFiles';
|
||||
import RunCommand from './RunCommand';
|
||||
+2
-1
@@ -5,7 +5,8 @@ import { memo } from 'react';
|
||||
|
||||
import { useChatStore } from '@/store/chat';
|
||||
import { chatToolSelectors } from '@/store/chat/selectors';
|
||||
import FileItem from '@/tools/local-system/components/FileItem';
|
||||
|
||||
import FileItem from '../../components/FileItem';
|
||||
|
||||
interface SearchFilesProps {
|
||||
listResults?: LocalFileItem[];
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
import { LocalSystemApiName } from '@lobechat/builtin-tool-local-system';
|
||||
|
||||
import { LocalSystemApiName } from '../..';
|
||||
import EditLocalFile from './EditLocalFile';
|
||||
import ListFiles from './ListFiles';
|
||||
import MoveLocalFiles from './MoveLocalFiles';
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
import { LocalSystemApiName } from '@lobechat/builtin-tool-local-system';
|
||||
|
||||
import { LocalSystemApiName } from '../..';
|
||||
import { RunCommandStreaming } from './RunCommand';
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,20 @@
|
||||
// Inspector components (customized tool call headers)
|
||||
export { LocalSystemInspectors } from './Inspector';
|
||||
|
||||
// Render components (read-only snapshots)
|
||||
export { LocalSystemRenders } from './Render';
|
||||
|
||||
// Intervention components (approval dialogs)
|
||||
export { LocalSystemInterventions } from './Intervention';
|
||||
|
||||
// Streaming components
|
||||
export { LocalSystemStreamings } from './Streaming';
|
||||
|
||||
// Placeholder components
|
||||
export { ListFiles as LocalSystemListFilesPlaceholder } from './Placeholder/ListFiles';
|
||||
export { default as LocalSystemSearchFilesPlaceholder } from './Placeholder/SearchFiles';
|
||||
|
||||
// Re-export types and manifest for convenience
|
||||
export { LocalSystemManifest } from '../manifest';
|
||||
export { LocalSystemIdentifier } from '../types';
|
||||
export * from '../types';
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { AccordionItem, ActionIcon, Dropdown, Flexbox, Text } from '@lobehub/ui';
|
||||
import { Loader2Icon } from 'lucide-react';
|
||||
import { AccordionItem, Dropdown, Flexbox, Text } from '@lobehub/ui';
|
||||
import React, { Suspense, memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
||||
import SkeletonList from '@/features/NavPanel/components/SkeletonList';
|
||||
import { useFetchTopics } from '@/hooks/useFetchTopics';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
@@ -45,7 +45,7 @@ const Topic = memo<TopicProps>(({ itemKey }) => {
|
||||
<Text ellipsis fontSize={12} type={'secondary'} weight={500}>
|
||||
{`${t('title')} ${topicCount > 0 ? topicCount : ''}`}
|
||||
</Text>
|
||||
{isRevalidating && <ActionIcon icon={Loader2Icon} loading size={'small'} />}
|
||||
{isRevalidating && <NeuralNetworkLoading size={14} />}
|
||||
</Flexbox>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { AccordionItem, ActionIcon, Dropdown, Flexbox, Text } from '@lobehub/ui';
|
||||
import { Loader2Icon } from 'lucide-react';
|
||||
import { AccordionItem, Dropdown, Flexbox, Text } from '@lobehub/ui';
|
||||
import React, { Suspense, memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
||||
import SkeletonList from '@/features/NavPanel/components/SkeletonList';
|
||||
import { useFetchTopics } from '@/hooks/useFetchTopics';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
@@ -45,7 +45,7 @@ const Topic = memo<TopicProps>(({ itemKey }) => {
|
||||
<Text ellipsis fontSize={12} type={'secondary'} weight={500}>
|
||||
{`${t('title')} ${topicCount > 0 ? topicCount : ''}`}
|
||||
</Text>
|
||||
{isRevalidating && <ActionIcon icon={Loader2Icon} loading size={'small'} />}
|
||||
{isRevalidating && <NeuralNetworkLoading size={14} />}
|
||||
</Flexbox>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { AccordionItem, ActionIcon, Dropdown, Flexbox, Text } from '@lobehub/ui';
|
||||
import { Loader2Icon } from 'lucide-react';
|
||||
import { AccordionItem, Dropdown, Flexbox, Text } from '@lobehub/ui';
|
||||
import React, { Suspense, memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
||||
import { useFetchAgentList } from '@/hooks/useFetchAgentList';
|
||||
|
||||
import SkeletonList from '../../../../../../../features/NavPanel/components/SkeletonList';
|
||||
@@ -56,7 +56,7 @@ const Agent = memo<AgentProps>(({ itemKey }) => {
|
||||
<Text ellipsis fontSize={12} type={'secondary'} weight={500}>
|
||||
{t('navPanel.agent')}
|
||||
</Text>
|
||||
{isRevalidating && <ActionIcon icon={Loader2Icon} loading size={'small'} />}
|
||||
{isRevalidating && <NeuralNetworkLoading size={14} />}
|
||||
</Flexbox>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import { ActionIcon, Dropdown } from '@lobehub/ui';
|
||||
import { FileTextIcon, Loader2Icon, MoreHorizontal } from 'lucide-react';
|
||||
import { FileTextIcon, MoreHorizontal } from 'lucide-react';
|
||||
import { Suspense, memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
||||
import { useInitRecentPage } from '@/hooks/useInitRecentPage';
|
||||
import { useHomeStore } from '@/store/home';
|
||||
import { homeRecentSelectors } from '@/store/home/selectors';
|
||||
@@ -35,7 +36,7 @@ const RecentPage = memo(() => {
|
||||
<GroupBlock
|
||||
action={
|
||||
<>
|
||||
{isRevalidating && <ActionIcon icon={Loader2Icon} loading size={'small'} />}
|
||||
{isRevalidating && <NeuralNetworkLoading size={14} />}
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: [
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import { ActionIcon, Dropdown } from '@lobehub/ui';
|
||||
import { Clock, Loader2Icon, MoreHorizontal } from 'lucide-react';
|
||||
import { Clock, MoreHorizontal } from 'lucide-react';
|
||||
import { Suspense, memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
||||
import { useInitRecentResource } from '@/hooks/useInitRecentResource';
|
||||
import { useHomeStore } from '@/store/home';
|
||||
import { homeRecentSelectors } from '@/store/home/selectors';
|
||||
@@ -35,7 +36,7 @@ const RecentResource = memo(() => {
|
||||
<GroupBlock
|
||||
action={
|
||||
<>
|
||||
{isRevalidating && <ActionIcon icon={Loader2Icon} loading size={'small'} />}
|
||||
{isRevalidating && <NeuralNetworkLoading size={14} />}
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: [
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ActionIcon } from '@lobehub/ui';
|
||||
import { BotMessageSquareIcon, Loader2Icon } from 'lucide-react';
|
||||
import { BotMessageSquareIcon } from 'lucide-react';
|
||||
import { Suspense, memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
||||
import { useInitRecentTopic } from '@/hooks/useInitRecentTopic';
|
||||
import { useHomeStore } from '@/store/home';
|
||||
import { homeRecentSelectors } from '@/store/home/selectors';
|
||||
@@ -26,7 +26,7 @@ const RecentTopic = memo(() => {
|
||||
|
||||
return (
|
||||
<GroupBlock
|
||||
action={isRevalidating && <ActionIcon icon={Loader2Icon} loading size={'small'} />}
|
||||
action={isRevalidating && <NeuralNetworkLoading size={14} />}
|
||||
icon={BotMessageSquareIcon}
|
||||
title={t('topic.recent')}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
'use client';
|
||||
|
||||
import { createStaticStyles, keyframes } from 'antd-style';
|
||||
import { CSSProperties, memo } from 'react';
|
||||
|
||||
const pulseAnim = keyframes`
|
||||
0%, 100% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
const flowAnim = keyframes`
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
opacity: 0.5;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateX(var(--flow-distance));
|
||||
opacity: 0.5;
|
||||
}
|
||||
`;
|
||||
|
||||
const rotateAnim = keyframes`
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
`;
|
||||
|
||||
const scaleAnim = keyframes`
|
||||
0%, 100% {
|
||||
transform: scale(0.8);
|
||||
opacity: 0.5;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
center: css`
|
||||
fill: ${cssVar.colorTextSecondary};
|
||||
animation: ${scaleAnim} 2s infinite;
|
||||
`,
|
||||
|
||||
connection: css`
|
||||
opacity: 0.3;
|
||||
stroke: ${cssVar.colorTextSecondary};
|
||||
stroke-width: 0.5;
|
||||
`,
|
||||
|
||||
container: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
`,
|
||||
|
||||
node: css`
|
||||
fill: ${cssVar.colorTextSecondary};
|
||||
animation: ${pulseAnim} 2s infinite;
|
||||
`,
|
||||
|
||||
particle: css`
|
||||
fill: ${cssVar.colorTextSecondary};
|
||||
animation: ${flowAnim} 2s infinite;
|
||||
`,
|
||||
|
||||
ring: css`
|
||||
transform-origin: center;
|
||||
|
||||
fill: none;
|
||||
stroke: ${cssVar.colorFill};
|
||||
stroke-dasharray: 0 8;
|
||||
stroke-width: 1;
|
||||
|
||||
animation: ${rotateAnim} 20s infinite linear;
|
||||
`,
|
||||
|
||||
svg: css`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
`,
|
||||
}));
|
||||
|
||||
interface NeuralNetworkLoadingProps {
|
||||
size?: number;
|
||||
}
|
||||
|
||||
const NeuralNetworkLoading = memo<NeuralNetworkLoadingProps>(({ size = 16 }) => {
|
||||
const nodeCount = 3;
|
||||
const layerCount = 3;
|
||||
|
||||
// Generate nodes for each layer
|
||||
const nodes = [];
|
||||
for (let layerIndex = 0; layerIndex < layerCount; layerIndex++) {
|
||||
for (let nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) {
|
||||
const x = 25 + layerIndex * 25;
|
||||
const y = 25 + nodeIndex * 25;
|
||||
const delay = (layerIndex * nodeCount + nodeIndex) * 0.2;
|
||||
nodes.push(
|
||||
<circle
|
||||
className={styles.node}
|
||||
cx={x}
|
||||
cy={y}
|
||||
key={`node-${layerIndex}-${nodeIndex}`}
|
||||
r="3"
|
||||
style={{ animationDelay: `${delay}s` }}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate connections between layers
|
||||
const connections = [];
|
||||
for (let layerIndex = 0; layerIndex < layerCount - 1; layerIndex++) {
|
||||
for (let nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) {
|
||||
const x1 = 25 + layerIndex * 25;
|
||||
const y1 = 25 + nodeIndex * 25;
|
||||
for (let targetIndex = 0; targetIndex < nodeCount; targetIndex++) {
|
||||
const x2 = 25 + (layerIndex + 1) * 25;
|
||||
const y2 = 25 + targetIndex * 25;
|
||||
connections.push(
|
||||
<line
|
||||
className={styles.connection}
|
||||
key={`connection-${layerIndex}-${nodeIndex}-${targetIndex}`}
|
||||
x1={x1}
|
||||
x2={x2}
|
||||
y1={y1}
|
||||
y2={y2}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate particles
|
||||
const particles = [0, 1, 2].map((index) => (
|
||||
<circle
|
||||
className={styles.particle}
|
||||
cx={25}
|
||||
cy={50}
|
||||
key={`particle-${index}`}
|
||||
r="1.5"
|
||||
style={
|
||||
{
|
||||
'--flow-distance': '50px',
|
||||
'animationDelay': `${index * 0.6}s`,
|
||||
} as CSSProperties
|
||||
}
|
||||
/>
|
||||
));
|
||||
|
||||
return (
|
||||
<div className={styles.container} style={{ height: size, width: size }}>
|
||||
<svg className={styles.svg} viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
{/* Connections */}
|
||||
{connections}
|
||||
|
||||
{/* Nodes */}
|
||||
{nodes}
|
||||
|
||||
{/* Particles */}
|
||||
{particles}
|
||||
|
||||
{/* Central processing unit */}
|
||||
<rect className={styles.center} height="6" width="6" x="47" y="47" />
|
||||
|
||||
{/* Rotating outer ring */}
|
||||
<circle className={styles.ring} cx="50" cy="50" r="40" />
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default NeuralNetworkLoading;
|
||||
@@ -1,6 +1,5 @@
|
||||
import useSWR, { type SWRHook } from 'swr';
|
||||
|
||||
import { isDesktop } from '@/const/version';
|
||||
|
||||
/**
|
||||
* This type of request method is relatively flexible data, which will be triggered on the first time
|
||||
@@ -27,13 +26,7 @@ export const useClientDataSWR: SWRHook = (key, fetch, config) =>
|
||||
// Cause issue like this: https://github.com/lobehub/lobe-chat/issues/532
|
||||
// we need to set it to 0.
|
||||
dedupingInterval: 0,
|
||||
focusThrottleInterval:
|
||||
// FIXME: desktop 云同步模式也是走 edge 请求,也应该增大延迟
|
||||
// desktop 1.5s
|
||||
isDesktop
|
||||
? 1500
|
||||
: // web 300s
|
||||
5 * 60 * 1000,
|
||||
focusThrottleInterval: 5 * 60 * 1000,
|
||||
// Custom error retry logic: don't retry on 401 errors
|
||||
onErrorRetry: (error: any, key: any, config: any, revalidate: any, { retryCount }: any) => {
|
||||
// Check if error is marked as non-retryable (e.g., 401 authentication errors)
|
||||
|
||||
@@ -7,16 +7,17 @@ import {
|
||||
GroupManagementManifest,
|
||||
} from '@lobechat/builtin-tool-group-management/client';
|
||||
import { GTDInspectors, GTDManifest } from '@lobechat/builtin-tool-gtd/client';
|
||||
import { LocalSystemManifest } from '@lobechat/builtin-tool-local-system';
|
||||
import { PageAgentIdentifier, PageAgentInspectors } from '@lobechat/builtin-tool-page-agent/client';
|
||||
import {
|
||||
LocalSystemInspectors,
|
||||
LocalSystemManifest,
|
||||
} from '@lobechat/builtin-tool-local-system/client';
|
||||
import { PageAgentInspectors, PageAgentManifest } from '@lobechat/builtin-tool-page-agent/client';
|
||||
import {
|
||||
WebBrowsingInspectors,
|
||||
WebBrowsingManifest,
|
||||
} from '@lobechat/builtin-tool-web-browsing/client';
|
||||
import { type BuiltinInspector } from '@lobechat/types';
|
||||
|
||||
import { LocalSystemInspectors } from './local-system/Inspector';
|
||||
|
||||
/**
|
||||
* Builtin tools inspector registry
|
||||
* Organized by toolset (identifier) -> API name
|
||||
@@ -32,7 +33,7 @@ const BuiltinToolInspectors: Record<string, Record<string, BuiltinInspector>> =
|
||||
>,
|
||||
[GTDManifest.identifier]: GTDInspectors as Record<string, BuiltinInspector>,
|
||||
[LocalSystemManifest.identifier]: LocalSystemInspectors as Record<string, BuiltinInspector>,
|
||||
[PageAgentIdentifier]: PageAgentInspectors as Record<string, BuiltinInspector>,
|
||||
[PageAgentManifest.identifier]: PageAgentInspectors as Record<string, BuiltinInspector>,
|
||||
[WebBrowsingManifest.identifier]: WebBrowsingInspectors as Record<string, BuiltinInspector>,
|
||||
};
|
||||
|
||||
|
||||
@@ -9,13 +9,14 @@ import {
|
||||
GroupManagementManifest,
|
||||
} from '@lobechat/builtin-tool-group-management/client';
|
||||
import { GTDInterventions, GTDManifest } from '@lobechat/builtin-tool-gtd/client';
|
||||
import { LocalSystemManifest } from '@lobechat/builtin-tool-local-system';
|
||||
import {
|
||||
LocalSystemIdentifier,
|
||||
LocalSystemInterventions,
|
||||
} from '@lobechat/builtin-tool-local-system/client';
|
||||
import { NotebookManifest } from '@lobechat/builtin-tool-notebook';
|
||||
import { NotebookInterventions } from '@lobechat/builtin-tool-notebook/client';
|
||||
import { type BuiltinIntervention } from '@lobechat/types';
|
||||
|
||||
import { LocalSystemInterventions } from './local-system/Intervention';
|
||||
|
||||
/**
|
||||
* Builtin tools interventions registry
|
||||
* Organized by toolset (identifier) -> API name
|
||||
@@ -26,7 +27,7 @@ export const BuiltinToolInterventions: Record<string, Record<string, any>> = {
|
||||
[CloudSandboxManifest.identifier]: CloudSandboxInterventions,
|
||||
[GroupManagementManifest.identifier]: GroupManagementInterventions,
|
||||
[GTDManifest.identifier]: GTDInterventions,
|
||||
[LocalSystemManifest.identifier]: LocalSystemInterventions,
|
||||
[LocalSystemIdentifier]: LocalSystemInterventions,
|
||||
[NotebookManifest.identifier]: NotebookInterventions,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { type EditLocalFileState } from '@lobechat/builtin-tool-local-system';
|
||||
import { type EditLocalFileParams } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import path from 'path-browserify-esm';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
content: css`
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
`,
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
}));
|
||||
|
||||
export const EditLocalFileInspector = memo<
|
||||
BuiltinInspectorProps<EditLocalFileParams, EditLocalFileState>
|
||||
>(({ args, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
// Show filename with parent directory for context
|
||||
let displayPath = '';
|
||||
if (args?.file_path) {
|
||||
const { base, dir } = path.parse(args.file_path);
|
||||
const parentDir = path.basename(dir);
|
||||
displayPath = parentDir ? `${parentDir}/${base}` : base;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.editLocalFile')}</span>
|
||||
{displayPath && (
|
||||
<>
|
||||
<Icon icon={ChevronRight} style={{ marginInline: 4 }} />
|
||||
<span className={styles.content}>{displayPath}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
EditLocalFileInspector.displayName = 'EditLocalFileInspector';
|
||||
@@ -1,59 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { type GlobFilesState } from '@lobechat/builtin-tool-local-system';
|
||||
import { type GlobFilesParams } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
content: css`
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
`,
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
}));
|
||||
|
||||
export const GlobLocalFilesInspector = memo<BuiltinInspectorProps<GlobFilesParams, GlobFilesState>>(
|
||||
({ args, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
const pattern = args?.pattern || '';
|
||||
|
||||
// When loading, show "本地系统 > 匹配搜索文件"
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.title')}</span>
|
||||
<Icon icon={ChevronRight} style={{ marginInline: 4 }} />
|
||||
<span>{t('builtins.lobe-local-system.apiName.globLocalFiles')}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.globLocalFiles')}</span>
|
||||
{pattern && (
|
||||
<>
|
||||
<Icon icon={ChevronRight} style={{ marginInline: 4 }} />
|
||||
<span className={styles.content}>{pattern}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
GlobLocalFilesInspector.displayName = 'GlobLocalFilesInspector';
|
||||
@@ -1,59 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { type GrepContentState } from '@lobechat/builtin-tool-local-system';
|
||||
import { type GrepContentParams } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
content: css`
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
`,
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
}));
|
||||
|
||||
export const GrepContentInspector = memo<
|
||||
BuiltinInspectorProps<GrepContentParams, GrepContentState>
|
||||
>(({ args, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
const pattern = args?.pattern || '';
|
||||
|
||||
// When loading, show "本地系统 > 搜索内容"
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.title')}</span>
|
||||
<Icon icon={ChevronRight} style={{ marginInline: 4 }} />
|
||||
<span>{t('builtins.lobe-local-system.apiName.grepContent')}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.grepContent')}</span>
|
||||
{pattern && (
|
||||
<>
|
||||
<Icon icon={ChevronRight} style={{ marginInline: 4 }} />
|
||||
<span className={styles.content}>{pattern}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
GrepContentInspector.displayName = 'GrepContentInspector';
|
||||
@@ -1,55 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import type { LocalReadFileState } from '@lobechat/builtin-tool-local-system';
|
||||
import { type LocalReadFileParams } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import path from 'path-browserify-esm';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
content: css`
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
`,
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
}));
|
||||
|
||||
export const ReadLocalFileInspector = memo<
|
||||
BuiltinInspectorProps<LocalReadFileParams, LocalReadFileState>
|
||||
>(({ args, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
// Show filename with parent directory for context
|
||||
let displayPath = '';
|
||||
if (args?.path) {
|
||||
const { base, dir } = path.parse(args.path);
|
||||
const parentDir = path.basename(dir);
|
||||
displayPath = parentDir ? `${parentDir}/${base}` : base;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx(styles.root, isLoading && shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.readLocalFile')}</span>
|
||||
{displayPath && (
|
||||
<>
|
||||
<Icon icon={ChevronRight} style={{ marginInline: 4 }} />
|
||||
<span className={styles.content}>{displayPath}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
ReadLocalFileInspector.displayName = 'ReadLocalFileInspector';
|
||||
@@ -1,66 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { type RunCommandParams, type RunCommandResult } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
content: css`
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
`,
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
}));
|
||||
|
||||
interface RunCommandState {
|
||||
message: string;
|
||||
result: RunCommandResult;
|
||||
}
|
||||
|
||||
export const RunCommandInspector = memo<BuiltinInspectorProps<RunCommandParams, RunCommandState>>(
|
||||
({ args, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
// Show description if available, otherwise show command
|
||||
const displayText = args?.description || args?.command || '';
|
||||
|
||||
// When loading, show "Local System > 执行命令"
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.title')}</span>
|
||||
<Icon icon={ChevronRight} style={{ marginInline: 4 }} />
|
||||
<span>{t('builtins.lobe-local-system.apiName.runCommand')}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.runCommand')}</span>
|
||||
{displayText && (
|
||||
<>
|
||||
<Icon icon={ChevronRight} style={{ marginInline: 4 }} />
|
||||
<span className={styles.content}>{displayText}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
RunCommandInspector.displayName = 'RunCommandInspector';
|
||||
|
||||
export default RunCommandInspector;
|
||||
@@ -1,59 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { type LocalFileSearchState } from '@lobechat/builtin-tool-local-system';
|
||||
import { type LocalSearchFilesParams } from '@lobechat/electron-client-ipc';
|
||||
import { type BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
content: css`
|
||||
font-family: ${cssVar.fontFamilyCode};
|
||||
`,
|
||||
root: css`
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
||||
color: ${cssVar.colorTextDescription};
|
||||
`,
|
||||
}));
|
||||
|
||||
export const SearchLocalFilesInspector = memo<
|
||||
BuiltinInspectorProps<LocalSearchFilesParams, LocalFileSearchState>
|
||||
>(({ args, isLoading }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
const keywords = args?.keywords || '';
|
||||
|
||||
// When loading, show "本地系统 > 搜索文件"
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{t('builtins.lobe-local-system.title')}</span>
|
||||
<Icon icon={ChevronRight} style={{ marginInline: 4 }} />
|
||||
<span>{t('builtins.lobe-local-system.apiName.searchLocalFiles')}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<span>{t('builtins.lobe-local-system.apiName.searchLocalFiles')}</span>
|
||||
{keywords && (
|
||||
<>
|
||||
<Icon icon={ChevronRight} style={{ marginInline: 4 }} />
|
||||
<span className={styles.content}>{keywords}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
SearchLocalFilesInspector.displayName = 'SearchLocalFilesInspector';
|
||||
@@ -1,21 +1,23 @@
|
||||
import { LocalSystemApiName, LocalSystemManifest } from '@lobechat/builtin-tool-local-system';
|
||||
import {
|
||||
LocalSystemApiName,
|
||||
LocalSystemIdentifier,
|
||||
LocalSystemListFilesPlaceholder,
|
||||
LocalSystemSearchFilesPlaceholder,
|
||||
} from '@lobechat/builtin-tool-local-system/client';
|
||||
import {
|
||||
WebBrowsingManifest,
|
||||
WebBrowsingPlaceholders,
|
||||
} from '@lobechat/builtin-tool-web-browsing/client';
|
||||
import { type BuiltinPlaceholder } from '@lobechat/types';
|
||||
|
||||
import { ListFiles as LocalSystemListFiles } from './local-system/Placeholder/ListFiles';
|
||||
import LocalSystemSearchFiles from './local-system/Placeholder/SearchFiles';
|
||||
|
||||
/**
|
||||
* Builtin tools placeholders registry
|
||||
* Organized by toolset (identifier) -> API name
|
||||
*/
|
||||
export const BuiltinToolPlaceholders: Record<string, Record<string, any>> = {
|
||||
[LocalSystemManifest.identifier]: {
|
||||
[LocalSystemApiName.searchLocalFiles]: LocalSystemSearchFiles,
|
||||
[LocalSystemApiName.listLocalFiles]: LocalSystemListFiles,
|
||||
[LocalSystemIdentifier]: {
|
||||
[LocalSystemApiName.searchLocalFiles]: LocalSystemSearchFilesPlaceholder,
|
||||
[LocalSystemApiName.listLocalFiles]: LocalSystemListFilesPlaceholder,
|
||||
},
|
||||
[WebBrowsingManifest.identifier]: WebBrowsingPlaceholders as Record<string, any>,
|
||||
};
|
||||
|
||||
@@ -10,7 +10,10 @@ import { GroupManagementRenders } from '@lobechat/builtin-tool-group-management/
|
||||
// gtd
|
||||
import { GTDManifest, GTDRenders } from '@lobechat/builtin-tool-gtd/client';
|
||||
// local-system
|
||||
import { LocalSystemManifest } from '@lobechat/builtin-tool-local-system';
|
||||
import {
|
||||
LocalSystemIdentifier,
|
||||
LocalSystemRenders,
|
||||
} from '@lobechat/builtin-tool-local-system/client';
|
||||
import { NotebookManifest, NotebookRenders } from '@lobechat/builtin-tool-notebook/client';
|
||||
// web-browsing
|
||||
import {
|
||||
@@ -22,7 +25,6 @@ import { type BuiltinRender } from '@lobechat/types';
|
||||
// knowledge-base
|
||||
import { KnowledgeBaseManifest } from './knowledge-base';
|
||||
import { KnowledgeBaseRenders } from './knowledge-base/Render';
|
||||
import { LocalSystemRenders } from './local-system/Render';
|
||||
|
||||
/**
|
||||
* Builtin tools renders registry
|
||||
@@ -35,7 +37,7 @@ const BuiltinToolsRenders: Record<string, Record<string, BuiltinRender>> = {
|
||||
[GTDManifest.identifier]: GTDRenders as Record<string, BuiltinRender>,
|
||||
[NotebookManifest.identifier]: NotebookRenders as Record<string, BuiltinRender>,
|
||||
[KnowledgeBaseManifest.identifier]: KnowledgeBaseRenders as Record<string, BuiltinRender>,
|
||||
[LocalSystemManifest.identifier]: LocalSystemRenders as Record<string, BuiltinRender>,
|
||||
[LocalSystemIdentifier]: LocalSystemRenders as Record<string, BuiltinRender>,
|
||||
[WebBrowsingManifest.identifier]: WebBrowsingRenders as Record<string, BuiltinRender>,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
CloudSandboxIdentifier,
|
||||
CloudSandboxManifest,
|
||||
CloudSandboxStreamings,
|
||||
} from '@lobechat/builtin-tool-cloud-sandbox/client';
|
||||
import {
|
||||
@@ -7,11 +7,12 @@ import {
|
||||
GroupManagementStreamings,
|
||||
} from '@lobechat/builtin-tool-group-management/client';
|
||||
import { GTDManifest, GTDStreamings } from '@lobechat/builtin-tool-gtd/client';
|
||||
import { LocalSystemManifest } from '@lobechat/builtin-tool-local-system';
|
||||
import {
|
||||
LocalSystemManifest,
|
||||
LocalSystemStreamings,
|
||||
} from '@lobechat/builtin-tool-local-system/client';
|
||||
import { type BuiltinStreaming } from '@lobechat/types';
|
||||
|
||||
import { LocalSystemStreamings } from './local-system/Streaming';
|
||||
|
||||
/**
|
||||
* Builtin tools streaming renderer registry
|
||||
* Organized by toolset (identifier) -> API name
|
||||
@@ -21,7 +22,7 @@ import { LocalSystemStreamings } from './local-system/Streaming';
|
||||
* The component should fetch streaming content from store internally.
|
||||
*/
|
||||
const BuiltinToolStreamings: Record<string, Record<string, BuiltinStreaming>> = {
|
||||
[CloudSandboxIdentifier]: CloudSandboxStreamings as Record<string, BuiltinStreaming>,
|
||||
[CloudSandboxManifest.identifier]: CloudSandboxStreamings as Record<string, BuiltinStreaming>,
|
||||
[GroupManagementManifest.identifier]: GroupManagementStreamings as Record<
|
||||
string,
|
||||
BuiltinStreaming
|
||||
|
||||
Reference in New Issue
Block a user