summaryrefslogtreecommitdiffhomepage
path: root/internal/tui
diff options
context:
space:
mode:
authoradamdottv <[email protected]>2025-05-29 15:37:06 -0500
committeradamdottv <[email protected]>2025-05-29 15:37:06 -0500
commit0e31bbcd9322e1f667b87c88445a4f6effa1d934 (patch)
tree428bbd368a197cb3e80523c629437d8cde86b092 /internal/tui
parent913b3434d8243cc9681a3bf7520e7b027ec3853b (diff)
downloadopencode-0e31bbcd9322e1f667b87c88445a4f6effa1d934.tar.gz
opencode-0e31bbcd9322e1f667b87c88445a4f6effa1d934.zip
wip: refactoring tui
Diffstat (limited to 'internal/tui')
-rw-r--r--internal/tui/app/app.go13
-rw-r--r--internal/tui/app/bridge.go87
-rw-r--r--internal/tui/app/interfaces.go20
-rw-r--r--internal/tui/components/chat/chat.go4
-rw-r--r--internal/tui/components/chat/editor.go5
-rw-r--r--internal/tui/components/chat/message.go269
-rw-r--r--internal/tui/components/chat/messages.go71
-rw-r--r--internal/tui/components/dialog/filepicker.go5
-rw-r--r--internal/tui/page/chat.go3
-rw-r--r--internal/tui/tui.go6
10 files changed, 181 insertions, 302 deletions
diff --git a/internal/tui/app/app.go b/internal/tui/app/app.go
index d169f6dc2..3ee0f564d 100644
--- a/internal/tui/app/app.go
+++ b/internal/tui/app/app.go
@@ -10,7 +10,6 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/sst/opencode/internal/config"
"github.com/sst/opencode/internal/fileutil"
- "github.com/sst/opencode/internal/message"
"github.com/sst/opencode/internal/status"
"github.com/sst/opencode/internal/tui/state"
"github.com/sst/opencode/internal/tui/theme"
@@ -24,7 +23,6 @@ type App struct {
Session *client.SessionInfo
Messages []client.MessageInfo
- MessagesOLD MessageService
LogsOLD any // TODO: Define LogService interface when needed
HistoryOLD any // TODO: Define HistoryService interface when needed
PermissionsOLD any // TODO: Define PermissionService interface when needed
@@ -66,14 +64,12 @@ func New(ctx context.Context) (*App, error) {
}
// Create service bridges
- messageBridge := NewMessageServiceBridge(httpClient)
agentBridge := NewAgentServiceBridge(httpClient)
app := &App{
Client: httpClient,
Events: eventClient,
Session: &client.SessionInfo{},
- MessagesOLD: messageBridge,
PrimaryAgentOLD: agentBridge,
Status: status.GetService(),
@@ -89,8 +85,15 @@ func New(ctx context.Context) (*App, error) {
return app, nil
}
+type Attachment struct {
+ FilePath string
+ FileName string
+ MimeType string
+ Content []byte
+}
+
// Create creates a new session
-func (a *App) SendChatMessage(ctx context.Context, text string, attachments []message.Attachment) tea.Cmd {
+func (a *App) SendChatMessage(ctx context.Context, text string, attachments []Attachment) tea.Cmd {
var cmds []tea.Cmd
if a.Session.Id == "" {
resp, err := a.Client.PostSessionCreateWithResponse(ctx)
diff --git a/internal/tui/app/bridge.go b/internal/tui/app/bridge.go
index 74abd712a..3e8768ac1 100644
--- a/internal/tui/app/bridge.go
+++ b/internal/tui/app/bridge.go
@@ -2,12 +2,8 @@ package app
import (
"context"
- "encoding/json"
"fmt"
- "time"
- "github.com/sst/opencode/internal/message"
- "github.com/sst/opencode/internal/pubsub"
"github.com/sst/opencode/pkg/client"
)
@@ -22,7 +18,7 @@ func NewAgentServiceBridge(client *client.ClientWithResponses) *AgentServiceBrid
}
// Run sends a message to the chat API
-func (a *AgentServiceBridge) Run(ctx context.Context, sessionID string, text string, attachments ...message.Attachment) (string, error) {
+func (a *AgentServiceBridge) Run(ctx context.Context, sessionID string, text string, attachments ...Attachment) (string, error) {
// TODO: Handle attachments when API supports them
if len(attachments) > 0 {
// For now, ignore attachments
@@ -71,84 +67,3 @@ func (a *AgentServiceBridge) CompactSession(ctx context.Context, sessionID strin
// TODO: Not implemented in TypeScript API yet
return fmt.Errorf("session compaction not implemented in API")
}
-
-// MessageServiceBridge provides a minimal message service that fetches from the API
-type MessageServiceBridge struct {
- client *client.ClientWithResponses
- broker *pubsub.Broker[message.Message]
-}
-
-// NewMessageServiceBridge creates a new message service bridge
-func NewMessageServiceBridge(client *client.ClientWithResponses) *MessageServiceBridge {
- return &MessageServiceBridge{
- client: client,
- broker: pubsub.NewBroker[message.Message](),
- }
-}
-
-// GetBySession retrieves messages for a session
-func (m *MessageServiceBridge) GetBySession(ctx context.Context, sessionID string) ([]message.Message, error) {
- return m.List(ctx, sessionID)
-}
-
-// List retrieves messages for a session
-func (m *MessageServiceBridge) List(ctx context.Context, sessionID string) ([]message.Message, error) {
- resp, err := m.client.PostSessionMessages(ctx, client.PostSessionMessagesJSONRequestBody{
- SessionID: sessionID,
- })
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- // The API returns a different format, we'll need to adapt it
- var rawMessages any
- if err := json.NewDecoder(resp.Body).Decode(&rawMessages); err != nil {
- return nil, err
- }
-
- // TODO: Convert the API message format to our internal format
- // For now, return empty to avoid compilation errors
- return []message.Message{}, nil
-}
-
-// Create creates a new message - NOT NEEDED, handled by chat API
-func (m *MessageServiceBridge) Create(ctx context.Context, sessionID string, params message.CreateMessageParams) (message.Message, error) {
- // Messages are created through the chat API
- return message.Message{}, fmt.Errorf("use chat API to send messages")
-}
-
-// Update updates a message - NOT IMPLEMENTED IN API YET
-func (m *MessageServiceBridge) Update(ctx context.Context, msg message.Message) (message.Message, error) {
- // TODO: Not implemented in TypeScript API yet
- return message.Message{}, fmt.Errorf("message update not implemented in API")
-}
-
-// Delete deletes a message - NOT IMPLEMENTED IN API YET
-func (m *MessageServiceBridge) Delete(ctx context.Context, id string) error {
- // TODO: Not implemented in TypeScript API yet
- return fmt.Errorf("message delete not implemented in API")
-}
-
-// DeleteSessionMessages deletes all messages for a session - NOT IMPLEMENTED IN API YET
-func (m *MessageServiceBridge) DeleteSessionMessages(ctx context.Context, sessionID string) error {
- // TODO: Not implemented in TypeScript API yet
- return fmt.Errorf("delete session messages not implemented in API")
-}
-
-// Get retrieves a message by ID - NOT IMPLEMENTED IN API YET
-func (m *MessageServiceBridge) Get(ctx context.Context, id string) (message.Message, error) {
- // TODO: Not implemented in TypeScript API yet
- return message.Message{}, fmt.Errorf("get message by ID not implemented in API")
-}
-
-// ListAfter retrieves messages after a timestamp - NOT IMPLEMENTED IN API YET
-func (m *MessageServiceBridge) ListAfter(ctx context.Context, sessionID string, timestamp time.Time) ([]message.Message, error) {
- // TODO: Not implemented in TypeScript API yet
- return []message.Message{}, fmt.Errorf("list messages after timestamp not implemented in API")
-}
-
-// Subscribe subscribes to message events
-func (m *MessageServiceBridge) Subscribe(ctx context.Context) <-chan pubsub.Event[message.Message] {
- return m.broker.Subscribe(ctx)
-}
diff --git a/internal/tui/app/interfaces.go b/internal/tui/app/interfaces.go
index 01271156e..4cc9b8022 100644
--- a/internal/tui/app/interfaces.go
+++ b/internal/tui/app/interfaces.go
@@ -2,29 +2,11 @@ package app
import (
"context"
- "time"
-
- "github.com/sst/opencode/internal/message"
- "github.com/sst/opencode/internal/pubsub"
)
-// MessageService defines the interface for message operations
-type MessageService interface {
- pubsub.Subscriber[message.Message]
-
- GetBySession(ctx context.Context, sessionID string) ([]message.Message, error)
- List(ctx context.Context, sessionID string) ([]message.Message, error)
- Create(ctx context.Context, sessionID string, params message.CreateMessageParams) (message.Message, error)
- Update(ctx context.Context, msg message.Message) (message.Message, error)
- Delete(ctx context.Context, id string) error
- DeleteSessionMessages(ctx context.Context, sessionID string) error
- Get(ctx context.Context, id string) (message.Message, error)
- ListAfter(ctx context.Context, sessionID string, timestamp time.Time) ([]message.Message, error)
-}
-
// AgentService defines the interface for agent operations
type AgentService interface {
- Run(ctx context.Context, sessionID string, text string, attachments ...message.Attachment) (string, error)
+ Run(ctx context.Context, sessionID string, text string, attachments ...Attachment) (string, error)
Cancel(sessionID string) error
IsBusy() bool
IsSessionBusy(sessionID string) bool
diff --git a/internal/tui/components/chat/chat.go b/internal/tui/components/chat/chat.go
index 7cd49ef6a..2fabea43d 100644
--- a/internal/tui/components/chat/chat.go
+++ b/internal/tui/components/chat/chat.go
@@ -7,7 +7,7 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/x/ansi"
"github.com/sst/opencode/internal/config"
- "github.com/sst/opencode/internal/message"
+ "github.com/sst/opencode/internal/tui/app"
"github.com/sst/opencode/internal/tui/styles"
"github.com/sst/opencode/internal/tui/theme"
"github.com/sst/opencode/internal/version"
@@ -15,7 +15,7 @@ import (
type SendMsg struct {
Text string
- Attachments []message.Attachment
+ Attachments []app.Attachment
}
func header(width int) string {
diff --git a/internal/tui/components/chat/editor.go b/internal/tui/components/chat/editor.go
index c3b06787e..6586f2020 100644
--- a/internal/tui/components/chat/editor.go
+++ b/internal/tui/components/chat/editor.go
@@ -13,7 +13,6 @@ import (
"github.com/charmbracelet/bubbles/textarea"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
- "github.com/sst/opencode/internal/message"
"github.com/sst/opencode/internal/status"
"github.com/sst/opencode/internal/tui/app"
"github.com/sst/opencode/internal/tui/components/dialog"
@@ -29,7 +28,7 @@ type editorCmp struct {
height int
app *app.App
textarea textarea.Model
- attachments []message.Attachment
+ attachments []app.Attachment
deleteMode bool
history []string
historyIndex int
@@ -233,7 +232,7 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
if len(imageBytes) != 0 {
attachmentName := fmt.Sprintf("clipboard-image-%d", len(m.attachments))
- attachment := message.Attachment{FilePath: attachmentName, FileName: attachmentName, Content: imageBytes, MimeType: "image/png"}
+ attachment := app.Attachment{FilePath: attachmentName, FileName: attachmentName, Content: imageBytes, MimeType: "image/png"}
m.attachments = append(m.attachments, attachment)
} else {
m.textarea.SetValue(m.textarea.Value() + text)
diff --git a/internal/tui/components/chat/message.go b/internal/tui/components/chat/message.go
index 9f8a9de64..c7b8234a0 100644
--- a/internal/tui/components/chat/message.go
+++ b/internal/tui/components/chat/message.go
@@ -8,7 +8,6 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/x/ansi"
"github.com/sst/opencode/internal/config"
- "github.com/sst/opencode/internal/message"
"github.com/sst/opencode/internal/tui/styles"
"github.com/sst/opencode/internal/tui/theme"
"github.com/sst/opencode/pkg/client"
@@ -244,17 +243,6 @@ func renderAssistantMessage(
return strings.Join(messages, "\n\n")
}
-func findToolResponse(toolCallID string, futureMessages []message.Message) *message.ToolResult {
- for _, msg := range futureMessages {
- for _, result := range msg.ToolResults() {
- if result.ToolCallID == toolCallID {
- return &result
- }
- }
- }
- return nil
-}
-
func renderToolName(name string) string {
switch name {
// case agent.AgentToolName:
@@ -354,9 +342,9 @@ func removeWorkingDirPrefix(path string) string {
return path
}
-func renderToolParams(paramWidth int, toolCall message.ToolCall) string {
+func renderToolParams(paramWidth int, toolCall any) string {
params := ""
- switch toolCall.Name {
+ switch toolCall {
// // case agent.AgentToolName:
// // var params agent.AgentParams
// // json.Unmarshal([]byte(toolCall.Input), &params)
@@ -445,9 +433,9 @@ func renderToolParams(paramWidth int, toolCall message.ToolCall) string {
// var params tools.BatchParams
// json.Unmarshal([]byte(toolCall.Input), &params)
// return renderParams(paramWidth, fmt.Sprintf("%d parallel calls", len(params.Calls)))
- default:
- input := strings.ReplaceAll(toolCall.Input, "\n", " ")
- params = renderParams(paramWidth, input)
+ // default:
+ // input := strings.ReplaceAll(toolCall, "\n", " ")
+ // params = renderParams(paramWidth, input)
}
return params
}
@@ -460,21 +448,22 @@ func truncateHeight(content string, height int) string {
return content
}
-func renderToolResponse(toolCall message.ToolCall, response message.ToolResult, width int) string {
- t := theme.CurrentTheme()
- baseStyle := styles.BaseStyle()
-
- if response.IsError {
- errContent := fmt.Sprintf("Error: %s", strings.ReplaceAll(response.Content, "\n", " "))
- errContent = ansi.Truncate(errContent, width-1, "...")
- return baseStyle.
- Width(width).
- Foreground(t.Error()).
- Render(errContent)
- }
-
- resultContent := truncateHeight(response.Content, maxResultHeight)
- switch toolCall.Name {
+func renderToolResponse(toolCall any, response any, width int) string {
+ return ""
+ // t := theme.CurrentTheme()
+ // baseStyle := styles.BaseStyle()
+ //
+ // if response.IsError {
+ // errContent := fmt.Sprintf("Error: %s", strings.ReplaceAll(response.Content, "\n", " "))
+ // errContent = ansi.Truncate(errContent, width-1, "...")
+ // return baseStyle.
+ // Width(width).
+ // Foreground(t.Error()).
+ // Render(errContent)
+ // }
+ //
+ // resultContent := truncateHeight(response.Content, maxResultHeight)
+ // switch toolCall.Name {
// case agent.AgentToolName:
// return styles.ForceReplaceBackgroundWithLipgloss(
// toMarkdown(resultContent, false, width),
@@ -574,113 +563,113 @@ func renderToolResponse(toolCall message.ToolCall, response message.ToolResult,
// }
//
// return baseStyle.Width(width).Foreground(t.TextMuted()).Render(strings.Join(toolCalls, "\n\n"))
- default:
- resultContent = fmt.Sprintf("```text\n%s\n```", resultContent)
- return styles.ForceReplaceBackgroundWithLipgloss(
- toMarkdown(resultContent, width),
- t.Background(),
- )
- }
-}
-
-func renderToolMessage(
- toolCall message.ToolCall,
- allMessages []message.Message,
- messagesService message.Service,
- focusedUIMessageId string,
- nested bool,
- width int,
- position int,
-) string {
- if nested {
- width = width - 3
- }
-
- t := theme.CurrentTheme()
- baseStyle := styles.BaseStyle()
-
- style := baseStyle.
- Width(width - 1).
- BorderLeft(true).
- BorderStyle(lipgloss.ThickBorder()).
- PaddingLeft(1).
- BorderForeground(t.TextMuted())
-
- response := findToolResponse(toolCall.ID, allMessages)
- toolNameText := baseStyle.Foreground(t.TextMuted()).
- Render(fmt.Sprintf("%s: ", renderToolName(toolCall.Name)))
-
- if !toolCall.Finished {
- // Get a brief description of what the tool is doing
- toolAction := renderToolAction(toolCall.Name)
-
- progressText := baseStyle.
- Width(width - 2 - lipgloss.Width(toolNameText)).
- Foreground(t.TextMuted()).
- Render(fmt.Sprintf("%s", toolAction))
-
- content := style.Render(lipgloss.JoinHorizontal(lipgloss.Left, toolNameText, progressText))
- return content
- }
-
- params := renderToolParams(width-1-lipgloss.Width(toolNameText), toolCall)
- responseContent := ""
- if response != nil {
- responseContent = renderToolResponse(toolCall, *response, width-2)
- responseContent = strings.TrimSuffix(responseContent, "\n")
- } else {
- responseContent = baseStyle.
- Italic(true).
- Width(width - 2).
- Foreground(t.TextMuted()).
- Render("Waiting for response...")
- }
-
- parts := []string{}
- if !nested {
- formattedParams := baseStyle.
- Width(width - 2 - lipgloss.Width(toolNameText)).
- Foreground(t.TextMuted()).
- Render(params)
-
- parts = append(parts, lipgloss.JoinHorizontal(lipgloss.Left, toolNameText, formattedParams))
- } else {
- prefix := baseStyle.
- Foreground(t.TextMuted()).
- Render(" └ ")
- formattedParams := baseStyle.
- Width(width - 2 - lipgloss.Width(toolNameText)).
- Foreground(t.TextMuted()).
- Render(params)
- parts = append(parts, lipgloss.JoinHorizontal(lipgloss.Left, prefix, toolNameText, formattedParams))
- }
-
- // if toolCall.Name == agent.AgentToolName {
- // taskMessages, _ := messagesService.List(context.Background(), toolCall.ID)
- // toolCalls := []message.ToolCall{}
- // for _, v := range taskMessages {
- // toolCalls = append(toolCalls, v.ToolCalls()...)
- // }
- // for _, call := range toolCalls {
- // rendered := renderToolMessage(call, []message.Message{}, messagesService, focusedUIMessageId, true, width, 0)
- // parts = append(parts, rendered.content)
- // }
+ // default:
+ // resultContent = fmt.Sprintf("```text\n%s\n```", resultContent)
+ // return styles.ForceReplaceBackgroundWithLipgloss(
+ // toMarkdown(resultContent, width),
+ // t.Background(),
+ // )
// }
- if responseContent != "" && !nested {
- parts = append(parts, responseContent)
- }
-
- content := style.Render(
- lipgloss.JoinVertical(
- lipgloss.Left,
- parts...,
- ),
- )
- if nested {
- content = lipgloss.JoinVertical(
- lipgloss.Left,
- parts...,
- )
- }
- return content
}
+
+// func renderToolMessage(
+// toolCall message.ToolCall,
+// allMessages []message.Message,
+// messagesService message.Service,
+// focusedUIMessageId string,
+// nested bool,
+// width int,
+// position int,
+// ) string {
+// if nested {
+// width = width - 3
+// }
+//
+// t := theme.CurrentTheme()
+// baseStyle := styles.BaseStyle()
+//
+// style := baseStyle.
+// Width(width - 1).
+// BorderLeft(true).
+// BorderStyle(lipgloss.ThickBorder()).
+// PaddingLeft(1).
+// BorderForeground(t.TextMuted())
+//
+// response := findToolResponse(toolCall.ID, allMessages)
+// toolNameText := baseStyle.Foreground(t.TextMuted()).
+// Render(fmt.Sprintf("%s: ", renderToolName(toolCall.Name)))
+//
+// if !toolCall.Finished {
+// // Get a brief description of what the tool is doing
+// toolAction := renderToolAction(toolCall.Name)
+//
+// progressText := baseStyle.
+// Width(width - 2 - lipgloss.Width(toolNameText)).
+// Foreground(t.TextMuted()).
+// Render(fmt.Sprintf("%s", toolAction))
+//
+// content := style.Render(lipgloss.JoinHorizontal(lipgloss.Left, toolNameText, progressText))
+// return content
+// }
+//
+// params := renderToolParams(width-1-lipgloss.Width(toolNameText), toolCall)
+// responseContent := ""
+// if response != nil {
+// responseContent = renderToolResponse(toolCall, *response, width-2)
+// responseContent = strings.TrimSuffix(responseContent, "\n")
+// } else {
+// responseContent = baseStyle.
+// Italic(true).
+// Width(width - 2).
+// Foreground(t.TextMuted()).
+// Render("Waiting for response...")
+// }
+//
+// parts := []string{}
+// if !nested {
+// formattedParams := baseStyle.
+// Width(width - 2 - lipgloss.Width(toolNameText)).
+// Foreground(t.TextMuted()).
+// Render(params)
+//
+// parts = append(parts, lipgloss.JoinHorizontal(lipgloss.Left, toolNameText, formattedParams))
+// } else {
+// prefix := baseStyle.
+// Foreground(t.TextMuted()).
+// Render(" └ ")
+// formattedParams := baseStyle.
+// Width(width - 2 - lipgloss.Width(toolNameText)).
+// Foreground(t.TextMuted()).
+// Render(params)
+// parts = append(parts, lipgloss.JoinHorizontal(lipgloss.Left, prefix, toolNameText, formattedParams))
+// }
+//
+// // if toolCall.Name == agent.AgentToolName {
+// // taskMessages, _ := messagesService.List(context.Background(), toolCall.ID)
+// // toolCalls := []message.ToolCall{}
+// // for _, v := range taskMessages {
+// // toolCalls = append(toolCalls, v.ToolCalls()...)
+// // }
+// // for _, call := range toolCalls {
+// // rendered := renderToolMessage(call, []message.Message{}, messagesService, focusedUIMessageId, true, width, 0)
+// // parts = append(parts, rendered.content)
+// // }
+// // }
+// if responseContent != "" && !nested {
+// parts = append(parts, responseContent)
+// }
+//
+// content := style.Render(
+// lipgloss.JoinVertical(
+// lipgloss.Left,
+// parts...,
+// ),
+// )
+// if nested {
+// content = lipgloss.JoinVertical(
+// lipgloss.Left,
+// parts...,
+// )
+// }
+// return content
+// }
diff --git a/internal/tui/components/chat/messages.go b/internal/tui/components/chat/messages.go
index 92e6ec471..50a0f4200 100644
--- a/internal/tui/components/chat/messages.go
+++ b/internal/tui/components/chat/messages.go
@@ -9,7 +9,6 @@ import (
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
- "github.com/sst/opencode/internal/message"
"github.com/sst/opencode/internal/tui/app"
"github.com/sst/opencode/internal/tui/components/dialog"
"github.com/sst/opencode/internal/tui/state"
@@ -177,41 +176,41 @@ func (m *messagesCmp) View() string {
)
}
-func hasToolsWithoutResponse(messages []message.Message) bool {
- toolCalls := make([]message.ToolCall, 0)
- toolResults := make([]message.ToolResult, 0)
- for _, m := range messages {
- toolCalls = append(toolCalls, m.ToolCalls()...)
- toolResults = append(toolResults, m.ToolResults()...)
- }
-
- for _, v := range toolCalls {
- found := false
- for _, r := range toolResults {
- if v.ID == r.ToolCallID {
- found = true
- break
- }
- }
- if !found && v.Finished {
- return true
- }
- }
- return false
-}
-
-func hasUnfinishedToolCalls(messages []message.Message) bool {
- toolCalls := make([]message.ToolCall, 0)
- for _, m := range messages {
- toolCalls = append(toolCalls, m.ToolCalls()...)
- }
- for _, v := range toolCalls {
- if !v.Finished {
- return true
- }
- }
- return false
-}
+// func hasToolsWithoutResponse(messages []message.Message) bool {
+// toolCalls := make([]message.ToolCall, 0)
+// toolResults := make([]message.ToolResult, 0)
+// for _, m := range messages {
+// toolCalls = append(toolCalls, m.ToolCalls()...)
+// toolResults = append(toolResults, m.ToolResults()...)
+// }
+//
+// for _, v := range toolCalls {
+// found := false
+// for _, r := range toolResults {
+// if v.ID == r.ToolCallID {
+// found = true
+// break
+// }
+// }
+// if !found && v.Finished {
+// return true
+// }
+// }
+// return false
+// }
+
+// func hasUnfinishedToolCalls(messages []message.Message) bool {
+// toolCalls := make([]message.ToolCall, 0)
+// for _, m := range messages {
+// toolCalls = append(toolCalls, m.ToolCalls()...)
+// }
+// for _, v := range toolCalls {
+// if !v.Finished {
+// return true
+// }
+// }
+// return false
+// }
func (m *messagesCmp) working() string {
text := ""
diff --git a/internal/tui/components/dialog/filepicker.go b/internal/tui/components/dialog/filepicker.go
index 980ab216b..088e205f2 100644
--- a/internal/tui/components/dialog/filepicker.go
+++ b/internal/tui/components/dialog/filepicker.go
@@ -17,7 +17,6 @@ import (
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
- "github.com/sst/opencode/internal/message"
"github.com/sst/opencode/internal/status"
"github.com/sst/opencode/internal/tui/app"
"github.com/sst/opencode/internal/tui/image"
@@ -116,7 +115,7 @@ func (s stack) Pop() (stack, int) {
}
type AttachmentAddedMsg struct {
- Attachment message.Attachment
+ Attachment app.Attachment
}
func (f *filepickerCmp) Init() tea.Cmd {
@@ -269,7 +268,7 @@ func (f *filepickerCmp) addAttachmentToMessage() (tea.Model, tea.Cmd) {
mimeBufferSize := min(512, len(content))
mimeType := http.DetectContentType(content[:mimeBufferSize])
fileName := filepath.Base(selectedFilePath)
- attachment := message.Attachment{FilePath: selectedFilePath, FileName: fileName, MimeType: mimeType, Content: content}
+ attachment := app.Attachment{FilePath: selectedFilePath, FileName: fileName, MimeType: mimeType, Content: content}
f.selectedFile = ""
return f, util.CmdHandler(AttachmentAddedMsg{attachment})
}
diff --git a/internal/tui/page/chat.go b/internal/tui/page/chat.go
index 4a4692bbe..134de6afd 100644
--- a/internal/tui/page/chat.go
+++ b/internal/tui/page/chat.go
@@ -8,7 +8,6 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/sst/opencode/internal/completions"
- "github.com/sst/opencode/internal/message"
"github.com/sst/opencode/internal/status"
"github.com/sst/opencode/internal/tui/app"
"github.com/sst/opencode/internal/tui/components/chat"
@@ -161,7 +160,7 @@ func (p *chatPage) clearSidebar() tea.Cmd {
return p.layout.ClearRightPanel()
}
-func (p *chatPage) sendMessage(text string, attachments []message.Attachment) tea.Cmd {
+func (p *chatPage) sendMessage(text string, attachments []app.Attachment) tea.Cmd {
var cmds []tea.Cmd
cmd := p.app.SendChatMessage(context.Background(), text, attachments)
cmds = append(cmds, cmd)
diff --git a/internal/tui/tui.go b/internal/tui/tui.go
index ec4f49fd7..c684b8c8f 100644
--- a/internal/tui/tui.go
+++ b/internal/tui/tui.go
@@ -13,7 +13,6 @@ import (
"github.com/sst/opencode/internal/config"
"github.com/sst/opencode/internal/tui/app"
- "github.com/sst/opencode/internal/message"
"github.com/sst/opencode/internal/permission"
"github.com/sst/opencode/internal/pubsub"
"github.com/sst/opencode/internal/status"
@@ -574,11 +573,6 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return a, nil
}
- case pubsub.Event[message.Message]:
- a.pages[page.ChatPage], cmd = a.pages[page.ChatPage].Update(msg)
- cmds = append(cmds, cmd)
- return a, tea.Batch(cmds...)
-
default:
f, filepickerCmd := a.filepicker.Update(msg)
a.filepicker = f.(dialog.FilepickerCmp)