@lobehub/chat 1.62.4 → 1.62.6
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/plugin.json +4 -0
- package/locales/bg-BG/plugin.json +4 -0
- package/locales/de-DE/plugin.json +4 -0
- package/locales/en-US/plugin.json +4 -0
- package/locales/es-ES/plugin.json +4 -0
- package/locales/fa-IR/plugin.json +4 -0
- package/locales/fr-FR/plugin.json +4 -0
- package/locales/it-IT/plugin.json +4 -0
- package/locales/ja-JP/plugin.json +4 -0
- package/locales/ko-KR/plugin.json +4 -0
- package/locales/nl-NL/plugin.json +4 -0
- package/locales/pl-PL/plugin.json +4 -0
- package/locales/pt-BR/plugin.json +4 -0
- package/locales/ru-RU/plugin.json +4 -0
- package/locales/tr-TR/plugin.json +4 -0
- package/locales/vi-VN/plugin.json +4 -0
- package/locales/zh-CN/plugin.json +5 -1
- package/locales/zh-TW/plugin.json +4 -0
- package/package.json +3 -3
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/agent/index.tsx +2 -1
- package/src/database/server/models/aiProvider.ts +22 -9
- package/src/database/server/models/topic.ts +2 -0
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/Debug.tsx +43 -0
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/Loader.tsx +58 -0
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/index.tsx +151 -0
- package/src/features/Conversation/Messages/Assistant/Tool/Render/Arguments.tsx +165 -0
- package/src/features/Conversation/Messages/Assistant/{ToolCallItem/Tool.tsx → Tool/Render/CustomRender.tsx} +34 -35
- package/src/features/Conversation/Messages/Assistant/Tool/Render/index.tsx +39 -0
- package/src/features/Conversation/Messages/Assistant/Tool/index.tsx +70 -0
- package/src/features/Conversation/Messages/Assistant/index.tsx +19 -27
- package/src/features/Conversation/components/ChatItem/index.tsx +1 -0
- package/src/features/InitClientDB/PGliteIcon.tsx +2 -2
- package/src/features/PluginsUI/Render/index.tsx +2 -11
- package/src/locales/default/plugin.ts +4 -0
- package/src/styles/loading.ts +27 -0
- package/src/tools/dalle/Render/GalleyGrid.tsx +60 -0
- package/src/tools/dalle/Render/index.tsx +1 -1
- package/src/utils/errorResponse.test.ts +6 -0
- package/src/features/Conversation/Messages/Assistant/ToolCallItem/Inspector/index.tsx +0 -166
- package/src/features/Conversation/Messages/Assistant/ToolCallItem/Inspector/style.ts +0 -35
- package/src/features/Conversation/Messages/Assistant/ToolCallItem/index.tsx +0 -89
- package/src/features/Conversation/Messages/Assistant/ToolCallItem/style.ts +0 -35
- package/src/features/Conversation/Messages/components/Arguments.tsx +0 -22
- /package/src/features/Conversation/Messages/Assistant/{ToolCallItem → Tool}/Inspector/PluginResultJSON.tsx +0 -0
- /package/src/features/Conversation/Messages/Assistant/{ToolCallItem → Tool}/Inspector/Settings.tsx +0 -0
@@ -0,0 +1,151 @@
|
|
1
|
+
import { ActionIcon, Icon } from '@lobehub/ui';
|
2
|
+
import { createStyles } from 'antd-style';
|
3
|
+
import isEqual from 'fast-deep-equal';
|
4
|
+
import {
|
5
|
+
ChevronDown,
|
6
|
+
ChevronRight,
|
7
|
+
LayoutPanelTop,
|
8
|
+
LogsIcon,
|
9
|
+
LucideBug,
|
10
|
+
LucideBugOff,
|
11
|
+
} from 'lucide-react';
|
12
|
+
import { CSSProperties, memo, useState } from 'react';
|
13
|
+
import { useTranslation } from 'react-i18next';
|
14
|
+
import { Flexbox } from 'react-layout-kit';
|
15
|
+
|
16
|
+
import PluginAvatar from '@/features/PluginAvatar';
|
17
|
+
import { useChatStore } from '@/store/chat';
|
18
|
+
import { chatSelectors } from '@/store/chat/selectors';
|
19
|
+
import { pluginHelpers, useToolStore } from '@/store/tool';
|
20
|
+
import { toolSelectors } from '@/store/tool/selectors';
|
21
|
+
import { shinyTextStylish } from '@/styles/loading';
|
22
|
+
|
23
|
+
import Debug from './Debug';
|
24
|
+
import Loader from './Loader';
|
25
|
+
import Settings from './Settings';
|
26
|
+
|
27
|
+
export const useStyles = createStyles(({ css, token }) => ({
|
28
|
+
apiName: css`
|
29
|
+
overflow: hidden;
|
30
|
+
display: -webkit-box;
|
31
|
+
-webkit-box-orient: vertical;
|
32
|
+
-webkit-line-clamp: 1;
|
33
|
+
|
34
|
+
font-family: ${token.fontFamilyCode};
|
35
|
+
font-size: 12px;
|
36
|
+
text-overflow: ellipsis;
|
37
|
+
`,
|
38
|
+
container: css`
|
39
|
+
cursor: pointer;
|
40
|
+
|
41
|
+
width: fit-content;
|
42
|
+
padding-block: 2px;
|
43
|
+
border-radius: 6px;
|
44
|
+
|
45
|
+
color: ${token.colorTextTertiary};
|
46
|
+
|
47
|
+
&:hover {
|
48
|
+
background: ${token.colorFillTertiary};
|
49
|
+
}
|
50
|
+
`,
|
51
|
+
plugin: css`
|
52
|
+
display: flex;
|
53
|
+
gap: 4px;
|
54
|
+
align-items: center;
|
55
|
+
width: fit-content;
|
56
|
+
`,
|
57
|
+
shinyText: shinyTextStylish(token),
|
58
|
+
}));
|
59
|
+
|
60
|
+
interface InspectorProps {
|
61
|
+
apiName: string;
|
62
|
+
arguments?: string;
|
63
|
+
id: string;
|
64
|
+
identifier: string;
|
65
|
+
index: number;
|
66
|
+
messageId: string;
|
67
|
+
payload: object;
|
68
|
+
setShowPluginRender: (show: boolean) => void;
|
69
|
+
setShowRender: (show: boolean) => void;
|
70
|
+
showPluginRender: boolean;
|
71
|
+
showPortal?: boolean;
|
72
|
+
showRender: boolean;
|
73
|
+
style?: CSSProperties;
|
74
|
+
}
|
75
|
+
|
76
|
+
const Inspectors = memo<InspectorProps>(
|
77
|
+
({
|
78
|
+
messageId,
|
79
|
+
index,
|
80
|
+
identifier,
|
81
|
+
apiName,
|
82
|
+
arguments: requestArgs,
|
83
|
+
showRender,
|
84
|
+
payload,
|
85
|
+
setShowRender,
|
86
|
+
showPluginRender,
|
87
|
+
setShowPluginRender,
|
88
|
+
}) => {
|
89
|
+
const { t } = useTranslation('plugin');
|
90
|
+
const { styles } = useStyles();
|
91
|
+
|
92
|
+
const [showDebug, setShowDebug] = useState(false);
|
93
|
+
|
94
|
+
const loading = useChatStore(chatSelectors.isToolCallStreaming(messageId, index));
|
95
|
+
|
96
|
+
const pluginMeta = useToolStore(toolSelectors.getMetaById(identifier), isEqual);
|
97
|
+
const pluginTitle = pluginHelpers.getPluginTitle(pluginMeta) ?? t('unknownPlugin');
|
98
|
+
|
99
|
+
return (
|
100
|
+
<Flexbox gap={4}>
|
101
|
+
<Flexbox align={'center'} distribution={'space-between'} gap={8} horizontal>
|
102
|
+
<Flexbox
|
103
|
+
align={'center'}
|
104
|
+
className={styles.container}
|
105
|
+
gap={8}
|
106
|
+
horizontal
|
107
|
+
onClick={() => {
|
108
|
+
setShowRender(!showRender);
|
109
|
+
}}
|
110
|
+
paddingInline={4}
|
111
|
+
>
|
112
|
+
<Flexbox
|
113
|
+
align={'center'}
|
114
|
+
className={loading ? styles.shinyText : ''}
|
115
|
+
gap={4}
|
116
|
+
horizontal
|
117
|
+
>
|
118
|
+
{loading ? <Loader /> : <PluginAvatar identifier={identifier} size={20} />}
|
119
|
+
<div>{pluginTitle}</div>/<span className={styles.apiName}>{apiName}</span>
|
120
|
+
</Flexbox>
|
121
|
+
<Icon icon={showRender ? ChevronDown : ChevronRight} />
|
122
|
+
</Flexbox>
|
123
|
+
<Flexbox horizontal>
|
124
|
+
{showRender && (
|
125
|
+
<ActionIcon
|
126
|
+
icon={showPluginRender ? LogsIcon : LayoutPanelTop}
|
127
|
+
onClick={() => {
|
128
|
+
setShowPluginRender(!showPluginRender);
|
129
|
+
}}
|
130
|
+
size={'small'}
|
131
|
+
title={showPluginRender ? t('inspector.args') : t('inspector.pluginRender')}
|
132
|
+
/>
|
133
|
+
)}
|
134
|
+
<ActionIcon
|
135
|
+
icon={showDebug ? LucideBugOff : LucideBug}
|
136
|
+
onClick={() => {
|
137
|
+
setShowDebug(!showDebug);
|
138
|
+
}}
|
139
|
+
size={'small'}
|
140
|
+
title={t(showDebug ? 'debug.off' : 'debug.on')}
|
141
|
+
/>
|
142
|
+
<Settings id={identifier} />
|
143
|
+
</Flexbox>
|
144
|
+
</Flexbox>
|
145
|
+
{showDebug && <Debug payload={payload} requestArgs={requestArgs} />}
|
146
|
+
</Flexbox>
|
147
|
+
);
|
148
|
+
},
|
149
|
+
);
|
150
|
+
|
151
|
+
export default Inspectors;
|
@@ -0,0 +1,165 @@
|
|
1
|
+
import { Highlighter, copyToClipboard } from '@lobehub/ui';
|
2
|
+
import { App } from 'antd';
|
3
|
+
import { createStyles } from 'antd-style';
|
4
|
+
import { parse } from 'partial-json';
|
5
|
+
import { memo, useMemo } from 'react';
|
6
|
+
import { useTranslation } from 'react-i18next';
|
7
|
+
|
8
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
9
|
+
import { useYamlArguments } from '@/hooks/useYamlArguments';
|
10
|
+
import { shinyTextStylish } from '@/styles/loading';
|
11
|
+
|
12
|
+
const useStyles = createStyles(({ css, token }) => ({
|
13
|
+
arrayRow: css`
|
14
|
+
&:not(:first-child) {
|
15
|
+
border-block-start: 1px dotted ${token.colorBorderSecondary};
|
16
|
+
}
|
17
|
+
`,
|
18
|
+
colon: css`
|
19
|
+
color: ${token.colorTextTertiary};
|
20
|
+
`,
|
21
|
+
container: css`
|
22
|
+
padding-block: 4px;
|
23
|
+
padding-inline: 12px;
|
24
|
+
border-radius: ${token.borderRadiusLG}px;
|
25
|
+
|
26
|
+
font-family: ${token.fontFamilyCode};
|
27
|
+
font-size: 13px;
|
28
|
+
line-height: 1.5;
|
29
|
+
|
30
|
+
background: ${token.colorFillQuaternary};
|
31
|
+
`,
|
32
|
+
copyable: css`
|
33
|
+
cursor: pointer;
|
34
|
+
width: 100%;
|
35
|
+
margin-block: 2px;
|
36
|
+
padding: 4px;
|
37
|
+
|
38
|
+
&:hover {
|
39
|
+
border-radius: 6px;
|
40
|
+
background: ${token.colorFillTertiary};
|
41
|
+
}
|
42
|
+
`,
|
43
|
+
key: css`
|
44
|
+
color: ${token.colorTextTertiary};
|
45
|
+
`,
|
46
|
+
row: css`
|
47
|
+
display: flex;
|
48
|
+
align-items: baseline;
|
49
|
+
|
50
|
+
&:not(:first-child) {
|
51
|
+
border-block-start: 1px dotted ${token.colorBorderSecondary};
|
52
|
+
}
|
53
|
+
`,
|
54
|
+
shineText: shinyTextStylish(token),
|
55
|
+
value: css`
|
56
|
+
color: ${token.colorTextSecondary};
|
57
|
+
`,
|
58
|
+
}));
|
59
|
+
|
60
|
+
interface ObjectDisplayProps {
|
61
|
+
data: Record<string, any>;
|
62
|
+
shine?: boolean;
|
63
|
+
}
|
64
|
+
|
65
|
+
const ObjectDisplay = memo(({ data, shine }: ObjectDisplayProps) => {
|
66
|
+
const { styles, cx } = useStyles();
|
67
|
+
const { t } = useTranslation('common');
|
68
|
+
|
69
|
+
const { message } = App.useApp();
|
70
|
+
const isMobile = useIsMobile();
|
71
|
+
|
72
|
+
const formatValue = (value: any): string | string[] => {
|
73
|
+
if (Array.isArray(value)) {
|
74
|
+
return value.map((v) => (typeof v === 'object' ? JSON.stringify(v) : v));
|
75
|
+
}
|
76
|
+
|
77
|
+
if (typeof value === 'object' && value !== null) {
|
78
|
+
return Object.entries(value)
|
79
|
+
.map(([k, v]) => `${k}: ${typeof v === 'object' ? JSON.stringify(v) : v}`)
|
80
|
+
.join(', ');
|
81
|
+
}
|
82
|
+
return String(value);
|
83
|
+
};
|
84
|
+
|
85
|
+
const hasMinWidth = Object.keys(data).length > 1;
|
86
|
+
if (Object.keys(data).length === 0) return null;
|
87
|
+
|
88
|
+
return (
|
89
|
+
<div className={styles.container}>
|
90
|
+
{Object.entries(data).map(([key, value]) => {
|
91
|
+
const formatedValue = formatValue(value);
|
92
|
+
return (
|
93
|
+
<div className={styles.row} key={key}>
|
94
|
+
<span
|
95
|
+
className={styles.key}
|
96
|
+
style={{ minWidth: hasMinWidth ? (isMobile ? 60 : 80) : undefined }}
|
97
|
+
>
|
98
|
+
{key}
|
99
|
+
</span>
|
100
|
+
<span className={styles.colon}>:</span>
|
101
|
+
<div className={cx(shine ? styles.shineText : styles.value)} style={{ width: '100%' }}>
|
102
|
+
{typeof formatedValue === 'string' ? (
|
103
|
+
<div
|
104
|
+
className={styles.copyable}
|
105
|
+
onClick={async () => {
|
106
|
+
await copyToClipboard(formatedValue);
|
107
|
+
message.success(t('copySuccess'));
|
108
|
+
}}
|
109
|
+
>
|
110
|
+
{formatedValue}
|
111
|
+
</div>
|
112
|
+
) : (
|
113
|
+
formatedValue.map((v, i) => (
|
114
|
+
<div
|
115
|
+
className={styles.arrayRow}
|
116
|
+
key={i}
|
117
|
+
onClick={async () => {
|
118
|
+
await copyToClipboard(v);
|
119
|
+
message.success(t('copySuccess'));
|
120
|
+
}}
|
121
|
+
>
|
122
|
+
<div className={styles.copyable}>{v}</div>
|
123
|
+
</div>
|
124
|
+
))
|
125
|
+
)}
|
126
|
+
</div>
|
127
|
+
</div>
|
128
|
+
);
|
129
|
+
})}
|
130
|
+
</div>
|
131
|
+
);
|
132
|
+
});
|
133
|
+
|
134
|
+
export interface ArgumentsProps {
|
135
|
+
arguments?: string;
|
136
|
+
shine?: boolean;
|
137
|
+
}
|
138
|
+
|
139
|
+
const Arguments = memo<ArgumentsProps>(({ arguments: args = '', shine }) => {
|
140
|
+
const requestArgs = useMemo(() => {
|
141
|
+
try {
|
142
|
+
const obj = parse(args);
|
143
|
+
|
144
|
+
if (Object.keys(obj).length === 0) return {};
|
145
|
+
|
146
|
+
return obj;
|
147
|
+
} catch {
|
148
|
+
return args;
|
149
|
+
}
|
150
|
+
}, [args]);
|
151
|
+
|
152
|
+
const yaml = useYamlArguments(args);
|
153
|
+
|
154
|
+
return typeof requestArgs === 'string' ? (
|
155
|
+
!!yaml && (
|
156
|
+
<Highlighter language={'yaml'} showLanguage={false}>
|
157
|
+
{yaml}
|
158
|
+
</Highlighter>
|
159
|
+
)
|
160
|
+
) : (
|
161
|
+
<ObjectDisplay data={requestArgs} shine={shine} />
|
162
|
+
);
|
163
|
+
});
|
164
|
+
|
165
|
+
export default Arguments;
|
@@ -2,7 +2,7 @@ import { Icon } from '@lobehub/ui';
|
|
2
2
|
import { ConfigProvider, Empty } from 'antd';
|
3
3
|
import { useTheme } from 'antd-style';
|
4
4
|
import { LucideSquareArrowLeft, LucideSquareArrowRight } from 'lucide-react';
|
5
|
-
import { memo, useContext,
|
5
|
+
import { memo, useContext, useEffect } from 'react';
|
6
6
|
import { useTranslation } from 'react-i18next';
|
7
7
|
import { Center, Flexbox } from 'react-layout-kit';
|
8
8
|
|
@@ -11,14 +11,15 @@ import { useChatStore } from '@/store/chat';
|
|
11
11
|
import { chatPortalSelectors, chatSelectors } from '@/store/chat/selectors';
|
12
12
|
import { ChatMessage } from '@/types/message';
|
13
13
|
|
14
|
-
import Arguments from '
|
15
|
-
import Inspector from './Inspector';
|
14
|
+
import Arguments from './Arguments';
|
16
15
|
|
17
|
-
const
|
16
|
+
const CustomRender = memo<
|
18
17
|
ChatMessage & {
|
19
|
-
|
18
|
+
requestArgs?: string;
|
19
|
+
setShowPluginRender: (show: boolean) => void;
|
20
|
+
showPluginRender: boolean;
|
20
21
|
}
|
21
|
-
>(({ id, content, pluginState, plugin,
|
22
|
+
>(({ id, content, pluginState, plugin, requestArgs, showPluginRender, setShowPluginRender }) => {
|
22
23
|
const [loading, isMessageToolUIOpen] = useChatStore((s) => [
|
23
24
|
chatSelectors.isPluginApiInvoking(id)(s),
|
24
25
|
chatPortalSelectors.isPluginUIOpen(id)(s),
|
@@ -27,36 +28,34 @@ const Tool = memo<
|
|
27
28
|
const { t } = useTranslation('plugin');
|
28
29
|
|
29
30
|
const theme = useTheme();
|
30
|
-
|
31
|
+
useEffect(() => {
|
32
|
+
if (!plugin?.type) return;
|
33
|
+
|
34
|
+
setShowPluginRender(plugin?.type !== 'default');
|
35
|
+
}, [plugin?.type]);
|
36
|
+
|
37
|
+
if (isMessageToolUIOpen)
|
38
|
+
return (
|
39
|
+
<Center paddingBlock={8} style={{ background: theme.colorFillQuaternary, borderRadius: 4 }}>
|
40
|
+
<Empty
|
41
|
+
description={t('showInPortal')}
|
42
|
+
image={
|
43
|
+
<Icon
|
44
|
+
color={theme.colorTextQuaternary}
|
45
|
+
icon={direction === 'rtl' ? LucideSquareArrowLeft : LucideSquareArrowRight}
|
46
|
+
size={'large'}
|
47
|
+
/>
|
48
|
+
}
|
49
|
+
styles={{
|
50
|
+
image: { height: 24 },
|
51
|
+
}}
|
52
|
+
/>
|
53
|
+
</Center>
|
54
|
+
);
|
31
55
|
|
32
56
|
return (
|
33
57
|
<Flexbox gap={12} id={id} width={'100%'}>
|
34
|
-
|
35
|
-
arguments={plugin?.arguments}
|
36
|
-
content={content}
|
37
|
-
id={id}
|
38
|
-
identifier={plugin?.identifier}
|
39
|
-
loading={loading}
|
40
|
-
payload={plugin}
|
41
|
-
setShow={setShow}
|
42
|
-
showPortal={showPortal}
|
43
|
-
showRender={showRender}
|
44
|
-
/>
|
45
|
-
{isMessageToolUIOpen ? (
|
46
|
-
<Center paddingBlock={8} style={{ background: theme.colorFillQuaternary, borderRadius: 4 }}>
|
47
|
-
<Empty
|
48
|
-
description={t('showInPortal')}
|
49
|
-
image={
|
50
|
-
<Icon
|
51
|
-
color={theme.colorTextQuaternary}
|
52
|
-
icon={direction === 'rtl' ? LucideSquareArrowLeft : LucideSquareArrowRight}
|
53
|
-
size={'large'}
|
54
|
-
/>
|
55
|
-
}
|
56
|
-
imageStyle={{ height: 24 }}
|
57
|
-
/>
|
58
|
-
</Center>
|
59
|
-
) : showRender || loading ? (
|
58
|
+
{showPluginRender ? (
|
60
59
|
<PluginRender
|
61
60
|
arguments={plugin?.arguments}
|
62
61
|
content={content}
|
@@ -68,10 +67,10 @@ const Tool = memo<
|
|
68
67
|
type={plugin?.type}
|
69
68
|
/>
|
70
69
|
) : (
|
71
|
-
<Arguments arguments={
|
70
|
+
<Arguments arguments={requestArgs} />
|
72
71
|
)}
|
73
72
|
</Flexbox>
|
74
73
|
);
|
75
74
|
});
|
76
75
|
|
77
|
-
export default
|
76
|
+
export default CustomRender;
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { Suspense, memo } from 'react';
|
2
|
+
|
3
|
+
import { useChatStore } from '@/store/chat';
|
4
|
+
import { chatSelectors } from '@/store/chat/selectors';
|
5
|
+
|
6
|
+
import Arguments from './Arguments';
|
7
|
+
import CustomRender from './CustomRender';
|
8
|
+
|
9
|
+
interface RenderProps {
|
10
|
+
messageId: string;
|
11
|
+
requestArgs?: string;
|
12
|
+
setShowPluginRender: (show: boolean) => void;
|
13
|
+
showPluginRender: boolean;
|
14
|
+
toolCallId: string;
|
15
|
+
toolIndex: number;
|
16
|
+
}
|
17
|
+
const Render = memo<RenderProps>(
|
18
|
+
({ toolCallId, toolIndex, messageId, requestArgs, showPluginRender, setShowPluginRender }) => {
|
19
|
+
const loading = useChatStore(chatSelectors.isToolCallStreaming(messageId, toolIndex));
|
20
|
+
const toolMessage = useChatStore(chatSelectors.getMessageByToolCallId(toolCallId));
|
21
|
+
|
22
|
+
// 如果处于 loading 或者找不到 toolMessage 则展示 Arguments
|
23
|
+
if (loading || !toolMessage) return <Arguments arguments={requestArgs} />;
|
24
|
+
|
25
|
+
if (!!toolMessage)
|
26
|
+
return (
|
27
|
+
<Suspense fallback={<Arguments arguments={requestArgs} shine />}>
|
28
|
+
<CustomRender
|
29
|
+
{...toolMessage}
|
30
|
+
requestArgs={requestArgs}
|
31
|
+
setShowPluginRender={setShowPluginRender}
|
32
|
+
showPluginRender={showPluginRender}
|
33
|
+
/>
|
34
|
+
</Suspense>
|
35
|
+
);
|
36
|
+
},
|
37
|
+
);
|
38
|
+
|
39
|
+
export default Render;
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import { AnimatePresence, motion } from 'framer-motion';
|
2
|
+
import { CSSProperties, memo, useState } from 'react';
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
4
|
+
|
5
|
+
import Inspectors from './Inspector';
|
6
|
+
import Render from './Render';
|
7
|
+
|
8
|
+
export interface InspectorProps {
|
9
|
+
apiName: string;
|
10
|
+
arguments?: string;
|
11
|
+
id: string;
|
12
|
+
identifier: string;
|
13
|
+
index: number;
|
14
|
+
messageId: string;
|
15
|
+
payload: object;
|
16
|
+
style?: CSSProperties;
|
17
|
+
}
|
18
|
+
|
19
|
+
const Tool = memo<InspectorProps>(
|
20
|
+
({ arguments: requestArgs, apiName, messageId, id, index, identifier, style, payload }) => {
|
21
|
+
const [showRender, setShowRender] = useState(true);
|
22
|
+
const [showPluginRender, setShowPluginRender] = useState(false);
|
23
|
+
|
24
|
+
return (
|
25
|
+
<Flexbox gap={8} style={style}>
|
26
|
+
<Inspectors
|
27
|
+
apiName={apiName}
|
28
|
+
arguments={requestArgs}
|
29
|
+
id={id}
|
30
|
+
identifier={identifier}
|
31
|
+
index={index}
|
32
|
+
messageId={messageId}
|
33
|
+
payload={payload}
|
34
|
+
setShowPluginRender={setShowPluginRender}
|
35
|
+
setShowRender={setShowRender}
|
36
|
+
showPluginRender={showPluginRender}
|
37
|
+
showRender={showRender}
|
38
|
+
/>
|
39
|
+
<AnimatePresence initial={false}>
|
40
|
+
{showRender && (
|
41
|
+
<motion.div
|
42
|
+
animate="open"
|
43
|
+
exit="collapsed"
|
44
|
+
initial="collapsed"
|
45
|
+
transition={{
|
46
|
+
duration: 0.1,
|
47
|
+
ease: [0.4, 0, 0.2, 1], // 使用 ease-out 缓动函数
|
48
|
+
}}
|
49
|
+
variants={{
|
50
|
+
collapsed: { height: 0, opacity: 0, width: 0 },
|
51
|
+
open: { height: 'auto', opacity: 1, width: 'auto' },
|
52
|
+
}}
|
53
|
+
>
|
54
|
+
<Render
|
55
|
+
messageId={messageId}
|
56
|
+
requestArgs={requestArgs}
|
57
|
+
setShowPluginRender={setShowPluginRender}
|
58
|
+
showPluginRender={showPluginRender}
|
59
|
+
toolCallId={id}
|
60
|
+
toolIndex={index}
|
61
|
+
/>
|
62
|
+
</motion.div>
|
63
|
+
)}
|
64
|
+
</AnimatePresence>
|
65
|
+
</Flexbox>
|
66
|
+
);
|
67
|
+
},
|
68
|
+
);
|
69
|
+
|
70
|
+
export default Tool;
|
@@ -1,18 +1,15 @@
|
|
1
|
-
import {
|
2
|
-
import { ReactNode, Suspense, memo, useContext } from 'react';
|
1
|
+
import { ReactNode, memo } from 'react';
|
3
2
|
import { Flexbox } from 'react-layout-kit';
|
4
3
|
|
5
4
|
import { LOADING_FLAT } from '@/const/message';
|
6
5
|
import { useChatStore } from '@/store/chat';
|
7
|
-
import { chatSelectors } from '@/store/chat/selectors';
|
8
|
-
import { aiChatSelectors } from '@/store/chat/slices/aiChat/selectors';
|
6
|
+
import { aiChatSelectors, chatSelectors } from '@/store/chat/selectors';
|
9
7
|
import { ChatMessage } from '@/types/message';
|
10
8
|
|
11
|
-
import { InPortalThreadContext } from '../../components/ChatItem/InPortalThreadContext';
|
12
9
|
import { DefaultMessage } from '../Default';
|
13
10
|
import FileChunks from './FileChunks';
|
14
|
-
import
|
15
|
-
import
|
11
|
+
import Reasoning from './Reasoning';
|
12
|
+
import Tool from './Tool';
|
16
13
|
|
17
14
|
export const AssistantMessage = memo<
|
18
15
|
ChatMessage & {
|
@@ -22,7 +19,6 @@ export const AssistantMessage = memo<
|
|
22
19
|
const editing = useChatStore(chatSelectors.isMessageEditing(id));
|
23
20
|
const generating = useChatStore(chatSelectors.isMessageGenerating(id));
|
24
21
|
|
25
|
-
const inThread = useContext(InPortalThreadContext);
|
26
22
|
const isToolCallGenerating = generating && (content === LOADING_FLAT || !content) && !!tools;
|
27
23
|
|
28
24
|
const isReasoning = useChatStore(aiChatSelectors.isMessageInReasoning(id));
|
@@ -43,7 +39,7 @@ export const AssistantMessage = memo<
|
|
43
39
|
) : (
|
44
40
|
<Flexbox gap={8} id={id}>
|
45
41
|
{!!chunksList && chunksList.length > 0 && <FileChunks data={chunksList} />}
|
46
|
-
{showReasoning && <
|
42
|
+
{showReasoning && <Reasoning {...props.reasoning} id={id} />}
|
47
43
|
{content && (
|
48
44
|
<DefaultMessage
|
49
45
|
addIdOnDOM={false}
|
@@ -54,24 +50,20 @@ export const AssistantMessage = memo<
|
|
54
50
|
/>
|
55
51
|
)}
|
56
52
|
{tools && (
|
57
|
-
<
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
/>
|
72
|
-
))}
|
73
|
-
</Flexbox>
|
74
|
-
</Suspense>
|
53
|
+
<Flexbox gap={8}>
|
54
|
+
{tools.map((toolCall, index) => (
|
55
|
+
<Tool
|
56
|
+
apiName={toolCall.apiName}
|
57
|
+
arguments={toolCall.arguments}
|
58
|
+
id={toolCall.id}
|
59
|
+
identifier={toolCall.identifier}
|
60
|
+
index={index}
|
61
|
+
key={toolCall.id}
|
62
|
+
messageId={id}
|
63
|
+
payload={toolCall}
|
64
|
+
/>
|
65
|
+
))}
|
66
|
+
</Flexbox>
|
75
67
|
)}
|
76
68
|
</Flexbox>
|
77
69
|
);
|
@@ -175,6 +175,7 @@ const Item = memo<ChatListItemProps>(
|
|
175
175
|
citations: item?.role === 'user' ? undefined : item?.search?.citations,
|
176
176
|
components,
|
177
177
|
customRender: markdownCustomRender,
|
178
|
+
enableCustomFootnotes: item?.role === 'assistant',
|
178
179
|
rehypePlugins: item?.role === 'user' ? undefined : rehypePlugins,
|
179
180
|
remarkPlugins: item?.role === 'user' ? undefined : remarkPlugins,
|
180
181
|
showCitations:
|
@@ -17,9 +17,9 @@ const PGliteIcon: IconType = forwardRef(({ size = '1em', style }, ref) => {
|
|
17
17
|
>
|
18
18
|
<title>PGlite</title>
|
19
19
|
<path
|
20
|
-
|
20
|
+
clipRule="evenodd"
|
21
21
|
d="M941.581 335.737v460.806c0 15.926-12.913 28.836-28.832 28.818l-115.283-.137c-15.243-.018-27.706-11.88-28.703-26.877.011-.569.018-1.138.018-1.711l-.004-172.904c0-47.745-38.736-86.451-86.454-86.451-46.245 0-84.052-36.359-86.342-82.068V191.496l201.708.149c79.484.058 143.892 64.553 143.892 144.092zm-576-144.281v201.818c0 47.746 38.682 86.456 86.4 86.456h86.4v-5.796c0 66.816 54.13 120.98 120.902 120.98 28.617 0 51.815 23.213 51.815 51.848v149.644c0 .688.011 1.372.025 2.057-.943 15.065-13.453 26.992-28.746 26.992l-144.982-.007.986-201.586c.079-15.915-12.755-28.88-28.66-28.959-15.904-.079-28.861 12.763-28.94 28.678l-.986 201.741v.118l-172.174-.01V623.722c0-15.915-12.895-28.819-28.8-28.819-15.906 0-28.8 12.904-28.8 28.819v201.704l-143.642-.007c-15.905-.004-28.798-12.904-28.798-28.819V335.547c0-79.58 64.471-144.093 144.001-144.092l143.999.001zm446.544 173.693c0-23.874-19.343-43.228-43.2-43.228-23.861 0-43.2 19.354-43.2 43.228 0 23.875 19.339 43.226 43.2 43.226 23.857 0 43.2-19.351 43.2-43.226z"
|
22
|
-
|
22
|
+
fillRule="evenodd"
|
23
23
|
/>
|
24
24
|
</svg>
|
25
25
|
);
|
@@ -1,21 +1,12 @@
|
|
1
1
|
import { PluginRequestPayload } from '@lobehub/chat-plugin-sdk';
|
2
|
-
import { Skeleton } from 'antd';
|
3
|
-
import dynamic from 'next/dynamic';
|
4
2
|
import { memo } from 'react';
|
5
3
|
|
6
4
|
import { LobeToolRenderType } from '@/types/tool';
|
7
5
|
|
6
|
+
import BuiltinType from './BuiltinType';
|
8
7
|
import DefaultType from './DefaultType';
|
9
8
|
import Markdown from './MarkdownType';
|
10
|
-
|
11
|
-
const loading = () => (
|
12
|
-
<Skeleton.Node active style={{ width: '100%' }}>
|
13
|
-
{' '}
|
14
|
-
</Skeleton.Node>
|
15
|
-
);
|
16
|
-
|
17
|
-
const Standalone = dynamic(() => import('./StandaloneType'), { loading });
|
18
|
-
const BuiltinType = dynamic(() => import('./BuiltinType'), { loading });
|
9
|
+
import Standalone from './StandaloneType';
|
19
10
|
|
20
11
|
export interface PluginRenderProps {
|
21
12
|
arguments?: string;
|