@@ -10,7 +10,6 @@ import (
1010 "charm.land/lipgloss/v2"
1111 "github.com/charmbracelet/x/ansi"
1212
13- "github.com/docker/cagent/pkg/app"
1413 "github.com/docker/cagent/pkg/chat"
1514 "github.com/docker/cagent/pkg/runtime"
1615 "github.com/docker/cagent/pkg/session"
@@ -71,7 +70,6 @@ type model struct {
7170 views []layout.Model
7271 width int // Full width including scrollbar space
7372 height int
74- app * app.App
7573
7674 // Height tracking system fields
7775 scrollOffset int // Current scroll position in lines
@@ -98,22 +96,17 @@ type model struct {
9896}
9997
10098// New creates a new message list component
101- func New (a * app.App , sessionState * service.SessionState ) Model {
102- return & model {
103- width : 120 ,
104- height : 24 ,
105- app : a ,
106- renderedItems : make (map [int ]renderedItem ),
107- sessionState : sessionState ,
108- scrollbar : scrollbar .New (),
109- selectedMessageIndex : - 1 ,
110- debugLayout : os .Getenv ("CAGENT_EXPERIMENTAL_DEBUG_LAYOUT" ) == "1" ,
111- }
99+ func New (sessionState * service.SessionState ) Model {
100+ return newModel (120 , 24 , sessionState )
112101}
113102
114103// NewScrollableView creates a simple scrollable view for displaying messages in dialogs
115104// This is a lightweight version that doesn't require app or session state management
116105func NewScrollableView (width , height int , sessionState * service.SessionState ) Model {
106+ return newModel (width , height , sessionState )
107+ }
108+
109+ func newModel (width , height int , sessionState * service.SessionState ) * model {
117110 return & model {
118111 width : width ,
119112 height : height ,
@@ -260,9 +253,7 @@ func (m *model) handleMouseRelease(msg tea.MouseReleaseMsg) (layout.Model, tea.C
260253
261254func (m * model ) handleMouseWheel (msg tea.MouseWheelMsg ) (layout.Model , tea.Cmd ) {
262255 const mouseScrollAmount = 2
263- buttonStr := msg .Button .String ()
264-
265- switch buttonStr {
256+ switch msg .Button .String () {
266257 case "wheelup" :
267258 if m .scrollOffset > 0 {
268259 m .userHasScrolled = true
@@ -649,8 +640,8 @@ func (m *model) renderItem(index int, view layout.Model) renderedItem {
649640 msgView .SetSelected (isSelected )
650641 }
651642
652- // Don't cache selected items since selection state can change
653- if ! isSelected && m . shouldCacheMessage ( index ) {
643+ shouldCache := ! isSelected && m . shouldCacheMessage ( index )
644+ if shouldCache {
654645 if cached , exists := m .renderedItems [index ]; exists {
655646 return cached
656647 }
@@ -664,7 +655,7 @@ func (m *model) renderItem(index int, view layout.Model) renderedItem {
664655
665656 item := renderedItem {view : rendered , height : height }
666657
667- if ! isSelected && m . shouldCacheMessage ( index ) {
658+ if shouldCache {
668659 m .renderedItems [index ] = item
669660 }
670661
@@ -794,7 +785,6 @@ func (m *model) addMessage(msg *types.Message) tea.Cmd {
794785 if initCmd := view .Init (); initCmd != nil {
795786 cmds = append (cmds , initCmd )
796787 }
797-
798788 if shouldAutoScroll {
799789 cmds = append (cmds , func () tea.Msg {
800790 m .scrollToBottom ()
@@ -806,6 +796,12 @@ func (m *model) addMessage(msg *types.Message) tea.Cmd {
806796}
807797
808798func (m * model ) LoadFromSession (sess * session.Session ) tea.Cmd {
799+ appendSessionMessage := func (msg * types.Message , view layout.Model ) {
800+ m .messages = append (m .messages , msg )
801+ m .views = append (m .views , view )
802+ m .sessionState .PreviousMessage = msg
803+ }
804+
809805 m .messages = nil
810806 m .views = nil
811807 m .renderedItems = make (map [int ]renderedItem )
@@ -829,32 +825,24 @@ func (m *model) LoadFromSession(sess *session.Session) tea.Cmd {
829825 switch smsg .Message .Role {
830826 case chat .MessageRoleUser :
831827 msg := types .User (smsg .Message .Content )
832- m .messages = append (m .messages , msg )
833- m .views = append (m .views , m .createMessageView (msg ))
834- m .sessionState .PreviousMessage = msg
828+ appendSessionMessage (msg , m .createMessageView (msg ))
835829 case chat .MessageRoleAssistant :
836830 // Reasoning content comes first (matches live stream order)
837831 if smsg .Message .ReasoningContent != "" {
838832 msg := types .Agent (types .MessageTypeAssistantReasoning , smsg .AgentName , smsg .Message .ReasoningContent )
839- m .messages = append (m .messages , msg )
840- m .views = append (m .views , m .createMessageView (msg ))
841- m .sessionState .PreviousMessage = msg
833+ appendSessionMessage (msg , m .createMessageView (msg ))
842834 }
843835 for i , tc := range smsg .Message .ToolCalls {
844836 var toolDef tools.Tool
845837 if i < len (smsg .Message .ToolDefinitions ) {
846838 toolDef = smsg .Message .ToolDefinitions [i ]
847839 }
848840 msg := types .ToolCallMessage (smsg .AgentName , tc , toolDef , types .ToolStatusCompleted )
849- m .messages = append (m .messages , msg )
850- m .views = append (m .views , m .createToolCallView (msg ))
851- m .sessionState .PreviousMessage = msg
841+ appendSessionMessage (msg , m .createToolCallView (msg ))
852842 }
853843 if smsg .Message .Content != "" {
854844 msg := types .Agent (types .MessageTypeAssistant , smsg .AgentName , smsg .Message .Content )
855- m .messages = append (m .messages , msg )
856- m .views = append (m .views , m .createMessageView (msg ))
857- m .sessionState .PreviousMessage = msg
845+ appendSessionMessage (msg , m .createMessageView (msg ))
858846 }
859847 case chat .MessageRoleTool :
860848 continue
@@ -974,24 +962,24 @@ func (m *model) removeSpinner() {
974962}
975963
976964func (m * model ) removePendingToolCallMessages () {
977- var newMessages []* types.Message
978- var newViews []layout.Model
965+ messages := make ( []* types.Message , 0 , len ( m . messages ))
966+ views := make ( []layout.Model , 0 , len ( m . views ))
979967
980968 for i , msg := range m .messages {
981- shouldRemove := msg .Type == types .MessageTypeToolCall &&
982- (msg .ToolStatus == types .ToolStatusPending || msg .ToolStatus == types .ToolStatusRunning )
969+ if msg .Type == types .MessageTypeToolCall &&
970+ (msg .ToolStatus == types .ToolStatusPending || msg .ToolStatus == types .ToolStatusRunning ) {
971+ continue
972+ }
983973
984- if ! shouldRemove {
985- newMessages = append (newMessages , msg )
986- if i < len (m .views ) {
987- newViews = append (newViews , m .views [i ])
988- }
974+ messages = append (messages , msg )
975+ if i < len (m .views ) {
976+ views = append (views , m .views [i ])
989977 }
990978 }
991979
992- if len (newMessages ) != len (m .messages ) {
993- m .messages = newMessages
994- m .views = newViews
980+ if len (messages ) != len (m .messages ) {
981+ m .messages = messages
982+ m .views = views
995983 m .invalidateAllItems ()
996984 }
997985}
0 commit comments