Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions pkg/tui/components/markdown/renderer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package markdown

import (
"github.com/charmbracelet/glamour/v2"
allstyles "github.com/charmbracelet/glamour/v2/styles"
)

func uintPtr(u uint) *uint { return &u }

func NewRenderer(width int) *glamour.TermRenderer {
customDarkStyle := *allstyles.DefaultStyles["dark"]

customDarkStyle.Document.Margin = uintPtr(0)
customDarkStyle.Document.BlockPrefix = ""
customDarkStyle.Document.BlockSuffix = ""

r, _ := glamour.NewTermRenderer(
glamour.WithWordWrap(min(width, 120)),
glamour.WithStyles(customDarkStyle),
)
return r
}
43 changes: 21 additions & 22 deletions pkg/tui/components/message/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import (

"github.com/charmbracelet/bubbles/v2/spinner"
tea "github.com/charmbracelet/bubbletea/v2"
"github.com/charmbracelet/glamour/v2"
"github.com/charmbracelet/lipgloss/v2"

"github.com/docker/cagent/pkg/tui/components/markdown"
"github.com/docker/cagent/pkg/tui/core/layout"
"github.com/docker/cagent/pkg/tui/styles"
"github.com/docker/cagent/pkg/tui/types"
Expand All @@ -23,23 +24,21 @@ type Model interface {

// messageModel implements Model
type messageModel struct {
message *types.Message
renderer *glamour.TermRenderer
width int
height int
focused bool
spinner spinner.Model
message *types.Message
width int
height int
focused bool
spinner spinner.Model
}

// New creates a new message view
func New(msg *types.Message, renderer *glamour.TermRenderer) Model {
func New(msg *types.Message) *messageModel {
return &messageModel{
message: msg,
width: 80, // Default width
height: 1, // Will be calculated
focused: false,
spinner: spinner.New(spinner.WithSpinner(spinner.Points)),
renderer: renderer,
message: msg,
width: 80, // Default width
height: 1, // Will be calculated
focused: false,
spinner: spinner.New(spinner.WithSpinner(spinner.Points)),
}
}

Expand Down Expand Up @@ -73,26 +72,26 @@ func (mv *messageModel) View() string {
return mv.Render(mv.width)
}

// MessageView specific methods

// Render renders the message view content
func (mv *messageModel) Render(int) string {
func (mv *messageModel) Render(width int) string {
msg := mv.message
switch msg.Type {
case types.MessageTypeSpinner:
return mv.spinner.View()
case types.MessageTypeUser:
if rendered, err := mv.renderer.Render("> " + msg.Content); err == nil {
return strings.TrimRight(rendered, "\n\r\t ")
s := lipgloss.NewStyle().PaddingLeft(1).BorderLeft(true).BorderStyle(lipgloss.ThickBorder())
if rendered, err := markdown.NewRenderer(width - len(s.Render(""))).Render(msg.Content); err == nil {
return s.Render(strings.TrimRight(rendered, "\n\r\t "))
}

return msg.Content
case types.MessageTypeAssistant:
if msg.Content == "" {
return mv.spinner.View()
}

text := senderPrefix(msg.Sender) + msg.Content
rendered, err := mv.renderer.Render(text)
rendered, err := markdown.NewRenderer(width).Render(text)
if err != nil {
return text
}
Expand All @@ -104,15 +103,15 @@ func (mv *messageModel) Render(int) string {
}
text := "Thinking: " + senderPrefix(msg.Sender) + msg.Content
// Render through the markdown renderer to ensure proper wrapping to width
rendered, err := mv.renderer.Render(text)
rendered, err := markdown.NewRenderer(width).Render(text)
if err != nil {
return styles.MutedStyle.Italic(true).Render(text)
}
// Strip ANSI from inner rendering so muted style fully applies
clean := stripANSI(strings.TrimRight(rendered, "\n\r\t "))
return styles.MutedStyle.Italic(true).Render(clean)
case types.MessageTypeShellOutput:
if rendered, err := mv.renderer.Render(fmt.Sprintf("```console\n%s\n```", msg.Content)); err == nil {
if rendered, err := markdown.NewRenderer(width).Render(fmt.Sprintf("```console\n%s\n```", msg.Content)); err == nil {
return strings.TrimRight(rendered, "\n\r\t ")
}
return msg.Content
Expand Down
22 changes: 3 additions & 19 deletions pkg/tui/components/messages/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ import (
"github.com/charmbracelet/bubbles/v2/help"
"github.com/charmbracelet/bubbles/v2/key"
tea "github.com/charmbracelet/bubbletea/v2"
"github.com/charmbracelet/glamour/v2"
"github.com/charmbracelet/glamour/v2/styles"
"github.com/charmbracelet/lipgloss/v2"

"github.com/docker/cagent/pkg/app"
"github.com/docker/cagent/pkg/runtime"
"github.com/docker/cagent/pkg/tools"
"github.com/docker/cagent/pkg/tui/components/markdown"
"github.com/docker/cagent/pkg/tui/components/message"
"github.com/docker/cagent/pkg/tui/components/tool"
"github.com/docker/cagent/pkg/tui/core"
Expand Down Expand Up @@ -53,7 +52,6 @@ type renderedItem struct {

// model implements Model
type model struct {
renderer *glamour.TermRenderer
messages []types.Message
views []layout.Model
width int
Expand Down Expand Up @@ -207,18 +205,6 @@ func (m *model) SetSize(width, height int) tea.Cmd {
width = 10
}

// Build a custom style
customDarkStyle := *styles.DefaultStyles["dark"]
customDarkStyle.Document.Margin = uintPtr(0)

// Initialize or update renderer
if r, err := glamour.NewTermRenderer(
glamour.WithWordWrap(min(width, 120)),
glamour.WithStyles(customDarkStyle),
); err == nil {
m.renderer = r
}

// Update all views with new size
for _, view := range m.views {
view.SetSize(width, 0)
Expand Down Expand Up @@ -626,13 +612,13 @@ func (m *model) PlainTextTranscript() string {
}

func (m *model) createToolCallView(msg *types.Message) layout.Model {
view := tool.New(msg, m.app, m.renderer)
view := tool.New(msg, m.app, markdown.NewRenderer(m.width))
view.SetSize(m.width, 0)
return view
}

func (m *model) createMessageView(msg *types.Message) layout.Model {
view := message.New(msg, m.renderer)
view := message.New(msg)
view.SetSize(m.width, 0)
return view
}
Expand Down Expand Up @@ -703,5 +689,3 @@ func toolResultLabel(msg types.Message) string {
}
return fmt.Sprintf("Tool Result (%s)", name)
}

func uintPtr(u uint) *uint { return &u }
Loading