@lowdefy/blocks-antd-x 5.3.0 → 5.4.0
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/dist/blocks/AgentChat/AgentChat.js +19 -9
- package/dist/blocks/AgentChat/MessageBubble.js +46 -31
- package/dist/blocks/AgentChat/MessageList.js +7 -6
- package/dist/blocks/AgentChat/ToolApproval.js +3 -3
- package/dist/blocks/AgentChat/formatToolResult.js +18 -17
- package/dist/blocks/AgentChat/meta.js +1 -0
- package/dist/blocks/AgentChat/useAgentEvents.js +17 -2
- package/package.json +3 -3
|
@@ -45,17 +45,25 @@ function AgentChat({ blockId, components: { Icon }, methods, pageId, properties
|
|
|
45
45
|
}
|
|
46
46
|
return initial;
|
|
47
47
|
});
|
|
48
|
+
// When no conversationId is supplied, mint a stable session id so every turn
|
|
49
|
+
// (including a welcome prompt sent before the app sets the prop) posts a
|
|
50
|
+
// consistent id. App-supplied ids remain authoritative.
|
|
51
|
+
const mintedIdRef = useRef(null);
|
|
52
|
+
if (!conversationId && !mintedIdRef.current) {
|
|
53
|
+
mintedIdRef.current = crypto.randomUUID();
|
|
54
|
+
}
|
|
55
|
+
const effectiveConversationId = conversationId ?? mintedIdRef.current;
|
|
48
56
|
const urlQueryKey = JSON.stringify(urlQuery ?? null);
|
|
49
57
|
const transport = useMemo(()=>createLowdefyChatTransport({
|
|
50
58
|
pageId,
|
|
51
59
|
agentId,
|
|
52
|
-
conversationId,
|
|
60
|
+
conversationId: effectiveConversationId,
|
|
53
61
|
urlQuery,
|
|
54
62
|
sharedStateRef
|
|
55
63
|
}), [
|
|
56
64
|
pageId,
|
|
57
65
|
agentId,
|
|
58
|
-
|
|
66
|
+
effectiveConversationId,
|
|
59
67
|
urlQueryKey
|
|
60
68
|
]);
|
|
61
69
|
const bubbleListRef = useRef(null);
|
|
@@ -134,14 +142,14 @@ function AgentChat({ blockId, components: { Icon }, methods, pageId, properties
|
|
|
134
142
|
});
|
|
135
143
|
// Clear messages when conversationId changes so the new conversation starts clean.
|
|
136
144
|
// Developers load saved messages via the messages property if needed.
|
|
137
|
-
const prevConversationIdRef = useRef(
|
|
145
|
+
const prevConversationIdRef = useRef(effectiveConversationId);
|
|
138
146
|
useEffect(()=>{
|
|
139
|
-
if (
|
|
140
|
-
prevConversationIdRef.current =
|
|
147
|
+
if (effectiveConversationId !== prevConversationIdRef.current) {
|
|
148
|
+
prevConversationIdRef.current = effectiveConversationId;
|
|
141
149
|
setMessages([]);
|
|
142
150
|
}
|
|
143
151
|
}, [
|
|
144
|
-
|
|
152
|
+
effectiveConversationId,
|
|
145
153
|
setMessages
|
|
146
154
|
]);
|
|
147
155
|
// Sync external messages when provided — undefined means "not provided" (no sync),
|
|
@@ -241,7 +249,8 @@ function AgentChat({ blockId, components: { Icon }, methods, pageId, properties
|
|
|
241
249
|
messages,
|
|
242
250
|
status,
|
|
243
251
|
methods,
|
|
244
|
-
finishMetaRef
|
|
252
|
+
finishMetaRef,
|
|
253
|
+
conversationId: effectiveConversationId
|
|
245
254
|
});
|
|
246
255
|
const isEmpty = messages.length === 0;
|
|
247
256
|
const isBusy = status === 'streaming' || status === 'submitted';
|
|
@@ -497,7 +506,8 @@ function AgentChat({ blockId, components: { Icon }, methods, pageId, properties
|
|
|
497
506
|
onFeedback: handleFeedback,
|
|
498
507
|
onRegenerate: handleRegenerate,
|
|
499
508
|
onDelete: handleDelete,
|
|
500
|
-
onEditMessage: handleEditMessage
|
|
509
|
+
onEditMessage: handleEditMessage,
|
|
510
|
+
translate: methods.translate
|
|
501
511
|
})), !isEmpty && activeSuggestions && activeSuggestions.length > 0 && !isBusy && /*#__PURE__*/ React.createElement("div", {
|
|
502
512
|
style: {
|
|
503
513
|
padding: '0 16px 8px'
|
|
@@ -557,7 +567,7 @@ function AgentChat({ blockId, components: { Icon }, methods, pageId, properties
|
|
|
557
567
|
}
|
|
558
568
|
}), /*#__PURE__*/ React.createElement(Sender, {
|
|
559
569
|
ref: senderRef,
|
|
560
|
-
placeholder: sender?.placeholder ?? '
|
|
570
|
+
placeholder: sender?.placeholder ?? methods.translate('agent.sender.placeholder'),
|
|
561
571
|
submitType: sender?.submitType ?? 'enter',
|
|
562
572
|
allowSpeech: sender?.allowSpeech ?? false,
|
|
563
573
|
onSubmit: handleSend,
|
|
@@ -71,13 +71,23 @@ function RichCodeBlock({ renderMermaid, codeHighlighter }) {
|
|
|
71
71
|
}, children));
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
|
-
function summarizeToolOutput(output) {
|
|
75
|
-
if (output === null || output === undefined) return '
|
|
76
|
-
if (Array.isArray(output))
|
|
74
|
+
function summarizeToolOutput(output, translate) {
|
|
75
|
+
if (output === null || output === undefined) return translate('agent.toolResult.completedNoData');
|
|
76
|
+
if (Array.isArray(output)) {
|
|
77
|
+
return translate('agent.toolResult.returnedCount', {
|
|
78
|
+
count: output.length
|
|
79
|
+
});
|
|
80
|
+
}
|
|
77
81
|
if (typeof output === 'object') {
|
|
78
82
|
const keys = Object.keys(output);
|
|
79
|
-
if (keys.length <= 3)
|
|
80
|
-
|
|
83
|
+
if (keys.length <= 3) {
|
|
84
|
+
return translate('agent.toolResult.returnedKeys', {
|
|
85
|
+
keys: keys.join(', ')
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return translate('agent.toolResult.returnedFields', {
|
|
89
|
+
count: keys.length
|
|
90
|
+
});
|
|
81
91
|
}
|
|
82
92
|
if (typeof output === 'string') {
|
|
83
93
|
return output.length > 80 ? `${output.substring(0, 80)}...` : output;
|
|
@@ -101,13 +111,13 @@ function normalizeActions(actions) {
|
|
|
101
111
|
}
|
|
102
112
|
return actions ?? {};
|
|
103
113
|
}
|
|
104
|
-
function BubbleActions({ actions, textContent, messageId, onFeedback, onRegenerate, onDelete }) {
|
|
114
|
+
function BubbleActions({ actions, textContent, messageId, onFeedback, onRegenerate, onDelete, translate }) {
|
|
105
115
|
const normalized = normalizeActions(actions);
|
|
106
116
|
const items = [];
|
|
107
117
|
if (normalized.copy) {
|
|
108
118
|
items.push({
|
|
109
119
|
key: 'copy',
|
|
110
|
-
label: '
|
|
120
|
+
label: translate('agent.message.copy'),
|
|
111
121
|
actionRender: ()=>/*#__PURE__*/ React.createElement(Actions.Copy, {
|
|
112
122
|
text: textContent
|
|
113
123
|
})
|
|
@@ -116,7 +126,7 @@ function BubbleActions({ actions, textContent, messageId, onFeedback, onRegenera
|
|
|
116
126
|
if (normalized.feedback) {
|
|
117
127
|
items.push({
|
|
118
128
|
key: 'feedback',
|
|
119
|
-
label: '
|
|
129
|
+
label: translate('agent.message.feedback'),
|
|
120
130
|
actionRender: ()=>/*#__PURE__*/ React.createElement(Actions.Feedback, {
|
|
121
131
|
onChange: (rating)=>onFeedback?.({
|
|
122
132
|
messageId,
|
|
@@ -129,7 +139,7 @@ function BubbleActions({ actions, textContent, messageId, onFeedback, onRegenera
|
|
|
129
139
|
items.push({
|
|
130
140
|
key: 'regenerate',
|
|
131
141
|
icon: /*#__PURE__*/ React.createElement(ReloadOutlined, null),
|
|
132
|
-
label: '
|
|
142
|
+
label: translate('agent.message.regenerate'),
|
|
133
143
|
onItemClick: ()=>onRegenerate?.({
|
|
134
144
|
messageId
|
|
135
145
|
})
|
|
@@ -139,7 +149,7 @@ function BubbleActions({ actions, textContent, messageId, onFeedback, onRegenera
|
|
|
139
149
|
items.push({
|
|
140
150
|
key: 'delete',
|
|
141
151
|
icon: /*#__PURE__*/ React.createElement(DeleteOutlined, null),
|
|
142
|
-
label: '
|
|
152
|
+
label: translate('agent.message.delete'),
|
|
143
153
|
danger: true,
|
|
144
154
|
onItemClick: ()=>onDelete?.({
|
|
145
155
|
messageId
|
|
@@ -151,7 +161,7 @@ function BubbleActions({ actions, textContent, messageId, onFeedback, onRegenera
|
|
|
151
161
|
items: items
|
|
152
162
|
});
|
|
153
163
|
}
|
|
154
|
-
function SourcesDisplay({ sourceParts, config }) {
|
|
164
|
+
function SourcesDisplay({ sourceParts, config, translate }) {
|
|
155
165
|
if (sourceParts.length === 0) return null;
|
|
156
166
|
const items = sourceParts.map((source, i)=>({
|
|
157
167
|
key: `source-${i}`,
|
|
@@ -161,12 +171,12 @@ function SourcesDisplay({ sourceParts, config }) {
|
|
|
161
171
|
}));
|
|
162
172
|
return /*#__PURE__*/ React.createElement(Sources, {
|
|
163
173
|
items: items,
|
|
164
|
-
title:
|
|
174
|
+
title: translate('agent.toolResult.sourcesTitle'),
|
|
165
175
|
inline: config?.sourcesDisplay?.inline ?? false,
|
|
166
176
|
expandIconPosition: config?.sourcesDisplay?.expandIconPosition ?? 'end'
|
|
167
177
|
});
|
|
168
178
|
}
|
|
169
|
-
function MessageBubble({ content, isStreaming, parts, config, addToolApprovalResponse, actions, messageId, onFeedback, onRegenerate, onDelete }) {
|
|
179
|
+
function MessageBubble({ content, isStreaming, parts, config, addToolApprovalResponse, actions, messageId, onFeedback, onRegenerate, onDelete, translate }) {
|
|
170
180
|
const showThoughtChain = config?.showThoughtChain !== false;
|
|
171
181
|
const showReasoning = config?.showReasoning !== false;
|
|
172
182
|
const reasoningDisplay = config?.reasoningDisplay ?? 'interleaved';
|
|
@@ -202,14 +212,16 @@ function MessageBubble({ content, isStreaming, parts, config, addToolApprovalRes
|
|
|
202
212
|
config: markdownConfig
|
|
203
213
|
}, content), /*#__PURE__*/ React.createElement(SourcesDisplay, {
|
|
204
214
|
sourceParts: sourceParts,
|
|
205
|
-
config: config
|
|
215
|
+
config: config,
|
|
216
|
+
translate: translate
|
|
206
217
|
}), showActions && /*#__PURE__*/ React.createElement(BubbleActions, {
|
|
207
218
|
actions: normalizedActions,
|
|
208
219
|
textContent: content,
|
|
209
220
|
messageId: messageId,
|
|
210
221
|
onFeedback: onFeedback,
|
|
211
222
|
onRegenerate: onRegenerate,
|
|
212
|
-
onDelete: onDelete
|
|
223
|
+
onDelete: onDelete,
|
|
224
|
+
translate: translate
|
|
213
225
|
}));
|
|
214
226
|
}
|
|
215
227
|
// Build segments of consecutive same-type parts.
|
|
@@ -285,7 +297,7 @@ function MessageBubble({ content, isStreaming, parts, config, addToolApprovalRes
|
|
|
285
297
|
const isActiveReasoning = isStreaming && segment.parts.some((p)=>p.state === 'streaming');
|
|
286
298
|
return /*#__PURE__*/ React.createElement(Think, {
|
|
287
299
|
key: `reasoning-${idx}`,
|
|
288
|
-
title:
|
|
300
|
+
title: translate('agent.toolResult.reasoningTitle'),
|
|
289
301
|
defaultExpanded: false,
|
|
290
302
|
loading: isActiveReasoning,
|
|
291
303
|
blink: isActiveReasoning
|
|
@@ -298,7 +310,7 @@ function MessageBubble({ content, isStreaming, parts, config, addToolApprovalRes
|
|
|
298
310
|
return {
|
|
299
311
|
key: tool.toolCallId,
|
|
300
312
|
title: tool.toolName,
|
|
301
|
-
description: '
|
|
313
|
+
description: translate('agent.toolResult.rejected'),
|
|
302
314
|
status: 'error'
|
|
303
315
|
};
|
|
304
316
|
}
|
|
@@ -317,7 +329,8 @@ function MessageBubble({ content, isStreaming, parts, config, addToolApprovalRes
|
|
|
317
329
|
onReject: (id)=>addToolApprovalResponse?.({
|
|
318
330
|
id,
|
|
319
331
|
approved: false
|
|
320
|
-
})
|
|
332
|
+
}),
|
|
333
|
+
translate: translate
|
|
321
334
|
}),
|
|
322
335
|
status: 'loading'
|
|
323
336
|
};
|
|
@@ -339,12 +352,12 @@ function MessageBubble({ content, isStreaming, parts, config, addToolApprovalRes
|
|
|
339
352
|
if (showInput && tool.input && Object.keys(tool.input).length > 0) {
|
|
340
353
|
description = `Input: ${JSON.stringify(tool.input, null, 2)}`;
|
|
341
354
|
} else {
|
|
342
|
-
description = '
|
|
355
|
+
description = translate('agent.toolResult.running');
|
|
343
356
|
}
|
|
344
357
|
} else if (status === 'error') {
|
|
345
|
-
description = '
|
|
358
|
+
description = translate('agent.toolResult.failed');
|
|
346
359
|
} else if (toolOutput?.display && typeof toolOutput.display === 'string') {
|
|
347
|
-
description = summarizeToolOutput(toolOutput.display);
|
|
360
|
+
description = summarizeToolOutput(toolOutput.display, translate);
|
|
348
361
|
content = /*#__PURE__*/ React.createElement(Markdown, {
|
|
349
362
|
components: markdownComponents,
|
|
350
363
|
config: markdownConfig
|
|
@@ -352,7 +365,7 @@ function MessageBubble({ content, isStreaming, parts, config, addToolApprovalRes
|
|
|
352
365
|
collapsible = true;
|
|
353
366
|
} else if (isSubAgent) {
|
|
354
367
|
// Sub-agent results: short status in description, full response in styled content
|
|
355
|
-
description = '
|
|
368
|
+
description = translate('agent.toolResult.completed');
|
|
356
369
|
const subAgentText = typeof toolOutput === 'string' ? toolOutput : JSON.stringify(toolOutput, null, 2);
|
|
357
370
|
content = /*#__PURE__*/ React.createElement("div", {
|
|
358
371
|
style: {
|
|
@@ -369,19 +382,19 @@ function MessageBubble({ content, isStreaming, parts, config, addToolApprovalRes
|
|
|
369
382
|
} else {
|
|
370
383
|
const mode = resolveToolResultMode(toolResultDisplay, tool.toolName);
|
|
371
384
|
if (mode === 'readable') {
|
|
372
|
-
description = summarizeToolOutput(toolOutput);
|
|
373
|
-
content = formatToolResult(toolOutput);
|
|
385
|
+
description = summarizeToolOutput(toolOutput, translate);
|
|
386
|
+
content = formatToolResult(toolOutput, translate);
|
|
374
387
|
collapsible = true;
|
|
375
388
|
} else if (mode === 'full') {
|
|
376
|
-
description = summarizeToolOutput(toolOutput);
|
|
389
|
+
description = summarizeToolOutput(toolOutput, translate);
|
|
377
390
|
content = JSON.stringify(toolOutput, null, 2);
|
|
378
391
|
collapsible = true;
|
|
379
392
|
} else if (mode === 'none') {
|
|
380
|
-
description = '
|
|
393
|
+
description = translate('agent.toolResult.completed');
|
|
381
394
|
} else {
|
|
382
395
|
// summary mode: show summary, add readable content behind collapse
|
|
383
|
-
description = summarizeToolOutput(toolOutput);
|
|
384
|
-
const readable = formatToolResult(toolOutput);
|
|
396
|
+
description = summarizeToolOutput(toolOutput, translate);
|
|
397
|
+
const readable = formatToolResult(toolOutput, translate);
|
|
385
398
|
if (readable != null) {
|
|
386
399
|
content = readable;
|
|
387
400
|
collapsible = true;
|
|
@@ -453,7 +466,7 @@ function MessageBubble({ content, isStreaming, parts, config, addToolApprovalRes
|
|
|
453
466
|
animation: 'spin 1s linear infinite',
|
|
454
467
|
display: 'inline-block'
|
|
455
468
|
}
|
|
456
|
-
}, "⟳"), lastStatus.data?.message ?? '
|
|
469
|
+
}, "⟳"), lastStatus.data?.message ?? translate('agent.toolResult.processing'));
|
|
457
470
|
}
|
|
458
471
|
if (segment.category === 'text') {
|
|
459
472
|
const text = segment.parts.map((p)=>p.text).join('');
|
|
@@ -471,14 +484,16 @@ function MessageBubble({ content, isStreaming, parts, config, addToolApprovalRes
|
|
|
471
484
|
return null;
|
|
472
485
|
}), /*#__PURE__*/ React.createElement(SourcesDisplay, {
|
|
473
486
|
sourceParts: sourceParts,
|
|
474
|
-
config: config
|
|
487
|
+
config: config,
|
|
488
|
+
translate: translate
|
|
475
489
|
}), showActions && /*#__PURE__*/ React.createElement(BubbleActions, {
|
|
476
490
|
actions: normalizedActions,
|
|
477
491
|
textContent: allTextContent,
|
|
478
492
|
messageId: messageId,
|
|
479
493
|
onFeedback: onFeedback,
|
|
480
494
|
onRegenerate: onRegenerate,
|
|
481
|
-
onDelete: onDelete
|
|
495
|
+
onDelete: onDelete,
|
|
496
|
+
translate: translate
|
|
482
497
|
}));
|
|
483
498
|
}
|
|
484
499
|
export default MessageBubble;
|
|
@@ -31,8 +31,8 @@ function roleAvatar(roleConfig, fallbackIcon) {
|
|
|
31
31
|
icon: fallbackIcon
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
-
function roleHeader(roleConfig,
|
|
35
|
-
const name = roleConfig?.name ??
|
|
34
|
+
function roleHeader(roleConfig, fallbackKey, translate) {
|
|
35
|
+
const name = roleConfig?.name ?? translate(fallbackKey);
|
|
36
36
|
return /*#__PURE__*/ React.createElement("h5", {
|
|
37
37
|
style: {
|
|
38
38
|
margin: 0
|
|
@@ -55,7 +55,7 @@ function ThinkingBubbleContent({ bubbleId, config }) {
|
|
|
55
55
|
label: label
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
const MessageList = /*#__PURE__*/ React.forwardRef(function MessageList({ messages, isStreaming, config, addToolApprovalResponse, onFeedback, onRegenerate, onDelete, onEditMessage }, ref) {
|
|
58
|
+
const MessageList = /*#__PURE__*/ React.forwardRef(function MessageList({ messages, isStreaming, config, addToolApprovalResponse, onFeedback, onRegenerate, onDelete, onEditMessage, translate }, ref) {
|
|
59
59
|
// Build a lookup map for message parts.
|
|
60
60
|
// Bubble.List's contentRender callback only receives (content, info) where info.key is the
|
|
61
61
|
// item key — it does not receive the full message object with its parts array. This map
|
|
@@ -128,7 +128,7 @@ const MessageList = /*#__PURE__*/ React.forwardRef(function MessageList({ messag
|
|
|
128
128
|
variant: config?.roles?.user?.variant ?? 'filled',
|
|
129
129
|
shape: config?.roles?.user?.shape ?? 'round',
|
|
130
130
|
avatar: roleAvatar(config?.roles?.user, /*#__PURE__*/ React.createElement(UserOutlined, null)),
|
|
131
|
-
header: roleHeader(config?.roles?.user, '
|
|
131
|
+
header: roleHeader(config?.roles?.user, 'agent.message.userHeader', translate),
|
|
132
132
|
editable: config?.editableMessages !== false ? {
|
|
133
133
|
onEditConfirm: (key, newContent)=>{
|
|
134
134
|
const parts = partsMap.get(key);
|
|
@@ -174,7 +174,7 @@ const MessageList = /*#__PURE__*/ React.forwardRef(function MessageList({ messag
|
|
|
174
174
|
maxWidth: '100%'
|
|
175
175
|
},
|
|
176
176
|
avatar: roleAvatar(config?.roles?.assistant, /*#__PURE__*/ React.createElement(RobotOutlined, null)),
|
|
177
|
-
header: roleHeader(config?.roles?.assistant, '
|
|
177
|
+
header: roleHeader(config?.roles?.assistant, 'agent.message.assistantHeader', translate),
|
|
178
178
|
typing: config?.roles?.assistant?.typing ? config.roles.assistant.typing : {
|
|
179
179
|
effect: 'fade-in'
|
|
180
180
|
},
|
|
@@ -190,7 +190,8 @@ const MessageList = /*#__PURE__*/ React.forwardRef(function MessageList({ messag
|
|
|
190
190
|
messageId: info.key,
|
|
191
191
|
onFeedback: onFeedback,
|
|
192
192
|
onRegenerate: onRegenerate,
|
|
193
|
-
onDelete: onDelete
|
|
193
|
+
onDelete: onDelete,
|
|
194
|
+
translate: translate
|
|
194
195
|
});
|
|
195
196
|
}
|
|
196
197
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import React from 'react';
|
|
16
16
|
import { Button, Space } from 'antd';
|
|
17
|
-
function ToolApproval({ toolName, input, approvalId, onApprove, onReject }) {
|
|
17
|
+
function ToolApproval({ toolName, input, approvalId, onApprove, onReject, translate }) {
|
|
18
18
|
return /*#__PURE__*/ React.createElement("div", {
|
|
19
19
|
style: {
|
|
20
20
|
padding: '8px 0'
|
|
@@ -37,9 +37,9 @@ function ToolApproval({ toolName, input, approvalId, onApprove, onReject }) {
|
|
|
37
37
|
type: "primary",
|
|
38
38
|
size: "small",
|
|
39
39
|
onClick: ()=>onApprove(approvalId)
|
|
40
|
-
},
|
|
40
|
+
}, translate('agent.toolApproval.approve')), /*#__PURE__*/ React.createElement(Button, {
|
|
41
41
|
size: "small",
|
|
42
42
|
onClick: ()=>onReject(approvalId)
|
|
43
|
-
},
|
|
43
|
+
}, translate('agent.toolApproval.reject'))));
|
|
44
44
|
}
|
|
45
45
|
export default ToolApproval;
|
|
@@ -24,7 +24,7 @@ function isIsoDate(value) {
|
|
|
24
24
|
function humanizeKey(key) {
|
|
25
25
|
return key.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/[_-]/g, ' ').replace(/^\w/, (c)=>c.toUpperCase());
|
|
26
26
|
}
|
|
27
|
-
function CollapsibleText({ text, limit }) {
|
|
27
|
+
function CollapsibleText({ text, limit, translate }) {
|
|
28
28
|
const [expanded, setExpanded] = useState(false);
|
|
29
29
|
if (text.length <= limit) return /*#__PURE__*/ React.createElement("span", null, text);
|
|
30
30
|
return /*#__PURE__*/ React.createElement("span", null, expanded ? text : `${text.slice(0, limit)}...`, /*#__PURE__*/ React.createElement("a", {
|
|
@@ -34,9 +34,9 @@ function CollapsibleText({ text, limit }) {
|
|
|
34
34
|
fontSize: '0.85em',
|
|
35
35
|
cursor: 'pointer'
|
|
36
36
|
}
|
|
37
|
-
}, expanded ? '
|
|
37
|
+
}, expanded ? translate('agent.toolResult.showLess') : translate('agent.toolResult.showMore')));
|
|
38
38
|
}
|
|
39
|
-
function formatValue(value, depth) {
|
|
39
|
+
function formatValue(value, depth, translate) {
|
|
40
40
|
if (value === null || value === undefined) {
|
|
41
41
|
return /*#__PURE__*/ React.createElement("span", {
|
|
42
42
|
style: {
|
|
@@ -67,26 +67,27 @@ function formatValue(value, depth) {
|
|
|
67
67
|
if (value.length > 200) {
|
|
68
68
|
return /*#__PURE__*/ React.createElement(CollapsibleText, {
|
|
69
69
|
text: value,
|
|
70
|
-
limit: 200
|
|
70
|
+
limit: 200,
|
|
71
|
+
translate: translate
|
|
71
72
|
});
|
|
72
73
|
}
|
|
73
74
|
return /*#__PURE__*/ React.createElement("span", null, value);
|
|
74
75
|
}
|
|
75
76
|
if (Array.isArray(value)) {
|
|
76
|
-
return formatArray(value, depth);
|
|
77
|
+
return formatArray(value, depth, translate);
|
|
77
78
|
}
|
|
78
79
|
if (typeof value === 'object') {
|
|
79
|
-
return formatObject(value, depth);
|
|
80
|
+
return formatObject(value, depth, translate);
|
|
80
81
|
}
|
|
81
82
|
return /*#__PURE__*/ React.createElement("span", null, String(value));
|
|
82
83
|
}
|
|
83
|
-
function formatArray(arr, depth) {
|
|
84
|
+
function formatArray(arr, depth, translate) {
|
|
84
85
|
if (arr.length === 0) {
|
|
85
86
|
return /*#__PURE__*/ React.createElement("span", {
|
|
86
87
|
style: {
|
|
87
88
|
color: '#999'
|
|
88
89
|
}
|
|
89
|
-
},
|
|
90
|
+
}, translate('agent.toolResult.emptyList'));
|
|
90
91
|
}
|
|
91
92
|
const allPrimitive = arr.every((item)=>item === null || item === undefined || typeof item !== 'object');
|
|
92
93
|
if (allPrimitive) {
|
|
@@ -97,7 +98,7 @@ function formatArray(arr, depth) {
|
|
|
97
98
|
}
|
|
98
99
|
}, arr.map((item, i)=>/*#__PURE__*/ React.createElement("li", {
|
|
99
100
|
key: i
|
|
100
|
-
}, formatValue(item, depth + 1))));
|
|
101
|
+
}, formatValue(item, depth + 1, translate))));
|
|
101
102
|
}
|
|
102
103
|
return /*#__PURE__*/ React.createElement("div", {
|
|
103
104
|
style: {
|
|
@@ -114,16 +115,16 @@ function formatArray(arr, depth) {
|
|
|
114
115
|
background: 'rgba(0, 0, 0, 0.02)',
|
|
115
116
|
border: '1px solid rgba(0, 0, 0, 0.06)'
|
|
116
117
|
}
|
|
117
|
-
}, formatValue(item, depth + 1))));
|
|
118
|
+
}, formatValue(item, depth + 1, translate))));
|
|
118
119
|
}
|
|
119
|
-
function formatObject(obj, depth) {
|
|
120
|
+
function formatObject(obj, depth, translate) {
|
|
120
121
|
const keys = Object.keys(obj);
|
|
121
122
|
if (keys.length === 0) {
|
|
122
123
|
return /*#__PURE__*/ React.createElement("span", {
|
|
123
124
|
style: {
|
|
124
125
|
color: '#999'
|
|
125
126
|
}
|
|
126
|
-
},
|
|
127
|
+
}, translate('agent.toolResult.empty'));
|
|
127
128
|
}
|
|
128
129
|
return /*#__PURE__*/ React.createElement("div", {
|
|
129
130
|
style: {
|
|
@@ -148,7 +149,7 @@ function formatObject(obj, depth) {
|
|
|
148
149
|
fontSize: '0.9em',
|
|
149
150
|
marginBottom: 2
|
|
150
151
|
}
|
|
151
|
-
}, humanizeKey(key)), formatValue(val, depth + 1));
|
|
152
|
+
}, humanizeKey(key)), formatValue(val, depth + 1, translate));
|
|
152
153
|
}
|
|
153
154
|
return /*#__PURE__*/ React.createElement("div", {
|
|
154
155
|
key: key
|
|
@@ -158,16 +159,16 @@ function formatObject(obj, depth) {
|
|
|
158
159
|
fontSize: '0.9em',
|
|
159
160
|
color: 'rgba(0, 0, 0, 0.55)'
|
|
160
161
|
}
|
|
161
|
-
}, humanizeKey(key), ":", ' '), formatValue(val, depth + 1));
|
|
162
|
+
}, humanizeKey(key), ":", ' '), formatValue(val, depth + 1, translate));
|
|
162
163
|
}));
|
|
163
164
|
}
|
|
164
|
-
function formatToolResult(output) {
|
|
165
|
+
function formatToolResult(output, translate) {
|
|
165
166
|
if (output === null || output === undefined) {
|
|
166
167
|
return /*#__PURE__*/ React.createElement("span", {
|
|
167
168
|
style: {
|
|
168
169
|
color: '#999'
|
|
169
170
|
}
|
|
170
|
-
},
|
|
171
|
+
}, translate('agent.toolResult.completedNoData'));
|
|
171
172
|
}
|
|
172
173
|
return /*#__PURE__*/ React.createElement("div", {
|
|
173
174
|
style: {
|
|
@@ -176,6 +177,6 @@ function formatToolResult(output) {
|
|
|
176
177
|
maxHeight: 400,
|
|
177
178
|
overflowY: 'auto'
|
|
178
179
|
}
|
|
179
|
-
}, formatValue(output, 0));
|
|
180
|
+
}, formatValue(output, 0, translate));
|
|
180
181
|
}
|
|
181
182
|
export default formatToolResult;
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
onToolCall: 'Trigger when a tool is invoked.',
|
|
22
22
|
onToolResult: 'Trigger when a tool completes.',
|
|
23
23
|
onUserMessage: 'Trigger when the user sends a message.',
|
|
24
|
+
onConversationStart: 'Trigger once when a conversation starts, on its first user message. Event contains the conversationId (auto-minted when no conversationId property is set).',
|
|
24
25
|
onError: 'Trigger on stream error.',
|
|
25
26
|
onFeedback: 'Trigger when the user clicks thumbs up or down on a message.',
|
|
26
27
|
onRegenerate: 'Trigger when the user clicks regenerate on a message.',
|
|
@@ -13,12 +13,13 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { useRef, useEffect } from 'react';
|
|
16
|
-
function useAgentEvents({ messages, status, methods, finishMetaRef }) {
|
|
16
|
+
function useAgentEvents({ messages, status, methods, finishMetaRef, conversationId }) {
|
|
17
17
|
const prevStatusRef = useRef(status);
|
|
18
18
|
const firedToolCallIds = useRef(new Set());
|
|
19
19
|
const firedToolResultIds = useRef(new Set());
|
|
20
20
|
const firedUserMessageIds = useRef(new Set());
|
|
21
21
|
const firedTitleIds = useRef(new Set());
|
|
22
|
+
const firedConversationStartRef = useRef(false);
|
|
22
23
|
const lastMessageCountRef = useRef(0);
|
|
23
24
|
// Fire onMessageComplete when streaming finishes
|
|
24
25
|
useEffect(()=>{
|
|
@@ -60,6 +61,18 @@ function useAgentEvents({ messages, status, methods, finishMetaRef }) {
|
|
|
60
61
|
const lastMessage = messages[messages.length - 1];
|
|
61
62
|
if (lastMessage && lastMessage.role === 'user' && !firedUserMessageIds.current.has(lastMessage.id)) {
|
|
62
63
|
firedUserMessageIds.current.add(lastMessage.id);
|
|
64
|
+
// Announce the conversation once, on its first user message, with the
|
|
65
|
+
// effective (possibly auto-minted) conversationId so apps can persist or
|
|
66
|
+
// track with a guaranteed id.
|
|
67
|
+
if (!firedConversationStartRef.current) {
|
|
68
|
+
firedConversationStartRef.current = true;
|
|
69
|
+
methods.triggerEvent({
|
|
70
|
+
name: 'onConversationStart',
|
|
71
|
+
event: {
|
|
72
|
+
conversationId
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
63
76
|
const textContent = lastMessage.parts?.filter((p)=>p.type === 'text').map((p)=>p.text).join('');
|
|
64
77
|
methods.triggerEvent({
|
|
65
78
|
name: 'onUserMessage',
|
|
@@ -78,7 +91,8 @@ function useAgentEvents({ messages, status, methods, finishMetaRef }) {
|
|
|
78
91
|
}
|
|
79
92
|
}, [
|
|
80
93
|
messages,
|
|
81
|
-
methods
|
|
94
|
+
methods,
|
|
95
|
+
conversationId
|
|
82
96
|
]);
|
|
83
97
|
// Scan for new tool calls and results
|
|
84
98
|
useEffect(()=>{
|
|
@@ -149,6 +163,7 @@ function useAgentEvents({ messages, status, methods, finishMetaRef }) {
|
|
|
149
163
|
firedToolResultIds.current.clear();
|
|
150
164
|
firedUserMessageIds.current.clear();
|
|
151
165
|
firedTitleIds.current.clear();
|
|
166
|
+
firedConversationStartRef.current = false;
|
|
152
167
|
}
|
|
153
168
|
lastMessageCountRef.current = messages.length;
|
|
154
169
|
}, [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/blocks-antd-x",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Lowdefy Ant Design X Blocks",
|
|
6
6
|
"homepage": "https://lowdefy.com",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"@ant-design/icons": "6.1.0",
|
|
42
42
|
"@ant-design/x": "2.7.0",
|
|
43
43
|
"@ant-design/x-markdown": "2.7.0",
|
|
44
|
-
"@lowdefy/block-utils": "5.
|
|
45
|
-
"@lowdefy/helpers": "5.
|
|
44
|
+
"@lowdefy/block-utils": "5.4.0",
|
|
45
|
+
"@lowdefy/helpers": "5.4.0",
|
|
46
46
|
"ai": "6.0.176"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|