@lobehub/lobehub 2.0.0-next.48 → 2.0.0-next.49
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 +33 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/changelog/v1.json +12 -0
- package/locales/ar/chat.json +1 -0
- package/locales/ar/topic.json +1 -0
- package/locales/bg-BG/chat.json +1 -0
- package/locales/bg-BG/topic.json +1 -0
- package/locales/de-DE/chat.json +1 -0
- package/locales/de-DE/topic.json +1 -0
- package/locales/en-US/chat.json +1 -0
- package/locales/en-US/topic.json +1 -0
- package/locales/es-ES/chat.json +1 -0
- package/locales/es-ES/topic.json +1 -0
- package/locales/fa-IR/chat.json +1 -0
- package/locales/fa-IR/topic.json +1 -0
- package/locales/fr-FR/chat.json +1 -0
- package/locales/fr-FR/topic.json +1 -0
- package/locales/it-IT/chat.json +1 -0
- package/locales/it-IT/topic.json +1 -0
- package/locales/ja-JP/chat.json +1 -0
- package/locales/ja-JP/topic.json +1 -0
- package/locales/ko-KR/chat.json +1 -0
- package/locales/ko-KR/topic.json +1 -0
- package/locales/nl-NL/chat.json +1 -0
- package/locales/nl-NL/topic.json +1 -0
- package/locales/pl-PL/chat.json +1 -0
- package/locales/pl-PL/topic.json +1 -0
- package/locales/pt-BR/chat.json +1 -0
- package/locales/pt-BR/topic.json +1 -0
- package/locales/ru-RU/chat.json +1 -0
- package/locales/ru-RU/topic.json +1 -0
- package/locales/tr-TR/chat.json +1 -0
- package/locales/tr-TR/topic.json +1 -0
- package/locales/vi-VN/chat.json +1 -0
- package/locales/vi-VN/topic.json +1 -0
- package/locales/zh-CN/chat.json +1 -0
- package/locales/zh-CN/discover.json +1 -1
- package/locales/zh-CN/topic.json +1 -0
- package/locales/zh-TW/chat.json +1 -0
- package/locales/zh-TW/topic.json +1 -0
- package/package.json +9 -3
- package/packages/agent-runtime/src/core/InterventionChecker.ts +5 -16
- package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +27 -80
- package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +32 -13
- package/packages/agent-runtime/src/core/runtime.ts +7 -3
- package/packages/agent-runtime/src/types/event.ts +2 -1
- package/packages/agent-runtime/src/types/generalAgent.ts +1 -0
- package/packages/agent-runtime/src/types/instruction.ts +3 -2
- package/packages/agent-runtime/src/types/state.ts +3 -1
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +4 -1
- package/packages/database/src/models/message.ts +3 -0
- package/packages/obervability-otel/src/node.ts +15 -1
- package/packages/types/src/message/common/base.ts +2 -2
- package/packages/types/src/message/common/tools.ts +16 -10
- package/packages/types/src/message/ui/chat.ts +7 -1
- package/packages/types/src/tool/intervention.ts +2 -3
- package/packages/types/src/user/settings/tool.ts +15 -28
- package/renovate.json +28 -11
- package/src/app/[variants]/(main)/chat/components/topic/features/Topic/TopicListContent/TopicItem/TopicContent.tsx +1 -1
- package/src/app/[variants]/(main)/chat/session/features/SessionListContent/List/Item/Actions.tsx +1 -1
- package/src/features/Conversation/Messages/Group/GroupChildren.tsx +20 -15
- package/src/features/Conversation/Messages/Group/GroupContext.tsx +15 -0
- package/src/features/Conversation/Messages/Group/Tool/Inspector/BuiltinPluginTitle.tsx +2 -4
- package/src/features/Conversation/Messages/Group/Tool/Inspector/ToolTitle.tsx +3 -5
- package/src/features/Conversation/Messages/Group/Tool/Inspector/index.tsx +19 -7
- package/src/features/Conversation/Messages/Group/Tool/Render/Arguments/index.tsx +14 -12
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/ApprovalActions.tsx +143 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/KeyValueEditor.tsx +213 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/ModeSelector.tsx +134 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/index.tsx +99 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/RejectedResponse.tsx +45 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/index.tsx +23 -1
- package/src/features/Conversation/Messages/Group/Tool/index.tsx +42 -18
- package/src/features/Conversation/Messages/Group/Tools.tsx +3 -1
- package/src/locales/default/chat.ts +22 -0
- package/src/locales/default/common.ts +1 -0
- package/src/locales/default/topic.ts +1 -0
- package/src/server/routers/lambda/message.ts +4 -1
- package/src/server/services/message/index.ts +13 -0
- package/src/services/message/index.ts +17 -2
- package/src/store/chat/agents/GeneralChatAgent.ts +141 -24
- package/src/store/chat/agents/__tests__/GeneralChatAgent.test.ts +605 -0
- package/src/store/chat/agents/createAgentExecutors.ts +144 -26
- package/src/store/chat/agents/createToolEngine.ts +22 -0
- package/src/store/chat/slices/aiChat/actions/conversationControl.ts +106 -0
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +54 -26
- package/src/store/chat/slices/message/reducer.ts +2 -1
- package/src/store/chat/slices/plugin/actions/optimisticUpdate.ts +26 -1
- package/src/store/user/slices/settings/action.ts +15 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Button, Dropdown, Icon, type MenuProps } from '@lobehub/ui';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
import { ChevronDown, Hand, ListChecks, Zap } from 'lucide-react';
|
|
4
|
+
import { memo, useCallback, useMemo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Center } from 'react-layout-kit';
|
|
7
|
+
|
|
8
|
+
import { useUserStore } from '@/store/user';
|
|
9
|
+
|
|
10
|
+
import { ApprovalMode } from './index';
|
|
11
|
+
|
|
12
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
13
|
+
icon: css`
|
|
14
|
+
border: 1px solid ${token.colorFillTertiary};
|
|
15
|
+
border-radius: ${token.borderRadius}px;
|
|
16
|
+
background: ${token.colorBgElevated};
|
|
17
|
+
`,
|
|
18
|
+
modeButton: css`
|
|
19
|
+
font-size: ${token.fontSizeSM}px;
|
|
20
|
+
color: ${token.colorTextSecondary};
|
|
21
|
+
`,
|
|
22
|
+
modeDesc: css`
|
|
23
|
+
margin-block-start: 2px;
|
|
24
|
+
font-size: 12px;
|
|
25
|
+
line-height: 1.4;
|
|
26
|
+
color: ${token.colorTextDescription};
|
|
27
|
+
`,
|
|
28
|
+
modeItem: css`
|
|
29
|
+
min-width: 160px;
|
|
30
|
+
`,
|
|
31
|
+
modeLabel: css`
|
|
32
|
+
font-size: ${token.fontSize}px;
|
|
33
|
+
font-weight: 500;
|
|
34
|
+
line-height: 1.4;
|
|
35
|
+
color: ${token.colorText};
|
|
36
|
+
`,
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
const ModeSelector = memo(() => {
|
|
40
|
+
const { t } = useTranslation('chat');
|
|
41
|
+
const { styles } = useStyles();
|
|
42
|
+
const [approvalMode, setSettings] = useUserStore((s) => [
|
|
43
|
+
s.settings.tool?.approvalMode || 'manual',
|
|
44
|
+
s.setSettings,
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
const modeLabels = useMemo(
|
|
48
|
+
() => ({
|
|
49
|
+
'allow-list': t('tool.intervention.mode.allowList'),
|
|
50
|
+
'auto-run': t('tool.intervention.mode.autoRun'),
|
|
51
|
+
'manual': t('tool.intervention.mode.manual'),
|
|
52
|
+
}),
|
|
53
|
+
[t],
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const handleModeChange = useCallback(
|
|
57
|
+
async (mode: ApprovalMode) => {
|
|
58
|
+
await setSettings({ tool: { approvalMode: mode } });
|
|
59
|
+
},
|
|
60
|
+
[setSettings],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const menuItems = useMemo<MenuProps['items']>(
|
|
64
|
+
() => [
|
|
65
|
+
{
|
|
66
|
+
icon: (
|
|
67
|
+
<Center className={styles.icon} height={32} width={32}>
|
|
68
|
+
<Icon icon={Zap} />
|
|
69
|
+
</Center>
|
|
70
|
+
),
|
|
71
|
+
key: 'auto-run',
|
|
72
|
+
label: (
|
|
73
|
+
<div className={styles.modeItem}>
|
|
74
|
+
<div className={styles.modeLabel}>{modeLabels['auto-run']}</div>
|
|
75
|
+
<div className={styles.modeDesc}>{t('tool.intervention.mode.autoRunDesc')}</div>
|
|
76
|
+
</div>
|
|
77
|
+
),
|
|
78
|
+
onClick: () => handleModeChange('auto-run'),
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
icon: (
|
|
82
|
+
<Center className={styles.icon} height={32} width={32}>
|
|
83
|
+
<Icon icon={ListChecks} />
|
|
84
|
+
</Center>
|
|
85
|
+
),
|
|
86
|
+
key: 'allow-list',
|
|
87
|
+
label: (
|
|
88
|
+
<div className={styles.modeItem}>
|
|
89
|
+
<div className={styles.modeLabel}>{modeLabels['allow-list']}</div>
|
|
90
|
+
<div className={styles.modeDesc}>{t('tool.intervention.mode.allowListDesc')}</div>
|
|
91
|
+
</div>
|
|
92
|
+
),
|
|
93
|
+
onClick: () => handleModeChange('allow-list'),
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
icon: (
|
|
97
|
+
<Center className={styles.icon} height={32} width={32}>
|
|
98
|
+
<Icon icon={Hand} />
|
|
99
|
+
</Center>
|
|
100
|
+
),
|
|
101
|
+
key: 'manual',
|
|
102
|
+
label: (
|
|
103
|
+
<div className={styles.modeItem}>
|
|
104
|
+
<div className={styles.modeLabel}>{modeLabels.manual}</div>
|
|
105
|
+
<div className={styles.modeDesc}>{t('tool.intervention.mode.manualDesc')}</div>
|
|
106
|
+
</div>
|
|
107
|
+
),
|
|
108
|
+
onClick: () => handleModeChange('manual'),
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
[modeLabels, handleModeChange, styles, t],
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<Dropdown
|
|
116
|
+
// @ts-expect-error activeKey 没在 Dropdown key 里很奇怪
|
|
117
|
+
menu={{ activeKey: approvalMode, items: menuItems }}
|
|
118
|
+
placement="bottomLeft"
|
|
119
|
+
>
|
|
120
|
+
<Button
|
|
121
|
+
className={styles.modeButton}
|
|
122
|
+
color={'default'}
|
|
123
|
+
icon={ChevronDown}
|
|
124
|
+
iconPosition="end"
|
|
125
|
+
size="small"
|
|
126
|
+
variant={'text'}
|
|
127
|
+
>
|
|
128
|
+
{modeLabels[approvalMode]}
|
|
129
|
+
</Button>
|
|
130
|
+
</Dropdown>
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
export default ModeSelector;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { safeParseJSON } from '@lobechat/utils';
|
|
2
|
+
import { ActionIcon } from '@lobehub/ui';
|
|
3
|
+
import { Edit3Icon } from 'lucide-react';
|
|
4
|
+
import { Suspense, memo, useCallback, useState } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
|
7
|
+
|
|
8
|
+
import { useChatStore } from '@/store/chat';
|
|
9
|
+
import { useUserStore } from '@/store/user';
|
|
10
|
+
|
|
11
|
+
import Arguments from '../Arguments';
|
|
12
|
+
import ApprovalActions from './ApprovalActions';
|
|
13
|
+
import KeyValueEditor from './KeyValueEditor';
|
|
14
|
+
import ModeSelector from './ModeSelector';
|
|
15
|
+
|
|
16
|
+
export type ApprovalMode = 'auto-run' | 'allow-list' | 'manual';
|
|
17
|
+
|
|
18
|
+
interface InterventionProps {
|
|
19
|
+
apiName: string;
|
|
20
|
+
id: string;
|
|
21
|
+
identifier: string;
|
|
22
|
+
requestArgs: string;
|
|
23
|
+
toolCallId: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const Intervention = memo<InterventionProps>(
|
|
27
|
+
({ requestArgs, id, identifier, apiName, toolCallId }) => {
|
|
28
|
+
const { t } = useTranslation('chat');
|
|
29
|
+
const approvalMode = useUserStore((s) => s.settings.tool?.approvalMode || 'manual');
|
|
30
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
31
|
+
const [optimisticUpdatePluginArguments] = useChatStore((s) => [
|
|
32
|
+
s.optimisticUpdatePluginArguments,
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
const handleCancel = useCallback(() => {
|
|
36
|
+
setIsEditing(false);
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
const handleFinish = useCallback(
|
|
40
|
+
async (editedObject: Record<string, any>) => {
|
|
41
|
+
if (!id) return;
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const newArgsString = JSON.stringify(editedObject, null, 2);
|
|
45
|
+
|
|
46
|
+
if (newArgsString !== requestArgs) {
|
|
47
|
+
await optimisticUpdatePluginArguments(id, editedObject, true);
|
|
48
|
+
}
|
|
49
|
+
setIsEditing(false);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error('Error stringifying arguments:', error);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
[requestArgs, id],
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (isEditing)
|
|
58
|
+
return (
|
|
59
|
+
<Suspense fallback={<Arguments arguments={requestArgs} />}>
|
|
60
|
+
<KeyValueEditor
|
|
61
|
+
initialValue={safeParseJSON(requestArgs || '')}
|
|
62
|
+
onCancel={handleCancel}
|
|
63
|
+
onFinish={handleFinish}
|
|
64
|
+
/>
|
|
65
|
+
</Suspense>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<Flexbox gap={12}>
|
|
70
|
+
<Arguments
|
|
71
|
+
actions={
|
|
72
|
+
<ActionIcon
|
|
73
|
+
icon={Edit3Icon}
|
|
74
|
+
onClick={() => {
|
|
75
|
+
setIsEditing(true);
|
|
76
|
+
}}
|
|
77
|
+
size={'small'}
|
|
78
|
+
title={t('edit', { ns: 'common' })}
|
|
79
|
+
/>
|
|
80
|
+
}
|
|
81
|
+
arguments={requestArgs}
|
|
82
|
+
/>
|
|
83
|
+
|
|
84
|
+
<Flexbox horizontal justify={'space-between'}>
|
|
85
|
+
<ModeSelector />
|
|
86
|
+
<ApprovalActions
|
|
87
|
+
apiName={apiName}
|
|
88
|
+
approvalMode={approvalMode}
|
|
89
|
+
identifier={identifier}
|
|
90
|
+
messageId={id}
|
|
91
|
+
toolCallId={toolCallId}
|
|
92
|
+
/>
|
|
93
|
+
</Flexbox>
|
|
94
|
+
</Flexbox>
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
export default Intervention;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
import { AlertTriangle } from 'lucide-react';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
|
7
|
+
|
|
8
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
9
|
+
container: css`
|
|
10
|
+
padding-block: 8px;
|
|
11
|
+
padding-inline: 6px;
|
|
12
|
+
`,
|
|
13
|
+
reason: css`
|
|
14
|
+
font-size: 12px;
|
|
15
|
+
color: ${token.colorTextTertiary};
|
|
16
|
+
`,
|
|
17
|
+
title: css`
|
|
18
|
+
font-size: 14px;
|
|
19
|
+
color: ${token.colorTextSecondary};
|
|
20
|
+
`,
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
interface RejectedResponseProps {
|
|
24
|
+
reason?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const RejectedResponse = memo<RejectedResponseProps>(({ reason }) => {
|
|
28
|
+
const { t } = useTranslation('chat');
|
|
29
|
+
const { styles, theme } = useStyles();
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Flexbox className={styles.container} gap={8}>
|
|
33
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
34
|
+
<Icon color={theme.colorWarning} icon={AlertTriangle} size={16} />
|
|
35
|
+
<div className={styles.title}>
|
|
36
|
+
{reason
|
|
37
|
+
? t('tool.intervention.rejectedWithReason', { reason })
|
|
38
|
+
: t('tool.intervention.toolRejected')}
|
|
39
|
+
</div>
|
|
40
|
+
</Flexbox>
|
|
41
|
+
</Flexbox>
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export default RejectedResponse;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { LOADING_FLAT } from '@lobechat/const';
|
|
2
|
-
import { ChatToolResult } from '@lobechat/types';
|
|
2
|
+
import { ChatToolResult, ToolIntervention } from '@lobechat/types';
|
|
3
3
|
import { Suspense, memo } from 'react';
|
|
4
4
|
|
|
5
5
|
import CustomRender from './CustomRender';
|
|
6
6
|
import ErrorResponse from './ErrorResponse';
|
|
7
|
+
import Intervention from './Intervention';
|
|
7
8
|
import LoadingPlaceholder from './LoadingPlaceholder';
|
|
9
|
+
import RejectedResponse from './RejectedResponse';
|
|
8
10
|
|
|
9
11
|
interface RenderProps {
|
|
10
12
|
apiName: string;
|
|
11
13
|
arguments?: string;
|
|
12
14
|
identifier: string;
|
|
15
|
+
intervention?: ToolIntervention;
|
|
13
16
|
/**
|
|
14
17
|
* ContentBlock ID (not the group message ID)
|
|
15
18
|
*/
|
|
@@ -18,6 +21,7 @@ interface RenderProps {
|
|
|
18
21
|
setShowPluginRender: (show: boolean) => void;
|
|
19
22
|
showPluginRender: boolean;
|
|
20
23
|
toolCallId: string;
|
|
24
|
+
toolMessageId?: string;
|
|
21
25
|
type?: string;
|
|
22
26
|
}
|
|
23
27
|
|
|
@@ -38,7 +42,25 @@ const Render = memo<RenderProps>(
|
|
|
38
42
|
apiName,
|
|
39
43
|
result,
|
|
40
44
|
type,
|
|
45
|
+
intervention,
|
|
46
|
+
toolMessageId,
|
|
41
47
|
}) => {
|
|
48
|
+
if (toolMessageId && intervention?.status === 'pending') {
|
|
49
|
+
return (
|
|
50
|
+
<Intervention
|
|
51
|
+
apiName={apiName}
|
|
52
|
+
id={toolMessageId}
|
|
53
|
+
identifier={identifier}
|
|
54
|
+
requestArgs={requestArgs || ''}
|
|
55
|
+
toolCallId={toolCallId}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (intervention?.status === 'rejected') {
|
|
61
|
+
return <RejectedResponse reason={intervention.rejectedReason} />;
|
|
62
|
+
}
|
|
63
|
+
|
|
42
64
|
if (!result) return null;
|
|
43
65
|
|
|
44
66
|
// Handle error state
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ChatToolResult } from '@lobechat/types';
|
|
2
|
-
import { CSSProperties, memo, useState } from 'react';
|
|
1
|
+
import { ChatToolResult, ToolIntervention } from '@lobechat/types';
|
|
2
|
+
import { CSSProperties, memo, useEffect, useState } from 'react';
|
|
3
3
|
import { Flexbox } from 'react-layout-kit';
|
|
4
4
|
|
|
5
5
|
import AnimatedCollapsed from '@/components/AnimatedCollapsed';
|
|
@@ -10,15 +10,17 @@ import Render from './Render';
|
|
|
10
10
|
export interface GroupToolProps {
|
|
11
11
|
apiName: string;
|
|
12
12
|
arguments?: string;
|
|
13
|
-
id: string;
|
|
14
|
-
identifier: string;
|
|
15
|
-
index: number;
|
|
16
13
|
/**
|
|
17
14
|
* ContentBlock ID (not the group message ID)
|
|
18
15
|
*/
|
|
19
|
-
|
|
16
|
+
assistantMessageId: string;
|
|
17
|
+
id: string;
|
|
18
|
+
identifier: string;
|
|
19
|
+
index: number;
|
|
20
|
+
intervention?: ToolIntervention;
|
|
20
21
|
result?: ChatToolResult;
|
|
21
22
|
style?: CSSProperties;
|
|
23
|
+
toolMessageId?: string;
|
|
22
24
|
type?: string;
|
|
23
25
|
}
|
|
24
26
|
|
|
@@ -29,10 +31,29 @@ export interface GroupToolProps {
|
|
|
29
31
|
* so we always show the results directly.
|
|
30
32
|
*/
|
|
31
33
|
const Tool = memo<GroupToolProps>(
|
|
32
|
-
({
|
|
34
|
+
({
|
|
35
|
+
arguments: requestArgs,
|
|
36
|
+
apiName,
|
|
37
|
+
assistantMessageId,
|
|
38
|
+
id,
|
|
39
|
+
intervention,
|
|
40
|
+
index,
|
|
41
|
+
identifier,
|
|
42
|
+
style,
|
|
43
|
+
result,
|
|
44
|
+
type,
|
|
45
|
+
toolMessageId,
|
|
46
|
+
}) => {
|
|
33
47
|
// Default to false since group messages are all completed
|
|
34
|
-
|
|
35
|
-
const [
|
|
48
|
+
|
|
49
|
+
const [showToolContent, setShowToolDetail] = useState(false);
|
|
50
|
+
const [showCustomPluginUI, setShowCustomPluginUI] = useState(false);
|
|
51
|
+
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (intervention?.status === 'pending') {
|
|
54
|
+
setShowToolDetail(true);
|
|
55
|
+
}
|
|
56
|
+
}, [intervention?.status]);
|
|
36
57
|
|
|
37
58
|
return (
|
|
38
59
|
<Flexbox gap={8} style={style}>
|
|
@@ -42,24 +63,27 @@ const Tool = memo<GroupToolProps>(
|
|
|
42
63
|
id={id}
|
|
43
64
|
identifier={identifier}
|
|
44
65
|
index={index}
|
|
45
|
-
|
|
66
|
+
intervention={intervention}
|
|
67
|
+
messageId={assistantMessageId}
|
|
46
68
|
result={result}
|
|
47
|
-
setShowPluginRender={
|
|
48
|
-
setShowRender={
|
|
49
|
-
showPluginRender={
|
|
50
|
-
showRender={
|
|
69
|
+
setShowPluginRender={setShowCustomPluginUI}
|
|
70
|
+
setShowRender={setShowToolDetail}
|
|
71
|
+
showPluginRender={showCustomPluginUI}
|
|
72
|
+
showRender={showToolContent}
|
|
51
73
|
type={type}
|
|
52
74
|
/>
|
|
53
|
-
<AnimatedCollapsed open={
|
|
75
|
+
<AnimatedCollapsed open={showToolContent} width={{ collapsed: 'auto' }}>
|
|
54
76
|
<Render
|
|
55
77
|
apiName={apiName}
|
|
56
78
|
arguments={requestArgs}
|
|
57
79
|
identifier={identifier}
|
|
58
|
-
|
|
80
|
+
intervention={intervention}
|
|
81
|
+
messageId={assistantMessageId}
|
|
59
82
|
result={result}
|
|
60
|
-
setShowPluginRender={
|
|
61
|
-
showPluginRender={
|
|
83
|
+
setShowPluginRender={setShowCustomPluginUI}
|
|
84
|
+
showPluginRender={showCustomPluginUI}
|
|
62
85
|
toolCallId={id}
|
|
86
|
+
toolMessageId={toolMessageId}
|
|
63
87
|
type={type}
|
|
64
88
|
/>
|
|
65
89
|
</AnimatedCollapsed>
|
|
@@ -32,12 +32,14 @@ export const Tools = memo<ToolsRendererProps>(({ messageId, tools }) => {
|
|
|
32
32
|
<Tool
|
|
33
33
|
apiName={tool.apiName}
|
|
34
34
|
arguments={tool.arguments}
|
|
35
|
+
assistantMessageId={messageId}
|
|
35
36
|
id={tool.id}
|
|
36
37
|
identifier={tool.identifier}
|
|
37
38
|
index={index}
|
|
39
|
+
intervention={tool.intervention}
|
|
38
40
|
key={tool.id}
|
|
39
|
-
messageId={messageId}
|
|
40
41
|
result={tool.result}
|
|
42
|
+
toolMessageId={tool.result_msg_id}
|
|
41
43
|
type={tool.type}
|
|
42
44
|
/>
|
|
43
45
|
))}
|
|
@@ -266,6 +266,8 @@ export default {
|
|
|
266
266
|
|
|
267
267
|
noSelectedAgents: '还未选择成员',
|
|
268
268
|
|
|
269
|
+
openInNewWindow: '单独打开页面',
|
|
270
|
+
|
|
269
271
|
owner: '群主',
|
|
270
272
|
|
|
271
273
|
pin: '置顶',
|
|
@@ -398,6 +400,26 @@ export default {
|
|
|
398
400
|
remained: '剩余',
|
|
399
401
|
used: '使用',
|
|
400
402
|
},
|
|
403
|
+
tool: {
|
|
404
|
+
intervention: {
|
|
405
|
+
approve: '批准',
|
|
406
|
+
approveAndRemember: '批准并记住',
|
|
407
|
+
approveOnce: '仅本次批准',
|
|
408
|
+
mode: {
|
|
409
|
+
allowList: '白名单',
|
|
410
|
+
allowListDesc: '仅自动执行已批准的工具',
|
|
411
|
+
autoRun: '自动批准',
|
|
412
|
+
autoRunDesc: '自动批准所有工具执行',
|
|
413
|
+
manual: '手动',
|
|
414
|
+
manualDesc: '每次调用都需要手动批准',
|
|
415
|
+
},
|
|
416
|
+
reject: '拒绝',
|
|
417
|
+
rejectReasonPlaceholder: '输入拒绝原因将帮助 Agent 理解并优化后续行动',
|
|
418
|
+
rejectTitle: '拒绝本次工具调用',
|
|
419
|
+
rejectedWithReason: '本次工具调用被主动拒绝:{{reason}}',
|
|
420
|
+
toolRejected: '本次工具调用被主动拒绝',
|
|
421
|
+
},
|
|
422
|
+
},
|
|
401
423
|
topic: {
|
|
402
424
|
checkOpenNewTopic: '是否开启新话题?',
|
|
403
425
|
checkSaveCurrentMessages: '是否保存当前会话为话题?',
|
|
@@ -179,11 +179,14 @@ export const messageRouter = router({
|
|
|
179
179
|
.input(
|
|
180
180
|
z.object({
|
|
181
181
|
id: z.string(),
|
|
182
|
+
sessionId: z.string().nullable().optional(),
|
|
183
|
+
topicId: z.string().nullable().optional(),
|
|
182
184
|
value: UpdateMessagePluginSchema.partial(),
|
|
183
185
|
}),
|
|
184
186
|
)
|
|
185
187
|
.mutation(async ({ input, ctx }) => {
|
|
186
|
-
|
|
188
|
+
const { id, value, ...options } = input;
|
|
189
|
+
return ctx.messageService.updateMessagePlugin(id, value, options);
|
|
187
190
|
}),
|
|
188
191
|
|
|
189
192
|
updateMessageRAG: messageProcedure
|
|
@@ -150,6 +150,19 @@ export class MessageService {
|
|
|
150
150
|
return this.queryWithSuccess(options);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Update message plugin and return message list
|
|
155
|
+
* Pattern: update + conditional query
|
|
156
|
+
*/
|
|
157
|
+
async updateMessagePlugin(
|
|
158
|
+
id: string,
|
|
159
|
+
value: any,
|
|
160
|
+
options: QueryOptions,
|
|
161
|
+
): Promise<{ messages?: UIChatMessage[], success: boolean; }> {
|
|
162
|
+
await this.messageModel.updateMessagePlugin(id, value);
|
|
163
|
+
return this.queryWithSuccess(options);
|
|
164
|
+
}
|
|
165
|
+
|
|
153
166
|
/**
|
|
154
167
|
* Update message and return message list
|
|
155
168
|
* Pattern: update + conditional query
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
CreateMessageParams,
|
|
7
7
|
CreateMessageResult,
|
|
8
8
|
MessageMetadata,
|
|
9
|
+
MessagePluginItem,
|
|
9
10
|
ModelRankItem,
|
|
10
11
|
UIChatMessage,
|
|
11
12
|
UpdateMessageParams,
|
|
@@ -77,8 +78,9 @@ export class MessageService {
|
|
|
77
78
|
};
|
|
78
79
|
|
|
79
80
|
updateMessageError = async (id: string, value: ChatMessageError) => {
|
|
80
|
-
const error = value.type
|
|
81
|
-
|
|
81
|
+
const error = value.type
|
|
82
|
+
? value
|
|
83
|
+
: { body: value, message: value.message, type: 'ApplicationRuntimeError' };
|
|
82
84
|
|
|
83
85
|
return lambdaClient.message.update.mutate({ id, value: { error } });
|
|
84
86
|
};
|
|
@@ -153,6 +155,19 @@ export class MessageService {
|
|
|
153
155
|
});
|
|
154
156
|
};
|
|
155
157
|
|
|
158
|
+
updateMessagePlugin = async (
|
|
159
|
+
id: string,
|
|
160
|
+
value: Partial<Omit<MessagePluginItem, 'id'>>,
|
|
161
|
+
options?: { sessionId?: string | null; topicId?: string | null },
|
|
162
|
+
): Promise<UpdateMessageResult> => {
|
|
163
|
+
return lambdaClient.message.updateMessagePlugin.mutate({
|
|
164
|
+
id,
|
|
165
|
+
sessionId: options?.sessionId,
|
|
166
|
+
topicId: options?.topicId,
|
|
167
|
+
value,
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
|
|
156
171
|
updateMessageRAG = async (
|
|
157
172
|
id: string,
|
|
158
173
|
data: UpdateMessageRAGParams,
|