summaryrefslogtreecommitdiffhomepage
path: root/packages/tui/internal/components/chat
diff options
context:
space:
mode:
authorDax <[email protected]>2025-08-07 16:32:12 -0400
committerGitHub <[email protected]>2025-08-07 16:32:12 -0400
commitc34aec060f2abb78486857b0e0d678cac52e2fab (patch)
tree7d2b42a0c87ab016ffbc096e332b186ec4bce7ac /packages/tui/internal/components/chat
parent12f1ad521fef2e1fa6f1b0ce6ec939664d61899f (diff)
downloadopencode-c34aec060f2abb78486857b0e0d678cac52e2fab.tar.gz
opencode-c34aec060f2abb78486857b0e0d678cac52e2fab.zip
Merge agent and mode into one (#1689)
The concept of mode has been deprecated, there is now only the agent field in the config. An agent can be cycled through as your primary agent with <tab> or you can spawn a subagent by @ mentioning it. if you include a description of when to use it, the primary agent will try to automatically use it Full docs here: https://opencode.ai/docs/agents/
Diffstat (limited to 'packages/tui/internal/components/chat')
-rw-r--r--packages/tui/internal/components/chat/editor.go25
-rw-r--r--packages/tui/internal/components/chat/message.go43
-rw-r--r--packages/tui/internal/components/chat/messages.go8
3 files changed, 74 insertions, 2 deletions
diff --git a/packages/tui/internal/components/chat/editor.go b/packages/tui/internal/components/chat/editor.go
index 1263a6e72..509de6244 100644
--- a/packages/tui/internal/components/chat/editor.go
+++ b/packages/tui/internal/components/chat/editor.go
@@ -288,6 +288,31 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.textarea.InsertAttachment(attachment)
m.textarea.InsertString(" ")
return m, nil
+ case "agents":
+ atIndex := m.textarea.LastRuneIndex('@')
+ if atIndex == -1 {
+ // Should not happen, but as a fallback, just insert.
+ m.textarea.InsertString(msg.Item.Value + " ")
+ return m, nil
+ }
+
+ cursorCol := m.textarea.CursorColumn()
+ m.textarea.ReplaceRange(atIndex, cursorCol, "")
+
+ name := msg.Item.Value
+ attachment := &attachment.Attachment{
+ ID: uuid.NewString(),
+ Type: "agent",
+ Display: "@" + name,
+ Source: &attachment.AgentSource{
+ Name: name,
+ },
+ }
+
+ m.textarea.InsertAttachment(attachment)
+ m.textarea.InsertString(" ")
+ return m, nil
+
default:
slog.Debug("Unknown provider", "provider", msg.Item.ProviderID)
return m, nil
diff --git a/packages/tui/internal/components/chat/message.go b/packages/tui/internal/components/chat/message.go
index 0a1982718..60d0fab55 100644
--- a/packages/tui/internal/components/chat/message.go
+++ b/packages/tui/internal/components/chat/message.go
@@ -209,6 +209,7 @@ func renderText(
width int,
extra string,
fileParts []opencode.FilePart,
+ agentParts []opencode.AgentPart,
toolCalls ...opencode.ToolPart,
) string {
t := theme.CurrentTheme()
@@ -229,9 +230,47 @@ func renderText(
// Apply highlighting to filenames and base style to rest of text BEFORE wrapping
textLen := int64(len(text))
+
+ // Collect all parts to highlight (both file and agent parts)
+ type highlightPart struct {
+ start int64
+ end int64
+ color compat.AdaptiveColor
+ }
+ var highlights []highlightPart
+
+ // Add file parts with secondary color
for _, filePart := range fileParts {
- highlight := base.Foreground(t.Secondary())
- start, end := filePart.Source.Text.Start, filePart.Source.Text.End
+ highlights = append(highlights, highlightPart{
+ start: filePart.Source.Text.Start,
+ end: filePart.Source.Text.End,
+ color: t.Secondary(),
+ })
+ }
+
+ // Add agent parts with secondary color (same as file parts)
+ for _, agentPart := range agentParts {
+ highlights = append(highlights, highlightPart{
+ start: agentPart.Source.Start,
+ end: agentPart.Source.End,
+ color: t.Secondary(),
+ })
+ }
+
+ // Sort highlights by start position
+ slices.SortFunc(highlights, func(a, b highlightPart) int {
+ if a.start < b.start {
+ return -1
+ }
+ if a.start > b.start {
+ return 1
+ }
+ return 0
+ })
+
+ for _, part := range highlights {
+ highlight := base.Foreground(part.color)
+ start, end := part.start, part.end
if end > textLen {
end = textLen
diff --git a/packages/tui/internal/components/chat/messages.go b/packages/tui/internal/components/chat/messages.go
index 5702cec5d..46036b75f 100644
--- a/packages/tui/internal/components/chat/messages.go
+++ b/packages/tui/internal/components/chat/messages.go
@@ -300,12 +300,17 @@ func (m *messagesComponent) renderView() tea.Cmd {
}
remainingParts := message.Parts[partIndex+1:]
fileParts := make([]opencode.FilePart, 0)
+ agentParts := make([]opencode.AgentPart, 0)
for _, part := range remainingParts {
switch part := part.(type) {
case opencode.FilePart:
if part.Source.Text.Start >= 0 && part.Source.Text.End >= part.Source.Text.Start {
fileParts = append(fileParts, part)
}
+ case opencode.AgentPart:
+ if part.Source.Start >= 0 && part.Source.End >= part.Source.Start {
+ agentParts = append(agentParts, part)
+ }
}
}
flexItems := []layout.FlexItem{}
@@ -355,6 +360,7 @@ func (m *messagesComponent) renderView() tea.Cmd {
width,
files,
fileParts,
+ agentParts,
)
content = lipgloss.PlaceHorizontal(
m.width,
@@ -433,6 +439,7 @@ func (m *messagesComponent) renderView() tea.Cmd {
width,
"",
[]opencode.FilePart{},
+ []opencode.AgentPart{},
toolCallParts...,
)
content = lipgloss.PlaceHorizontal(
@@ -453,6 +460,7 @@ func (m *messagesComponent) renderView() tea.Cmd {
width,
"",
[]opencode.FilePart{},
+ []opencode.AgentPart{},
toolCallParts...,
)
content = lipgloss.PlaceHorizontal(