@agentscope-ai/chat 1.1.49 → 1.1.50-beta.1770277970282
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/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Request/Builder.tsx +10 -1
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Request/Card.tsx +2 -1
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Actions.tsx +3 -1
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Approval.tsx +100 -0
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/ApprovalCancelPopover.tsx +169 -0
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Card.tsx +2 -0
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Tool.tsx +12 -3
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/types.tsx +1 -1
- package/components/AgentScopeRuntimeWebUI/core/Chat/Input/index.tsx +1 -1
- package/components/AgentScopeRuntimeWebUI/core/Chat/MessageList/index.tsx +1 -1
- package/components/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatController.tsx +21 -1
- package/components/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatMessageHandler.tsx +23 -1
- package/components/AgentScopeRuntimeWebUI/core/ChatAnywhere/ComposedProvider.tsx +2 -0
- package/components/AgentScopeRuntimeWebUI/core/Context/ChatAnywhereI18nContext.tsx +151 -0
- package/components/AgentScopeRuntimeWebUI/core/Context/ChatAnywhereInputContext.tsx +2 -2
- package/components/AgentScopeRuntimeWebUI/core/Sessions/index.tsx +1 -1
- package/components/AgentScopeRuntimeWebUI/core/types/IChatAnywhere.ts +11 -6
- package/components/AgentScopeRuntimeWebUI/starter/MessageImport/index.tsx +52 -0
- package/components/AgentScopeRuntimeWebUI/starter/OptionsPanel/OptionsEditor.tsx +12 -1
- package/components/AgentScopeRuntimeWebUI/starter/OptionsPanel/defaultConfig.ts +1 -0
- package/components/AgentScopeRuntimeWebUI/starter/OptionsPanel/index.tsx +2 -1
- package/components/AgentScopeRuntimeWebUI/starter/index.tsx +14 -6
- package/components/Sender/components/LoadingButton.tsx +22 -15
- package/components/Sender/index.tsx +5 -5
- package/components/StatusCard/index.tsx +20 -14
- package/components/StatusCard/style.ts +4 -4
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Request/Builder.d.ts +3 -1
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Request/Builder.js +36 -20
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Request/Card.js +1 -0
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Actions.js +4 -1
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Approval.d.ts +4 -0
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Approval.js +113 -0
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/ApprovalCancelPopover.d.ts +25 -0
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/ApprovalCancelPopover.js +129 -0
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Card.js +5 -0
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Tool.d.ts +1 -0
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Tool.js +14 -3
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/types.d.ts +1 -1
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/types.js +1 -1
- package/lib/AgentScopeRuntimeWebUI/core/Chat/Input/index.js +1 -1
- package/lib/AgentScopeRuntimeWebUI/core/Chat/MessageList/index.js +1 -1
- package/lib/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatController.js +72 -22
- package/lib/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatMessageHandler.d.ts +1 -0
- package/lib/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatMessageHandler.js +17 -1
- package/lib/AgentScopeRuntimeWebUI/core/ChatAnywhere/ComposedProvider.js +4 -1
- package/lib/AgentScopeRuntimeWebUI/core/Context/ChatAnywhereI18nContext.d.ts +83 -0
- package/lib/AgentScopeRuntimeWebUI/core/Context/ChatAnywhereI18nContext.js +143 -0
- package/lib/AgentScopeRuntimeWebUI/core/Sessions/index.js +1 -1
- package/lib/AgentScopeRuntimeWebUI/core/types/IChatAnywhere.d.ts +11 -5
- package/lib/AgentScopeRuntimeWebUI/starter/MessageImport/index.d.ts +1 -0
- package/lib/AgentScopeRuntimeWebUI/starter/MessageImport/index.js +87 -0
- package/lib/AgentScopeRuntimeWebUI/starter/OptionsPanel/OptionsEditor.js +16 -1
- package/lib/AgentScopeRuntimeWebUI/starter/OptionsPanel/defaultConfig.d.ts +1 -0
- package/lib/AgentScopeRuntimeWebUI/starter/OptionsPanel/defaultConfig.js +1 -0
- package/lib/AgentScopeRuntimeWebUI/starter/index.js +15 -8
- package/lib/Sender/components/LoadingButton.d.ts +3 -1
- package/lib/Sender/components/LoadingButton.js +16 -3
- package/lib/Sender/index.d.ts +2 -2
- package/lib/Sender/index.js +5 -3
- package/lib/StatusCard/index.d.ts +7 -2
- package/lib/StatusCard/index.js +4 -4
- package/lib/StatusCard/style.js +1 -1
- package/package.json +1 -1
|
@@ -50,7 +50,11 @@ class AgentScopeRuntimeRequestBuilder {
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
constructor(
|
|
53
|
+
constructor() { }
|
|
54
|
+
|
|
55
|
+
handle(data: IAgentScopeRuntimeWebUIInputData) {
|
|
56
|
+
this.data = { input: [] };
|
|
57
|
+
|
|
54
58
|
const content: IContent[] = [
|
|
55
59
|
this.buildTextContent(data.query),
|
|
56
60
|
];
|
|
@@ -74,7 +78,12 @@ class AgentScopeRuntimeRequestBuilder {
|
|
|
74
78
|
}
|
|
75
79
|
],
|
|
76
80
|
};
|
|
81
|
+
return this.data
|
|
82
|
+
}
|
|
77
83
|
|
|
84
|
+
handleApproval(input) {
|
|
85
|
+
this.data = { input };
|
|
86
|
+
return this.data;
|
|
78
87
|
}
|
|
79
88
|
}
|
|
80
89
|
|
|
@@ -6,7 +6,6 @@ import { Bubble } from '@agentscope-ai/chat';
|
|
|
6
6
|
export default function AgentScopeRuntimeRequestCard(props: {
|
|
7
7
|
data: IAgentScopeRuntimeRequest;
|
|
8
8
|
}) {
|
|
9
|
-
|
|
10
9
|
const cards = useMemo(() => {
|
|
11
10
|
|
|
12
11
|
return props.data.input[0].content.reduce<any>((p, c) => {
|
|
@@ -48,6 +47,8 @@ export default function AgentScopeRuntimeRequestCard(props: {
|
|
|
48
47
|
}, []);
|
|
49
48
|
}, [props.data.input]);
|
|
50
49
|
|
|
50
|
+
if (!cards?.length) return null;
|
|
51
|
+
|
|
51
52
|
return <Bubble role="user" cards={cards}></Bubble>;
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -6,6 +6,7 @@ import { copy, Tooltip } from "@agentscope-ai/design";
|
|
|
6
6
|
import compact from 'lodash/compact';
|
|
7
7
|
import { emit } from "../../Context/useChatAnywhereEventEmitter";
|
|
8
8
|
import { useChatAnywhereOptions } from "../../Context/ChatAnywhereOptionsContext";
|
|
9
|
+
import { useTranslation } from "../../Context/ChatAnywhereI18nContext";
|
|
9
10
|
import React from "react";
|
|
10
11
|
|
|
11
12
|
|
|
@@ -24,6 +25,7 @@ export default function Tools(props: {
|
|
|
24
25
|
data: IAgentScopeRuntimeResponse
|
|
25
26
|
isLast?: boolean;
|
|
26
27
|
}) {
|
|
28
|
+
const { t } = useTranslation();
|
|
27
29
|
const actionsOptionsList = useChatAnywhereOptions(v => v.actions?.list) || [
|
|
28
30
|
{
|
|
29
31
|
icon: <SparkCopyLine />,
|
|
@@ -49,7 +51,7 @@ export default function Tools(props: {
|
|
|
49
51
|
}
|
|
50
52
|
}),
|
|
51
53
|
replace && props.isLast ? {
|
|
52
|
-
icon: <Tooltip title=
|
|
54
|
+
icon: <Tooltip title={t?.('actions.regenerate') || '重新生成'}><SparkReplaceLine /></Tooltip>,
|
|
53
55
|
onClick: () => {
|
|
54
56
|
emit({
|
|
55
57
|
type: 'handleReplace',
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { StatusCard } from '@agentscope-ai/chat';
|
|
2
|
+
import { Button, Popover } from '@agentscope-ai/design';
|
|
3
|
+
import { Flex } from 'antd';
|
|
4
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
5
|
+
import { createStyles } from 'antd-style'
|
|
6
|
+
import ApprovalCancelPopover from './ApprovalCancelPopover';
|
|
7
|
+
import { AgentScopeRuntimeContentType, AgentScopeRuntimeMessageRole, AgentScopeRuntimeMessageType, IAgentScopeRuntimeMessage, IDataContent } from '../types';
|
|
8
|
+
import { useChatAnywhereInput } from '../../Context/ChatAnywhereInputContext';
|
|
9
|
+
import { emit } from "../../Context/useChatAnywhereEventEmitter";
|
|
10
|
+
import { useTranslation } from '../../Context/ChatAnywhereI18nContext';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
14
|
+
desc: css`
|
|
15
|
+
font-size: 12px;
|
|
16
|
+
color: ${token.colorTextTertiary};
|
|
17
|
+
`,
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export default function Approval({ data }: { data: IAgentScopeRuntimeMessage }) {
|
|
22
|
+
const inputContext = useChatAnywhereInput(v => v);
|
|
23
|
+
const { styles } = useStyles();
|
|
24
|
+
const { t } = useTranslation();
|
|
25
|
+
const [status, setStatus] = useState<'pending' | 'confirmed' | 'canceled'>('pending');
|
|
26
|
+
const title = t?.('approval.title') || '人工干预';
|
|
27
|
+
|
|
28
|
+
const description = useMemo(() => {
|
|
29
|
+
if (status === 'pending') return t?.('approval.pending') || '请确认是否执行该操作';
|
|
30
|
+
if (status === 'confirmed') return t?.('approval.confirmed') || '确认执行任务';
|
|
31
|
+
return t?.('approval.canceled') || '取消执行任务';
|
|
32
|
+
}, [status, t]);
|
|
33
|
+
|
|
34
|
+
const handleConfirm = useCallback((status: 'confirmed' | 'canceled', reason?: string) => {
|
|
35
|
+
setStatus(status);
|
|
36
|
+
inputContext.setLoading(false);
|
|
37
|
+
inputContext.setDisabled(false);
|
|
38
|
+
|
|
39
|
+
const request = data
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
const id = request.content[0]?.data?.id;
|
|
42
|
+
const response = {
|
|
43
|
+
type: AgentScopeRuntimeMessageType.MCP_APPROVAL_RESPONSE,
|
|
44
|
+
role: AgentScopeRuntimeMessageRole.USER,
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: AgentScopeRuntimeContentType.DATA,
|
|
48
|
+
data: {
|
|
49
|
+
"approve": status === 'confirmed',
|
|
50
|
+
"id": id,
|
|
51
|
+
"approval_request_id": id,
|
|
52
|
+
"reason": reason
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
emit({
|
|
60
|
+
type: 'handleApproval', data: {
|
|
61
|
+
input: [
|
|
62
|
+
request,
|
|
63
|
+
response,
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
}, [data]);
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
const actions = useMemo(() => {
|
|
72
|
+
if (status === 'pending') {
|
|
73
|
+
return <Flex gap={8}>
|
|
74
|
+
<ApprovalCancelPopover onConfirm={(reason) => handleConfirm('canceled', reason)} />
|
|
75
|
+
<Button size="small" type="primary" onClick={() => handleConfirm('confirmed')}>
|
|
76
|
+
{t?.('approval.confirm') || '确认执行'}
|
|
77
|
+
</Button>
|
|
78
|
+
</Flex>
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}, [status, t]);
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (status === 'pending') {
|
|
86
|
+
inputContext.setLoading(t?.('approval.taskRunning') || '当前有正在执行的任务,无法发送新的任务');
|
|
87
|
+
inputContext.setDisabled(true);
|
|
88
|
+
}
|
|
89
|
+
}, [status, t]);
|
|
90
|
+
|
|
91
|
+
return <StatusCard.HITL
|
|
92
|
+
done={status !== 'pending'}
|
|
93
|
+
onDone={() => { }}
|
|
94
|
+
title={<Flex gap={8}>
|
|
95
|
+
{title}
|
|
96
|
+
<span className={styles.desc}>{description}</span>
|
|
97
|
+
</Flex>}
|
|
98
|
+
actions={actions}
|
|
99
|
+
/>
|
|
100
|
+
}
|
package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/ApprovalCancelPopover.tsx
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Button, Input, Popover } from '@agentscope-ai/design';
|
|
2
|
+
import { Flex } from 'antd';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { createStyles } from 'antd-style';
|
|
5
|
+
import { useTranslation } from '../../Context/ChatAnywhereI18nContext';
|
|
6
|
+
|
|
7
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
8
|
+
container: css`
|
|
9
|
+
width: 386px;
|
|
10
|
+
`,
|
|
11
|
+
title: css`
|
|
12
|
+
font-size: 14px;
|
|
13
|
+
font-weight: 500;
|
|
14
|
+
color: ${token.colorText};
|
|
15
|
+
margin-bottom: 16px;
|
|
16
|
+
`,
|
|
17
|
+
content: css`
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
gap: 8px;
|
|
21
|
+
`,
|
|
22
|
+
tabsContainer: css`
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-wrap: wrap;
|
|
25
|
+
gap: 8px;
|
|
26
|
+
`,
|
|
27
|
+
tabItem: css`
|
|
28
|
+
padding: 0 8px;
|
|
29
|
+
font-size: 14px;
|
|
30
|
+
color: ${token.colorText};
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
border: 1px solid ${token.colorBorderSecondary};
|
|
33
|
+
background: ${token.colorBgContainer};
|
|
34
|
+
transition: all 0.2s;
|
|
35
|
+
user-select: none;
|
|
36
|
+
border-radius: 4px;
|
|
37
|
+
`,
|
|
38
|
+
tabItemSelected: css`
|
|
39
|
+
color: ${token.colorPrimary};
|
|
40
|
+
border-color: ${token.colorPrimary};
|
|
41
|
+
border: 1px solid ${token.colorPrimary};
|
|
42
|
+
position: relative;
|
|
43
|
+
z-index: 1;
|
|
44
|
+
`,
|
|
45
|
+
textarea: css`
|
|
46
|
+
resize: none;
|
|
47
|
+
`,
|
|
48
|
+
actions: css`
|
|
49
|
+
display: flex;
|
|
50
|
+
justify-content: flex-end;
|
|
51
|
+
gap: 8px;
|
|
52
|
+
`,
|
|
53
|
+
}));
|
|
54
|
+
|
|
55
|
+
export interface ApprovalCancelPopoverProps {
|
|
56
|
+
/**
|
|
57
|
+
* @description 预设的取消原因选项
|
|
58
|
+
* @descriptionEn Preset cancel reason options
|
|
59
|
+
*/
|
|
60
|
+
options?: string[];
|
|
61
|
+
/**
|
|
62
|
+
* @description 确认回调
|
|
63
|
+
* @descriptionEn Confirm callback
|
|
64
|
+
*/
|
|
65
|
+
onConfirm?: (reason: string) => void;
|
|
66
|
+
/**
|
|
67
|
+
* @description 标题
|
|
68
|
+
* @descriptionEn Title
|
|
69
|
+
* @default '取消原因'
|
|
70
|
+
*/
|
|
71
|
+
title?: string;
|
|
72
|
+
/**
|
|
73
|
+
* @description 文本框占位符
|
|
74
|
+
* @descriptionEn Textarea placeholder
|
|
75
|
+
* @default '请输入原因,以便大模型做进一步规划'
|
|
76
|
+
*/
|
|
77
|
+
placeholder?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function useDefaultOptions() {
|
|
81
|
+
const { t } = useTranslation();
|
|
82
|
+
return [
|
|
83
|
+
t?.('cancelPopover.options.notNeeded') || '不需要',
|
|
84
|
+
t?.('cancelPopover.options.poorResult') || '效果不理想',
|
|
85
|
+
t?.('cancelPopover.options.tooSlow') || '等待时间久',
|
|
86
|
+
t?.('cancelPopover.options.wrongInput') || '输入错误',
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface TabSelectProps {
|
|
91
|
+
options: string[];
|
|
92
|
+
onSelect: (value: string) => void;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function TabSelect(props: TabSelectProps) {
|
|
96
|
+
const { options, } = props;
|
|
97
|
+
const [value, setValue] = useState<string>();
|
|
98
|
+
const { styles } = useStyles();
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div className={styles.tabsContainer}>
|
|
102
|
+
{options.map((option) => (
|
|
103
|
+
<div
|
|
104
|
+
key={option}
|
|
105
|
+
className={`${styles.tabItem} ${value === option ? styles.tabItemSelected : ''}`}
|
|
106
|
+
onClick={() => {
|
|
107
|
+
setValue(option);
|
|
108
|
+
props.onSelect(option);
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
{option}
|
|
112
|
+
</div>
|
|
113
|
+
))}
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export default function ApprovalCancelPopover(props: ApprovalCancelPopoverProps) {
|
|
119
|
+
const { t } = useTranslation();
|
|
120
|
+
const defaultOptions = useDefaultOptions();
|
|
121
|
+
|
|
122
|
+
const {
|
|
123
|
+
options = defaultOptions,
|
|
124
|
+
onConfirm,
|
|
125
|
+
title = t?.('cancelPopover.title') || '取消原因',
|
|
126
|
+
placeholder = t?.('cancelPopover.placeholder') || '请输入原因,以便大模型做进一步规划',
|
|
127
|
+
} = props;
|
|
128
|
+
|
|
129
|
+
const [open, setOpen] = useState<boolean>(false);
|
|
130
|
+
|
|
131
|
+
const { styles } = useStyles();
|
|
132
|
+
const [reason, setReason] = useState<string>('');
|
|
133
|
+
|
|
134
|
+
const handleConfirm = () => {
|
|
135
|
+
onConfirm?.(reason.trim());
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const content = <div className={styles.container}>
|
|
139
|
+
<div className={styles.title}>{title}</div>
|
|
140
|
+
<div className={styles.content}>
|
|
141
|
+
<TabSelect
|
|
142
|
+
options={options}
|
|
143
|
+
onSelect={setReason}
|
|
144
|
+
/>
|
|
145
|
+
<Input.TextArea
|
|
146
|
+
className={styles.textarea}
|
|
147
|
+
value={reason}
|
|
148
|
+
onChange={(e) => setReason(e.target.value)}
|
|
149
|
+
placeholder={placeholder}
|
|
150
|
+
rows={3}
|
|
151
|
+
/>
|
|
152
|
+
<Flex className={styles.actions}>
|
|
153
|
+
<Button size="small" onClick={() => setOpen(false)}>
|
|
154
|
+
{t?.('cancelPopover.cancel') || '取消'}
|
|
155
|
+
</Button>
|
|
156
|
+
<Button size="small" type="primary" onClick={() => {
|
|
157
|
+
setOpen(false);
|
|
158
|
+
handleConfirm();
|
|
159
|
+
}}>
|
|
160
|
+
{t?.('cancelPopover.confirm') || '确认'}
|
|
161
|
+
</Button>
|
|
162
|
+
</Flex>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
return <Popover open={open} onOpenChange={setOpen} trigger="click" content={content}>
|
|
167
|
+
<Button size="small" >{t?.('approval.cancel') || '取消执行'}</Button>
|
|
168
|
+
</Popover>
|
|
169
|
+
}
|
|
@@ -29,6 +29,8 @@ export default function AgentScopeRuntimeResponseCard(props: {
|
|
|
29
29
|
case AgentScopeRuntimeMessageType.MCP_CALL:
|
|
30
30
|
case AgentScopeRuntimeMessageType.MCP_CALL_OUTPUT:
|
|
31
31
|
return <Tool key={item.id} data={item} />
|
|
32
|
+
case AgentScopeRuntimeMessageType.MCP_APPROVAL_REQUEST:
|
|
33
|
+
return <Tool key={item.id} data={item} isApproval={true} />
|
|
32
34
|
case AgentScopeRuntimeMessageType.REASONING:
|
|
33
35
|
return <Reasoning key={item.id} data={item} />
|
|
34
36
|
case AgentScopeRuntimeMessageType.ERROR:
|
|
@@ -2,8 +2,9 @@ import React from "react";
|
|
|
2
2
|
import { AgentScopeRuntimeRunStatus, IAgentScopeRuntimeMessage, IDataContent } from "../types";
|
|
3
3
|
import { ToolCall } from '@agentscope-ai/chat';
|
|
4
4
|
import { useChatAnywhereOptions } from "../../Context/ChatAnywhereOptionsContext";
|
|
5
|
+
import Approval from "./Approval";
|
|
5
6
|
|
|
6
|
-
const Tool = React.memo(function ({ data }: { data: IAgentScopeRuntimeMessage }) {
|
|
7
|
+
const Tool = React.memo(function ({ data, isApproval = false }: { data: IAgentScopeRuntimeMessage, isApproval?: boolean }) {
|
|
7
8
|
const customToolRenderConfig = useChatAnywhereOptions(v => v.customToolRenderConfig) || {};
|
|
8
9
|
|
|
9
10
|
if (!data.content?.length) return null;
|
|
@@ -18,13 +19,21 @@ const Tool = React.memo(function ({ data }: { data: IAgentScopeRuntimeMessage })
|
|
|
18
19
|
const serverLabel = `${content[0].data.server_label ? content[0].data.server_label + ' / ' : ''}`
|
|
19
20
|
const title = `${serverLabel}${toolName}`
|
|
20
21
|
|
|
22
|
+
let node
|
|
23
|
+
|
|
21
24
|
if (customToolRenderConfig[toolName]) {
|
|
22
25
|
const C = customToolRenderConfig[toolName];
|
|
23
|
-
|
|
26
|
+
node = <C data={data} />
|
|
24
27
|
} else {
|
|
25
|
-
|
|
28
|
+
node = <ToolCall loading={loading} defaultOpen={false} title={title === 'undefined' ? '' : title} input={content[0]?.data?.arguments} output={content[1]?.data?.output}></ToolCall>
|
|
26
29
|
}
|
|
30
|
+
|
|
31
|
+
return <>
|
|
32
|
+
{node}
|
|
33
|
+
{isApproval && <Approval data={data}/>}
|
|
34
|
+
</>;
|
|
27
35
|
})
|
|
28
36
|
|
|
37
|
+
|
|
29
38
|
export default Tool;
|
|
30
39
|
|
|
@@ -25,9 +25,9 @@ export enum AgentScopeRuntimeMessageType {
|
|
|
25
25
|
COMPONENT_CALL_OUTPUT = "component_call_output",
|
|
26
26
|
MCP_LIST_TOOLS = "mcp_list_tools",
|
|
27
27
|
MCP_APPROVAL_REQUEST = "mcp_approval_request",
|
|
28
|
+
MCP_APPROVAL_RESPONSE = "mcp_approval_response",
|
|
28
29
|
MCP_CALL = "mcp_call",
|
|
29
30
|
MCP_CALL_OUTPUT = "mcp_call_output",
|
|
30
|
-
MCP_APPROVAL_RESPONSE = "mcp_approval_response",
|
|
31
31
|
HEARTBEAT = "heartbeat",
|
|
32
32
|
ERROR = "error",
|
|
33
33
|
}
|
|
@@ -33,7 +33,7 @@ export default function Input(props: InputProps) {
|
|
|
33
33
|
setFileList,
|
|
34
34
|
uploadIconButton,
|
|
35
35
|
uploadFileListHeader
|
|
36
|
-
} = useAttachments(attachments, { disabled: inputContext.disabled });
|
|
36
|
+
} = useAttachments(attachments, { disabled: !!inputContext.disabled });
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
const handleSubmit = useCallback(async () => {
|
|
@@ -70,7 +70,6 @@ export default function useChatController() {
|
|
|
70
70
|
// 3. 创建用户请求消息
|
|
71
71
|
messageHandler.createRequestMessage(data);
|
|
72
72
|
setLoading(true);
|
|
73
|
-
|
|
74
73
|
await sleep(100);
|
|
75
74
|
|
|
76
75
|
// 4. 创建助手响应消息
|
|
@@ -84,6 +83,20 @@ export default function useChatController() {
|
|
|
84
83
|
// mockRequest(mockdata);
|
|
85
84
|
}, [messageHandler, sessionHandler, request]);
|
|
86
85
|
|
|
86
|
+
|
|
87
|
+
const handleApproval = useCallback(async ({ input }) => {
|
|
88
|
+
messageHandler.createApprovalMessage(input);
|
|
89
|
+
|
|
90
|
+
setLoading(true);
|
|
91
|
+
await sleep(100);
|
|
92
|
+
|
|
93
|
+
messageHandler.createResponseMessage();
|
|
94
|
+
const historyMessages = messageHandler.getHistoryMessages();
|
|
95
|
+
await sessionHandler.syncSessionMessages(messageHandler.getMessages());
|
|
96
|
+
|
|
97
|
+
await request(historyMessages);
|
|
98
|
+
}, [messageHandler, sessionHandler, request]);
|
|
99
|
+
|
|
87
100
|
/**
|
|
88
101
|
* 处理取消
|
|
89
102
|
*/
|
|
@@ -133,6 +146,13 @@ export default function useChatController() {
|
|
|
133
146
|
}
|
|
134
147
|
}, [handleSubmit]);
|
|
135
148
|
|
|
149
|
+
useChatAnywhereEventEmitter({
|
|
150
|
+
type: 'handleApproval',
|
|
151
|
+
callback: async (data) => {
|
|
152
|
+
await handleApproval(data.detail);
|
|
153
|
+
}
|
|
154
|
+
}, [handleApproval]);
|
|
155
|
+
|
|
136
156
|
|
|
137
157
|
return {
|
|
138
158
|
handleSubmit,
|
|
@@ -32,7 +32,7 @@ export default function useChatMessageHandler(options: UseChatMessageHandlerOpti
|
|
|
32
32
|
role: 'user',
|
|
33
33
|
cards: [{
|
|
34
34
|
code: 'AgentScopeRuntimeRequestCard',
|
|
35
|
-
data: new AgentScopeRuntimeRequestBuilder(
|
|
35
|
+
data: new AgentScopeRuntimeRequestBuilder().handle(data),
|
|
36
36
|
}]
|
|
37
37
|
};
|
|
38
38
|
|
|
@@ -43,6 +43,27 @@ export default function useChatMessageHandler(options: UseChatMessageHandlerOpti
|
|
|
43
43
|
return currentQARef.current.request;
|
|
44
44
|
}, [currentQARef, updateMessage]);
|
|
45
45
|
|
|
46
|
+
|
|
47
|
+
const createApprovalMessage = useCallback((data) => {
|
|
48
|
+
currentQARef.current.abortController = new AbortController();
|
|
49
|
+
|
|
50
|
+
currentQARef.current.request = {
|
|
51
|
+
id: uuid(),
|
|
52
|
+
role: 'user',
|
|
53
|
+
cards: [{
|
|
54
|
+
code: 'AgentScopeRuntimeRequestCard',
|
|
55
|
+
data: new AgentScopeRuntimeRequestBuilder().handleApproval(data),
|
|
56
|
+
}]
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
ReactDOM.flushSync(() => {
|
|
60
|
+
updateMessage(currentQARef.current.request!);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return currentQARef.current.request;
|
|
64
|
+
|
|
65
|
+
}, [currentQARef, updateMessage]);
|
|
66
|
+
|
|
46
67
|
/**
|
|
47
68
|
* 创建助手响应消息
|
|
48
69
|
*/
|
|
@@ -77,6 +98,7 @@ export default function useChatMessageHandler(options: UseChatMessageHandlerOpti
|
|
|
77
98
|
|
|
78
99
|
return {
|
|
79
100
|
createRequestMessage,
|
|
101
|
+
createApprovalMessage,
|
|
80
102
|
createResponseMessage,
|
|
81
103
|
getHistoryMessages,
|
|
82
104
|
updateMessage,
|
|
@@ -4,10 +4,12 @@ import { ChatAnywhereOptionsContextProvider } from "../Context/ChatAnywhereOptio
|
|
|
4
4
|
import { ChatAnywhereSessionsContextProvider } from "../Context/ChatAnywhereSessionsContext";
|
|
5
5
|
import { ChatAnywhereMessagesContextProvider } from "../Context/ChatAnywhereMessagesContext";
|
|
6
6
|
import { ChatAnyWhereLayoutContextProvider } from "../Context/ChatAnywhereLayoutContext";
|
|
7
|
+
import { ChatAnywhereI18nContextProvider, Locale } from "../Context/ChatAnywhereI18nContext";
|
|
7
8
|
|
|
8
9
|
function ComposedProvider(props: { options, cards, children }) {
|
|
9
10
|
const { options, cards, children } = props;
|
|
10
11
|
const providers = [
|
|
12
|
+
[ChatAnywhereI18nContextProvider, { defaultLocale: options.theme.locale }],
|
|
11
13
|
[ChatAnywhereOptionsContextProvider, { options }],
|
|
12
14
|
[CustomCardsProvider, { cardConfig: cards }],
|
|
13
15
|
[ChatAnywhereSessionsContextProvider, {}],
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { createContext, useContextSelector } from 'use-context-selector';
|
|
2
|
+
import { useMemo, useState, useCallback } from 'react';
|
|
3
|
+
|
|
4
|
+
export type Locale = 'cn' | 'en';
|
|
5
|
+
|
|
6
|
+
// 国际化文案定义
|
|
7
|
+
const messages = {
|
|
8
|
+
cn: {
|
|
9
|
+
// Approval 相关
|
|
10
|
+
'approval.title': '人工干预',
|
|
11
|
+
'approval.pending': '请确认是否执行该操作',
|
|
12
|
+
'approval.confirmed': '确认执行任务',
|
|
13
|
+
'approval.canceled': '取消执行任务',
|
|
14
|
+
'approval.cancel': '取消执行',
|
|
15
|
+
'approval.confirm': '确认执行',
|
|
16
|
+
'approval.taskRunning': '当前有正在执行的任务,无法发送新的任务',
|
|
17
|
+
|
|
18
|
+
// ApprovalCancelPopover 相关
|
|
19
|
+
'cancelPopover.title': '取消原因',
|
|
20
|
+
'cancelPopover.placeholder': '请输入原因,以便大模型做进一步规划',
|
|
21
|
+
'cancelPopover.cancel': '取消',
|
|
22
|
+
'cancelPopover.confirm': '确认',
|
|
23
|
+
'cancelPopover.options.notNeeded': '不需要',
|
|
24
|
+
'cancelPopover.options.poorResult': '效果不理想',
|
|
25
|
+
'cancelPopover.options.tooSlow': '等待时间久',
|
|
26
|
+
'cancelPopover.options.wrongInput': '输入错误',
|
|
27
|
+
|
|
28
|
+
// 通用
|
|
29
|
+
'common.save': '保存',
|
|
30
|
+
'common.cancel': '取消',
|
|
31
|
+
'common.confirm': '确认',
|
|
32
|
+
'common.delete': '删除',
|
|
33
|
+
'common.edit': '编辑',
|
|
34
|
+
'common.loading': '加载中...',
|
|
35
|
+
'common.saveSuccess': '保存成功',
|
|
36
|
+
'common.saveFailed': '保存失败',
|
|
37
|
+
|
|
38
|
+
// Actions 相关
|
|
39
|
+
'actions.regenerate': '重新生成',
|
|
40
|
+
|
|
41
|
+
// MessageImport 相关
|
|
42
|
+
'messageImport.title': 'Sessions 数据导入',
|
|
43
|
+
'messageImport.placeholder': '输入 JSON 数据以覆盖当前 sessions',
|
|
44
|
+
'messageImport.saveToLocalStorage': '保存到 LocalStorage',
|
|
45
|
+
},
|
|
46
|
+
en: {
|
|
47
|
+
// Approval related
|
|
48
|
+
'approval.title': 'Human Intervention',
|
|
49
|
+
'approval.pending': 'Please confirm whether to execute this operation',
|
|
50
|
+
'approval.confirmed': 'Confirmed to execute task',
|
|
51
|
+
'approval.canceled': 'Canceled task execution',
|
|
52
|
+
'approval.cancel': 'Cancel',
|
|
53
|
+
'approval.confirm': 'Confirm',
|
|
54
|
+
'approval.taskRunning': 'A task is currently running, cannot send new task',
|
|
55
|
+
|
|
56
|
+
// ApprovalCancelPopover related
|
|
57
|
+
'cancelPopover.title': 'Cancel Reason',
|
|
58
|
+
'cancelPopover.placeholder': 'Please enter the reason for better AI planning',
|
|
59
|
+
'cancelPopover.cancel': 'Cancel',
|
|
60
|
+
'cancelPopover.confirm': 'Confirm',
|
|
61
|
+
'cancelPopover.options.notNeeded': 'Not needed',
|
|
62
|
+
'cancelPopover.options.poorResult': 'Poor result',
|
|
63
|
+
'cancelPopover.options.tooSlow': 'Too slow',
|
|
64
|
+
'cancelPopover.options.wrongInput': 'Wrong input',
|
|
65
|
+
|
|
66
|
+
// Common
|
|
67
|
+
'common.save': 'Save',
|
|
68
|
+
'common.cancel': 'Cancel',
|
|
69
|
+
'common.confirm': 'Confirm',
|
|
70
|
+
'common.delete': 'Delete',
|
|
71
|
+
'common.edit': 'Edit',
|
|
72
|
+
'common.loading': 'Loading...',
|
|
73
|
+
'common.saveSuccess': 'Saved successfully',
|
|
74
|
+
'common.saveFailed': 'Failed to save',
|
|
75
|
+
|
|
76
|
+
// Actions related
|
|
77
|
+
'actions.regenerate': 'Regenerate',
|
|
78
|
+
|
|
79
|
+
// MessageImport related
|
|
80
|
+
'messageImport.title': 'Import Sessions Data',
|
|
81
|
+
'messageImport.placeholder': 'Enter JSON data to override current sessions',
|
|
82
|
+
'messageImport.saveToLocalStorage': 'Save to LocalStorage',
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export type MessageKey = keyof typeof messages.cn;
|
|
87
|
+
type Messages = Record<MessageKey, string>;
|
|
88
|
+
|
|
89
|
+
export interface I18nContextValue {
|
|
90
|
+
locale: Locale;
|
|
91
|
+
setLocale: (locale: Locale) => void;
|
|
92
|
+
t: (key: MessageKey, params?: Record<string, string | number>) => string;
|
|
93
|
+
messages: Messages;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const ChatAnywhereI18nContext = createContext<I18nContextValue | undefined>(undefined);
|
|
97
|
+
|
|
98
|
+
export function useChatAnywhereI18n<Selected>(selector: (value: I18nContextValue) => Selected): Selected {
|
|
99
|
+
try {
|
|
100
|
+
const context = useContextSelector(ChatAnywhereI18nContext, selector);
|
|
101
|
+
return context;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
return {} as Selected;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 便捷 hook:直接获取翻译函数
|
|
108
|
+
export function useTranslation() {
|
|
109
|
+
const t = useChatAnywhereI18n((ctx) => ctx?.t);
|
|
110
|
+
const locale = useChatAnywhereI18n((ctx) => ctx?.locale);
|
|
111
|
+
const setLocale = useChatAnywhereI18n((ctx) => ctx?.setLocale);
|
|
112
|
+
return { t, locale, setLocale };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface ChatAnywhereI18nContextProviderProps {
|
|
116
|
+
children: React.ReactNode;
|
|
117
|
+
defaultLocale?: Locale;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function ChatAnywhereI18nContextProvider(props: ChatAnywhereI18nContextProviderProps) {
|
|
121
|
+
const { children, defaultLocale = 'en' } = props;
|
|
122
|
+
const [locale, setLocale] = useState<Locale>(defaultLocale);
|
|
123
|
+
|
|
124
|
+
const t = useCallback((key: MessageKey, params?: Record<string, string | number>): string => {
|
|
125
|
+
let message = messages[locale][key] || key;
|
|
126
|
+
|
|
127
|
+
// 支持参数替换,如 t('hello', { name: 'World' }) => "Hello, World"
|
|
128
|
+
if (params) {
|
|
129
|
+
Object.entries(params).forEach(([paramKey, value]) => {
|
|
130
|
+
message = message.replace(new RegExp(`\\{${paramKey}\\}`, 'g'), String(value));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return message;
|
|
135
|
+
}, [locale]);
|
|
136
|
+
|
|
137
|
+
const value = useMemo<I18nContextValue>(() => ({
|
|
138
|
+
locale,
|
|
139
|
+
setLocale,
|
|
140
|
+
t,
|
|
141
|
+
messages: messages[locale],
|
|
142
|
+
}), [locale, setLocale, t]);
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<ChatAnywhereI18nContext.Provider value={value}>
|
|
146
|
+
{children}
|
|
147
|
+
</ChatAnywhereI18nContext.Provider>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export default ChatAnywhereI18nContext;
|
|
@@ -14,8 +14,8 @@ export const ChatAnywhereInputContext = createContext<IAgentScopeRuntimeWebUIInp
|
|
|
14
14
|
export function ChatAnywhereInputContextProvider(props: {
|
|
15
15
|
children: React.ReactNode | React.ReactNode[];
|
|
16
16
|
}) {
|
|
17
|
-
const [loading, setLoading, getLoading] = useGetState<boolean>(false);
|
|
18
|
-
const [disabled, setDisabled, getDisabled] = useGetState<boolean>(false);
|
|
17
|
+
const [loading, setLoading, getLoading] = useGetState<boolean | string>(false);
|
|
18
|
+
const [disabled, setDisabled, getDisabled] = useGetState<boolean | string>(false);
|
|
19
19
|
|
|
20
20
|
return <ChatAnywhereInputContext.Provider value={{ loading, setLoading, getLoading, disabled, setDisabled, getDisabled }}>
|
|
21
21
|
{props.children}
|