wip: refactoring tui

This commit is contained in:
adamdottv
2025-05-29 14:04:44 -05:00
parent 26606ccbf7
commit ce5b3126d3
6 changed files with 241 additions and 158 deletions

View File

@@ -23,7 +23,6 @@ import (
type App struct {
Client *client.ClientWithResponses
Events *client.Client
State map[string]any
Session *client.SessionInfo
Messages []client.MessageInfo
@@ -76,7 +75,6 @@ func New(ctx context.Context) (*App, error) {
agentBridge := NewAgentServiceBridge(httpClient)
app := &App{
State: make(map[string]any),
Client: httpClient,
Events: eventClient,
Session: &client.SessionInfo{},

View File

@@ -1,6 +1,7 @@
package chat
import (
"fmt"
"time"
"github.com/charmbracelet/bubbles/key"
@@ -93,63 +94,9 @@ func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case renderFinishedMsg:
m.rendering = false
m.viewport.GotoBottom()
case state.StateUpdatedMsg:
m.renderView()
m.viewport.GotoBottom()
// case pubsub.Event[message.Message]:
// needsRerender := false
// if msg.Type == message.EventMessageCreated {
// if msg.Payload.SessionID == m.app.CurrentSessionOLD.ID {
// messageExists := false
// for _, v := range m.messages {
// if v.ID == msg.Payload.ID {
// messageExists = true
// break
// }
// }
//
// if !messageExists {
// if len(m.messages) > 0 {
// lastMsgID := m.messages[len(m.messages)-1].ID
// delete(m.cachedContent, lastMsgID)
// }
//
// m.messages = append(m.messages, msg.Payload)
// delete(m.cachedContent, m.currentMsgID)
// m.currentMsgID = msg.Payload.ID
// needsRerender = true
// }
// }
// // There are tool calls from the child task
// for _, v := range m.messages {
// for _, c := range v.ToolCalls() {
// if c.ID == msg.Payload.SessionID {
// delete(m.cachedContent, v.ID)
// needsRerender = true
// }
// }
// }
// } else if msg.Type == message.EventMessageUpdated && msg.Payload.SessionID == m.app.CurrentSessionOLD.ID {
// for i, v := range m.messages {
// if v.ID == msg.Payload.ID {
// m.messages[i] = msg.Payload
// delete(m.cachedContent, msg.Payload.ID)
// needsRerender = true
// break
// }
// }
// }
// if needsRerender {
// m.renderView()
// if len(m.messages) > 0 {
// if (msg.Type == message.EventMessageCreated) ||
// (msg.Type == message.EventMessageUpdated && msg.Payload.ID == m.messages[len(m.messages)-1].ID) {
// m.viewport.GotoBottom()
// }
// }
// }
}
spinner, cmd := m.spinner.Update(msg)
@@ -190,7 +137,6 @@ func (m *messagesCmp) renderView() {
m.viewport.SetContent(
styles.ForceReplaceBackgroundWithLipgloss(
styles.BaseStyle().
Width(m.width).
Render(
lipgloss.JoinVertical(
lipgloss.Top,
@@ -212,11 +158,12 @@ func (m *messagesCmp) View() string {
lipgloss.JoinVertical(
lipgloss.Top,
"Loading...",
// m.working(),
m.working(),
m.help(),
),
)
}
if len(m.app.Messages) == 0 {
content := baseStyle.
Width(m.width).
@@ -243,7 +190,7 @@ func (m *messagesCmp) View() string {
lipgloss.JoinVertical(
lipgloss.Top,
m.viewport.View(),
// m.working(),
m.working(),
m.help(),
),
)
@@ -285,31 +232,31 @@ func hasUnfinishedToolCalls(messages []message.Message) bool {
return false
}
// func (m *messagesCmp) working() string {
// text := ""
// if m.IsAgentWorking() && len(m.app.Messages) > 0 {
// t := theme.CurrentTheme()
// baseStyle := styles.BaseStyle()
//
// task := "Thinking..."
// lastMessage := m.app.Messages[len(m.app.Messages)-1]
// if hasToolsWithoutResponse(m.app.Messages) {
// task = "Waiting for tool response..."
// } else if hasUnfinishedToolCalls(m.app.Messages) {
// task = "Building tool call..."
// } else if !lastMessage.IsFinished() {
// task = "Generating..."
// }
// if task != "" {
// text += baseStyle.
// Width(m.width).
// Foreground(t.Primary()).
// Bold(true).
// Render(fmt.Sprintf("%s %s ", m.spinner.View(), task))
// }
// }
// return text
// }
func (m *messagesCmp) working() string {
text := ""
if len(m.app.Messages) > 0 {
t := theme.CurrentTheme()
baseStyle := styles.BaseStyle()
task := "Working..."
// lastMessage := m.app.Messages[len(m.app.Messages)-1]
// if hasToolsWithoutResponse(m.app.Messages) {
// task = "Waiting for tool response..."
// } else if hasUnfinishedToolCalls(m.app.Messages) {
// task = "Building tool call..."
// } else if !lastMessage.IsFinished() {
// task = "Generating..."
// }
if task != "" {
text += baseStyle.
Width(m.width).
Foreground(t.Primary()).
Bold(true).
Render(fmt.Sprintf("%s %s ", m.spinner.View(), task))
}
}
return text
}
func (m *messagesCmp) help() string {
t := theme.CurrentTheme()

View File

@@ -86,7 +86,7 @@ func (m *sidebarCmp) sessionSection() string {
sessionValue := baseStyle.
Foreground(t.Text()).
Render(fmt.Sprintf(": %s", m.app.CurrentSessionOLD.Title))
Render(fmt.Sprintf(": %s", m.app.Session.Title))
return sessionKey + sessionValue
}

View File

@@ -2,7 +2,6 @@ package tui
import (
"context"
"encoding/json"
"log/slog"
"strings"
@@ -267,85 +266,27 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
}
case client.EventStorageWrite:
parts := strings.Split(msg.Key, "/")
if len(parts) < 3 {
return a, nil
}
if parts[0] == "session" && parts[1] == "info" {
sessionId := parts[2]
if sessionId == a.app.Session.Id {
var sessionInfo client.SessionInfo
bytes, _ := json.Marshal(msg.Content)
if err := json.Unmarshal(bytes, &sessionInfo); err != nil {
status.Error(err.Error())
return a, nil
case client.EventMessageUpdated:
if msg.Properties.Info.Metadata.SessionID == a.app.Session.Id {
for i, m := range a.app.Messages {
if m.Id == msg.Properties.Info.Id {
a.app.Messages[i] = msg.Properties.Info
slog.Debug("Updated message", "message", msg.Properties.Info)
return a.updateAllPages(state.StateUpdatedMsg{State: nil})
}
a.app.Session = &sessionInfo
}
return a.updateAllPages(state.StateUpdatedMsg{State: a.app.State})
a.app.Messages = append(a.app.Messages, msg.Properties.Info)
slog.Debug("Appended message", "message", msg.Properties.Info)
return a.updateAllPages(state.StateUpdatedMsg{State: nil})
}
if parts[0] == "session" && parts[1] == "message" {
sessionId := parts[2]
if sessionId == a.app.Session.Id {
messageId := parts[3]
var message client.MessageInfo
bytes, _ := json.Marshal(msg.Content)
if err := json.Unmarshal(bytes, &message); err != nil {
status.Error(err.Error())
return a, nil
}
for i, m := range a.app.Messages {
if m.Id == messageId {
a.app.Messages[i] = message
slog.Debug("Updated message", "message", message)
return a.updateAllPages(state.StateUpdatedMsg{State: a.app.State})
}
}
a.app.Messages = append(a.app.Messages, message)
slog.Debug("Appended message", "message", message)
// a.app.CurrentSession.MessageCount++
// a.app.CurrentSession.PromptTokens += message.PromptTokens
// a.app.CurrentSession.CompletionTokens += message.CompletionTokens
// a.app.CurrentSession.Cost += message.Cost
// a.app.CurrentSession.UpdatedAt = message.CreatedAt
}
return a.updateAllPages(state.StateUpdatedMsg{State: a.app.State})
case client.EventSessionUpdated:
if msg.Properties.Info.Id == a.app.Session.Id {
a.app.Session = &msg.Properties.Info
return a.updateAllPages(state.StateUpdatedMsg{State: nil})
}
// log key and content
slog.Debug("Received SSE event", "key", msg.Key, "content", msg.Content)
current := a.app.State
for i, part := range parts {
if i == len(parts)-1 {
current[part] = msg.Content
} else {
if _, exists := current[part]; !exists {
current[part] = make(map[string]any)
}
nextLevel, ok := current[part].(map[string]any)
if !ok {
current[part] = make(map[string]any)
nextLevel = current[part].(map[string]any)
}
current = nextLevel
}
}
// Trigger UI update by updating all pages with the new state
return a.updateAllPages(state.StateUpdatedMsg{State: a.app.State})
case dialog.CloseQuitMsg:
a.showQuit = false
return a, nil