Skip to content

Commit 75f49f7

Browse files
authored
Merge pull request #944 from dgageot/better-sidebar
Better sidebar
2 parents 946ff55 + aa1411e commit 75f49f7

5 files changed

Lines changed: 36 additions & 139 deletions

File tree

pkg/runtime/event.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -427,23 +427,6 @@ func ToolsetInfo(availableTools int, agentName string) Event {
427427
}
428428
}
429429

430-
// ToolStatusEvent is sent when a tool's execution status changes
431-
type ToolStatusEvent struct {
432-
Type string `json:"type"`
433-
ToolName string `json:"tool_name"`
434-
Status string `json:"status"` // running, completed, failed
435-
AgentContext
436-
}
437-
438-
func ToolStatus(toolName, status, agentName string) Event {
439-
return &ToolStatusEvent{
440-
Type: "tool_status",
441-
ToolName: toolName,
442-
Status: status,
443-
AgentContext: AgentContext{AgentName: agentName},
444-
}
445-
}
446-
447430
// RAG lifecycle events
448431
type RAGIndexingStartedEvent struct {
449432
Type string `json:"type"`

pkg/runtime/runtime.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,9 +1131,6 @@ func (r *LocalRuntime) runTool(ctx context.Context, tool tools.Tool, toolCall to
11311131

11321132
events <- ToolCall(toolCall, tool, a.Name())
11331133

1134-
// Emit tool status: running
1135-
events <- ToolStatus(toolCall.Function.Name, "running", a.Name())
1136-
11371134
var res *tools.ToolCallResult
11381135
var err error
11391136
var duration time.Duration
@@ -1148,23 +1145,17 @@ func (r *LocalRuntime) runTool(ctx context.Context, tool tools.Tool, toolCall to
11481145
// Synthesize a cancellation response so the transcript remains consistent
11491146
res = &tools.ToolCallResult{Output: "The tool call was canceled by the user."}
11501147
span.SetStatus(codes.Ok, "tool handler canceled by user")
1151-
// Emit tool status: failed (cancelled)
1152-
events <- ToolStatus(toolCall.Function.Name, "failed", a.Name())
11531148
} else {
11541149
span.RecordError(err)
11551150
span.SetStatus(codes.Error, "tool handler error")
11561151
slog.Error("Error calling tool", "tool", toolCall.Function.Name, "error", err)
11571152
res = &tools.ToolCallResult{
11581153
Output: fmt.Sprintf("Error calling tool: %v", err),
11591154
}
1160-
// Emit tool status: failed
1161-
events <- ToolStatus(toolCall.Function.Name, "failed", a.Name())
11621155
}
11631156
} else {
11641157
span.SetStatus(codes.Ok, "tool handler completed")
11651158
slog.Debug("Agent tool call completed", "tool", toolCall.Function.Name, "output_length", len(res.Output))
1166-
// Emit tool status: completed
1167-
events <- ToolStatus(toolCall.Function.Name, "completed", a.Name())
11681159
}
11691160

11701161
events <- ToolCallResponse(toolCall, tool, res.Output, a.Name())

pkg/tui/components/sidebar/sidebar.go

Lines changed: 35 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ type Model interface {
3939
SetTeamInfo(availableAgents []string)
4040
SetAgentSwitching(switching bool)
4141
SetToolsetInfo(availableTools int)
42-
SetToolStatus(toolName, status string)
4342
GetSize() (width, height int)
4443
}
4544

@@ -69,21 +68,18 @@ type model struct {
6968
availableAgents []string
7069
agentSwitching bool
7170
availableTools int
72-
activeTools []string
73-
toolExecutions map[string]string // tool name -> status (running, completed, failed)
7471
}
7572

7673
func New(manager *service.TodoManager) Model {
7774
return &model{
78-
width: 20,
79-
height: 24,
80-
sessionUsage: make(map[string]*runtime.Usage),
81-
sessionAgent: make(map[string]string),
82-
todoComp: todotool.NewSidebarComponent(manager),
83-
spinner: spinner.New(spinner.ModeSpinnerOnly),
84-
sessionTitle: "New session",
85-
ragIndexing: make(map[string]*ragIndexingState),
86-
toolExecutions: make(map[string]string),
75+
width: 20,
76+
height: 24,
77+
sessionUsage: make(map[string]*runtime.Usage),
78+
sessionAgent: make(map[string]string),
79+
todoComp: todotool.NewSidebarComponent(manager),
80+
spinner: spinner.New(spinner.ModeSpinnerOnly),
81+
sessionTitle: "New session",
82+
ragIndexing: make(map[string]*ragIndexingState),
8783
}
8884
}
8985

@@ -137,24 +133,6 @@ func (m *model) SetToolsetInfo(availableTools int) {
137133
m.availableTools = availableTools
138134
}
139135

140-
// SetToolStatus updates the status of a specific tool
141-
func (m *model) SetToolStatus(toolName, status string) {
142-
if m.toolExecutions == nil {
143-
m.toolExecutions = make(map[string]string)
144-
}
145-
146-
// Update tool status
147-
m.toolExecutions[toolName] = status
148-
149-
// Update active tools list
150-
m.activeTools = nil
151-
for tool, stat := range m.toolExecutions {
152-
if stat == "running" {
153-
m.activeTools = append(m.activeTools, tool)
154-
}
155-
}
156-
}
157-
158136
// formatTokenCount formats a token count with K/M suffixes for readability
159137
func formatTokenCount(count int) string {
160138
if count >= 1000000 {
@@ -260,9 +238,6 @@ func (m *model) Update(msg tea.Msg) (layout.Model, tea.Cmd) {
260238
case *runtime.ToolsetInfoEvent:
261239
m.SetToolsetInfo(msg.AvailableTools)
262240
return m, nil
263-
case *runtime.ToolStatusEvent:
264-
m.SetToolStatus(msg.ToolName, msg.Status)
265-
return m, nil
266241
default:
267242
var cmds []tea.Cmd
268243

@@ -313,36 +288,39 @@ func (m *model) horizontalView() string {
313288
}
314289

315290
func (m *model) verticalView() string {
316-
topContent := m.sessionTitle + "\n"
317-
291+
var main []string
292+
main = append(main, m.sessionTitle)
318293
if pwd := getCurrentWorkingDirectory(); pwd != "" {
319-
topContent += styles.MutedStyle.Render(pwd) + "\n\n"
294+
main = append(main, styles.MutedStyle.Render(pwd))
295+
}
296+
if working := m.workingIndicator(); working != "" {
297+
main = append(main, working)
298+
} else {
299+
main = append(main, "") // spacer for layout consistency
320300
}
321301

322-
topContent += m.tokenUsage()
323-
topContent += "\n" + m.workingIndicator()
324-
325-
// Add agent information
302+
var more []string
326303
if agentInfo := m.agentInfo(); agentInfo != "" {
327-
topContent += "\n\n" + agentInfo
304+
more = append(more, agentInfo)
328305
}
329-
330-
// Add toolset information
331306
if toolsetInfo := m.toolsetInfo(); toolsetInfo != "" {
332-
topContent += "\n\n" + toolsetInfo
307+
more = append(more, toolsetInfo)
308+
}
309+
if usage := m.tokenUsage(); usage != "" {
310+
more = append(more, usage)
333311
}
334312

335313
m.todoComp.SetSize(m.width)
336314
todoContent := strings.TrimSuffix(m.todoComp.Render(), "\n")
337315
if todoContent != "" {
338-
topContent += "\n\n" + todoContent
316+
more = append(more, todoContent)
339317
}
340318

341319
return styles.BaseStyle.
342320
Width(m.width).
343321
Height(m.height-2).
344322
Align(lipgloss.Left, lipgloss.Top).
345-
Render(topContent)
323+
Render(strings.Join(main, "\n") + "\n\n" + strings.Join(more, "\n\n"))
346324
}
347325

348326
func (m *model) workingIndicator() string {
@@ -515,51 +493,15 @@ func (m *model) tokenUsage() string {
515493
totalCost += usage.Cost
516494
}
517495

518-
agentTotals := make(map[string]*runtime.Usage)
519-
for sessionID, usage := range m.sessionUsage {
520-
agent := m.sessionAgent[sessionID]
521-
if agent == "" {
522-
continue
523-
}
524-
if existing, ok := agentTotals[agent]; ok {
525-
existing.InputTokens += usage.InputTokens
526-
existing.OutputTokens += usage.OutputTokens
527-
existing.Cost += usage.Cost
528-
} else {
529-
u := *usage
530-
agentTotals[agent] = &u
531-
}
532-
}
533-
534496
var b strings.Builder
535-
b.WriteString(styles.HighlightStyle.Render("TOTAL USAGE"))
536-
b.WriteString("\n ")
537-
line := fmt.Sprintf("Tokens: %s | Cost: $%s", formatTokenCount(totalTokens), formatCost(totalCost))
497+
b.WriteString(styles.HighlightStyle.Render("Usage"))
498+
b.WriteString("\n")
499+
b.WriteString(styles.MutedStyle.Render(fmt.Sprintf("Tokens: %s", formatTokenCount(totalTokens))))
500+
b.WriteString("\n")
501+
b.WriteString(styles.MutedStyle.Render(fmt.Sprintf("Cost: $%s", formatCost(totalCost))))
538502
if ctxText, ok := m.contextPercent(); ok {
539-
line = fmt.Sprintf("%s | %s", line, ctxText)
540-
}
541-
b.WriteString(line)
542-
543-
b.WriteString("\n--------------------------------\n")
544-
b.WriteString(styles.HighlightStyle.Render("SESSION BREAKDOWN"))
545-
546-
agentNames := make([]string, 0, len(agentTotals))
547-
for name := range agentTotals {
548-
agentNames = append(agentNames, name)
549-
}
550-
sort.Strings(agentNames)
551-
552-
if len(agentNames) == 0 {
553-
b.WriteString("\n ")
554-
b.WriteString(styles.SubtleStyle.Render("No usage yet"))
555-
return b.String()
556-
}
557-
558-
for _, name := range agentNames {
559-
usage := agentTotals[name]
560-
tokens := usage.InputTokens + usage.OutputTokens
561-
b.WriteString(fmt.Sprintf("\n %s", styles.SubtleStyle.Render(name)))
562-
b.WriteString(fmt.Sprintf("\n Tokens: %s | Cost: $%s", formatTokenCount(tokens), formatCost(usage.Cost)))
503+
b.WriteString("\n")
504+
b.WriteString(styles.MutedStyle.Render(ctxText))
563505
}
564506

565507
return b.String()
@@ -594,9 +536,9 @@ func (m *model) agentInfo() string {
594536
var content strings.Builder
595537

596538
// Agent name with highlight and switching indicator
597-
agentTitle := "AGENT"
539+
agentTitle := "Agent"
598540
if m.agentSwitching {
599-
agentTitle = "AGENT ↔" // switching indicator
541+
agentTitle += " ↔" // switching indicator
600542
}
601543
content.WriteString(styles.HighlightStyle.Render(agentTitle))
602544
content.WriteString("\n")
@@ -645,25 +587,8 @@ func (m *model) toolsetInfo() string {
645587
}
646588

647589
var content strings.Builder
648-
649-
// Tools header
650-
content.WriteString(styles.HighlightStyle.Render("TOOLS"))
651-
content.WriteString("\n")
652-
653-
// Available tools count
654-
content.WriteString(styles.MutedStyle.Render(fmt.Sprintf("%d tools available", m.availableTools)))
655-
656-
// Active/running tools
657-
if len(m.activeTools) > 0 {
658-
content.WriteString("\n")
659-
for i, tool := range m.activeTools {
660-
if i > 0 {
661-
content.WriteString(", ")
662-
}
663-
content.WriteString(styles.ActiveStyle.Render("[>] " + tool))
664-
}
665-
}
666-
590+
content.WriteString(styles.HighlightStyle.Render("Tools"))
591+
content.WriteString(styles.MutedStyle.Render(fmt.Sprintf("\n%d tools available", m.availableTools)))
667592
return content.String()
668593
}
669594

pkg/tui/components/tool/todotool/sidebar.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (c *SidebarComponent) Render() string {
6363
}
6464

6565
var content strings.Builder
66-
content.WriteString(styles.HighlightStyle.Render("TODOS"))
66+
content.WriteString(styles.HighlightStyle.Render("Todo"))
6767
content.WriteString("\n")
6868

6969
for _, todo := range c.manager.GetTodos() {

pkg/tui/page/chat/chat.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,6 @@ func (p *chatPage) Update(msg tea.Msg) (layout.Model, tea.Cmd) {
306306
p.sidebar.SetAgentSwitching(msg.Switching)
307307
case *runtime.ToolsetInfoEvent:
308308
p.sidebar.SetToolsetInfo(msg.AvailableTools)
309-
case *runtime.ToolStatusEvent:
310-
p.sidebar.SetToolStatus(msg.ToolName, msg.Status)
311309
case *runtime.StreamStoppedEvent:
312310
spinnerCmd := p.setWorking(false)
313311
if p.msgCancel != nil {

0 commit comments

Comments
 (0)