Skip to content

Commit 4d96f2c

Browse files
authored
Merge pull request #612 from Deepam02/feat/agent-commands-in-tui
feat: add agent commands support in TUI
2 parents 793ae5e + 777af54 commit 4d96f2c

4 files changed

Lines changed: 93 additions & 3 deletions

File tree

pkg/app/app.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package app
33
import (
44
"context"
55
"os/exec"
6+
"strings"
67
"time"
78

89
tea "github.com/charmbracelet/bubbletea/v2"
@@ -49,6 +50,47 @@ func (a *App) Title() string {
4950
return a.title
5051
}
5152

53+
// CurrentAgentCommands returns the commands for the active agent
54+
func (a *App) CurrentAgentCommands() map[string]string {
55+
if a.runtime == nil {
56+
return nil
57+
}
58+
59+
agent := a.runtime.CurrentAgent()
60+
if agent == nil {
61+
return nil
62+
}
63+
64+
return agent.Commands()
65+
}
66+
67+
// ResolveCommand converts /command to its prompt text
68+
func (a *App) ResolveCommand(input string) string {
69+
if !strings.HasPrefix(input, "/") {
70+
return input
71+
}
72+
73+
trimmed := strings.TrimSpace(input)
74+
parts := strings.Fields(trimmed)
75+
if len(parts) == 0 {
76+
return input
77+
}
78+
79+
cmdName := strings.TrimPrefix(parts[0], "/")
80+
commands := a.CurrentAgentCommands()
81+
82+
if prompt, ok := commands[cmdName]; ok {
83+
// If there are additional arguments, append them to the prompt
84+
if len(parts) > 1 {
85+
args := strings.Join(parts[1:], " ")
86+
return prompt + " " + args
87+
}
88+
return prompt
89+
}
90+
91+
return input
92+
}
93+
5294
// Run one agent loop
5395
func (a *App) Run(ctx context.Context, cancel context.CancelFunc, message string) {
5496
a.cancel = cancel

pkg/tui/components/editor/editor.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ type Editor interface {
2828
// editor implements Editor
2929
type editor struct {
3030
textarea *textarea.Model
31+
resolver func(string) string
3132
width int
3233
height int
3334
working bool
3435
}
3536

3637
// New creates a new editor component
37-
func New() Editor {
38+
func New(resolver func(string) string) Editor {
3839
ta := textarea.New()
3940
ta.SetStyles(styles.InputStyle)
4041
ta.Placeholder = "Type your message here..."
@@ -48,6 +49,7 @@ func New() Editor {
4849

4950
return &editor{
5051
textarea: ta,
52+
resolver: resolver,
5153
}
5254
}
5355

@@ -71,6 +73,10 @@ func (e *editor) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7173
value := e.textarea.Value()
7274
if value != "" && !e.working {
7375
e.textarea.Reset()
76+
// Resolve command before sending
77+
if e.resolver != nil {
78+
value = e.resolver(value)
79+
}
7480
return e, core.CmdHandler(SendMsg{Content: value})
7581
}
7682
return e, nil

pkg/tui/page/chat/chat.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type Page interface {
3939
layout.Help
4040
CompactSession() tea.Cmd
4141
CopySessionToClipboard() tea.Cmd
42+
ExecuteCommand(commandText string) tea.Cmd
4243
Cleanup()
4344
}
4445

@@ -95,7 +96,7 @@ func New(a *app.App) Page {
9596
title: a.Title(),
9697
sidebar: sidebar.New(),
9798
messages: messages.New(a),
98-
editor: editor.New(),
99+
editor: editor.New(a.ResolveCommand),
99100
focusedPanel: PanelEditor,
100101
app: a,
101102
keyMap: defaultKeyMap(),
@@ -511,6 +512,13 @@ func (p *chatPage) CompactSession() tea.Cmd {
511512
return p.messages.ScrollToBottom()
512513
}
513514

515+
// ExecuteCommand sends a command text as a message (used by command palette)
516+
func (p *chatPage) ExecuteCommand(commandText string) tea.Cmd {
517+
return func() tea.Msg {
518+
return editor.SendMsg{Content: commandText}
519+
}
520+
}
521+
514522
func (p *chatPage) Cleanup() {
515523
p.stopProgressBar()
516524
}

pkg/tui/tui.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ func toFullscreenView(content string) tea.View {
321321

322322
// buildCommandCategories builds the list of command categories for the command palette
323323
func (a *appModel) buildCommandCategories() []dialog.CommandCategory {
324-
return []dialog.CommandCategory{
324+
categories := []dialog.CommandCategory{
325325
{
326326
Name: "Session",
327327
Commands: []dialog.Command{
@@ -370,4 +370,38 @@ func (a *appModel) buildCommandCategories() []dialog.CommandCategory {
370370
},
371371
},
372372
}
373+
374+
// Add agent commands if available
375+
agentCommands := a.application.CurrentAgentCommands()
376+
if len(agentCommands) > 0 {
377+
commands := make([]dialog.Command, 0, len(agentCommands))
378+
for name, prompt := range agentCommands {
379+
cmdText := "/" + name
380+
381+
// Truncate long descriptions to fit on one line
382+
description := prompt
383+
if len(description) > 60 {
384+
description = description[:57] + "..."
385+
}
386+
387+
// Capture cmdText in closure properly
388+
commandText := cmdText
389+
commands = append(commands, dialog.Command{
390+
ID: "agent.command." + name,
391+
Label: commandText,
392+
Description: description,
393+
Category: "Agent Commands",
394+
Execute: func() tea.Cmd {
395+
return a.chatPage.ExecuteCommand(commandText)
396+
},
397+
})
398+
}
399+
400+
categories = append(categories, dialog.CommandCategory{
401+
Name: "Agent Commands",
402+
Commands: commands,
403+
})
404+
}
405+
406+
return categories
373407
}

0 commit comments

Comments
 (0)