@blocksdiy/react-common 1.28.1 → 1.28.2
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.
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { type Message,
|
|
2
|
-
import { useRenderToolCall } from "@copilotkit/react-core/v2";
|
|
1
|
+
import { type Message, type UserMessage } from "@ag-ui/client";
|
|
3
2
|
import { ReactNode, SetStateAction } from "react";
|
|
4
|
-
export { type Message, type AssistantMessage
|
|
5
|
-
export { useRenderTool, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
|
|
3
|
+
export { type Message, type AssistantMessage } from "@ag-ui/client";
|
|
4
|
+
export { useRenderTool, useRenderToolCall, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
|
|
6
5
|
export interface Attachment {
|
|
7
6
|
url: string;
|
|
8
7
|
fileType: string;
|
|
@@ -11,7 +10,8 @@ export interface Attachment {
|
|
|
11
10
|
export interface AgentChatComponent {
|
|
12
11
|
id: string;
|
|
13
12
|
name: string;
|
|
14
|
-
|
|
13
|
+
toolName?: string;
|
|
14
|
+
code?: string;
|
|
15
15
|
input?: Record<string, unknown>;
|
|
16
16
|
description?: string;
|
|
17
17
|
/**
|
|
@@ -51,14 +51,6 @@ export interface AgentChatContextValue {
|
|
|
51
51
|
agent: Agent | null;
|
|
52
52
|
agentChat: AgentChat | null;
|
|
53
53
|
components: AgentChatComponent[];
|
|
54
|
-
messageGroups: {
|
|
55
|
-
messageIds: string[];
|
|
56
|
-
role: "assistant" | "user";
|
|
57
|
-
}[];
|
|
58
|
-
messageById: Map<string, Message>;
|
|
59
|
-
toolMessages: ToolMessage[];
|
|
60
|
-
renderToolCall: ReturnType<typeof useRenderToolCall>;
|
|
61
|
-
hasSentMessageInSession: boolean;
|
|
62
54
|
sendMessage: (message: Omit<UserMessage, "id" | "role">) => Promise<void>;
|
|
63
55
|
sendFromInputs: () => Promise<void>;
|
|
64
56
|
stopGeneration: () => void;
|
|
@@ -72,11 +64,6 @@ export interface AgentChatContextValue {
|
|
|
72
64
|
}
|
|
73
65
|
export declare const AgentChatContext: import("react").Context<AgentChatContextValue | null>;
|
|
74
66
|
export declare const useAgentChat: () => AgentChatContextValue;
|
|
75
|
-
interface AgentChatScrollContextValue {
|
|
76
|
-
isAtBottom: boolean;
|
|
77
|
-
scrollToBottom: () => void;
|
|
78
|
-
}
|
|
79
|
-
export declare const useAgentChatScroll: () => AgentChatScrollContextValue;
|
|
80
67
|
export interface AgentChatRootProps {
|
|
81
68
|
appId: string;
|
|
82
69
|
token?: string;
|
|
@@ -101,22 +88,10 @@ export interface AgentChatMessageProps {
|
|
|
101
88
|
index: number;
|
|
102
89
|
}
|
|
103
90
|
export declare function AgentChatMessage({ message, index, ...props }: React.ComponentProps<"div"> & AgentChatMessageProps): import("react/jsx-runtime").JSX.Element | null;
|
|
104
|
-
export interface AgentChatMessageGroupProps {
|
|
105
|
-
messageGroup: {
|
|
106
|
-
messageIds: string[];
|
|
107
|
-
role: "assistant" | "user";
|
|
108
|
-
};
|
|
109
|
-
isLast?: boolean;
|
|
110
|
-
}
|
|
111
|
-
export declare function AgentChatMessageGroup({ messageGroup, isLast, style, ...props }: React.ComponentProps<"div"> & AgentChatMessageGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
112
91
|
export interface AgentChatMessagesProps {
|
|
113
92
|
scrollAreaClassName?: string;
|
|
114
93
|
}
|
|
115
|
-
export declare function AgentChatMessages({ scrollAreaClassName,
|
|
116
|
-
export interface AgentChatScrollToBottomProps {
|
|
117
|
-
asChild?: boolean;
|
|
118
|
-
}
|
|
119
|
-
export declare function AgentChatScrollToBottom({ asChild, onClick, ...props }: React.ComponentProps<"button"> & AgentChatScrollToBottomProps): import("react/jsx-runtime").JSX.Element | null;
|
|
94
|
+
export declare function AgentChatMessages({ scrollAreaClassName, ...props }: React.ComponentProps<"div"> & AgentChatMessagesProps): import("react/jsx-runtime").JSX.Element;
|
|
120
95
|
export interface AgentChatThinkingProps {
|
|
121
96
|
asChild?: boolean;
|
|
122
97
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"new-agent-chat.d.ts","sourceRoot":"","sources":["../../src/components/new-agent-chat.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"new-agent-chat.d.ts","sourceRoot":"","sources":["../../src/components/new-agent-chat.tsx"],"names":[],"mappings":"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"}
|
|
@@ -2,10 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { AppVersionService, BlocksApiService, websocketsService } from "@blocksdiy/blocks-client-api";
|
|
3
3
|
import { getApiHost } from "@blocksdiy/blocks-client-api/envService";
|
|
4
4
|
import { CopilotKit, useCopilotChatInternal } from "@copilotkit/react-core";
|
|
5
|
-
import { useCopilotKit
|
|
5
|
+
import { useCopilotKit } from "@copilotkit/react-core/v2";
|
|
6
6
|
import { Slot } from "@radix-ui/react-slot";
|
|
7
7
|
import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
8
|
-
export { useRenderTool, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
|
|
8
|
+
export { useRenderTool, useRenderToolCall, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
|
|
9
|
+
import { useStickToBottom } from "use-stick-to-bottom";
|
|
9
10
|
// Client-only `useLayoutEffect`, falls back to `useEffect` during SSR.
|
|
10
11
|
// Needed so the `agent.threadId` mirror commits before CopilotKit's
|
|
11
12
|
// connect-on-mount effect reads it.
|
|
@@ -60,82 +61,15 @@ const validateAndConvertFiles = (files) => {
|
|
|
60
61
|
}
|
|
61
62
|
const hasOversizedFiles = files.some((file) => file.size > MAX_FILE_SIZE_BYTES);
|
|
62
63
|
if (hasOversizedFiles) {
|
|
64
|
+
console.error(`Upload failed because some files are bigger than ${MAX_FILE_SIZE_MB} MB.`);
|
|
63
65
|
return null;
|
|
64
66
|
}
|
|
65
67
|
return files.map((file) => ({
|
|
66
|
-
fileType: file.type
|
|
68
|
+
fileType: file.type,
|
|
67
69
|
fileName: file.name,
|
|
68
70
|
url: URL.createObjectURL(file),
|
|
69
71
|
}));
|
|
70
72
|
};
|
|
71
|
-
const fileFromAttachment = async (attachment) => {
|
|
72
|
-
const response = await fetch(attachment.url);
|
|
73
|
-
if (!response.ok) {
|
|
74
|
-
throw new Error("The blob URL is no longer valid");
|
|
75
|
-
}
|
|
76
|
-
const blob = await response.blob();
|
|
77
|
-
return new File([blob], attachment.fileName, {
|
|
78
|
-
type: attachment.fileType,
|
|
79
|
-
lastModified: Date.now(),
|
|
80
|
-
});
|
|
81
|
-
};
|
|
82
|
-
const getBrowserUploadUrl = (uploadUrl) => {
|
|
83
|
-
try {
|
|
84
|
-
const url = new URL(uploadUrl);
|
|
85
|
-
if (url.hostname === "localhost" && url.port === "4566") {
|
|
86
|
-
url.hostname = "blocks.localhost";
|
|
87
|
-
return url.toString();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
return uploadUrl;
|
|
92
|
-
}
|
|
93
|
-
return uploadUrl;
|
|
94
|
-
};
|
|
95
|
-
const uploadFile = async ({ appId, blocksApiService, file, }) => {
|
|
96
|
-
const formData = new FormData();
|
|
97
|
-
const { uploadUrl, fields, protectedUrl } = await blocksApiService.getDataAssetUploadUrl({
|
|
98
|
-
productId: appId,
|
|
99
|
-
fileName: file.name,
|
|
100
|
-
fileType: file.type,
|
|
101
|
-
});
|
|
102
|
-
const request = new XMLHttpRequest();
|
|
103
|
-
if (uploadUrl && fields) {
|
|
104
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
105
|
-
formData.append(key, value);
|
|
106
|
-
}
|
|
107
|
-
formData.append("file", file);
|
|
108
|
-
request.open("POST", getBrowserUploadUrl(uploadUrl));
|
|
109
|
-
}
|
|
110
|
-
return new Promise((resolve, reject) => {
|
|
111
|
-
request.onload = () => {
|
|
112
|
-
if (request.status >= 200 && request.status < 300) {
|
|
113
|
-
resolve(protectedUrl);
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
reject(new Error("Error uploading file"));
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
request.onerror = () => {
|
|
120
|
-
reject(new Error("Error uploading file"));
|
|
121
|
-
};
|
|
122
|
-
request.send(formData);
|
|
123
|
-
});
|
|
124
|
-
};
|
|
125
|
-
const uploadAttachments = async ({ attachments, blocksApiService, appId, }) => {
|
|
126
|
-
if (!attachments?.length) {
|
|
127
|
-
return undefined;
|
|
128
|
-
}
|
|
129
|
-
return Promise.all(attachments.map(async (attachment) => {
|
|
130
|
-
const file = await fileFromAttachment(attachment);
|
|
131
|
-
const protectedUrl = await uploadFile({ appId, blocksApiService, file });
|
|
132
|
-
return {
|
|
133
|
-
url: protectedUrl,
|
|
134
|
-
fileName: attachment.fileName,
|
|
135
|
-
fileType: attachment.fileType,
|
|
136
|
-
};
|
|
137
|
-
}));
|
|
138
|
-
};
|
|
139
73
|
const hasSendableInput = (prompt, attachments) => {
|
|
140
74
|
return prompt.trim().length > 0 || attachments.length > 0;
|
|
141
75
|
};
|
|
@@ -147,55 +81,6 @@ export const useAgentChat = () => {
|
|
|
147
81
|
}
|
|
148
82
|
return context;
|
|
149
83
|
};
|
|
150
|
-
const NEW_MESSAGE_SCROLL_HIDE_MS = 500;
|
|
151
|
-
const AgentChatScrollContext = createContext(null);
|
|
152
|
-
export const useAgentChatScroll = () => {
|
|
153
|
-
const context = useContext(AgentChatScrollContext);
|
|
154
|
-
if (!context) {
|
|
155
|
-
throw new Error("useAgentChatScroll must be used within an AgentChatMessages provider");
|
|
156
|
-
}
|
|
157
|
-
return context;
|
|
158
|
-
};
|
|
159
|
-
const getMessageGroups = (scrollElement) => {
|
|
160
|
-
return Array.from(scrollElement.querySelectorAll('[data-slot="agent-chat-message-group"]'));
|
|
161
|
-
};
|
|
162
|
-
const SCROLL_BOTTOM_OFFSET_PX = 70;
|
|
163
|
-
const getTargetScrollTop = (scrollElement) => {
|
|
164
|
-
return Math.max(scrollElement.scrollHeight - 1 - scrollElement.clientHeight, 0);
|
|
165
|
-
};
|
|
166
|
-
const isScrollAtBottom = (scrollElement) => {
|
|
167
|
-
return getTargetScrollTop(scrollElement) - scrollElement.scrollTop <= SCROLL_BOTTOM_OFFSET_PX;
|
|
168
|
-
};
|
|
169
|
-
const setScrollTopInstantly = (scrollElement, scrollTop) => {
|
|
170
|
-
const { scrollBehavior } = getComputedStyle(scrollElement);
|
|
171
|
-
if (scrollBehavior !== "auto") {
|
|
172
|
-
scrollElement.style.scrollBehavior = "auto";
|
|
173
|
-
}
|
|
174
|
-
scrollElement.scrollTop = scrollTop;
|
|
175
|
-
if (scrollBehavior !== "auto") {
|
|
176
|
-
scrollElement.style.scrollBehavior = scrollBehavior;
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
const AGENT_CHAT_CONTAINER_HEIGHT_VAR = "--agent-chat-container-height";
|
|
180
|
-
const AGENT_CHAT_LATEST_USER_HEIGHT_VAR = "--agent-chat-latest-user-message-height";
|
|
181
|
-
const LAST_ASSISTANT_MESSAGE_GROUP_STYLE = {
|
|
182
|
-
minHeight: `max(calc(var(${AGENT_CHAT_CONTAINER_HEIGHT_VAR}, 0px) - var(${AGENT_CHAT_LATEST_USER_HEIGHT_VAR}, var(${AGENT_CHAT_CONTAINER_HEIGHT_VAR}, 0px))), 0px)`,
|
|
183
|
-
};
|
|
184
|
-
const updateScrollHeightVariables = (scrollElement) => {
|
|
185
|
-
const messageGroups = getMessageGroups(scrollElement);
|
|
186
|
-
const latestUserGroup = messageGroups.reverse().find((messageGroup) => messageGroup.dataset.messageGroup === "user");
|
|
187
|
-
scrollElement.style.setProperty(AGENT_CHAT_CONTAINER_HEIGHT_VAR, `${scrollElement.clientHeight}px`);
|
|
188
|
-
if (latestUserGroup) {
|
|
189
|
-
scrollElement.style.setProperty(AGENT_CHAT_LATEST_USER_HEIGHT_VAR, `${latestUserGroup.offsetHeight}px`);
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
scrollElement.style.removeProperty(AGENT_CHAT_LATEST_USER_HEIGHT_VAR);
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
const clearScrollHeightVariables = (scrollElement) => {
|
|
196
|
-
scrollElement.style.removeProperty(AGENT_CHAT_CONTAINER_HEIGHT_VAR);
|
|
197
|
-
scrollElement.style.removeProperty(AGENT_CHAT_LATEST_USER_HEIGHT_VAR);
|
|
198
|
-
};
|
|
199
84
|
const SessionReadables = () => {
|
|
200
85
|
// const now = new Date();
|
|
201
86
|
// useCopilotReadable({
|
|
@@ -220,33 +105,6 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
|
|
|
220
105
|
const [isConfigLoaded, setIsConfigLoaded] = useState(false);
|
|
221
106
|
const { messages: copilotMessages, sendMessage: copilotSendMessage, stopGeneration: copilotStopGeneration, isAvailable: isAgentReady, isLoading: isAgentRunning, agent: copilotAgent, } = useCopilotChatInternal();
|
|
222
107
|
const { copilotkit } = useCopilotKit();
|
|
223
|
-
const renderToolCall = useRenderToolCall();
|
|
224
|
-
const messageById = useMemo(() => {
|
|
225
|
-
const messagesSet = new Map();
|
|
226
|
-
copilotMessages.forEach((message) => {
|
|
227
|
-
messagesSet.set(message.id, message);
|
|
228
|
-
});
|
|
229
|
-
return messagesSet;
|
|
230
|
-
}, [copilotMessages]);
|
|
231
|
-
const toolMessages = useMemo(() => {
|
|
232
|
-
return copilotMessages.filter((message) => message.role === "tool");
|
|
233
|
-
}, [copilotMessages]);
|
|
234
|
-
const messageGroups = useMemo(() => {
|
|
235
|
-
const groups = [];
|
|
236
|
-
copilotMessages.forEach((message) => {
|
|
237
|
-
if (message.role !== "assistant" && message.role !== "user") {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
const lastGroup = groups[groups.length - 1];
|
|
241
|
-
if (!lastGroup || lastGroup.role !== message.role) {
|
|
242
|
-
groups.push({ role: message.role, messageIds: [message.id] });
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
lastGroup.messageIds.push(message.id);
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
return groups;
|
|
249
|
-
}, [copilotMessages]);
|
|
250
108
|
// Mirror `currentThreadId` onto the agent instance — the `<CopilotKit>`
|
|
251
109
|
// prop only feeds React context, but `agent.threadId` is what hits the
|
|
252
110
|
// wire and the LangGraph checkpoint. `<CopilotChat>` does this for you;
|
|
@@ -262,7 +120,6 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
|
|
|
262
120
|
const [prompt, setPrompt] = useState("");
|
|
263
121
|
const [attachments, setAttachments] = useState([]);
|
|
264
122
|
const [isDraggingFiles, setIsDraggingFiles] = useState(false);
|
|
265
|
-
const [hasSentMessageInSession, setHasSentMessageInSession] = useState(false);
|
|
266
123
|
const blocksApiService = useMemo(() => new BlocksApiService({ token }), [token]);
|
|
267
124
|
const attachmentsEnabled = agentChat ? agentChat.disableAttachments !== true : false;
|
|
268
125
|
const canSendMessage = Boolean(agentChatId && agentChat && agent && isConfigLoaded && isAgentReady && !isAgentRunning);
|
|
@@ -274,7 +131,6 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
|
|
|
274
131
|
if (!canSendMessage) {
|
|
275
132
|
return Promise.resolve();
|
|
276
133
|
}
|
|
277
|
-
setHasSentMessageInSession(true);
|
|
278
134
|
return copilotSendMessage({ id: generateId(), role: "user", ...message });
|
|
279
135
|
}, [canSendMessage, copilotSendMessage]);
|
|
280
136
|
const stopGeneration = useCallback(() => {
|
|
@@ -295,7 +151,7 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
|
|
|
295
151
|
if (!componentIds?.length) {
|
|
296
152
|
return [];
|
|
297
153
|
}
|
|
298
|
-
const
|
|
154
|
+
const maybeComponentBlocks = await Promise.all(componentIds.map(async (componentId) => {
|
|
299
155
|
try {
|
|
300
156
|
const block = await blocksApiService.getBlock(componentId);
|
|
301
157
|
const id = block?.id ?? componentId;
|
|
@@ -311,6 +167,7 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
|
|
|
311
167
|
code,
|
|
312
168
|
input: block?.data?.input,
|
|
313
169
|
description,
|
|
170
|
+
toolName: getAgentChatComponentToolName(name),
|
|
314
171
|
userInterrupt: Boolean(block?.data?.userInterrupt),
|
|
315
172
|
};
|
|
316
173
|
}
|
|
@@ -318,7 +175,7 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
|
|
|
318
175
|
return null;
|
|
319
176
|
}
|
|
320
177
|
}));
|
|
321
|
-
return
|
|
178
|
+
return maybeComponentBlocks.filter((component) => Boolean(component));
|
|
322
179
|
}, [blocksApiService, componentIds]);
|
|
323
180
|
const componentIdsKey = componentIds?.join(",") ?? "";
|
|
324
181
|
const initKeyRef = useRef(null);
|
|
@@ -341,7 +198,6 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
|
|
|
341
198
|
}
|
|
342
199
|
initKeyRef.current = initKey;
|
|
343
200
|
initialPromptSentRef.current = false;
|
|
344
|
-
setHasSentMessageInSession(false);
|
|
345
201
|
const ac = new AbortController();
|
|
346
202
|
const initialize = async () => {
|
|
347
203
|
setIsConfigLoaded(false);
|
|
@@ -446,45 +302,12 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
|
|
|
446
302
|
});
|
|
447
303
|
void copilotkit.runAgent({ agent: copilotAgent });
|
|
448
304
|
}, [isAgentReady, isConfigLoaded, agentChat, copilotAgent, canSendMessage, copilotkit]);
|
|
449
|
-
const buildMessageContentFromInput = (currentPrompt = prompt, currentAttachments = attachments) => {
|
|
450
|
-
if (currentAttachments.length === 0) {
|
|
451
|
-
return currentPrompt;
|
|
452
|
-
}
|
|
453
|
-
const contentArray = [];
|
|
454
|
-
currentAttachments.forEach((attachment) => {
|
|
455
|
-
const source = { type: "url", value: attachment.url, mimeType: attachment.fileType };
|
|
456
|
-
const metadata = { filename: attachment.fileName };
|
|
457
|
-
switch (true) {
|
|
458
|
-
case attachment.fileType.startsWith("image/"):
|
|
459
|
-
contentArray.push({ type: "image", source, metadata });
|
|
460
|
-
break;
|
|
461
|
-
case attachment.fileType.startsWith("audio/"):
|
|
462
|
-
contentArray.push({ type: "audio", source, metadata });
|
|
463
|
-
break;
|
|
464
|
-
case attachment.fileType.startsWith("video/"):
|
|
465
|
-
contentArray.push({ type: "video", source, metadata });
|
|
466
|
-
break;
|
|
467
|
-
default:
|
|
468
|
-
contentArray.push({ type: "document", source, metadata });
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
if (currentPrompt) {
|
|
472
|
-
contentArray.push({ type: "text", text: currentPrompt });
|
|
473
|
-
}
|
|
474
|
-
return contentArray;
|
|
475
|
-
};
|
|
476
305
|
const sendFromInputs = async () => {
|
|
477
306
|
if (!canSendMessage || !hasSendableInput(prompt, attachments)) {
|
|
478
307
|
return;
|
|
479
308
|
}
|
|
480
309
|
const currentPrompt = prompt;
|
|
481
|
-
const currentAttachments = attachments;
|
|
482
|
-
const uploadedAttachments = await uploadAttachments({
|
|
483
|
-
attachments: currentAttachments,
|
|
484
|
-
appId,
|
|
485
|
-
blocksApiService,
|
|
486
|
-
});
|
|
487
|
-
const messageContent = buildMessageContentFromInput(currentPrompt, uploadedAttachments ?? []);
|
|
310
|
+
// const currentAttachments = attachments;
|
|
488
311
|
setPrompt("");
|
|
489
312
|
setAttachments([]);
|
|
490
313
|
// Auto-skip any frontend user-choice tool call that's still waiting.
|
|
@@ -525,9 +348,7 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
|
|
|
525
348
|
});
|
|
526
349
|
}
|
|
527
350
|
}
|
|
528
|
-
await sendMessage({
|
|
529
|
-
content: messageContent,
|
|
530
|
-
});
|
|
351
|
+
await sendMessage({ content: currentPrompt });
|
|
531
352
|
};
|
|
532
353
|
const addAttachments = (attachments) => {
|
|
533
354
|
if (!attachmentsEnabled) {
|
|
@@ -556,11 +377,6 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
|
|
|
556
377
|
};
|
|
557
378
|
return (_jsx(AgentChatContext.Provider, { value: {
|
|
558
379
|
messages: copilotMessages,
|
|
559
|
-
messageGroups,
|
|
560
|
-
renderToolCall,
|
|
561
|
-
messageById,
|
|
562
|
-
toolMessages,
|
|
563
|
-
hasSentMessageInSession,
|
|
564
380
|
prompt,
|
|
565
381
|
attachments,
|
|
566
382
|
sendMessage,
|
|
@@ -622,139 +438,24 @@ export function AgentChatMessage({ message, index, ...props }) {
|
|
|
622
438
|
}
|
|
623
439
|
return _jsx("div", { "data-message-index": index, "data-message-role": message.role, ...props });
|
|
624
440
|
}
|
|
625
|
-
export function
|
|
626
|
-
const {
|
|
627
|
-
const
|
|
628
|
-
const
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
? {
|
|
634
|
-
...style,
|
|
635
|
-
...LAST_ASSISTANT_MESSAGE_GROUP_STYLE,
|
|
636
|
-
}
|
|
637
|
-
: style;
|
|
638
|
-
return (_jsx("div", { "data-slot": "agent-chat-message-group", "data-message-group": messageGroup.role, "data-message-group-role": messageGroup.role, style: mergedStyle, ...props }));
|
|
639
|
-
}
|
|
640
|
-
export function AgentChatMessages({ scrollAreaClassName, children, ...props }) {
|
|
641
|
-
const { isFetchingMessages, isThinking, messageGroups } = useAgentChat();
|
|
642
|
-
const messageGroupCount = messageGroups.length;
|
|
643
|
-
const scrollRef = useRef(null);
|
|
644
|
-
const previousMessageGroupCountRef = useRef(messageGroupCount);
|
|
645
|
-
const hasCompletedInitialScrollRef = useRef(false);
|
|
646
|
-
const previousIsThinkingRef = useRef(isThinking);
|
|
647
|
-
const newMessageScrollTimeoutRef = useRef(null);
|
|
648
|
-
const [isNewMessageScrollInProgress, setIsNewMessageScrollInProgress] = useState(false);
|
|
649
|
-
const [isAtBottom, setIsAtBottom] = useState(true);
|
|
650
|
-
const scrollToBottom = useCallback((behavior = "smooth") => {
|
|
651
|
-
const scrollElement = scrollRef.current;
|
|
652
|
-
if (!scrollElement) {
|
|
653
|
-
return;
|
|
654
|
-
}
|
|
655
|
-
const targetScrollTop = getTargetScrollTop(scrollElement);
|
|
656
|
-
if (behavior === "instant") {
|
|
657
|
-
setScrollTopInstantly(scrollElement, targetScrollTop);
|
|
658
|
-
}
|
|
659
|
-
else {
|
|
660
|
-
scrollElement.scrollTo({ top: targetScrollTop, behavior });
|
|
661
|
-
}
|
|
662
|
-
setIsAtBottom(true);
|
|
663
|
-
}, []);
|
|
664
|
-
const scrollContextValue = useMemo(() => ({
|
|
665
|
-
isAtBottom: isAtBottom || isNewMessageScrollInProgress,
|
|
666
|
-
scrollToBottom: () => {
|
|
667
|
-
void scrollToBottom();
|
|
668
|
-
},
|
|
669
|
-
}), [isAtBottom, isNewMessageScrollInProgress, scrollToBottom]);
|
|
670
|
-
useIsomorphicLayoutEffect(() => {
|
|
671
|
-
const scrollElement = scrollRef.current;
|
|
672
|
-
if (!scrollElement) {
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
if (getComputedStyle(scrollElement).overflow === "visible") {
|
|
676
|
-
scrollElement.style.overflow = "auto";
|
|
677
|
-
}
|
|
678
|
-
const updateIsAtBottom = () => {
|
|
679
|
-
setIsAtBottom(isScrollAtBottom(scrollElement));
|
|
680
|
-
};
|
|
681
|
-
updateIsAtBottom();
|
|
682
|
-
scrollElement.addEventListener("scroll", updateIsAtBottom, { passive: true });
|
|
683
|
-
return () => {
|
|
684
|
-
scrollElement.removeEventListener("scroll", updateIsAtBottom);
|
|
685
|
-
};
|
|
686
|
-
}, []);
|
|
687
|
-
useEffect(() => {
|
|
688
|
-
return () => {
|
|
689
|
-
if (newMessageScrollTimeoutRef.current !== null) {
|
|
690
|
-
window.clearTimeout(newMessageScrollTimeoutRef.current);
|
|
691
|
-
}
|
|
692
|
-
};
|
|
693
|
-
}, []);
|
|
441
|
+
export function AgentChatMessages({ scrollAreaClassName, ...props }) {
|
|
442
|
+
const { messages } = useAgentChat();
|
|
443
|
+
const userMessageCount = messages.filter((message) => message.role === "user" && message.name !== HIDDEN_INITIAL_PROMPT_MESSAGE_NAME).length;
|
|
444
|
+
const previousUserMessageCountRef = useRef(userMessageCount);
|
|
445
|
+
const { scrollRef, contentRef, scrollToBottom } = useStickToBottom({
|
|
446
|
+
resize: "smooth",
|
|
447
|
+
initial: { damping: 1, stiffness: 1 },
|
|
448
|
+
});
|
|
694
449
|
useEffect(() => {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
}, [
|
|
703
|
-
|
|
704
|
-
const scrollElement = scrollRef.current;
|
|
705
|
-
if (isFetchingMessages) {
|
|
706
|
-
previousMessageGroupCountRef.current = messageGroupCount;
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
if (!scrollElement) {
|
|
710
|
-
previousMessageGroupCountRef.current = messageGroupCount;
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
|
-
if (!hasCompletedInitialScrollRef.current) {
|
|
714
|
-
clearScrollHeightVariables(scrollElement);
|
|
715
|
-
scrollToBottom("instant");
|
|
716
|
-
previousMessageGroupCountRef.current = messageGroupCount;
|
|
717
|
-
hasCompletedInitialScrollRef.current = true;
|
|
718
|
-
return;
|
|
719
|
-
}
|
|
720
|
-
if (messageGroupCount < previousMessageGroupCountRef.current) {
|
|
721
|
-
previousMessageGroupCountRef.current = messageGroupCount;
|
|
722
|
-
clearScrollHeightVariables(scrollElement);
|
|
723
|
-
scrollToBottom("instant");
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
if (messageGroupCount > previousMessageGroupCountRef.current) {
|
|
727
|
-
updateScrollHeightVariables(scrollElement);
|
|
728
|
-
setIsNewMessageScrollInProgress(true);
|
|
729
|
-
if (newMessageScrollTimeoutRef.current !== null) {
|
|
730
|
-
window.clearTimeout(newMessageScrollTimeoutRef.current);
|
|
731
|
-
}
|
|
732
|
-
newMessageScrollTimeoutRef.current = window.setTimeout(() => {
|
|
733
|
-
setIsNewMessageScrollInProgress(false);
|
|
734
|
-
newMessageScrollTimeoutRef.current = null;
|
|
735
|
-
}, NEW_MESSAGE_SCROLL_HIDE_MS);
|
|
736
|
-
scrollToBottom("smooth");
|
|
737
|
-
}
|
|
738
|
-
previousMessageGroupCountRef.current = messageGroupCount;
|
|
739
|
-
}, [isFetchingMessages, messageGroupCount, scrollToBottom]);
|
|
740
|
-
return (_jsx(AgentChatScrollContext.Provider, { value: scrollContextValue, children: _jsx("div", { ...props, children: _jsx("div", { ref: scrollRef, style: {
|
|
741
|
-
height: "100%",
|
|
742
|
-
width: "100%",
|
|
743
|
-
scrollbarGutter: "stable both-edges",
|
|
744
|
-
}, children: _jsx("div", { className: scrollAreaClassName, children: children }) }) }) }));
|
|
745
|
-
}
|
|
746
|
-
export function AgentChatScrollToBottom({ asChild = false, onClick, ...props }) {
|
|
747
|
-
const { isAtBottom, scrollToBottom } = useAgentChatScroll();
|
|
748
|
-
const Comp = asChild ? Slot : "button";
|
|
749
|
-
if (isAtBottom) {
|
|
750
|
-
return null;
|
|
751
|
-
}
|
|
752
|
-
return (_jsx(Comp, { "data-slot": "agent-chat-scroll-to-bottom", onClick: (event) => {
|
|
753
|
-
onClick?.(event);
|
|
754
|
-
if (!event.defaultPrevented) {
|
|
755
|
-
scrollToBottom();
|
|
756
|
-
}
|
|
757
|
-
}, ...props }));
|
|
450
|
+
if (userMessageCount > previousUserMessageCountRef.current) {
|
|
451
|
+
void scrollToBottom({
|
|
452
|
+
animation: "smooth",
|
|
453
|
+
ignoreEscapes: true,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
previousUserMessageCountRef.current = userMessageCount;
|
|
457
|
+
}, [scrollToBottom, userMessageCount]);
|
|
458
|
+
return (_jsx("div", { ref: scrollRef, style: { overflow: "auto" }, className: scrollAreaClassName, children: _jsx("div", { ref: contentRef, "data-slot": "agent-chat-messages", ...props }) }));
|
|
758
459
|
}
|
|
759
460
|
export function AgentChatThinking({ asChild = false, ...props }) {
|
|
760
461
|
const { isThinking } = useAgentChat();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocksdiy/react-common",
|
|
3
|
-
"version": "1.28.
|
|
3
|
+
"version": "1.28.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "React common",
|
|
6
6
|
"keywords": [],
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"penpal": "^7.0.6",
|
|
39
39
|
"react": "^19.2.4",
|
|
40
40
|
"use-stick-to-bottom": "1.1.4",
|
|
41
|
-
"@blocksdiy/blocks-client-api": "1.10.
|
|
41
|
+
"@blocksdiy/blocks-client-api": "1.10.2"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/react": "^19.2.14",
|