Skip to content

Commit abf25e1

Browse files
authored
Merge pull request #907 from rumpl/shell-render
Tool rendering niceties
2 parents 692256e + ac2a706 commit abf25e1

File tree

14 files changed

+284
-205
lines changed

14 files changed

+284
-205
lines changed

pkg/tui/components/tool/defaulttool/defaulttool.go

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package defaulttool
22

33
import (
4-
"fmt"
5-
64
tea "charm.land/bubbletea/v2"
7-
"github.com/charmbracelet/glamour/v2"
85

96
"github.com/docker/cagent/pkg/tui/components/spinner"
107
"github.com/docker/cagent/pkg/tui/components/toolcommon"
@@ -18,25 +15,22 @@ import (
1815
// that don't have a specialized component registered.
1916
// It provides a standard visualization with tool name, arguments, and results.
2017
type Component struct {
21-
message *types.Message
22-
renderer *glamour.TermRenderer
23-
spinner spinner.Spinner
24-
width int
25-
height int
18+
message *types.Message
19+
spinner spinner.Spinner
20+
width int
21+
height int
2622
}
2723

2824
// New creates a new default tool component.
2925
func New(
3026
msg *types.Message,
31-
renderer *glamour.TermRenderer,
3227
_ *service.SessionState,
3328
) layout.Model {
3429
return &Component{
35-
message: msg,
36-
renderer: renderer,
37-
spinner: spinner.New(spinner.ModeSpinnerOnly),
38-
width: 80,
39-
height: 1,
30+
message: msg,
31+
spinner: spinner.New(spinner.ModeSpinnerOnly),
32+
width: 80,
33+
height: 1,
4034
}
4135
}
4236

@@ -68,20 +62,20 @@ func (c *Component) Update(msg tea.Msg) (layout.Model, tea.Cmd) {
6862
func (c *Component) View() string {
6963
msg := c.message
7064
displayName := msg.ToolDefinition.DisplayName()
71-
content := fmt.Sprintf("%s %s", toolcommon.Icon(msg.ToolStatus), styles.HighlightStyle.Render(displayName))
7265

73-
if msg.ToolStatus == types.ToolStatusPending || msg.ToolStatus == types.ToolStatusRunning {
74-
content += " " + c.spinner.View()
66+
var argsContent string
67+
if msg.ToolCall.Function.Arguments != "" {
68+
argsContent = renderToolArgs(msg.ToolCall, c.width-3)
7569
}
7670

77-
if msg.ToolCall.Function.Arguments != "" {
78-
content += "\n" + renderToolArgs(msg.ToolCall, c.width-3)
71+
if argsContent == "" {
72+
return toolcommon.RenderTool(toolcommon.Icon(msg.ToolStatus), msg.ToolDefinition.DisplayName(), c.spinner.View(), "", c.width)
7973
}
8074

8175
var resultContent string
8276
if (msg.ToolStatus == types.ToolStatusCompleted || msg.ToolStatus == types.ToolStatusError) && msg.Content != "" {
8377
resultContent = toolcommon.FormatToolResult(msg.Content, c.width)
8478
}
8579

86-
return styles.BaseStyle.PaddingLeft(2).PaddingTop(1).Render(content + resultContent)
80+
return toolcommon.RenderTool(toolcommon.Icon(msg.ToolStatus), styles.HighlightStyle.Render(displayName), argsContent, resultContent, c.width)
8781
}

pkg/tui/components/tool/editfile/editfile.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66

77
tea "charm.land/bubbletea/v2"
8-
"github.com/charmbracelet/glamour/v2"
98

109
"github.com/docker/cagent/pkg/tools/builtin"
1110
"github.com/docker/cagent/pkg/tui/components/spinner"
@@ -21,7 +20,6 @@ type ToggleDiffViewMsg struct{}
2120
// Component is a specialized component for rendering edit_file tool calls.
2221
type Component struct {
2322
message *types.Message
24-
renderer *glamour.TermRenderer
2523
spinner spinner.Spinner
2624
width int
2725
height int
@@ -30,12 +28,10 @@ type Component struct {
3028

3129
func New(
3230
msg *types.Message,
33-
renderer *glamour.TermRenderer,
3431
sessionState *service.SessionState,
3532
) layout.Model {
3633
return &Component{
3734
message: msg,
38-
renderer: renderer,
3935
spinner: spinner.New(spinner.ModeSpinnerOnly),
4036
width: 80,
4137
height: 1,
@@ -91,5 +87,5 @@ func (c *Component) View() string {
9187
resultContent = toolcommon.FormatToolResult(msg.Content, c.width)
9288
}
9389

94-
return styles.BaseStyle.PaddingLeft(2).PaddingTop(1).Render(content + resultContent)
90+
return styles.BaseStyle.Render(content + resultContent)
9591
}

pkg/tui/components/tool/factory.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/docker/cagent/pkg/tui/components/tool/defaulttool"
88
"github.com/docker/cagent/pkg/tui/components/tool/editfile"
99
"github.com/docker/cagent/pkg/tui/components/tool/readfile"
10+
"github.com/docker/cagent/pkg/tui/components/tool/shell"
1011
"github.com/docker/cagent/pkg/tui/components/tool/todotool"
1112
"github.com/docker/cagent/pkg/tui/components/tool/transfertask"
1213
"github.com/docker/cagent/pkg/tui/components/tool/writefile"
@@ -36,10 +37,10 @@ func (f *Factory) Create(
3637
toolName := msg.ToolCall.Function.Name
3738

3839
if builder, ok := f.registry.Get(toolName); ok {
39-
return builder(msg, renderer, sessionState)
40+
return builder(msg, sessionState)
4041
}
4142

42-
return defaulttool.New(msg, renderer, sessionState)
43+
return defaulttool.New(msg, sessionState)
4344
}
4445

4546
var (
@@ -58,6 +59,7 @@ func newDefaultRegistry() *Registry {
5859
registry.Register(builtin.ToolNameCreateTodos, todotool.New)
5960
registry.Register(builtin.ToolNameUpdateTodo, todotool.New)
6061
registry.Register(builtin.ToolNameListTodos, todotool.New)
62+
registry.Register(builtin.ToolNameShell, shell.New)
6163

6264
return registry
6365
}

pkg/tui/components/tool/readfile/readfile.go

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ package readfile
22

33
import (
44
"encoding/json"
5-
"fmt"
65

76
tea "charm.land/bubbletea/v2"
8-
"github.com/charmbracelet/glamour/v2"
97

108
"github.com/docker/cagent/pkg/tools/builtin"
119
"github.com/docker/cagent/pkg/tui/components/spinner"
@@ -27,7 +25,6 @@ type Component struct {
2725
// New creates a new read file component.
2826
func New(
2927
msg *types.Message,
30-
_ *glamour.TermRenderer,
3128
_ *service.SessionState,
3229
) layout.Model {
3330
return &Component{
@@ -67,15 +64,8 @@ func (c *Component) View() string {
6764
msg := c.message
6865
var args builtin.ReadFileArgs
6966
if err := json.Unmarshal([]byte(msg.ToolCall.Function.Arguments), &args); err != nil {
70-
return ""
67+
return toolcommon.RenderTool(toolcommon.Icon(msg.ToolStatus), msg.ToolDefinition.DisplayName(), c.spinner.View(), "", c.width)
7168
}
7269

73-
displayName := msg.ToolDefinition.DisplayName()
74-
content := fmt.Sprintf("%s %s %s", toolcommon.Icon(msg.ToolStatus), styles.HighlightStyle.Render(displayName), styles.MutedStyle.Render(args.Path))
75-
76-
if msg.ToolStatus == types.ToolStatusPending || msg.ToolStatus == types.ToolStatusRunning {
77-
content += " " + c.spinner.View()
78-
}
79-
80-
return styles.BaseStyle.PaddingLeft(2).Render(content)
70+
return toolcommon.RenderTool(toolcommon.Icon(msg.ToolStatus), msg.ToolDefinition.DisplayName(), styles.MutedStyle.Render(args.Path), "", c.width)
8171
}

pkg/tui/components/tool/registry.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package tool
33
import (
44
"sync"
55

6-
"github.com/charmbracelet/glamour/v2"
7-
86
"github.com/docker/cagent/pkg/tui/core/layout"
97
"github.com/docker/cagent/pkg/tui/service"
108
"github.com/docker/cagent/pkg/tui/types"
@@ -13,7 +11,6 @@ import (
1311
// ComponentBuilder is a function that creates a tool component.
1412
type ComponentBuilder func(
1513
msg *types.Message,
16-
renderer *glamour.TermRenderer,
1714
sessionState *service.SessionState,
1815
) layout.Model
1916

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package shell
2+
3+
import (
4+
"encoding/json"
5+
6+
tea "charm.land/bubbletea/v2"
7+
8+
"github.com/docker/cagent/pkg/tools/builtin"
9+
"github.com/docker/cagent/pkg/tui/components/spinner"
10+
"github.com/docker/cagent/pkg/tui/components/toolcommon"
11+
"github.com/docker/cagent/pkg/tui/core/layout"
12+
"github.com/docker/cagent/pkg/tui/service"
13+
"github.com/docker/cagent/pkg/tui/styles"
14+
"github.com/docker/cagent/pkg/tui/types"
15+
)
16+
17+
type Component struct {
18+
message *types.Message
19+
spinner spinner.Spinner
20+
width int
21+
height int
22+
}
23+
24+
func New(
25+
msg *types.Message,
26+
_ *service.SessionState,
27+
) layout.Model {
28+
return &Component{
29+
message: msg,
30+
spinner: spinner.New(spinner.ModeSpinnerOnly),
31+
width: 80,
32+
height: 1,
33+
}
34+
}
35+
36+
func (c *Component) SetSize(width, height int) tea.Cmd {
37+
c.width = width
38+
c.height = height
39+
return nil
40+
}
41+
42+
func (c *Component) Init() tea.Cmd {
43+
if c.message.ToolStatus == types.ToolStatusPending || c.message.ToolStatus == types.ToolStatusRunning {
44+
return c.spinner.Init()
45+
}
46+
return nil
47+
}
48+
49+
func (c *Component) Update(msg tea.Msg) (layout.Model, tea.Cmd) {
50+
if c.message.ToolStatus == types.ToolStatusPending || c.message.ToolStatus == types.ToolStatusRunning {
51+
var cmd tea.Cmd
52+
var model layout.Model
53+
model, cmd = c.spinner.Update(msg)
54+
c.spinner = model.(spinner.Spinner)
55+
return c, cmd
56+
}
57+
58+
return c, nil
59+
}
60+
61+
func (c *Component) View() string {
62+
msg := c.message
63+
var args builtin.RunShellArgs
64+
if err := json.Unmarshal([]byte(msg.ToolCall.Function.Arguments), &args); err != nil {
65+
return toolcommon.RenderTool(toolcommon.Icon(msg.ToolStatus), msg.ToolDefinition.DisplayName(), c.spinner.View(), "", c.width)
66+
}
67+
68+
return toolcommon.RenderTool(toolcommon.Icon(msg.ToolStatus), msg.ToolDefinition.DisplayName(), styles.MutedStyle.Render(args.Cmd), "", c.width)
69+
}

0 commit comments

Comments
 (0)