@agentscope-ai/chat 1.1.65 → 1.1.67
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/Actions.tsx +8 -4
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Request/Builder.tsx +7 -1
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Request/Card.tsx +5 -1
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Actions.tsx +1 -1
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Builder.tsx +55 -4
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Message.tsx +2 -1
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Tool.tsx +28 -5
- package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/types.tsx +1 -0
- package/components/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatController.tsx +129 -33
- package/components/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatRequest.tsx +74 -39
- package/components/AgentScopeRuntimeWebUI/core/types/IChatAnywhere.ts +10 -0
- package/components/DefaultCards/Files/index.tsx +5 -1
- package/components/Markdown/Markdown.tsx +2 -1
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Request/Actions.js +8 -1
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Request/Builder.js +4 -0
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Request/Card.js +8 -2
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Actions.js +1 -1
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Builder.js +80 -12
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Message.js +6 -1
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Tool.js +29 -4
- package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/types.d.ts +1 -0
- package/lib/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatController.d.ts +1 -1
- package/lib/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatController.js +167 -68
- package/lib/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatRequest.d.ts +7 -3
- package/lib/AgentScopeRuntimeWebUI/core/Chat/hooks/useChatRequest.js +151 -117
- package/lib/AgentScopeRuntimeWebUI/core/types/IChatAnywhere.d.ts +15 -0
- package/lib/DefaultCards/Files/index.js +5 -1
- package/lib/Markdown/Markdown.js +1 -0
- package/package.json +1 -1
- package/bin/starter_webui/README.md +0 -75
- package/bin/starter_webui/eslint.config.js +0 -28
- package/bin/starter_webui/index.html +0 -12
- package/bin/starter_webui/package.json +0 -34
- package/bin/starter_webui/src/App.tsx +0 -20
- package/bin/starter_webui/src/components/Chat/OptionsPanel/FormItem.tsx +0 -37
- package/bin/starter_webui/src/components/Chat/OptionsPanel/OptionsEditor.tsx +0 -160
- package/bin/starter_webui/src/components/Chat/OptionsPanel/defaultConfig.ts +0 -41
- package/bin/starter_webui/src/components/Chat/OptionsPanel/index.tsx +0 -27
- package/bin/starter_webui/src/components/Chat/index.tsx +0 -45
- package/bin/starter_webui/src/components/Chat/sessionApi/index.ts +0 -53
- package/bin/starter_webui/src/main.tsx +0 -9
- package/bin/starter_webui/src/vite-env.d.ts +0 -4
- package/bin/starter_webui/tsconfig.app.json +0 -24
- package/bin/starter_webui/tsconfig.json +0 -7
- package/bin/starter_webui/tsconfig.node.json +0 -22
- package/bin/starter_webui/vite.config.ts +0 -11
|
@@ -11,6 +11,10 @@ interface UseChatRequestOptions {
|
|
|
11
11
|
request?: IAgentScopeRuntimeWebUIMessage;
|
|
12
12
|
response?: IAgentScopeRuntimeWebUIMessage;
|
|
13
13
|
abortController?: AbortController;
|
|
14
|
+
/** Active request id, maintained by the controller. Incrementing it invalidates any in-flight SSE. */
|
|
15
|
+
activeRequestId: number;
|
|
16
|
+
/** Session id snapshot for the active request. */
|
|
17
|
+
activeSessionId?: string;
|
|
14
18
|
}>;
|
|
15
19
|
updateMessage: (message: IAgentScopeRuntimeWebUIMessage) => void;
|
|
16
20
|
getCurrentSessionId: () => string;
|
|
@@ -18,13 +22,13 @@ interface UseChatRequestOptions {
|
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
/**
|
|
21
|
-
*
|
|
25
|
+
* Hook for handling API requests and streaming SSE responses.
|
|
22
26
|
*/
|
|
23
27
|
export default function useChatRequest(options: UseChatRequestOptions) {
|
|
24
28
|
const { currentQARef, updateMessage, getCurrentSessionId, onFinish } = options;
|
|
25
29
|
const apiOptions = useChatAnywhereOptions(v => v.api);
|
|
26
30
|
|
|
27
|
-
//
|
|
31
|
+
// Keep apiOptions in a ref to avoid stale closure issues
|
|
28
32
|
const apiOptionsRef = useRef(apiOptions);
|
|
29
33
|
|
|
30
34
|
useEffect(() => {
|
|
@@ -57,7 +61,11 @@ export default function useChatRequest(options: UseChatRequestOptions) {
|
|
|
57
61
|
}, [])
|
|
58
62
|
|
|
59
63
|
|
|
60
|
-
const processSSEResponse = useCallback(async (
|
|
64
|
+
const processSSEResponse = useCallback(async (
|
|
65
|
+
response: Response,
|
|
66
|
+
myRequestId: number,
|
|
67
|
+
mySessionId?: string,
|
|
68
|
+
) => {
|
|
61
69
|
const currentApiOptions = apiOptionsRef.current;
|
|
62
70
|
const agentScopeRuntimeResponseBuilder = new AgentScopeRuntimeResponseBuilder({
|
|
63
71
|
id: '',
|
|
@@ -65,6 +73,19 @@ export default function useChatRequest(options: UseChatRequestOptions) {
|
|
|
65
73
|
created_at: 0,
|
|
66
74
|
});
|
|
67
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Guard: check whether this SSE stream is still the active request.
|
|
78
|
+
* If any of the following is true, writing should stop immediately:
|
|
79
|
+
* - requestId mismatch: user cancelled / sent new message / switched session
|
|
80
|
+
* - sessionId mismatch: session was switched away, prevents cross-session leakage
|
|
81
|
+
*/
|
|
82
|
+
const isStillActive = () => {
|
|
83
|
+
if (currentQARef.current.activeRequestId !== myRequestId) return false;
|
|
84
|
+
if (mySessionId && currentQARef.current.activeSessionId &&
|
|
85
|
+
currentQARef.current.activeSessionId !== mySessionId) return false;
|
|
86
|
+
return true;
|
|
87
|
+
};
|
|
88
|
+
|
|
68
89
|
if (!response.ok) {
|
|
69
90
|
try {
|
|
70
91
|
const data = await response.json();
|
|
@@ -79,16 +100,18 @@ export default function useChatRequest(options: UseChatRequestOptions) {
|
|
|
79
100
|
message: JSON.stringify(data),
|
|
80
101
|
});
|
|
81
102
|
|
|
82
|
-
currentQARef.current.response
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
103
|
+
if (isStillActive() && currentQARef.current.response) {
|
|
104
|
+
currentQARef.current.response.cards = [
|
|
105
|
+
{
|
|
106
|
+
code: 'AgentScopeRuntimeResponseCard',
|
|
107
|
+
data: res,
|
|
108
|
+
}
|
|
109
|
+
];
|
|
110
|
+
}
|
|
88
111
|
} catch {
|
|
89
112
|
// Ignore JSON parse errors — still call onFinish to reset loading state
|
|
90
113
|
}
|
|
91
|
-
onFinish();
|
|
114
|
+
if (isStillActive()) onFinish();
|
|
92
115
|
return;
|
|
93
116
|
}
|
|
94
117
|
|
|
@@ -99,22 +122,23 @@ export default function useChatRequest(options: UseChatRequestOptions) {
|
|
|
99
122
|
readableStream: response.body,
|
|
100
123
|
signal: abortSignal,
|
|
101
124
|
})) {
|
|
125
|
+
// Primary guard: if this SSE is no longer active, stop immediately
|
|
126
|
+
// to prevent ghost writes into a different session/request.
|
|
127
|
+
if (!isStillActive()) break;
|
|
128
|
+
|
|
102
129
|
if (currentQARef.current.response?.msgStatus === 'interrupted') {
|
|
103
130
|
currentQARef.current.abortController?.abort();
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
131
|
+
// Cancel was already sent by handleCancel; don't repeat it here.
|
|
132
|
+
|
|
133
|
+
if (isStillActive() && currentQARef.current.response) {
|
|
134
|
+
currentQARef.current.response.cards = [
|
|
135
|
+
{
|
|
136
|
+
code: 'AgentScopeRuntimeResponseCard',
|
|
137
|
+
data: agentScopeRuntimeResponseBuilder.cancel(),
|
|
138
|
+
}
|
|
139
|
+
];
|
|
140
|
+
updateMessage(currentQARef.current.response);
|
|
108
141
|
}
|
|
109
|
-
|
|
110
|
-
currentQARef.current.response.cards = [
|
|
111
|
-
{
|
|
112
|
-
code: 'AgentScopeRuntimeResponseCard',
|
|
113
|
-
data: agentScopeRuntimeResponseBuilder.cancel(),
|
|
114
|
-
}
|
|
115
|
-
];
|
|
116
|
-
|
|
117
|
-
updateMessage(currentQARef.current.response);
|
|
118
142
|
break;
|
|
119
143
|
}
|
|
120
144
|
|
|
@@ -122,7 +146,9 @@ export default function useChatRequest(options: UseChatRequestOptions) {
|
|
|
122
146
|
const chunkData = responseParser(chunk.data);
|
|
123
147
|
const res = agentScopeRuntimeResponseBuilder.handle(chunkData);
|
|
124
148
|
|
|
125
|
-
if (res.status !== AgentScopeRuntimeRunStatus.Failed && !res.output?.
|
|
149
|
+
if (res.status !== AgentScopeRuntimeRunStatus.Failed && !res.output?.some(msg => msg.content?.length)) continue;
|
|
150
|
+
|
|
151
|
+
if (!isStillActive()) break;
|
|
126
152
|
|
|
127
153
|
if (currentQARef.current.response) {
|
|
128
154
|
currentQARef.current.response.cards = [
|
|
@@ -140,19 +166,21 @@ export default function useChatRequest(options: UseChatRequestOptions) {
|
|
|
140
166
|
}
|
|
141
167
|
}
|
|
142
168
|
} catch (error) {
|
|
169
|
+
if (!isStillActive()) {
|
|
170
|
+
// Request is no longer active; do not write cards or fire cancel.
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
143
173
|
if (currentQARef.current.response?.msgStatus === 'interrupted') {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
174
|
+
// Cancel was already sent by handleCancel; don't repeat it here.
|
|
175
|
+
if (currentQARef.current.response) {
|
|
176
|
+
currentQARef.current.response.cards = [
|
|
177
|
+
{
|
|
178
|
+
code: 'AgentScopeRuntimeResponseCard',
|
|
179
|
+
data: agentScopeRuntimeResponseBuilder.cancel(),
|
|
180
|
+
}
|
|
181
|
+
];
|
|
182
|
+
updateMessage(currentQARef.current.response);
|
|
148
183
|
}
|
|
149
|
-
currentQARef.current.response.cards = [
|
|
150
|
-
{
|
|
151
|
-
code: 'AgentScopeRuntimeResponseCard',
|
|
152
|
-
data: agentScopeRuntimeResponseBuilder.cancel(),
|
|
153
|
-
}
|
|
154
|
-
];
|
|
155
|
-
updateMessage(currentQARef.current.response);
|
|
156
184
|
} else {
|
|
157
185
|
console.error(error);
|
|
158
186
|
}
|
|
@@ -160,10 +188,16 @@ export default function useChatRequest(options: UseChatRequestOptions) {
|
|
|
160
188
|
}, [getCurrentSessionId, currentQARef, updateMessage, onFinish]);
|
|
161
189
|
|
|
162
190
|
|
|
163
|
-
const request = useCallback(async (
|
|
191
|
+
const request = useCallback(async (
|
|
192
|
+
historyMessages: any[],
|
|
193
|
+
biz_params?: IAgentScopeRuntimeWebUIInputData['biz_params'],
|
|
194
|
+
myRequestId?: number,
|
|
195
|
+
) => {
|
|
164
196
|
const currentApiOptions = apiOptionsRef.current;
|
|
165
197
|
const { enableHistoryMessages = false } = currentApiOptions;
|
|
166
198
|
const abortSignal = currentQARef.current.abortController?.signal;
|
|
199
|
+
const requestId = myRequestId ?? currentQARef.current.activeRequestId;
|
|
200
|
+
const sessionId = currentQARef.current.activeSessionId ?? getCurrentSessionId();
|
|
167
201
|
let response
|
|
168
202
|
try {
|
|
169
203
|
response = currentApiOptions.fetch ? await currentApiOptions.fetch({
|
|
@@ -188,15 +222,16 @@ export default function useChatRequest(options: UseChatRequestOptions) {
|
|
|
188
222
|
}
|
|
189
223
|
|
|
190
224
|
if (response && response.body) {
|
|
191
|
-
await processSSEResponse(response);
|
|
225
|
+
await processSSEResponse(response, requestId, sessionId);
|
|
192
226
|
}
|
|
193
227
|
}, [getCurrentSessionId, currentQARef, processSSEResponse]);
|
|
194
228
|
|
|
195
|
-
const reconnect = useCallback(async (sessionId: string) => {
|
|
229
|
+
const reconnect = useCallback(async (sessionId: string, myRequestId?: number) => {
|
|
196
230
|
const currentApiOptions = apiOptionsRef.current;
|
|
197
231
|
if (!currentApiOptions.reconnect) return;
|
|
198
232
|
|
|
199
233
|
const abortSignal = currentQARef.current.abortController?.signal;
|
|
234
|
+
const requestId = myRequestId ?? currentQARef.current.activeRequestId;
|
|
200
235
|
let response: Response | undefined;
|
|
201
236
|
try {
|
|
202
237
|
response = await currentApiOptions.reconnect({
|
|
@@ -207,7 +242,7 @@ export default function useChatRequest(options: UseChatRequestOptions) {
|
|
|
207
242
|
}
|
|
208
243
|
|
|
209
244
|
if (response && response.body) {
|
|
210
|
-
await processSSEResponse(response);
|
|
245
|
+
await processSSEResponse(response, requestId, sessionId);
|
|
211
246
|
}
|
|
212
247
|
}, [currentQARef, processSSEResponse]);
|
|
213
248
|
|
|
@@ -68,6 +68,12 @@ export interface IAgentScopeRuntimeWebUIAPIOptions {
|
|
|
68
68
|
* @descriptionEn Custom media URL transformer (e.g. sign URL, replace CDN domain)
|
|
69
69
|
*/
|
|
70
70
|
replaceMediaURL?: (url: string) => string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @description 自定义文件点击事件(桌面端可通过此钩子调用原生 API 打开文件链接),不传则默认 window.open
|
|
74
|
+
* @descriptionEn Custom file click handler (desktop apps can use native APIs to open file URLs), defaults to window.open
|
|
75
|
+
*/
|
|
76
|
+
onFileCardClick?: (file: { url?: string; name?: string; size?: number }) => void;
|
|
71
77
|
}
|
|
72
78
|
|
|
73
79
|
/**
|
|
@@ -434,6 +440,8 @@ export interface IAgentScopeRuntimeWebUIRequestActionsOptions {
|
|
|
434
440
|
*/
|
|
435
441
|
list?: {
|
|
436
442
|
icon?: React.ReactElement;
|
|
443
|
+
children?: React.ReactElement;
|
|
444
|
+
render?: ({ data }: { data: IAgentScopeRuntimeRequest }) => React.ReactElement;
|
|
437
445
|
onClick?: ({ data }: { data: IAgentScopeRuntimeRequest }) => void;
|
|
438
446
|
}[];
|
|
439
447
|
}
|
|
@@ -445,6 +453,7 @@ export interface IAgentScopeRuntimeWebUIActionsOptions {
|
|
|
445
453
|
*/
|
|
446
454
|
list: {
|
|
447
455
|
icon?: React.ReactElement;
|
|
456
|
+
children?: React.ReactElement;
|
|
448
457
|
render?: ({
|
|
449
458
|
data,
|
|
450
459
|
}: {
|
|
@@ -459,6 +468,7 @@ export interface IAgentScopeRuntimeWebUIActionsOptions {
|
|
|
459
468
|
*/
|
|
460
469
|
right?: false | {
|
|
461
470
|
icon?: React.ReactElement;
|
|
471
|
+
children?: React.ReactElement;
|
|
462
472
|
render?: ({ data }: { data: IAgentScopeRuntimeResponse }) => React.ReactElement;
|
|
463
473
|
onClick?: ({ data }: { data: IAgentScopeRuntimeResponse }) => void;
|
|
464
474
|
}[];
|
|
@@ -56,7 +56,11 @@ export default function Files(props) {
|
|
|
56
56
|
|
|
57
57
|
{
|
|
58
58
|
fileInfo.url && <div className={`${prefixCls}-download`} onClick={() => {
|
|
59
|
-
|
|
59
|
+
if (props.onClick) {
|
|
60
|
+
props.onClick(fileInfo);
|
|
61
|
+
} else {
|
|
62
|
+
window.open(fileInfo.url, '_blank');
|
|
63
|
+
}
|
|
60
64
|
}}>
|
|
61
65
|
<SparkDownloadLine />
|
|
62
66
|
</div>
|
|
@@ -88,11 +88,12 @@ export default memo(function (props: MarkdownProps) {
|
|
|
88
88
|
const config = useMemo(() => ({
|
|
89
89
|
extensions,
|
|
90
90
|
walkTokens,
|
|
91
|
-
// 当 allowHtml 为 false
|
|
91
|
+
// 当 allowHtml 为 false 时,仅放行安全的内联 HTML 标签,其余转义
|
|
92
92
|
...(!allowHtml && {
|
|
93
93
|
renderer: {
|
|
94
94
|
html(token: { text?: string; raw?: string }) {
|
|
95
95
|
const text = token.text || token.raw || '';
|
|
96
|
+
if (/^<br\s*\/?>$/i.test(text.trim())) return '<br />';
|
|
96
97
|
return text.replace(/</g, '<').replace(/>/g, '>');
|
|
97
98
|
}
|
|
98
99
|
}
|
|
@@ -4,6 +4,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
4
4
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
5
5
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
6
6
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
7
|
+
import React from "react";
|
|
7
8
|
import { SparkCopyLine } from "@agentscope-ai/icons";
|
|
8
9
|
import { AgentScopeRuntimeContentType } from "../types";
|
|
9
10
|
import { Bubble } from "../../../..";
|
|
@@ -32,7 +33,13 @@ export default function RequestActions(props) {
|
|
|
32
33
|
}
|
|
33
34
|
}] : [];
|
|
34
35
|
var actions = (requestActionsOptions.list || defaultActions).map(function (i) {
|
|
35
|
-
|
|
36
|
+
var res = _objectSpread({}, i);
|
|
37
|
+
if (i.render) {
|
|
38
|
+
res.children = /*#__PURE__*/React.createElement(i.render, {
|
|
39
|
+
data: props.data
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return _objectSpread(_objectSpread({}, res), {}, {
|
|
36
43
|
onClick: function onClick() {
|
|
37
44
|
var _i$onClick;
|
|
38
45
|
(_i$onClick = i.onClick) === null || _i$onClick === void 0 || _i$onClick.call(i, {
|
|
@@ -103,6 +103,9 @@ var AgentScopeRuntimeRequestBuilder = /*#__PURE__*/function () {
|
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
105
|
this.data = {
|
|
106
|
+
// Client-side send timestamp (seconds), aligns with response.created_at.
|
|
107
|
+
// Backend has not yet returned, so this represents the local send moment.
|
|
108
|
+
created_at: Math.floor(Date.now() / 1000),
|
|
106
109
|
input: [{
|
|
107
110
|
role: 'user',
|
|
108
111
|
type: AgentScopeRuntimeMessageType.MESSAGE,
|
|
@@ -115,6 +118,7 @@ var AgentScopeRuntimeRequestBuilder = /*#__PURE__*/function () {
|
|
|
115
118
|
key: "handleApproval",
|
|
116
119
|
value: function handleApproval(input) {
|
|
117
120
|
this.data = {
|
|
121
|
+
created_at: Math.floor(Date.now() / 1000),
|
|
118
122
|
input: input
|
|
119
123
|
};
|
|
120
124
|
return this.data;
|
|
@@ -2,10 +2,15 @@ import { AgentScopeRuntimeContentType } from "../types";
|
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
import { Bubble } from "../../../..";
|
|
4
4
|
import Actions from "./Actions";
|
|
5
|
+
import { useChatAnywhereOptions } from "../../Context/ChatAnywhereOptionsContext";
|
|
5
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
7
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
7
8
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
9
|
export default function AgentScopeRuntimeRequestCard(props) {
|
|
10
|
+
var onFileCardClick = useChatAnywhereOptions(function (v) {
|
|
11
|
+
var _v$api;
|
|
12
|
+
return (_v$api = v.api) === null || _v$api === void 0 ? void 0 : _v$api.onFileCardClick;
|
|
13
|
+
});
|
|
9
14
|
var cards = useMemo(function () {
|
|
10
15
|
return props.data.input[0].content.reduce(function (p, c) {
|
|
11
16
|
if (c.type === AgentScopeRuntimeContentType.TEXT) {
|
|
@@ -81,7 +86,8 @@ export default function AgentScopeRuntimeRequestCard(props) {
|
|
|
81
86
|
url: c.file_url,
|
|
82
87
|
name: c.file_name || c.fileName,
|
|
83
88
|
size: c.file_size
|
|
84
|
-
}]
|
|
89
|
+
}],
|
|
90
|
+
onClick: onFileCardClick
|
|
85
91
|
});
|
|
86
92
|
} else {
|
|
87
93
|
fileCard.data.push({
|
|
@@ -93,7 +99,7 @@ export default function AgentScopeRuntimeRequestCard(props) {
|
|
|
93
99
|
}
|
|
94
100
|
return p;
|
|
95
101
|
}, []);
|
|
96
|
-
}, [props.data.input]);
|
|
102
|
+
}, [props.data.input, onFileCardClick]);
|
|
97
103
|
if (!(cards !== null && cards !== void 0 && cards.length)) return null;
|
|
98
104
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
99
105
|
children: [/*#__PURE__*/_jsx(Bubble, {
|
|
@@ -49,7 +49,7 @@ export default function Tools(props) {
|
|
|
49
49
|
return (_v$actions3 = v.actions) === null || _v$actions3 === void 0 ? void 0 : _v$actions3.right;
|
|
50
50
|
});
|
|
51
51
|
var actions = compact([].concat(_toConsumableArray(actionsOptionsList.map(function (i) {
|
|
52
|
-
var res = i;
|
|
52
|
+
var res = _objectSpread({}, i);
|
|
53
53
|
if (i.render) {
|
|
54
54
|
res.children = /*#__PURE__*/React.createElement(i.render, {
|
|
55
55
|
data: props
|
|
@@ -3,11 +3,15 @@ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableTo
|
|
|
3
3
|
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
4
4
|
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
5
5
|
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
6
|
-
function
|
|
7
|
-
function
|
|
6
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
7
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
8
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
9
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
8
10
|
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
9
11
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
10
12
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
13
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
14
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
11
15
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
12
16
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
|
|
13
17
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
@@ -36,10 +40,56 @@ var AgentScopeRuntimeResponseBuilder = /*#__PURE__*/function () {
|
|
|
36
40
|
key: "handleResponse",
|
|
37
41
|
value: function handleResponse(data) {
|
|
38
42
|
this.data = produce(this.data, function (draft) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
43
|
+
var existingOutput = draft.output || [];
|
|
44
|
+
var incomingOutput = data.output;
|
|
42
45
|
Object.assign(draft, data);
|
|
46
|
+
|
|
47
|
+
// If incoming response has no output or empty output, preserve the
|
|
48
|
+
// accumulated output from streaming to avoid losing intermediate
|
|
49
|
+
// tool-call messages that were already collected.
|
|
50
|
+
if (!incomingOutput || incomingOutput.length === 0) {
|
|
51
|
+
draft.output = existingOutput;
|
|
52
|
+
} else if (existingOutput.length > 0) {
|
|
53
|
+
// Merge by id: prefer the version with non-empty content to avoid
|
|
54
|
+
// a partial-update response wiping out previously accumulated
|
|
55
|
+
// tool-call data (Bug 2 of issue #4644).
|
|
56
|
+
var existingMap = new Map(existingOutput.map(function (m) {
|
|
57
|
+
return [m.id, m];
|
|
58
|
+
}));
|
|
59
|
+
var incomingIds = new Set(incomingOutput.map(function (m) {
|
|
60
|
+
return m.id;
|
|
61
|
+
}));
|
|
62
|
+
var merged = incomingOutput.map(function (incoming) {
|
|
63
|
+
var _incoming$content, _existing$content;
|
|
64
|
+
var existing = existingMap.get(incoming.id);
|
|
65
|
+
if (!existing) return incoming;
|
|
66
|
+
// Prefer the message with content already populated.
|
|
67
|
+
var incomingHasContent = ((_incoming$content = incoming.content) === null || _incoming$content === void 0 ? void 0 : _incoming$content.length) > 0;
|
|
68
|
+
var existingHasContent = ((_existing$content = existing.content) === null || _existing$content === void 0 ? void 0 : _existing$content.length) > 0;
|
|
69
|
+
if (existingHasContent && !incomingHasContent) {
|
|
70
|
+
return _objectSpread(_objectSpread({}, incoming), {}, {
|
|
71
|
+
content: existing.content
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return incoming;
|
|
75
|
+
});
|
|
76
|
+
// Append existing-only messages (not present in incoming).
|
|
77
|
+
var _iterator = _createForOfIteratorHelper(existingOutput),
|
|
78
|
+
_step;
|
|
79
|
+
try {
|
|
80
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
81
|
+
var existing = _step.value;
|
|
82
|
+
if (!incomingIds.has(existing.id)) {
|
|
83
|
+
merged.push(existing);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
_iterator.e(err);
|
|
88
|
+
} finally {
|
|
89
|
+
_iterator.f();
|
|
90
|
+
}
|
|
91
|
+
draft.output = merged;
|
|
92
|
+
}
|
|
43
93
|
});
|
|
44
94
|
}
|
|
45
95
|
}, {
|
|
@@ -85,7 +135,25 @@ var AgentScopeRuntimeResponseBuilder = /*#__PURE__*/function () {
|
|
|
85
135
|
} else if (data.type === AgentScopeRuntimeContentType.IMAGE) {
|
|
86
136
|
lastContent.image_url = data.image_url;
|
|
87
137
|
} else if (data.type === AgentScopeRuntimeContentType.DATA) {
|
|
88
|
-
|
|
138
|
+
var isStreamingToolInput = [AgentScopeRuntimeMessageType.PLUGIN_CALL, AgentScopeRuntimeMessageType.TOOL_CALL, AgentScopeRuntimeMessageType.MCP_CALL].includes(msg.type);
|
|
139
|
+
if (isStreamingToolInput) {
|
|
140
|
+
var oldData = lastContent.data || {};
|
|
141
|
+
var newData = data.data || {};
|
|
142
|
+
var merged = _objectSpread({}, oldData);
|
|
143
|
+
for (var _i = 0, _Object$entries = Object.entries(newData); _i < _Object$entries.length; _i++) {
|
|
144
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
145
|
+
key = _Object$entries$_i[0],
|
|
146
|
+
value = _Object$entries$_i[1];
|
|
147
|
+
if (typeof value === 'string' && typeof merged[key] === 'string') {
|
|
148
|
+
merged[key] = merged[key] + value;
|
|
149
|
+
} else {
|
|
150
|
+
merged[key] = value;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
lastContent.data = merged;
|
|
154
|
+
} else {
|
|
155
|
+
lastContent.data = data.data;
|
|
156
|
+
}
|
|
89
157
|
}
|
|
90
158
|
} else {
|
|
91
159
|
msg.content.push(data);
|
|
@@ -155,12 +223,12 @@ var AgentScopeRuntimeResponseBuilder = /*#__PURE__*/function () {
|
|
|
155
223
|
value: function mergeToolMessages(messages) {
|
|
156
224
|
var bufferMessagesMap = new Map();
|
|
157
225
|
var resMessages = [];
|
|
158
|
-
var
|
|
159
|
-
|
|
226
|
+
var _iterator2 = _createForOfIteratorHelper(messages),
|
|
227
|
+
_step2;
|
|
160
228
|
try {
|
|
161
229
|
var _loop = function _loop() {
|
|
162
230
|
var _message$content, _message$content2;
|
|
163
|
-
var message =
|
|
231
|
+
var message = _step2.value;
|
|
164
232
|
if (AgentScopeRuntimeResponseBuilder.maybeToolInput(message) && (_message$content = message.content) !== null && _message$content !== void 0 && _message$content.length) {
|
|
165
233
|
var content = message.content[0];
|
|
166
234
|
var key = content.data.call_id || content.data.name;
|
|
@@ -188,13 +256,13 @@ var AgentScopeRuntimeResponseBuilder = /*#__PURE__*/function () {
|
|
|
188
256
|
resMessages.push(message);
|
|
189
257
|
}
|
|
190
258
|
};
|
|
191
|
-
for (
|
|
259
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
192
260
|
_loop();
|
|
193
261
|
}
|
|
194
262
|
} catch (err) {
|
|
195
|
-
|
|
263
|
+
_iterator2.e(err);
|
|
196
264
|
} finally {
|
|
197
|
-
|
|
265
|
+
_iterator2.f();
|
|
198
266
|
}
|
|
199
267
|
return resMessages;
|
|
200
268
|
}
|
|
@@ -15,6 +15,10 @@ var Message = /*#__PURE__*/React.memo(function (_ref) {
|
|
|
15
15
|
var _v$api;
|
|
16
16
|
return (_v$api = v.api) === null || _v$api === void 0 ? void 0 : _v$api.replaceMediaURL;
|
|
17
17
|
});
|
|
18
|
+
var onFileCardClick = useChatAnywhereOptions(function (v) {
|
|
19
|
+
var _v$api2;
|
|
20
|
+
return (_v$api2 = v.api) === null || _v$api2 === void 0 ? void 0 : _v$api2.onFileCardClick;
|
|
21
|
+
});
|
|
18
22
|
var formatMediaURL = React.useCallback(function (url) {
|
|
19
23
|
if (!url) return url;
|
|
20
24
|
return (replaceMediaURL === null || replaceMediaURL === void 0 ? void 0 : replaceMediaURL(url)) || url;
|
|
@@ -52,7 +56,8 @@ var Message = /*#__PURE__*/React.memo(function (_ref) {
|
|
|
52
56
|
url: formatMediaURL(item.file_url),
|
|
53
57
|
name: item.file_name || item.fileName || item.file_id,
|
|
54
58
|
size: item.file_size
|
|
55
|
-
}]
|
|
59
|
+
}],
|
|
60
|
+
onClick: onFileCardClick
|
|
56
61
|
}, index);
|
|
57
62
|
case AgentScopeRuntimeContentType.AUDIO:
|
|
58
63
|
return /*#__PURE__*/_jsx(Audios, {
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
5
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
7
|
+
import React, { useEffect, useState } from "react";
|
|
8
|
+
import { AgentScopeRuntimeMessageType, AgentScopeRuntimeRunStatus } from "../types";
|
|
3
9
|
import { ToolCall } from "../../../..";
|
|
4
10
|
import { useChatAnywhereOptions } from "../../Context/ChatAnywhereOptionsContext";
|
|
5
11
|
import Approval from "./Approval";
|
|
12
|
+
|
|
13
|
+
// output展示后,2s自动关闭
|
|
6
14
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
15
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
8
16
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
17
|
+
var OUTPUT_AUTO_COLLAPSE_MS = 2000;
|
|
9
18
|
var Tool = /*#__PURE__*/React.memo(function (_ref) {
|
|
10
19
|
var _data$content;
|
|
11
20
|
var data = _ref.data,
|
|
@@ -14,12 +23,28 @@ var Tool = /*#__PURE__*/React.memo(function (_ref) {
|
|
|
14
23
|
var customToolRenderConfig = useChatAnywhereOptions(function (v) {
|
|
15
24
|
return v.customToolRenderConfig;
|
|
16
25
|
}) || {};
|
|
26
|
+
var isOutput = [AgentScopeRuntimeMessageType.PLUGIN_CALL_OUTPUT, AgentScopeRuntimeMessageType.TOOL_CALL_OUTPUT, AgentScopeRuntimeMessageType.MCP_CALL_OUTPUT].includes(data.type);
|
|
27
|
+
var _useState = useState(false),
|
|
28
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
29
|
+
autoCollapsed = _useState2[0],
|
|
30
|
+
setAutoCollapsed = _useState2[1];
|
|
31
|
+
useEffect(function () {
|
|
32
|
+
if (!isOutput || autoCollapsed) return;
|
|
33
|
+
var timer = setTimeout(function () {
|
|
34
|
+
return setAutoCollapsed(true);
|
|
35
|
+
}, OUTPUT_AUTO_COLLAPSE_MS);
|
|
36
|
+
return function () {
|
|
37
|
+
return clearTimeout(timer);
|
|
38
|
+
};
|
|
39
|
+
}, [isOutput, autoCollapsed]);
|
|
17
40
|
if (!((_data$content = data.content) !== null && _data$content !== void 0 && _data$content.length)) return null;
|
|
18
41
|
var content = data.content;
|
|
19
42
|
var loading = data.status === AgentScopeRuntimeRunStatus.InProgress;
|
|
20
43
|
var toolName = content[0].data.name;
|
|
21
44
|
var serverLabel = "".concat(content[0].data.server_label ? content[0].data.server_label + ' / ' : '');
|
|
22
45
|
var title = "".concat(serverLabel).concat(toolName);
|
|
46
|
+
var isInput = [AgentScopeRuntimeMessageType.PLUGIN_CALL, AgentScopeRuntimeMessageType.TOOL_CALL, AgentScopeRuntimeMessageType.MCP_CALL].includes(data.type);
|
|
47
|
+
var defaultOpen = isInput || isOutput && !autoCollapsed;
|
|
23
48
|
var node;
|
|
24
49
|
if (customToolRenderConfig[toolName]) {
|
|
25
50
|
var C = customToolRenderConfig[toolName];
|
|
@@ -30,11 +55,11 @@ var Tool = /*#__PURE__*/React.memo(function (_ref) {
|
|
|
30
55
|
var _content$, _content$2;
|
|
31
56
|
node = /*#__PURE__*/_jsx(ToolCall, {
|
|
32
57
|
loading: loading,
|
|
33
|
-
defaultOpen:
|
|
58
|
+
defaultOpen: defaultOpen,
|
|
34
59
|
title: title === 'undefined' ? '' : title,
|
|
35
60
|
input: (_content$ = content[0]) === null || _content$ === void 0 || (_content$ = _content$.data) === null || _content$ === void 0 ? void 0 : _content$.arguments,
|
|
36
61
|
output: (_content$2 = content[1]) === null || _content$2 === void 0 || (_content$2 = _content$2.data) === null || _content$2 === void 0 ? void 0 : _content$2.output
|
|
37
|
-
});
|
|
62
|
+
}, autoCollapsed ? 'collapsed' : 'open');
|
|
38
63
|
}
|
|
39
64
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
40
65
|
children: [node, isApproval && /*#__PURE__*/_jsx(Approval, {
|