@@ -19,8 +19,10 @@ import (
1919 "github.com/docker/cagent/pkg/tui/components/message"
2020 "github.com/docker/cagent/pkg/tui/components/notification"
2121 "github.com/docker/cagent/pkg/tui/components/tool"
22+ "github.com/docker/cagent/pkg/tui/components/tool/editfile"
2223 "github.com/docker/cagent/pkg/tui/core"
2324 "github.com/docker/cagent/pkg/tui/core/layout"
25+ "github.com/docker/cagent/pkg/tui/service"
2426 "github.com/docker/cagent/pkg/tui/styles"
2527 "github.com/docker/cagent/pkg/tui/types"
2628)
@@ -46,7 +48,6 @@ type Model interface {
4648 AddUserMessage (content string ) tea.Cmd
4749 AddErrorMessage (content string ) tea.Cmd
4850 AddAssistantMessage () tea.Cmd
49- AddSeparatorMessage () tea.Cmd
5051 AddCancelledMessage () tea.Cmd
5152 AddWelcomeMessage (content string ) tea.Cmd
5253 AddOrUpdateToolCall (agentName string , toolCall tools.ToolCall , toolDef tools.Tool , status types.ToolStatus ) tea.Cmd
@@ -55,7 +56,6 @@ type Model interface {
5556 AddShellOutputMessage (content string ) tea.Cmd
5657
5758 ScrollToBottom () tea.Cmd
58- IsAtBottom () bool
5959}
6060
6161// renderedItem represents a cached rendered message with position information
@@ -112,19 +112,30 @@ type model struct {
112112
113113 selection selectionState
114114
115- splitDiffView bool
115+ sessionState * service. SessionState
116116
117117 xPos , yPos int
118118}
119119
120120// New creates a new message list component
121- func New (a * app.App ) Model {
121+ func New (a * app.App , sessionState * service. SessionState ) Model {
122122 return & model {
123123 width : 120 ,
124124 height : 24 ,
125125 app : a ,
126126 renderedItems : make (map [int ]renderedItem ),
127- splitDiffView : true ,
127+ sessionState : sessionState ,
128+ }
129+ }
130+
131+ // NewScrollableView creates a simple scrollable view for displaying messages in dialogs
132+ // This is a lightweight version that doesn't require app or session state management
133+ func NewScrollableView (width , height int , sessionState * service.SessionState ) Model {
134+ return & model {
135+ width : width ,
136+ height : height ,
137+ renderedItems : make (map [int ]renderedItem ),
138+ sessionState : sessionState ,
128139 }
129140}
130141
@@ -220,19 +231,11 @@ func (m *model) Update(msg tea.Msg) (layout.Model, tea.Cmd) {
220231 }
221232 return m , nil
222233
223- case tool.ToggleDiffViewMsg :
224- m .splitDiffView = ! m .splitDiffView
225-
226- var cmds []tea.Cmd
227- for i , view := range m .views {
228- updatedView , cmd := view .Update (tool.ToggleDiffViewMsg {})
229- m .views [i ] = updatedView
230- cmds = append (cmds , cmd )
231- }
234+ case editfile.ToggleDiffViewMsg :
235+ m .sessionState .ToggleSplitDiffView ()
232236
233237 m .invalidateAllItems ()
234-
235- return m , tea .Batch (cmds ... )
238+ return m , nil
236239
237240 case tea.KeyPressMsg :
238241 switch msg .String () {
@@ -403,14 +406,16 @@ func (m *model) shouldCacheMessage(index int) bool {
403406
404407 switch msg .Type {
405408 case types .MessageTypeToolCall :
406- return msg .ToolStatus == types .ToolStatusCompleted || msg .ToolStatus == types .ToolStatusError
409+ return msg .ToolStatus == types .ToolStatusCompleted ||
410+ msg .ToolStatus == types .ToolStatusError ||
411+ msg .ToolStatus == types .ToolStatusConfirmation
407412 case types .MessageTypeToolResult :
408413 return true
409414 case types .MessageTypeAssistant , types .MessageTypeAssistantReasoning :
410415 // Only cache assistant messages that have content (completed streaming)
411416 // Empty assistant messages have spinners and need constant re-rendering
412417 return strings .Trim (msg .Content , "\r \n \t " ) != ""
413- case types .MessageTypeUser , types . MessageTypeSeparator :
418+ case types .MessageTypeUser :
414419 // Always cache static content
415420 return true
416421 default :
@@ -493,8 +498,8 @@ func (m *model) invalidateAllItems() {
493498 m .totalHeight = 0
494499}
495500
496- // IsAtBottom returns true if the viewport is at the bottom
497- func (m * model ) IsAtBottom () bool {
501+ // isAtBottom returns true if the viewport is at the bottom
502+ func (m * model ) isAtBottom () bool {
498503 if len (m .messages ) == 0 {
499504 return true
500505 }
@@ -504,11 +509,6 @@ func (m *model) IsAtBottom() bool {
504509 return m .scrollOffset >= maxScrollOffset
505510}
506511
507- // isAtBottom is kept as a private method for internal use
508- func (m * model ) isAtBottom () bool {
509- return m .IsAtBottom ()
510- }
511-
512512// AddUserMessage adds a user message to the chat
513513func (m * model ) AddUserMessage (content string ) tea.Cmd {
514514 return m .addMessage (& types.Message {
@@ -563,20 +563,6 @@ func (m *model) addMessage(msg *types.Message) tea.Cmd {
563563 return tea .Batch (cmds ... )
564564}
565565
566- // AddSeparatorMessage adds a separator message to the chat
567- func (m * model ) AddSeparatorMessage () tea.Cmd {
568- m .removeSpinner ()
569- msg := types.Message {
570- Type : types .MessageTypeSeparator ,
571- }
572- m .messages = append (m .messages , msg )
573-
574- view := m .createMessageView (& msg )
575- m .views = append (m .views , view )
576-
577- return view .Init ()
578- }
579-
580566// AddCancelledMessage adds a cancellation indicator to the chat
581567func (m * model ) AddCancelledMessage () tea.Cmd {
582568 msg := types.Message {
@@ -707,7 +693,7 @@ func (m *model) ScrollToBottom() tea.Cmd {
707693}
708694
709695func (m * model ) createToolCallView (msg * types.Message ) layout.Model {
710- view := tool .New (msg , m . app , markdown .NewRenderer (m .width ), m .splitDiffView )
696+ view := tool .New (msg , markdown .NewRenderer (m .width ), m .sessionState )
711697 view .SetSize (m .width , 0 )
712698 return view
713699}
0 commit comments