@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.
@@ -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
- inner.scrollTo({
60
- top: inner.scrollHeight + 1000,
61
- behavior: 'smooth',
62
- });
63
- }
58
+ if (!inner)
59
+ return;
60
+ inner.scrollTo({
61
+ top: inner.scrollHeight + 1000,
62
+ behavior,
63
+ });
64
64
  };
65
- const inner = scrollRef.current?.innerElem;
66
- if (inner)
67
- setTimeout(scrollToBottom, 100);
68
- }, [isEmpty, messages.length]);
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, loadingLabelFromSendPayload } from '../buildChatSendMessagePayload.js';
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 = '0';
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
- const assistantResponse = await sendMessage(payload);
337
- onMessage?.(displayTextFromSendPayload(payload), assistantResponse);
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 showSyntheticBranchButtons = lastMsg?.role === MessageRole.ASSISTANT &&
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 = Boolean(presetsWithFreeform?.length) &&
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sybilion/uilib",
3
- "version": "1.3.76",
3
+ "version": "1.3.77",
4
4
  "description": "Sybilion Design System — React UI components (Webpack + Stylus)",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -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
- inner.scrollTo({
125
- top: inner.scrollHeight + 1000,
126
- behavior: 'smooth',
127
- });
128
- }
123
+ if (!inner) return;
124
+ inner.scrollTo({
125
+ top: inner.scrollHeight + 1000,
126
+ behavior,
127
+ });
129
128
  };
130
129
 
131
- const inner = scrollRef.current?.innerElem as HTMLDivElement | undefined;
132
- if (inner) setTimeout(scrollToBottom, 100);
133
- }, [isEmpty, messages.length]);
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 = suppressedQuickReplyKeys?.has(branchKey);
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 = '0';
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
- const assistantResponse = await sendMessage(payload);
558
- onMessage?.(displayTextFromSendPayload(payload), assistantResponse);
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 &&