@@ -13,7 +13,6 @@ import {
1313 mergeConsecutiveStreamErrors ,
1414} from "@/utils/messages/messageUtils" ;
1515import { hasInterruptedStream } from "@/utils/messages/retryEligibility" ;
16- import { ChatProvider } from "@/contexts/ChatContext" ;
1716import { ThinkingProvider } from "@/contexts/ThinkingContext" ;
1817import { ModeProvider } from "@/contexts/ModeContext" ;
1918import { formatKeybind , KEYBINDS } from "@/utils/ui/keybinds" ;
@@ -379,8 +378,7 @@ const AIViewInner: React.FC<AIViewProps> = ({
379378 }
380379
381380 // Extract state from workspace state
382- const { messages, canInterrupt, isCompacting, loading, cmuxMessages, currentModel } =
383- workspaceState ;
381+ const { messages, canInterrupt, isCompacting, loading, currentModel } = workspaceState ;
384382
385383 // Get active stream message ID for token counting
386384 const activeStreamMessageId = aggregator . getActiveStreamMessageId ( ) ;
@@ -426,147 +424,143 @@ const AIViewInner: React.FC<AIViewProps> = ({
426424 }
427425
428426 return (
429- < ChatProvider messages = { messages } cmuxMessages = { cmuxMessages } model = { currentModel ?? "unknown" } >
430- < ViewContainer className = { className } >
431- < ChatArea ref = { chatAreaRef } >
432- < ViewHeader >
433- < WorkspaceTitle >
434- < StatusIndicator
435- streaming = { canInterrupt }
436- title = {
437- canInterrupt && currentModel ? `${ getModelName ( currentModel ) } streaming` : "Idle"
427+ < ViewContainer className = { className } >
428+ < ChatArea ref = { chatAreaRef } >
429+ < ViewHeader >
430+ < WorkspaceTitle >
431+ < StatusIndicator
432+ streaming = { canInterrupt }
433+ title = {
434+ canInterrupt && currentModel ? `${ getModelName ( currentModel ) } streaming` : "Idle"
435+ }
436+ />
437+ < GitStatusIndicator
438+ gitStatus = { gitStatus }
439+ workspaceId = { workspaceId }
440+ tooltipPosition = "bottom"
441+ />
442+ { projectName } / { branch }
443+ < WorkspacePath > { namedWorkspacePath } </ WorkspacePath >
444+ < TooltipWrapper inline >
445+ < TerminalIconButton onClick = { handleOpenTerminal } >
446+ < svg viewBox = "0 0 16 16" fill = "currentColor" >
447+ < path d = "M0 2.75C0 1.784.784 1 1.75 1h12.5c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0114.25 15H1.75A1.75 1.75 0 010 13.25V2.75zm1.75-.25a.25.25 0 00-.25.25v10.5c0 .138.112.25.25.25h12.5a.25.25 0 00.25-.25V2.75a.25.25 0 00-.25-.25H1.75zM7.25 8a.75.75 0 01-.22.53l-2.25 2.25a.75.75 0 01-1.06-1.06L5.44 8 3.72 6.28a.75.75 0 111.06-1.06l2.25 2.25c.141.14.22.331.22.53zm1.5 1.5a.75.75 0 000 1.5h3a.75.75 0 000-1.5h-3z" />
448+ </ svg >
449+ </ TerminalIconButton >
450+ < Tooltip className = "tooltip" position = "bottom" align = "center" >
451+ Open in terminal ({ formatKeybind ( KEYBINDS . OPEN_TERMINAL ) } )
452+ </ Tooltip >
453+ </ TooltipWrapper >
454+ </ WorkspaceTitle >
455+ </ ViewHeader >
456+
457+ < OutputContainer >
458+ < OutputContent
459+ ref = { contentRef }
460+ onWheel = { markUserInteraction }
461+ onTouchMove = { markUserInteraction }
462+ onScroll = { handleScroll }
463+ role = "log"
464+ aria-live = { canInterrupt ? "polite" : "off" }
465+ aria-busy = { canInterrupt }
466+ aria-label = "Conversation transcript"
467+ tabIndex = { 0 }
468+ >
469+ { mergedMessages . length === 0 ? (
470+ < EmptyState >
471+ < h3 > No Messages Yet</ h3 >
472+ < p > Send a message below to begin</ p >
473+ </ EmptyState >
474+ ) : (
475+ < >
476+ { mergedMessages . map ( ( msg ) => {
477+ const isAtCutoff =
478+ editCutoffHistoryId !== undefined &&
479+ msg . type !== "history-hidden" &&
480+ msg . historyId === editCutoffHistoryId ;
481+
482+ return (
483+ < React . Fragment key = { msg . id } >
484+ < div
485+ data-message-id = { msg . type !== "history-hidden" ? msg . historyId : undefined }
486+ >
487+ < MessageRenderer
488+ message = { msg }
489+ onEditUserMessage = { handleEditUserMessage }
490+ workspaceId = { workspaceId }
491+ isCompacting = { isCompacting }
492+ />
493+ </ div >
494+ { isAtCutoff && (
495+ < EditBarrier >
496+ ⚠️ Messages below this line will be removed when you submit the edit
497+ </ EditBarrier >
498+ ) }
499+ { shouldShowInterruptedBarrier ( msg ) && < InterruptedBarrier /> }
500+ </ React . Fragment >
501+ ) ;
502+ } ) }
503+ { /* Show RetryBarrier after the last message if needed */ }
504+ { showRetryBarrier && (
505+ < RetryBarrier
506+ workspaceId = { workspaceId }
507+ autoRetry = { autoRetry }
508+ onStopAutoRetry = { ( ) => setAutoRetry ( false ) }
509+ onResetAutoRetry = { ( ) => setAutoRetry ( true ) }
510+ />
511+ ) }
512+ </ >
513+ ) }
514+ < PinnedTodoList workspaceId = { workspaceId } />
515+ { canInterrupt && (
516+ < StreamingBarrier
517+ statusText = {
518+ isCompacting
519+ ? currentModel
520+ ? `${ getModelName ( currentModel ) } compacting...`
521+ : "compacting..."
522+ : currentModel
523+ ? `${ getModelName ( currentModel ) } streaming...`
524+ : "streaming..."
525+ }
526+ cancelText = { `hit ${ formatKeybind ( KEYBINDS . INTERRUPT_STREAM ) } to cancel` }
527+ tokenCount = {
528+ activeStreamMessageId
529+ ? aggregator . getStreamingTokenCount ( activeStreamMessageId )
530+ : undefined
531+ }
532+ tps = {
533+ activeStreamMessageId
534+ ? aggregator . getStreamingTPS ( activeStreamMessageId )
535+ : undefined
438536 }
439537 />
440- < GitStatusIndicator
441- gitStatus = { gitStatus }
442- workspaceId = { workspaceId }
443- tooltipPosition = "bottom"
444- />
445- { projectName } / { branch }
446- < WorkspacePath > { namedWorkspacePath } </ WorkspacePath >
447- < TooltipWrapper inline >
448- < TerminalIconButton onClick = { handleOpenTerminal } >
449- < svg viewBox = "0 0 16 16" fill = "currentColor" >
450- < path d = "M0 2.75C0 1.784.784 1 1.75 1h12.5c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0114.25 15H1.75A1.75 1.75 0 010 13.25V2.75zm1.75-.25a.25.25 0 00-.25.25v10.5c0 .138.112.25.25.25h12.5a.25.25 0 00.25-.25V2.75a.25.25 0 00-.25-.25H1.75zM7.25 8a.75.75 0 01-.22.53l-2.25 2.25a.75.75 0 01-1.06-1.06L5.44 8 3.72 6.28a.75.75 0 111.06-1.06l2.25 2.25c.141.14.22.331.22.53zm1.5 1.5a.75.75 0 000 1.5h3a.75.75 0 000-1.5h-3z" />
451- </ svg >
452- </ TerminalIconButton >
453- < Tooltip className = "tooltip" position = "bottom" align = "center" >
454- Open in terminal ({ formatKeybind ( KEYBINDS . OPEN_TERMINAL ) } )
455- </ Tooltip >
456- </ TooltipWrapper >
457- </ WorkspaceTitle >
458- </ ViewHeader >
459-
460- < OutputContainer >
461- < OutputContent
462- ref = { contentRef }
463- onWheel = { markUserInteraction }
464- onTouchMove = { markUserInteraction }
465- onScroll = { handleScroll }
466- role = "log"
467- aria-live = { canInterrupt ? "polite" : "off" }
468- aria-busy = { canInterrupt }
469- aria-label = "Conversation transcript"
470- tabIndex = { 0 }
471- >
472- { mergedMessages . length === 0 ? (
473- < EmptyState >
474- < h3 > No Messages Yet</ h3 >
475- < p > Send a message below to begin</ p >
476- </ EmptyState >
477- ) : (
478- < >
479- { mergedMessages . map ( ( msg ) => {
480- const isAtCutoff =
481- editCutoffHistoryId !== undefined &&
482- msg . type !== "history-hidden" &&
483- msg . historyId === editCutoffHistoryId ;
484-
485- return (
486- < React . Fragment key = { msg . id } >
487- < div
488- data-message-id = {
489- msg . type !== "history-hidden" ? msg . historyId : undefined
490- }
491- >
492- < MessageRenderer
493- message = { msg }
494- onEditUserMessage = { handleEditUserMessage }
495- workspaceId = { workspaceId }
496- isCompacting = { isCompacting }
497- />
498- </ div >
499- { isAtCutoff && (
500- < EditBarrier >
501- ⚠️ Messages below this line will be removed when you submit the edit
502- </ EditBarrier >
503- ) }
504- { shouldShowInterruptedBarrier ( msg ) && < InterruptedBarrier /> }
505- </ React . Fragment >
506- ) ;
507- } ) }
508- { /* Show RetryBarrier after the last message if needed */ }
509- { showRetryBarrier && (
510- < RetryBarrier
511- workspaceId = { workspaceId }
512- autoRetry = { autoRetry }
513- onStopAutoRetry = { ( ) => setAutoRetry ( false ) }
514- onResetAutoRetry = { ( ) => setAutoRetry ( true ) }
515- />
516- ) }
517- </ >
518- ) }
519- < PinnedTodoList workspaceId = { workspaceId } />
520- { canInterrupt && (
521- < StreamingBarrier
522- statusText = {
523- isCompacting
524- ? currentModel
525- ? `${ getModelName ( currentModel ) } compacting...`
526- : "compacting..."
527- : currentModel
528- ? `${ getModelName ( currentModel ) } streaming...`
529- : "streaming..."
530- }
531- cancelText = { `hit ${ formatKeybind ( KEYBINDS . INTERRUPT_STREAM ) } to cancel` }
532- tokenCount = {
533- activeStreamMessageId
534- ? aggregator . getStreamingTokenCount ( activeStreamMessageId )
535- : undefined
536- }
537- tps = {
538- activeStreamMessageId
539- ? aggregator . getStreamingTPS ( activeStreamMessageId )
540- : undefined
541- }
542- />
543- ) }
544- </ OutputContent >
545- { ! autoScroll && (
546- < JumpToBottomIndicator onClick = { jumpToBottom } type = "button" >
547- Press { formatKeybind ( KEYBINDS . JUMP_TO_BOTTOM ) } to jump to bottom
548- </ JumpToBottomIndicator >
549538 ) }
550- </ OutputContainer >
551-
552- < ChatInput
553- workspaceId = { workspaceId }
554- onMessageSent = { handleMessageSent }
555- onTruncateHistory = { handleClearHistory }
556- onProviderConfig = { handleProviderConfig }
557- disabled = { ! projectName || ! branch }
558- isCompacting = { isCompacting }
559- editingMessage = { editingMessage }
560- onCancelEdit = { handleCancelEdit }
561- onEditLastUserMessage = { handleEditLastUserMessage }
562- canInterrupt = { canInterrupt }
563- onReady = { handleChatInputReady }
564- />
565- </ ChatArea >
566-
567- < ChatMetaSidebar workspaceId = { workspaceId } chatAreaRef = { chatAreaRef } />
568- </ ViewContainer >
569- </ ChatProvider >
539+ </ OutputContent >
540+ { ! autoScroll && (
541+ < JumpToBottomIndicator onClick = { jumpToBottom } type = "button" >
542+ Press { formatKeybind ( KEYBINDS . JUMP_TO_BOTTOM ) } to jump to bottom
543+ </ JumpToBottomIndicator >
544+ ) }
545+ </ OutputContainer >
546+
547+ < ChatInput
548+ workspaceId = { workspaceId }
549+ onMessageSent = { handleMessageSent }
550+ onTruncateHistory = { handleClearHistory }
551+ onProviderConfig = { handleProviderConfig }
552+ disabled = { ! projectName || ! branch }
553+ isCompacting = { isCompacting }
554+ editingMessage = { editingMessage }
555+ onCancelEdit = { handleCancelEdit }
556+ onEditLastUserMessage = { handleEditLastUserMessage }
557+ canInterrupt = { canInterrupt }
558+ onReady = { handleChatInputReady }
559+ />
560+ </ ChatArea >
561+
562+ < ChatMetaSidebar workspaceId = { workspaceId } chatAreaRef = { chatAreaRef } />
563+ </ ViewContainer >
570564 ) ;
571565} ;
572566
0 commit comments