@sybilion/uilib 1.3.76 → 1.3.77
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/esm/components/ui/Chat/ChatChrome/ChatChrome.js +20 -12
- package/dist/esm/components/ui/Chat/ChatMessage/AgentMessageContent.js +4 -2
- package/dist/esm/components/ui/Chat/ChatMessage/ChatMessage.js +2 -2
- package/dist/esm/components/ui/Chat/ChatSheet/useChatPanelChromeModel.js +18 -8
- package/dist/esm/types/src/components/ui/Chat/Chat.types.d.ts +2 -0
- package/dist/esm/types/src/components/ui/Chat/ChatMessage/AgentMessageContent.d.ts +2 -1
- package/dist/esm/types/src/components/ui/Chat/ChatMessage/ChatMessage.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/ui/Chat/Chat.types.ts +2 -0
- package/src/components/ui/Chat/ChatChrome/ChatChrome.tsx +20 -10
- package/src/components/ui/Chat/ChatMessage/AgentMessageContent.tsx +6 -1
- package/src/components/ui/Chat/ChatMessage/ChatMessage.tsx +2 -0
- package/src/components/ui/Chat/ChatSheet/useChatPanelChromeModel.tsx +15 -5
|
@@ -53,22 +53,30 @@ function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPr
|
|
|
53
53
|
useEffect(() => {
|
|
54
54
|
if (isEmpty)
|
|
55
55
|
return;
|
|
56
|
-
const scrollToBottom = () => {
|
|
56
|
+
const scrollToBottom = (behavior) => {
|
|
57
57
|
const inner = scrollRef.current?.innerElem;
|
|
58
|
-
if (inner)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
58
|
+
if (!inner)
|
|
59
|
+
return;
|
|
60
|
+
inner.scrollTo({
|
|
61
|
+
top: inner.scrollHeight + 1000,
|
|
62
|
+
behavior,
|
|
63
|
+
});
|
|
64
64
|
};
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
const behavior = loadingLabel ? 'instant' : 'smooth';
|
|
66
|
+
const frameId = requestAnimationFrame(() => {
|
|
67
|
+
requestAnimationFrame(() => scrollToBottom(behavior));
|
|
68
|
+
});
|
|
69
|
+
return () => cancelAnimationFrame(frameId);
|
|
70
|
+
}, [
|
|
71
|
+
isEmpty,
|
|
72
|
+
messages.length,
|
|
73
|
+
loadingLabel,
|
|
74
|
+
showInlinePresets,
|
|
75
|
+
showSyntheticBranchButtons,
|
|
76
|
+
]);
|
|
69
77
|
return (jsxs("div", { className: S.root, children: [showResizeHandle && resizeHandle ? (jsx(PanelResizeHandle, { edge: "leading", isActive: resizeHandle.isActive, startWidthPx: resizeHandle.startWidthPx, getShellWidth: resizeHandle.getShellWidth, onDragWidth: resizeHandle.onDragWidth, onDragComplete: resizeHandle.onDragComplete, className: cn(SidebarStem.sidebarResizeHandle, S.chatResizeHandle) })) : null, jsx("div", { className: S.panelHeader, children: onClose ? (jsx(Button, { type: "button", variant: "ghost", icon: true, className: S.panelClose, "aria-label": "Close chat", onClick: onClose, children: jsx(X, { className: "size-4" }) })) : null }), jsxs("div", { className: S.content, children: [attachmentsDropzoneEnabled ? (jsx(DropZone, { accept: attachmentAccept, label: "Drop text files to attach", multiple: true, ghost: true, overlayScope: "container", disabled: promptDisabled, className: S.attachmentDropzone, onFiles: handleAttachmentFiles })) : null, jsxs(Chat, { isEmpty: isEmpty, scopeId: effectiveScopeId, onChatDeleted: onChatDeleted, onNewChat: onNewChat, children: [isEmpty ? (jsxs(Fragment, { children: [jsx(Chat.EmptyState, { ...emptyState }), renderPresets('fixed')] })) : (jsx("div", { className: S.scrollWrapper, children: jsxs(Scroll, { y: true, yScrollbarClassName: S.scrollbar, className: S.scroll, innerClassName: S.scrollInner, offset: { y: { before: 56, after: 180 } }, fadeSize: "m", autoHide: true, ref: scrollRef, children: [messages.map((msg, index, arr) => {
|
|
70
78
|
const isLast = index === arr.length - 1;
|
|
71
|
-
return (jsx(Chat.Message, { role: msg.role, text: msg.text, inProgress: msg.inProgress, userTextFileAttachments: msg.userTextFileAttachments, onQuickReply: onQuickReply, suppressedQuickReplyKeys: suppressedQuickReplyKeys, quickReplyDisabled: isLoading, isLastMessage: isLast, scriptContinue: isLast && scriptContinueLabel
|
|
79
|
+
return (jsx(Chat.Message, { role: msg.role, text: msg.text, inProgress: msg.inProgress, userTextFileAttachments: msg.userTextFileAttachments, onQuickReply: onQuickReply, suppressedQuickReplyKeys: suppressedQuickReplyKeys, quickReplyDisabled: isLoading, quickReplyHidden: Boolean(loadingLabel), isLastMessage: isLast, scriptContinue: isLast && scriptContinueLabel
|
|
72
80
|
? { label: scriptContinueLabel }
|
|
73
81
|
: undefined, onScriptContinue: isLast && scriptContinueLabel
|
|
74
82
|
? onScriptContinue
|
|
@@ -13,7 +13,7 @@ import S from './ChatMessage.styl.js';
|
|
|
13
13
|
import { DocIcon } from './icons/DocIcon.js';
|
|
14
14
|
import { XlsIcon } from './icons/XlsIcon.js';
|
|
15
15
|
|
|
16
|
-
function AgentMessageContent({ text, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, isLastMessage = true, scriptContinue, onScriptContinue, renderMessageChart, }) {
|
|
16
|
+
function AgentMessageContent({ text, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage = true, scriptContinue, onScriptContinue, renderMessageChart, }) {
|
|
17
17
|
const [showRaw, setShowRaw] = useState(false);
|
|
18
18
|
const parts = useMemo(() => {
|
|
19
19
|
// Convert markdown tables to HTML first
|
|
@@ -97,7 +97,7 @@ function AgentMessageContent({ text, onQuickReply, suppressedQuickReplyKeys, qui
|
|
|
97
97
|
const displayLabel = pipeIdx >= 0 ? inner.slice(0, pipeIdx).trim() : inner;
|
|
98
98
|
const branchKey = pipeIdx >= 0 ? inner.slice(pipeIdx + 1).trim() : inner;
|
|
99
99
|
if (branchKey && displayLabel) {
|
|
100
|
-
const suppressed = suppressedQuickReplyKeys?.has(branchKey);
|
|
100
|
+
const suppressed = quickReplyHidden || suppressedQuickReplyKeys?.has(branchKey);
|
|
101
101
|
if (!suppressed && onQuickReply) {
|
|
102
102
|
result.push(jsx("span", { className: S.quickReplyWrap, children: jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled: quickReplyDisabled, onClick: () => onQuickReply(branchKey, displayLabel), children: [jsx(PaperPlaneRightIcon, {}), displayLabel] }) }, `quick-${match.index}`));
|
|
103
103
|
}
|
|
@@ -121,10 +121,12 @@ function AgentMessageContent({ text, onQuickReply, suppressedQuickReplyKeys, qui
|
|
|
121
121
|
onQuickReply,
|
|
122
122
|
suppressedQuickReplyKeys,
|
|
123
123
|
quickReplyDisabled,
|
|
124
|
+
quickReplyHidden,
|
|
124
125
|
isLastMessage,
|
|
125
126
|
renderMessageChart,
|
|
126
127
|
]);
|
|
127
128
|
return (jsxs("div", { className: S.text, children: [showRaw ? text : parts, !showRaw &&
|
|
129
|
+
!quickReplyHidden &&
|
|
128
130
|
isLastMessage &&
|
|
129
131
|
scriptContinue &&
|
|
130
132
|
onScriptContinue &&
|
|
@@ -10,13 +10,13 @@ import { AgentMessageContent } from './AgentMessageContent.js';
|
|
|
10
10
|
import S from './ChatMessage.styl.js';
|
|
11
11
|
import { UserTextFileAttachmentBubble } from './UserTextFileAttachmentBubble.js';
|
|
12
12
|
|
|
13
|
-
function ChatMessage({ role, text, inProgress, userTextFileAttachments, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, isLastMessage = true, scriptContinue, onScriptContinue, renderMessageChart, }) {
|
|
13
|
+
function ChatMessage({ role, text, inProgress, userTextFileAttachments, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage = true, scriptContinue, onScriptContinue, renderMessageChart, }) {
|
|
14
14
|
const fileAttachments = userTextFileAttachmentsFromMessage({
|
|
15
15
|
userTextFileAttachments,
|
|
16
16
|
});
|
|
17
17
|
const isAssistant = role === MessageRole.ASSISTANT;
|
|
18
18
|
const isSystem = role === MessageRole.SYSTEM;
|
|
19
|
-
return (jsx("div", { className: cn(S.root, S[`role-${role}`]), children: isSystem ? (jsx("div", { className: S.text, children: inProgress ? jsx(TextShimmer, { as: "span", children: text }) : text })) : isAssistant ? (jsx(AgentMessageContent, { text: text, onQuickReply: onQuickReply, suppressedQuickReplyKeys: suppressedQuickReplyKeys, quickReplyDisabled: quickReplyDisabled, isLastMessage: isLastMessage, scriptContinue: scriptContinue, onScriptContinue: onScriptContinue, renderMessageChart: renderMessageChart })) : (jsxs("div", { className: S.userColumn, children: [jsx("div", { className: S.text, children: jsx(InteractiveContent, { text: text }) }), fileAttachments.map(attachment => (jsx(UserTextFileAttachmentBubble, { attachment: attachment }, `${attachment.displayName}:${attachment.filename}`)))] })) }));
|
|
19
|
+
return (jsx("div", { className: cn(S.root, S[`role-${role}`]), children: isSystem ? (jsx("div", { className: S.text, children: inProgress ? jsx(TextShimmer, { as: "span", children: text }) : text })) : isAssistant ? (jsx(AgentMessageContent, { text: text, onQuickReply: onQuickReply, suppressedQuickReplyKeys: suppressedQuickReplyKeys, quickReplyDisabled: quickReplyDisabled, quickReplyHidden: quickReplyHidden, isLastMessage: isLastMessage, scriptContinue: scriptContinue, onScriptContinue: onScriptContinue, renderMessageChart: renderMessageChart })) : (jsxs("div", { className: S.userColumn, children: [jsx("div", { className: S.text, children: jsx(InteractiveContent, { text: text }) }), fileAttachments.map(attachment => (jsx(UserTextFileAttachmentBubble, { attachment: attachment }, `${attachment.displayName}:${attachment.filename}`)))] })) }));
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export { ChatMessage };
|
|
@@ -2,7 +2,7 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
|
|
3
3
|
import { MessageRole } from '../Chat.types.js';
|
|
4
4
|
import { isGraphIntakeAssistantStepComplete, matchUserTextToQuickReply, isPresetScriptGraph, branchesFromPresetScriptGraph, parseScriptLine, textHasQuickReplyMarkers, branchKeysUsedFromChatHistory, branchKeysUsedByUserMessages, extractQuickReplyLabelKeyPairsFromText, entryBranchKeyBeforeLastAssistant } from '../ChatMessage/presetScript.js';
|
|
5
|
-
import { displayTextFromSendPayload, buildChatSendMessagePayload
|
|
5
|
+
import { loadingLabelFromSendPayload, displayTextFromSendPayload, buildChatSendMessagePayload } from '../buildChatSendMessagePayload.js';
|
|
6
6
|
import { usedPresetIdsFromMessages } from '../chat-preset-utils.js';
|
|
7
7
|
import { useChatsForScopeId, useChat, useChatOutboundPending, useSyncChatPanelBusy, isChatEmpty } from '../../../../contexts/chat-context.js';
|
|
8
8
|
import { shellFitsSidebarsLayout } from '../../../../hooks/panelWidth.js';
|
|
@@ -18,7 +18,7 @@ import { shouldOpenChatFromUrl, shouldHealChatShellDesync, shouldCloseStaleLocal
|
|
|
18
18
|
/** Fallback when `scopeId` prop omitted; apps should pass an explicit composite scope (e.g. `${userId}-dashboard`). */
|
|
19
19
|
const NO_SCOPE_FALLBACK = '__uilib_chat_scope_unset__';
|
|
20
20
|
const SCRIPT_STEP_DELAY_MS = 1200;
|
|
21
|
-
const CHAT_NEW_SHORTCUT_KEY = '
|
|
21
|
+
const CHAT_NEW_SHORTCUT_KEY = 'o';
|
|
22
22
|
const CHAT_QUERY_PARAM = 'chat';
|
|
23
23
|
const CHAT_OPEN_VALUE = 'open';
|
|
24
24
|
const PROMPT_QUERY_PARAM = 'prompt';
|
|
@@ -246,11 +246,12 @@ function useChatPanelChromeModel({ embedAsPage, presets, scopeId, onMessage, onS
|
|
|
246
246
|
}, []);
|
|
247
247
|
useEvent({
|
|
248
248
|
event: 'keydown',
|
|
249
|
+
isCapture: true,
|
|
249
250
|
callback: (e) => {
|
|
250
251
|
const ke = e;
|
|
251
|
-
if (ke.key !== CHAT_NEW_SHORTCUT_KEY ||
|
|
252
|
+
if (ke.key.toLowerCase() !== CHAT_NEW_SHORTCUT_KEY ||
|
|
252
253
|
!(ke.metaKey || ke.ctrlKey) ||
|
|
253
|
-
ke.shiftKey ||
|
|
254
|
+
!ke.shiftKey ||
|
|
254
255
|
ke.altKey) {
|
|
255
256
|
return;
|
|
256
257
|
}
|
|
@@ -333,8 +334,14 @@ function useChatPanelChromeModel({ embedAsPage, presets, scopeId, onMessage, onS
|
|
|
333
334
|
if (transformSendPayload) {
|
|
334
335
|
payload = await transformSendPayload(displayLabel, undefined, displayLabel);
|
|
335
336
|
}
|
|
336
|
-
|
|
337
|
-
|
|
337
|
+
setOutboundLoadingLabel(loadingLabelFromSendPayload(payload));
|
|
338
|
+
try {
|
|
339
|
+
const assistantResponse = await sendMessage(payload);
|
|
340
|
+
onMessage?.(displayTextFromSendPayload(payload), assistantResponse);
|
|
341
|
+
}
|
|
342
|
+
finally {
|
|
343
|
+
setOutboundLoadingLabel(undefined);
|
|
344
|
+
}
|
|
338
345
|
}
|
|
339
346
|
catch (error) {
|
|
340
347
|
logger.error('Error sending chat message:', error);
|
|
@@ -865,12 +872,15 @@ function useChatPanelChromeModel({ embedAsPage, presets, scopeId, onMessage, onS
|
|
|
865
872
|
}, [usedBranchSet, lastAssistantQuickPairs, entryBranchKeyBeforeLast]);
|
|
866
873
|
const unusedBranchKeys = allBranchKeys.filter(k => !usedBranchSet.has(k));
|
|
867
874
|
const unsuppressedInlineKeysOnLast = useMemo(() => lastAssistantQuickPairs.filter(p => !suppressedQuickReplyKeys.has(p.key)), [lastAssistantQuickPairs, suppressedQuickReplyKeys]);
|
|
868
|
-
const
|
|
875
|
+
const hideChatChromeDuringOutboundAction = Boolean(outboundLoadingLabel);
|
|
876
|
+
const showSyntheticBranchButtons = !hideChatChromeDuringOutboundAction &&
|
|
877
|
+
lastMsg?.role === MessageRole.ASSISTANT &&
|
|
869
878
|
!linearScriptActive &&
|
|
870
879
|
graphActive &&
|
|
871
880
|
(!lastHasQuickMarkers || unsuppressedInlineKeysOnLast.length === 0) &&
|
|
872
881
|
unusedBranchKeys.length > 0;
|
|
873
|
-
const showInlinePresets =
|
|
882
|
+
const showInlinePresets = !hideChatChromeDuringOutboundAction &&
|
|
883
|
+
Boolean(presetsWithFreeform?.length) &&
|
|
874
884
|
lastMsg?.role === MessageRole.ASSISTANT &&
|
|
875
885
|
!linearScriptActive &&
|
|
876
886
|
(!graphActive || (!lastHasQuickMarkers && unusedBranchKeys.length === 0));
|
|
@@ -100,6 +100,8 @@ export interface ChatMessageProps {
|
|
|
100
100
|
/** Branch keys already taken (e.g. from chat history); hide quick-reply buttons for these. */
|
|
101
101
|
suppressedQuickReplyKeys?: ReadonlySet<string>;
|
|
102
102
|
quickReplyDisabled?: boolean;
|
|
103
|
+
/** Hide bracket quick-reply buttons (e.g. while a custom outbound status is shown). */
|
|
104
|
+
quickReplyHidden?: boolean;
|
|
103
105
|
/** When false, bracket quick-replies render as plain text (no button). */
|
|
104
106
|
isLastMessage?: boolean;
|
|
105
107
|
/** Preset script continuation (last message only); not sent to LLM. */
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
export declare function AgentMessageContent({ text, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, isLastMessage, scriptContinue, onScriptContinue, renderMessageChart, }: {
|
|
2
|
+
export declare function AgentMessageContent({ text, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage, scriptContinue, onScriptContinue, renderMessageChart, }: {
|
|
3
3
|
text: string;
|
|
4
4
|
onQuickReply?: (branchKey: string, displayLabel: string) => void;
|
|
5
5
|
suppressedQuickReplyKeys?: ReadonlySet<string>;
|
|
6
6
|
quickReplyDisabled?: boolean;
|
|
7
|
+
quickReplyHidden?: boolean;
|
|
7
8
|
isLastMessage?: boolean;
|
|
8
9
|
scriptContinue?: {
|
|
9
10
|
label: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type ChatMessageProps } from '../Chat.types';
|
|
2
|
-
export declare function ChatMessage({ role, text, inProgress, userTextFileAttachments, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, isLastMessage, scriptContinue, onScriptContinue, renderMessageChart, }: ChatMessageProps): import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare function ChatMessage({ role, text, inProgress, userTextFileAttachments, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage, scriptContinue, onScriptContinue, renderMessageChart, }: ChatMessageProps): import("react/jsx-runtime").JSX.Element;
|
package/package.json
CHANGED
|
@@ -115,6 +115,8 @@ export interface ChatMessageProps {
|
|
|
115
115
|
/** Branch keys already taken (e.g. from chat history); hide quick-reply buttons for these. */
|
|
116
116
|
suppressedQuickReplyKeys?: ReadonlySet<string>;
|
|
117
117
|
quickReplyDisabled?: boolean;
|
|
118
|
+
/** Hide bracket quick-reply buttons (e.g. while a custom outbound status is shown). */
|
|
119
|
+
quickReplyHidden?: boolean;
|
|
118
120
|
/** When false, bracket quick-replies render as plain text (no button). */
|
|
119
121
|
isLastMessage?: boolean;
|
|
120
122
|
/** Preset script continuation (last message only); not sent to LLM. */
|
|
@@ -118,19 +118,28 @@ export function ChatChrome({
|
|
|
118
118
|
useEffect(() => {
|
|
119
119
|
if (isEmpty) return;
|
|
120
120
|
|
|
121
|
-
const scrollToBottom = () => {
|
|
121
|
+
const scrollToBottom = (behavior: ScrollBehavior) => {
|
|
122
122
|
const inner = scrollRef.current?.innerElem as HTMLDivElement | undefined;
|
|
123
|
-
if (inner)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
123
|
+
if (!inner) return;
|
|
124
|
+
inner.scrollTo({
|
|
125
|
+
top: inner.scrollHeight + 1000,
|
|
126
|
+
behavior,
|
|
127
|
+
});
|
|
129
128
|
};
|
|
130
129
|
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
const behavior: ScrollBehavior = loadingLabel ? 'instant' : 'smooth';
|
|
131
|
+
const frameId = requestAnimationFrame(() => {
|
|
132
|
+
requestAnimationFrame(() => scrollToBottom(behavior));
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return () => cancelAnimationFrame(frameId);
|
|
136
|
+
}, [
|
|
137
|
+
isEmpty,
|
|
138
|
+
messages.length,
|
|
139
|
+
loadingLabel,
|
|
140
|
+
showInlinePresets,
|
|
141
|
+
showSyntheticBranchButtons,
|
|
142
|
+
]);
|
|
134
143
|
|
|
135
144
|
return (
|
|
136
145
|
<div className={S.root}>
|
|
@@ -207,6 +216,7 @@ export function ChatChrome({
|
|
|
207
216
|
onQuickReply={onQuickReply}
|
|
208
217
|
suppressedQuickReplyKeys={suppressedQuickReplyKeys}
|
|
209
218
|
quickReplyDisabled={isLoading}
|
|
219
|
+
quickReplyHidden={Boolean(loadingLabel)}
|
|
210
220
|
isLastMessage={isLast}
|
|
211
221
|
scriptContinue={
|
|
212
222
|
isLast && scriptContinueLabel
|
|
@@ -18,6 +18,7 @@ export function AgentMessageContent({
|
|
|
18
18
|
onQuickReply,
|
|
19
19
|
suppressedQuickReplyKeys,
|
|
20
20
|
quickReplyDisabled,
|
|
21
|
+
quickReplyHidden,
|
|
21
22
|
isLastMessage = true,
|
|
22
23
|
scriptContinue,
|
|
23
24
|
onScriptContinue,
|
|
@@ -27,6 +28,7 @@ export function AgentMessageContent({
|
|
|
27
28
|
onQuickReply?: (branchKey: string, displayLabel: string) => void;
|
|
28
29
|
suppressedQuickReplyKeys?: ReadonlySet<string>;
|
|
29
30
|
quickReplyDisabled?: boolean;
|
|
31
|
+
quickReplyHidden?: boolean;
|
|
30
32
|
isLastMessage?: boolean;
|
|
31
33
|
scriptContinue?: { label: string };
|
|
32
34
|
onScriptContinue?: () => void;
|
|
@@ -156,7 +158,8 @@ export function AgentMessageContent({
|
|
|
156
158
|
const branchKey =
|
|
157
159
|
pipeIdx >= 0 ? inner.slice(pipeIdx + 1).trim() : inner;
|
|
158
160
|
if (branchKey && displayLabel) {
|
|
159
|
-
const suppressed =
|
|
161
|
+
const suppressed =
|
|
162
|
+
quickReplyHidden || suppressedQuickReplyKeys?.has(branchKey);
|
|
160
163
|
if (!suppressed && onQuickReply) {
|
|
161
164
|
result.push(
|
|
162
165
|
<span key={`quick-${match.index}`} className={S.quickReplyWrap}>
|
|
@@ -201,6 +204,7 @@ export function AgentMessageContent({
|
|
|
201
204
|
onQuickReply,
|
|
202
205
|
suppressedQuickReplyKeys,
|
|
203
206
|
quickReplyDisabled,
|
|
207
|
+
quickReplyHidden,
|
|
204
208
|
isLastMessage,
|
|
205
209
|
renderMessageChart,
|
|
206
210
|
]);
|
|
@@ -212,6 +216,7 @@ export function AgentMessageContent({
|
|
|
212
216
|
>
|
|
213
217
|
{showRaw ? text : parts}
|
|
214
218
|
{!showRaw &&
|
|
219
|
+
!quickReplyHidden &&
|
|
215
220
|
isLastMessage &&
|
|
216
221
|
scriptContinue &&
|
|
217
222
|
onScriptContinue &&
|
|
@@ -17,6 +17,7 @@ export function ChatMessage({
|
|
|
17
17
|
onQuickReply,
|
|
18
18
|
suppressedQuickReplyKeys,
|
|
19
19
|
quickReplyDisabled,
|
|
20
|
+
quickReplyHidden,
|
|
20
21
|
isLastMessage = true,
|
|
21
22
|
scriptContinue,
|
|
22
23
|
onScriptContinue,
|
|
@@ -40,6 +41,7 @@ export function ChatMessage({
|
|
|
40
41
|
onQuickReply={onQuickReply}
|
|
41
42
|
suppressedQuickReplyKeys={suppressedQuickReplyKeys}
|
|
42
43
|
quickReplyDisabled={quickReplyDisabled}
|
|
44
|
+
quickReplyHidden={quickReplyHidden}
|
|
43
45
|
isLastMessage={isLastMessage}
|
|
44
46
|
scriptContinue={scriptContinue}
|
|
45
47
|
onScriptContinue={onScriptContinue}
|
|
@@ -131,7 +131,7 @@ type PresetScriptState = {
|
|
|
131
131
|
};
|
|
132
132
|
|
|
133
133
|
const SCRIPT_STEP_DELAY_MS = 1200;
|
|
134
|
-
const CHAT_NEW_SHORTCUT_KEY = '
|
|
134
|
+
const CHAT_NEW_SHORTCUT_KEY = 'o';
|
|
135
135
|
|
|
136
136
|
const CHAT_QUERY_PARAM = 'chat';
|
|
137
137
|
const CHAT_OPEN_VALUE = 'open';
|
|
@@ -450,12 +450,13 @@ export function useChatPanelChromeModel({
|
|
|
450
450
|
|
|
451
451
|
useEvent({
|
|
452
452
|
event: 'keydown',
|
|
453
|
+
isCapture: true,
|
|
453
454
|
callback: (e: Event) => {
|
|
454
455
|
const ke = e as KeyboardEvent;
|
|
455
456
|
if (
|
|
456
|
-
ke.key !== CHAT_NEW_SHORTCUT_KEY ||
|
|
457
|
+
ke.key.toLowerCase() !== CHAT_NEW_SHORTCUT_KEY ||
|
|
457
458
|
!(ke.metaKey || ke.ctrlKey) ||
|
|
458
|
-
ke.shiftKey ||
|
|
459
|
+
!ke.shiftKey ||
|
|
459
460
|
ke.altKey
|
|
460
461
|
) {
|
|
461
462
|
return;
|
|
@@ -554,8 +555,13 @@ export function useChatPanelChromeModel({
|
|
|
554
555
|
displayLabel,
|
|
555
556
|
);
|
|
556
557
|
}
|
|
557
|
-
|
|
558
|
-
|
|
558
|
+
setOutboundLoadingLabel(loadingLabelFromSendPayload(payload));
|
|
559
|
+
try {
|
|
560
|
+
const assistantResponse = await sendMessage(payload);
|
|
561
|
+
onMessage?.(displayTextFromSendPayload(payload), assistantResponse);
|
|
562
|
+
} finally {
|
|
563
|
+
setOutboundLoadingLabel(undefined);
|
|
564
|
+
}
|
|
559
565
|
} catch (error) {
|
|
560
566
|
logger.error('Error sending chat message:', error);
|
|
561
567
|
}
|
|
@@ -1176,7 +1182,10 @@ export function useChatPanelChromeModel({
|
|
|
1176
1182
|
[lastAssistantQuickPairs, suppressedQuickReplyKeys],
|
|
1177
1183
|
);
|
|
1178
1184
|
|
|
1185
|
+
const hideChatChromeDuringOutboundAction = Boolean(outboundLoadingLabel);
|
|
1186
|
+
|
|
1179
1187
|
const showSyntheticBranchButtons =
|
|
1188
|
+
!hideChatChromeDuringOutboundAction &&
|
|
1180
1189
|
lastMsg?.role === MessageRole.ASSISTANT &&
|
|
1181
1190
|
!linearScriptActive &&
|
|
1182
1191
|
graphActive &&
|
|
@@ -1184,6 +1193,7 @@ export function useChatPanelChromeModel({
|
|
|
1184
1193
|
unusedBranchKeys.length > 0;
|
|
1185
1194
|
|
|
1186
1195
|
const showInlinePresets =
|
|
1196
|
+
!hideChatChromeDuringOutboundAction &&
|
|
1187
1197
|
Boolean(presetsWithFreeform?.length) &&
|
|
1188
1198
|
lastMsg?.role === MessageRole.ASSISTANT &&
|
|
1189
1199
|
!linearScriptActive &&
|