11import { memo , type MouseEventHandler , type PointerEventHandler } from "react" ;
2- import { CheckIcon , ChevronDownIcon , ChevronLeftIcon , PlayIcon } from "lucide-react" ;
2+ import { CheckIcon , ChevronDownIcon , ChevronLeftIcon , Minimize2Icon , PlayIcon } from "lucide-react" ;
33import { CornerUpRight , ListPlus } from "lucide" ;
44import { MorphIcon } from "~/components/MorphIcon" ;
55import { useEnvironmentIdentificationMode } from "~/hooks/useSettings" ;
@@ -51,9 +51,11 @@ interface ComposerPrimaryActionsProps {
5151 onPreviousPendingQuestion : ( ) => void ;
5252 onInterrupt : ( ) => void ;
5353 onImplementPlanInNewThread : ( ) => void ;
54- /** Tokens a stale session would re-read. When set, Enter compacts first and the button says so . */
54+ /** Tokens a stale session would re-read. When set, a Compact chip shows the count and Enter compacts first . */
5555 compactBeforeSendTokens ?: number | null ;
56- onSendWithFullHistory ?: ( ) => void ;
56+ /** The Compact chip is turned off, so the next send keeps full history. */
57+ keepFullHistory ?: boolean ;
58+ onToggleKeepFullHistory ?: ( ) => void ;
5759}
5860
5961const formatPendingPrimaryActionLabel = ( input : {
@@ -108,7 +110,8 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({
108110 onInterrupt,
109111 onImplementPlanInNewThread,
110112 compactBeforeSendTokens = null ,
111- onSendWithFullHistory,
113+ keepFullHistory = false ,
114+ onToggleKeepFullHistory,
112115} : ComposerPrimaryActionsProps ) {
113116 const pointerFocusProps = preserveComposerFocusOnPointerDown
114117 ? { onPointerDown : preventPointerFocus }
@@ -266,68 +269,24 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({
266269 }
267270
268271 const showResume = canResume && ! hasSendableContent && ! isEditingQueuedMessage ;
269- const sendBlocked = isSendBusy || isSendDisabled || isConnecting || isEnvironmentUnavailable ;
270272
271- if ( compactBeforeSendTokens !== null && ! showResume && ! isEditingQueuedMessage ) {
272- const tokens = formatContextWindowTokens ( compactBeforeSendTokens ) ;
273- return (
274- < div data-chat-composer-compact-send = "true" className = "flex items-center justify-end" >
275- < Tooltip >
276- < TooltipTrigger
277- render = {
278- < button
279- type = "submit"
280- className = { cn (
281- messageActionPillClassName ,
282- "h-9 rounded-r-none sm:h-8" ,
283- compact ? "px-3" : "px-4" ,
284- ) }
285- { ...pointerFocusProps }
286- onClick = { onSubmitMessage }
287- disabled = { sendBlocked || ! hasSendableContent }
288- />
289- }
290- >
291- { isConnecting || isSendBusy ? "Sending..." : "Compact and send" }
292- </ TooltipTrigger >
293- < TooltipPopup > Summarize { tokens } tokens of history, then send</ TooltipPopup >
294- </ Tooltip >
295- < Menu >
296- < MenuTrigger
297- render = {
298- < button
299- type = "button"
300- className = { cn (
301- messageActionPillClassName ,
302- "h-9 rounded-l-none border-l border-message-action-foreground/20 px-2 sm:h-8" ,
303- ) }
304- aria-label = "Send options"
305- { ...pointerFocusProps }
306- disabled = { sendBlocked || ! hasSendableContent }
307- />
308- }
309- >
310- < ChevronDownIcon className = "size-3.5" />
311- </ MenuTrigger >
312- < MenuPopup align = "end" side = "top" { ...composerFloatingLayerProps } >
313- < MenuItem disabled = { sendBlocked } onClick = { onSendWithFullHistory } >
314- Send with full history ({ tokens } tokens)
315- </ MenuItem >
316- </ MenuPopup >
317- </ Menu >
318- </ div >
319- ) ;
320- }
273+ const compactTokens =
274+ compactBeforeSendTokens !== null && ! showResume && ! isEditingQueuedMessage
275+ ? formatContextWindowTokens ( compactBeforeSendTokens )
276+ : null ;
277+ const compactsBeforeSend = compactTokens !== null && ! keepFullHistory ;
321278
322279 const submitLabel = showResume
323280 ? "Resume thread"
324281 : isEditingQueuedMessage
325282 ? "Update queued message"
326- : isQueuing
327- ? "Queue message"
328- : isRunning
329- ? "Steer message"
330- : "Submit message" ;
283+ : compactsBeforeSend
284+ ? "Compact and send"
285+ : isQueuing
286+ ? "Queue message"
287+ : isRunning
288+ ? "Steer message"
289+ : "Submit message" ;
331290 const submitStatus = isEnvironmentUnavailable
332291 ? "Environment disconnected"
333292 : ( sendDisabledReason ??
@@ -342,9 +301,11 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({
342301 : null ) ) ;
343302 const submitTooltip =
344303 submitStatus ??
345- ( isRunning && ! isEditingQueuedMessage
346- ? `Click to ${ followUpBehavior } , Ctrl/⌘-click${ alternateShortcutLabel ? ` or ${ alternateShortcutLabel } ` : "" } to ${ alternateAction } `
347- : submitLabel ) ;
304+ ( compactsBeforeSend
305+ ? `Summarize ${ compactTokens } tokens of history, then send`
306+ : isRunning && ! isEditingQueuedMessage
307+ ? `Click to ${ followUpBehavior } , Ctrl/⌘-click${ alternateShortcutLabel ? ` or ${ alternateShortcutLabel } ` : "" } to ${ alternateAction } `
308+ : submitLabel ) ;
348309
349310 const sendButton = (
350311 < button
@@ -393,10 +354,46 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({
393354 </ button >
394355 ) ;
395356
396- return (
357+ const submit = (
397358 < Tooltip key = "submit" >
398359 < TooltipTrigger render = { < span className = "inline-flex" /> } > { sendButton } </ TooltipTrigger >
399360 < TooltipPopup > { submitTooltip } </ TooltipPopup >
400361 </ Tooltip >
401362 ) ;
363+ if ( compactTokens === null ) return submit ;
364+
365+ return (
366+ < div data-chat-composer-compact-send = "true" className = "flex items-center gap-2" >
367+ < Tooltip >
368+ < TooltipTrigger
369+ render = {
370+ < button
371+ type = "button"
372+ className = { cn (
373+ "flex h-7 shrink-0 cursor-pointer items-center gap-1.5 rounded-full border px-2.5 text-xs tabular-nums outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-64 [&_svg]:pointer-events-none [&_svg]:size-3.5" ,
374+ keepFullHistory
375+ ? "border-border text-muted-foreground hover:text-foreground"
376+ : "border-warning/40 text-warning hover:bg-warning/8" ,
377+ ) }
378+ { ...pointerFocusProps }
379+ aria-pressed = { ! keepFullHistory }
380+ aria-label = { `Compact ${ compactTokens } tokens of history before sending` }
381+ disabled = { ! canOperateThread }
382+ onClick = { onToggleKeepFullHistory }
383+ />
384+ }
385+ >
386+ < Minimize2Icon aria-hidden = "true" />
387+ { keepFullHistory ? "Full" : "Compact" }
388+ < span > { compactTokens } </ span >
389+ </ TooltipTrigger >
390+ < TooltipPopup >
391+ { keepFullHistory
392+ ? `Next send keeps all ${ compactTokens } tokens. Click to compact first`
393+ : `Next send compacts ${ compactTokens } tokens first. Click to keep full history` }
394+ </ TooltipPopup >
395+ </ Tooltip >
396+ { submit }
397+ </ div >
398+ ) ;
402399} ) ;
0 commit comments