@lobehub/lobehub 2.0.0-next.23 → 2.0.0-next.25
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 +50 -0
- package/changelog/v1.json +18 -0
- package/locales/ar/labs.json +4 -0
- package/locales/bg-BG/labs.json +4 -0
- package/locales/de-DE/labs.json +4 -0
- package/locales/en-US/labs.json +4 -0
- package/locales/es-ES/labs.json +4 -0
- package/locales/fa-IR/labs.json +4 -0
- package/locales/fr-FR/labs.json +4 -0
- package/locales/it-IT/labs.json +4 -0
- package/locales/ja-JP/labs.json +4 -0
- package/locales/ko-KR/labs.json +4 -0
- package/locales/nl-NL/labs.json +4 -0
- package/locales/pl-PL/labs.json +4 -0
- package/locales/pt-BR/labs.json +4 -0
- package/locales/ru-RU/labs.json +4 -0
- package/locales/tr-TR/labs.json +4 -0
- package/locales/vi-VN/labs.json +4 -0
- package/locales/zh-CN/labs.json +4 -0
- package/locales/zh-TW/labs.json +4 -0
- package/package.json +1 -1
- package/packages/const/src/user.ts +5 -2
- package/packages/types/src/index.ts +0 -1
- package/packages/types/src/user/index.ts +2 -88
- package/packages/types/src/user/preference.ts +105 -0
- package/renovate.json +1 -6
- package/src/app/[variants]/(main)/labs/components/LabCard.tsx +5 -5
- package/src/app/[variants]/(main)/labs/page.tsx +19 -22
- package/src/app/[variants]/(main)/settings/provider/detail/azure/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/provider/detail/azureai/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/provider/detail/bedrock/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/provider/detail/cloudflare/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/provider/detail/comfyui/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/provider/detail/github/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/provider/detail/vertexai/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +2 -4
- package/src/components/Skeleton/SkeletonSwitch.tsx +13 -0
- package/src/components/Skeleton/index.ts +2 -0
- package/src/features/ChatInput/ActionBar/index.tsx +2 -2
- package/src/features/ChatInput/InputEditor/index.tsx +2 -2
- package/src/features/Conversation/Messages/Group/Actions/WithContentId.tsx +152 -0
- package/src/features/Conversation/Messages/Group/Actions/WithoutContentId.tsx +70 -0
- package/src/features/Conversation/Messages/Group/Actions/index.tsx +21 -0
- package/src/features/Conversation/Messages/Group/ContentBlock.tsx +91 -0
- package/src/features/Conversation/Messages/Group/EditState.tsx +51 -0
- package/src/features/Conversation/Messages/Group/Error/index.tsx +53 -0
- package/src/features/Conversation/Messages/Group/GroupChildren.tsx +73 -0
- package/src/features/Conversation/Messages/Group/MessageContent.tsx +39 -0
- package/src/features/Conversation/Messages/Group/Tool/Inspector/BuiltinPluginTitle.tsx +49 -0
- package/src/features/Conversation/Messages/Group/Tool/Inspector/Debug.tsx +70 -0
- package/src/features/Conversation/Messages/Group/Tool/Inspector/PluginResult.tsx +34 -0
- package/src/features/Conversation/Messages/Group/Tool/Inspector/PluginState.tsx +18 -0
- package/src/features/Conversation/Messages/Group/Tool/Inspector/Settings.tsx +40 -0
- package/src/features/Conversation/Messages/Group/Tool/Inspector/ToolTitle.tsx +92 -0
- package/src/features/Conversation/Messages/Group/Tool/Inspector/index.tsx +176 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Arguments/ObjectEntity.tsx +81 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Arguments/ValueCell.tsx +43 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Arguments/index.tsx +134 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/CustomRender.tsx +88 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/ErrorResponse.tsx +35 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/LoadingPlaceholder/index.tsx +29 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/PluginSettings.tsx +66 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/index.tsx +105 -0
- package/src/features/Conversation/Messages/Group/Tool/index.tsx +75 -0
- package/src/features/Conversation/Messages/Group/Tools.tsx +46 -0
- package/src/features/Conversation/Messages/Group/index.tsx +140 -0
- package/src/features/Conversation/Messages/index.tsx +12 -0
- package/src/features/Conversation/components/ShareMessageModal/ShareImage/Preview.tsx +2 -2
- package/src/locales/default/labs.ts +4 -0
- package/src/server/routers/lambda/message.ts +5 -20
- package/src/services/chat/contextEngineering.ts +6 -5
- package/src/services/message/server.ts +10 -10
- package/src/services/message/type.ts +0 -2
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +309 -2
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +2 -22
- package/src/store/chat/slices/aiChat/actions/generateAIChatV2.ts +272 -14
- package/src/store/user/selectors.ts +1 -1
- package/src/store/user/slices/preference/action.ts +8 -1
- package/src/store/user/slices/preference/selectors/index.ts +2 -0
- package/src/store/user/slices/preference/selectors/labPrefer.ts +13 -0
- package/src/store/user/slices/preference/{selectors.ts → selectors/preference.ts} +0 -2
- /package/src/{app/[variants]/(main)/settings/provider/features/ProviderConfig → components/Skeleton}/SkeletonInput.tsx +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { copyToClipboard } from '@lobehub/ui';
|
|
2
|
+
import { App } from 'antd';
|
|
3
|
+
import { createStyles } from 'antd-style';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
|
|
7
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
8
|
+
copyable: css`
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
width: 100%;
|
|
11
|
+
margin-block: 2px;
|
|
12
|
+
padding: 4px;
|
|
13
|
+
|
|
14
|
+
&:hover {
|
|
15
|
+
border-radius: 6px;
|
|
16
|
+
background: ${token.colorFillTertiary};
|
|
17
|
+
}
|
|
18
|
+
`,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
interface ValueCellProps {
|
|
22
|
+
value: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const ValueCell = memo<ValueCellProps>(({ value }) => {
|
|
26
|
+
const { message } = App.useApp();
|
|
27
|
+
const { t } = useTranslation('common');
|
|
28
|
+
const { styles } = useStyles();
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
className={styles.copyable}
|
|
33
|
+
onClick={async () => {
|
|
34
|
+
await copyToClipboard(value);
|
|
35
|
+
message.success(t('copySuccess'));
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
{value}
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export default ValueCell;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Highlighter } from '@lobehub/ui';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
import { parse } from 'partial-json';
|
|
4
|
+
import { ReactNode, memo, useMemo } from 'react';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import { useYamlArguments } from '@/hooks/useYamlArguments';
|
|
8
|
+
|
|
9
|
+
import ObjectEntity from './ObjectEntity';
|
|
10
|
+
|
|
11
|
+
const useStyles = createStyles(({ css, token, cx }) => ({
|
|
12
|
+
button: css`
|
|
13
|
+
color: ${token.colorTextSecondary};
|
|
14
|
+
|
|
15
|
+
&:hover {
|
|
16
|
+
color: ${token.colorText};
|
|
17
|
+
}
|
|
18
|
+
`,
|
|
19
|
+
codeContainer: css`
|
|
20
|
+
border-radius: ${token.borderRadiusLG}px;
|
|
21
|
+
`,
|
|
22
|
+
container: css`
|
|
23
|
+
position: relative;
|
|
24
|
+
|
|
25
|
+
overflow: auto;
|
|
26
|
+
|
|
27
|
+
max-height: 200px;
|
|
28
|
+
padding-block: 4px;
|
|
29
|
+
padding-inline: 12px 64px;
|
|
30
|
+
border-radius: ${token.borderRadiusLG}px;
|
|
31
|
+
|
|
32
|
+
font-family: ${token.fontFamilyCode};
|
|
33
|
+
font-size: 13px;
|
|
34
|
+
line-height: 1.5;
|
|
35
|
+
|
|
36
|
+
background: ${token.colorFillQuaternary};
|
|
37
|
+
|
|
38
|
+
pre {
|
|
39
|
+
margin: 0 !important;
|
|
40
|
+
background: none !important;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&:hover {
|
|
44
|
+
.actions {
|
|
45
|
+
opacity: 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
`,
|
|
49
|
+
editButton: cx(
|
|
50
|
+
'actions',
|
|
51
|
+
css`
|
|
52
|
+
position: absolute;
|
|
53
|
+
z-index: 10;
|
|
54
|
+
inset-block-start: 4px;
|
|
55
|
+
inset-inline-end: 4px;
|
|
56
|
+
|
|
57
|
+
opacity: 0;
|
|
58
|
+
|
|
59
|
+
transition: opacity 0.2s ${token.motionEaseInOut};
|
|
60
|
+
`,
|
|
61
|
+
),
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
export interface ArgumentsProps {
|
|
65
|
+
actions?: ReactNode;
|
|
66
|
+
arguments?: string;
|
|
67
|
+
shine?: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const Arguments = memo<ArgumentsProps>(({ arguments: args = '', shine, actions }) => {
|
|
71
|
+
const { styles } = useStyles();
|
|
72
|
+
|
|
73
|
+
const displayArgs = useMemo(() => {
|
|
74
|
+
try {
|
|
75
|
+
const obj = parse(args);
|
|
76
|
+
if (Object.keys(obj).length === 0) return {};
|
|
77
|
+
return obj;
|
|
78
|
+
} catch {
|
|
79
|
+
return args;
|
|
80
|
+
}
|
|
81
|
+
}, [args]);
|
|
82
|
+
|
|
83
|
+
const yaml = useYamlArguments(args);
|
|
84
|
+
|
|
85
|
+
const showActions = !!actions;
|
|
86
|
+
|
|
87
|
+
if (typeof displayArgs === 'string') {
|
|
88
|
+
return (
|
|
89
|
+
!!yaml && (
|
|
90
|
+
<div className={styles.container}>
|
|
91
|
+
<Highlighter language={'yaml'} showLanguage={false}>
|
|
92
|
+
{yaml}
|
|
93
|
+
</Highlighter>
|
|
94
|
+
</div>
|
|
95
|
+
)
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// if (args.length > 100) {
|
|
100
|
+
// return (
|
|
101
|
+
// <Highlighter language={'json'} showLanguage={false} variant={'filled'}>
|
|
102
|
+
// {JSON.stringify(displayArgs, null, 2)}
|
|
103
|
+
// </Highlighter>
|
|
104
|
+
// );
|
|
105
|
+
// }
|
|
106
|
+
|
|
107
|
+
const hasMinWidth = Object.keys(displayArgs).length > 1;
|
|
108
|
+
|
|
109
|
+
if (Object.keys(displayArgs).length === 0) return null;
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<div className={styles.container}>
|
|
113
|
+
{showActions && (
|
|
114
|
+
<Flexbox className={styles.editButton} gap={4} horizontal>
|
|
115
|
+
{actions}
|
|
116
|
+
</Flexbox>
|
|
117
|
+
)}
|
|
118
|
+
{Object.entries(displayArgs).map(([key, value]) => {
|
|
119
|
+
return (
|
|
120
|
+
<ObjectEntity
|
|
121
|
+
editable={false}
|
|
122
|
+
hasMinWidth={hasMinWidth}
|
|
123
|
+
key={key}
|
|
124
|
+
objectKey={key}
|
|
125
|
+
shine={shine}
|
|
126
|
+
value={value}
|
|
127
|
+
/>
|
|
128
|
+
);
|
|
129
|
+
})}
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
export default Arguments;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ChatPluginPayload } from '@lobechat/types';
|
|
2
|
+
import { Highlighter } from '@lobehub/ui';
|
|
3
|
+
import { memo, useEffect, useMemo } from 'react';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import PluginRender from '@/features/PluginsUI/Render';
|
|
7
|
+
|
|
8
|
+
import Arguments from './Arguments';
|
|
9
|
+
|
|
10
|
+
interface CustomRenderProps {
|
|
11
|
+
content: string;
|
|
12
|
+
id: string;
|
|
13
|
+
plugin?: ChatPluginPayload;
|
|
14
|
+
pluginState?: any;
|
|
15
|
+
requestArgs?: string;
|
|
16
|
+
setShowPluginRender: (value: boolean) => void;
|
|
17
|
+
showPluginRender: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Custom Render for Group Messages
|
|
22
|
+
*
|
|
23
|
+
* Group messages are already completed, so:
|
|
24
|
+
* - No loading state needed
|
|
25
|
+
* - No edit/re-run functionality
|
|
26
|
+
* - Results are directly available in content prop
|
|
27
|
+
*/
|
|
28
|
+
const CustomRender = memo<CustomRenderProps>(
|
|
29
|
+
({ id, content, pluginState, plugin, requestArgs, showPluginRender, setShowPluginRender }) => {
|
|
30
|
+
// Determine if plugin UI should be shown based on plugin type
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!plugin?.type) return;
|
|
33
|
+
setShowPluginRender(!['default', 'mcp'].includes(plugin.type));
|
|
34
|
+
}, [plugin?.type, setShowPluginRender]);
|
|
35
|
+
|
|
36
|
+
// Parse and display result content
|
|
37
|
+
const { data, language } = useMemo(() => {
|
|
38
|
+
try {
|
|
39
|
+
const parsed = JSON.parse(content || '');
|
|
40
|
+
// If parsed result is a string, return it directly
|
|
41
|
+
if (typeof parsed === 'string') {
|
|
42
|
+
return { data: parsed, language: 'plaintext' };
|
|
43
|
+
}
|
|
44
|
+
return { data: JSON.stringify(parsed, null, 2), language: 'json' };
|
|
45
|
+
} catch {
|
|
46
|
+
return { data: content || '', language: 'plaintext' };
|
|
47
|
+
}
|
|
48
|
+
}, [content]);
|
|
49
|
+
|
|
50
|
+
// Show plugin custom UI if applicable
|
|
51
|
+
if (showPluginRender) {
|
|
52
|
+
return (
|
|
53
|
+
<Flexbox gap={12} id={id} width={'100%'}>
|
|
54
|
+
<PluginRender
|
|
55
|
+
arguments={plugin?.arguments}
|
|
56
|
+
content={content}
|
|
57
|
+
id={id}
|
|
58
|
+
identifier={plugin?.identifier}
|
|
59
|
+
loading={false}
|
|
60
|
+
payload={plugin}
|
|
61
|
+
pluginState={pluginState}
|
|
62
|
+
type={plugin?.type}
|
|
63
|
+
/>
|
|
64
|
+
</Flexbox>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Default render: show arguments and result
|
|
69
|
+
return (
|
|
70
|
+
<Flexbox gap={12} id={id} width={'100%'}>
|
|
71
|
+
<Arguments arguments={requestArgs} />
|
|
72
|
+
{content && (
|
|
73
|
+
<Highlighter
|
|
74
|
+
language={language}
|
|
75
|
+
style={{ maxHeight: 200, overflow: 'scroll', width: '100%' }}
|
|
76
|
+
variant={'outlined'}
|
|
77
|
+
>
|
|
78
|
+
{data}
|
|
79
|
+
</Highlighter>
|
|
80
|
+
)}
|
|
81
|
+
</Flexbox>
|
|
82
|
+
);
|
|
83
|
+
},
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
CustomRender.displayName = 'GroupCustomRender';
|
|
87
|
+
|
|
88
|
+
export default CustomRender;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ChatMessageError, ChatPluginPayload } from '@lobechat/types';
|
|
2
|
+
import { Alert, Highlighter } from '@lobehub/ui';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import PluginSettings from './PluginSettings';
|
|
8
|
+
|
|
9
|
+
interface ErrorResponseProps extends ChatMessageError {
|
|
10
|
+
id: string;
|
|
11
|
+
plugin?: ChatPluginPayload;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const ErrorResponse = memo<ErrorResponseProps>(({ id, type, body, message, plugin }) => {
|
|
15
|
+
const { t } = useTranslation('error');
|
|
16
|
+
if (type === 'PluginSettingsInvalid') {
|
|
17
|
+
return <PluginSettings id={id} plugin={plugin} />;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Alert
|
|
22
|
+
extra={
|
|
23
|
+
<Flexbox>
|
|
24
|
+
<Highlighter actionIconSize={'small'} language={'json'} variant={'borderless'}>
|
|
25
|
+
{JSON.stringify(body || { message, type }, null, 2)}
|
|
26
|
+
</Highlighter>
|
|
27
|
+
</Flexbox>
|
|
28
|
+
}
|
|
29
|
+
message={t(`response.${type}` as any)}
|
|
30
|
+
showIcon
|
|
31
|
+
type={'error'}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
export default ErrorResponse;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { safeParseJSON } from '@lobechat/utils';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
|
|
4
|
+
import { BuiltinToolPlaceholders } from '@/tools/placeholders';
|
|
5
|
+
|
|
6
|
+
import Arguments from '../Arguments';
|
|
7
|
+
|
|
8
|
+
interface LoadingPlaceholderProps {
|
|
9
|
+
apiName: string;
|
|
10
|
+
identifier: string;
|
|
11
|
+
loading?: boolean;
|
|
12
|
+
requestArgs?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const LoadingPlaceholder = memo<LoadingPlaceholderProps>(
|
|
16
|
+
({ identifier, requestArgs, apiName, loading }) => {
|
|
17
|
+
const Render = BuiltinToolPlaceholders[identifier || ''];
|
|
18
|
+
|
|
19
|
+
if (identifier && Render) {
|
|
20
|
+
return (
|
|
21
|
+
<Render apiName={apiName} args={safeParseJSON(requestArgs) || {}} identifier={identifier} />
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return <Arguments arguments={requestArgs} shine={loading} />;
|
|
26
|
+
},
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export default LoadingPlaceholder;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ChatPluginPayload } from '@lobechat/types';
|
|
2
|
+
import { Avatar, Button } from '@lobehub/ui';
|
|
3
|
+
import { Divider } from 'antd';
|
|
4
|
+
import { useTheme } from 'antd-style';
|
|
5
|
+
import isEqual from 'fast-deep-equal';
|
|
6
|
+
import { memo } from 'react';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
|
9
|
+
|
|
10
|
+
import PluginSettingsConfig from '@/features/PluginSettings';
|
|
11
|
+
import { useChatStore } from '@/store/chat';
|
|
12
|
+
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
13
|
+
import { pluginSelectors } from '@/store/tool/selectors';
|
|
14
|
+
|
|
15
|
+
import { ErrorActionContainer, useStyles } from '../../../../Error/style';
|
|
16
|
+
|
|
17
|
+
interface PluginSettingsProps {
|
|
18
|
+
id: string;
|
|
19
|
+
plugin?: ChatPluginPayload;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const PluginSettings = memo<PluginSettingsProps>(({ id, plugin }) => {
|
|
23
|
+
const { styles } = useStyles();
|
|
24
|
+
const { t } = useTranslation('error');
|
|
25
|
+
const theme = useTheme();
|
|
26
|
+
const [resend, deleteMessage] = useChatStore((s) => [s.regenerateMessage, s.deleteMessage]);
|
|
27
|
+
const pluginIdentifier = plugin?.identifier as string;
|
|
28
|
+
const pluginMeta = useToolStore(pluginSelectors.getPluginMetaById(pluginIdentifier), isEqual);
|
|
29
|
+
const manifest = useToolStore(pluginSelectors.getToolManifestById(pluginIdentifier), isEqual);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
!!manifest && (
|
|
33
|
+
<ErrorActionContainer>
|
|
34
|
+
<Center gap={16} style={{ maxWidth: 400 }}>
|
|
35
|
+
<Avatar
|
|
36
|
+
avatar={pluginHelpers.getPluginAvatar(pluginMeta) || '⚙️'}
|
|
37
|
+
background={theme.colorFillContent}
|
|
38
|
+
gap={12}
|
|
39
|
+
size={80}
|
|
40
|
+
/>
|
|
41
|
+
<Flexbox style={{ fontSize: 20 }}>
|
|
42
|
+
{t('pluginSettings.title', { name: pluginHelpers.getPluginTitle(pluginMeta) })}
|
|
43
|
+
</Flexbox>
|
|
44
|
+
<Flexbox className={styles.desc}>{t('pluginSettings.desc')}</Flexbox>
|
|
45
|
+
<Divider style={{ margin: '0 16px' }} />
|
|
46
|
+
{manifest.settings && (
|
|
47
|
+
<PluginSettingsConfig id={manifest.identifier} schema={manifest.settings} />
|
|
48
|
+
)}
|
|
49
|
+
<Button
|
|
50
|
+
block
|
|
51
|
+
onClick={() => {
|
|
52
|
+
resend(id);
|
|
53
|
+
deleteMessage(id);
|
|
54
|
+
}}
|
|
55
|
+
style={{ marginTop: 8 }}
|
|
56
|
+
type={'primary'}
|
|
57
|
+
>
|
|
58
|
+
{t('unlock.confirm')}
|
|
59
|
+
</Button>
|
|
60
|
+
</Center>
|
|
61
|
+
</ErrorActionContainer>
|
|
62
|
+
)
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
export default PluginSettings;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { LOADING_FLAT } from '@lobechat/const';
|
|
2
|
+
import { ChatToolResult } from '@lobechat/types';
|
|
3
|
+
import { Suspense, memo } from 'react';
|
|
4
|
+
|
|
5
|
+
import CustomRender from './CustomRender';
|
|
6
|
+
import ErrorResponse from './ErrorResponse';
|
|
7
|
+
import LoadingPlaceholder from './LoadingPlaceholder';
|
|
8
|
+
|
|
9
|
+
interface RenderProps {
|
|
10
|
+
apiName: string;
|
|
11
|
+
arguments?: string;
|
|
12
|
+
identifier: string;
|
|
13
|
+
/**
|
|
14
|
+
* ContentBlock ID (not the group message ID)
|
|
15
|
+
*/
|
|
16
|
+
messageId: string;
|
|
17
|
+
result?: ChatToolResult;
|
|
18
|
+
setShowPluginRender: (show: boolean) => void;
|
|
19
|
+
showPluginRender: boolean;
|
|
20
|
+
toolCallId: string;
|
|
21
|
+
type?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Tool Render for Group Messages
|
|
26
|
+
*
|
|
27
|
+
* In group messages, tool results are already embedded in the payload,
|
|
28
|
+
* so we don't need to query them from the store or handle streaming.
|
|
29
|
+
*/
|
|
30
|
+
const Render = memo<RenderProps>(
|
|
31
|
+
({
|
|
32
|
+
toolCallId,
|
|
33
|
+
messageId,
|
|
34
|
+
arguments: requestArgs,
|
|
35
|
+
showPluginRender,
|
|
36
|
+
setShowPluginRender,
|
|
37
|
+
identifier,
|
|
38
|
+
apiName,
|
|
39
|
+
result,
|
|
40
|
+
type,
|
|
41
|
+
}) => {
|
|
42
|
+
if (!result) return null;
|
|
43
|
+
|
|
44
|
+
// Handle error state
|
|
45
|
+
if (result.error) {
|
|
46
|
+
return (
|
|
47
|
+
<ErrorResponse
|
|
48
|
+
{...result.error}
|
|
49
|
+
id={messageId}
|
|
50
|
+
plugin={
|
|
51
|
+
type
|
|
52
|
+
? ({
|
|
53
|
+
apiName,
|
|
54
|
+
arguments: requestArgs || '',
|
|
55
|
+
identifier,
|
|
56
|
+
type,
|
|
57
|
+
} as any)
|
|
58
|
+
: undefined
|
|
59
|
+
}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const placeholder = (
|
|
65
|
+
<LoadingPlaceholder
|
|
66
|
+
apiName={apiName}
|
|
67
|
+
identifier={identifier}
|
|
68
|
+
loading
|
|
69
|
+
requestArgs={requestArgs}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// Standalone plugins always have LOADING_FLAT as content
|
|
74
|
+
const inPlaceholder = result.content === LOADING_FLAT && type !== 'standalone';
|
|
75
|
+
|
|
76
|
+
if (inPlaceholder) return placeholder;
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Suspense fallback={placeholder}>
|
|
80
|
+
<CustomRender
|
|
81
|
+
content={result.content || ''}
|
|
82
|
+
id={toolCallId}
|
|
83
|
+
plugin={
|
|
84
|
+
type
|
|
85
|
+
? ({
|
|
86
|
+
apiName,
|
|
87
|
+
arguments: requestArgs || '',
|
|
88
|
+
identifier,
|
|
89
|
+
type,
|
|
90
|
+
} as any)
|
|
91
|
+
: undefined
|
|
92
|
+
}
|
|
93
|
+
pluginState={result.state}
|
|
94
|
+
requestArgs={requestArgs}
|
|
95
|
+
setShowPluginRender={setShowPluginRender}
|
|
96
|
+
showPluginRender={showPluginRender}
|
|
97
|
+
/>
|
|
98
|
+
</Suspense>
|
|
99
|
+
);
|
|
100
|
+
},
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
Render.displayName = 'GroupToolRender';
|
|
104
|
+
|
|
105
|
+
export default Render;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ChatToolResult } from '@lobechat/types';
|
|
2
|
+
import { CSSProperties, memo, useState } from 'react';
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
|
|
5
|
+
import AnimatedCollapsed from '@/components/AnimatedCollapsed';
|
|
6
|
+
|
|
7
|
+
import Inspectors from './Inspector';
|
|
8
|
+
import Render from './Render';
|
|
9
|
+
|
|
10
|
+
export interface GroupToolProps {
|
|
11
|
+
apiName: string;
|
|
12
|
+
arguments?: string;
|
|
13
|
+
id: string;
|
|
14
|
+
identifier: string;
|
|
15
|
+
index: number;
|
|
16
|
+
/**
|
|
17
|
+
* ContentBlock ID (not the group message ID)
|
|
18
|
+
*/
|
|
19
|
+
messageId: string;
|
|
20
|
+
result?: ChatToolResult;
|
|
21
|
+
style?: CSSProperties;
|
|
22
|
+
type?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Tool component for Group Messages
|
|
27
|
+
*
|
|
28
|
+
* In group messages, all tools are completed (no streaming),
|
|
29
|
+
* so we always show the results directly.
|
|
30
|
+
*/
|
|
31
|
+
const Tool = memo<GroupToolProps>(
|
|
32
|
+
({ arguments: requestArgs, apiName, messageId, id, index, identifier, style, result, type }) => {
|
|
33
|
+
// Default to false since group messages are all completed
|
|
34
|
+
const [showDetail, setShowDetail] = useState(false);
|
|
35
|
+
const [showPluginRender, setShowPluginRender] = useState(false);
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Flexbox gap={8} style={style}>
|
|
39
|
+
<Inspectors
|
|
40
|
+
apiName={apiName}
|
|
41
|
+
arguments={requestArgs}
|
|
42
|
+
// mcp don't have ui render
|
|
43
|
+
hidePluginUI={type === 'mcp'}
|
|
44
|
+
id={id}
|
|
45
|
+
identifier={identifier}
|
|
46
|
+
index={index}
|
|
47
|
+
messageId={messageId}
|
|
48
|
+
result={result}
|
|
49
|
+
setShowPluginRender={setShowPluginRender}
|
|
50
|
+
setShowRender={setShowDetail}
|
|
51
|
+
showPluginRender={showPluginRender}
|
|
52
|
+
showRender={showDetail}
|
|
53
|
+
type={type}
|
|
54
|
+
/>
|
|
55
|
+
<AnimatedCollapsed open={showDetail} width={{ collapsed: 'auto' }}>
|
|
56
|
+
<Render
|
|
57
|
+
apiName={apiName}
|
|
58
|
+
arguments={requestArgs}
|
|
59
|
+
identifier={identifier}
|
|
60
|
+
messageId={messageId}
|
|
61
|
+
result={result}
|
|
62
|
+
setShowPluginRender={setShowPluginRender}
|
|
63
|
+
showPluginRender={showPluginRender}
|
|
64
|
+
toolCallId={id}
|
|
65
|
+
type={type}
|
|
66
|
+
/>
|
|
67
|
+
</AnimatedCollapsed>
|
|
68
|
+
</Flexbox>
|
|
69
|
+
);
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
Tool.displayName = 'GroupTool';
|
|
74
|
+
|
|
75
|
+
export default Tool;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ChatToolPayloadWithResult } from '@lobechat/types';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import Tool from './Tool';
|
|
7
|
+
|
|
8
|
+
const useStyles = createStyles(({ css, token }) => {
|
|
9
|
+
return {
|
|
10
|
+
toolsContainer: css`
|
|
11
|
+
padding-block: 6px;
|
|
12
|
+
padding-inline: 12px;
|
|
13
|
+
border: 1px solid ${token.colorBorderSecondary};
|
|
14
|
+
border-radius: 8px;
|
|
15
|
+
`,
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
interface ToolsRendererProps {
|
|
20
|
+
messageId: string;
|
|
21
|
+
tools: ChatToolPayloadWithResult[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const Tools = memo<ToolsRendererProps>(({ messageId, tools }) => {
|
|
25
|
+
const { styles, cx } = useStyles();
|
|
26
|
+
|
|
27
|
+
if (!tools || tools.length === 0) return null;
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Flexbox className={cx(styles.toolsContainer, 'tool-blocks')} gap={8}>
|
|
31
|
+
{tools.map((tool, index) => (
|
|
32
|
+
<Tool
|
|
33
|
+
apiName={tool.apiName}
|
|
34
|
+
arguments={tool.arguments}
|
|
35
|
+
id={tool.id}
|
|
36
|
+
identifier={tool.identifier}
|
|
37
|
+
index={index}
|
|
38
|
+
key={tool.id}
|
|
39
|
+
messageId={messageId}
|
|
40
|
+
result={tool.result}
|
|
41
|
+
type={tool.type}
|
|
42
|
+
/>
|
|
43
|
+
))}
|
|
44
|
+
</Flexbox>
|
|
45
|
+
);
|
|
46
|
+
});
|