TUI refactor
- Clean up, improved startup logic, initial conversation load - Moved converation/message business logic (mostly) into `model/tui`
This commit is contained in:
@@ -15,7 +15,7 @@ func (m *Model) HandleResize(width, height int) {
|
||||
m.Width, m.Height = width, height
|
||||
m.content.Width = width
|
||||
m.input.SetWidth(width - m.input.FocusedStyle.Base.GetHorizontalFrameSize())
|
||||
if len(m.messages) > 0 {
|
||||
if len(m.App.Messages) > 0 {
|
||||
m.rebuildMessageCache()
|
||||
m.updateContent()
|
||||
}
|
||||
@@ -36,26 +36,21 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
// wake up spinners and cursors
|
||||
cmds = append(cmds, cursor.Blink, m.spinner.Tick)
|
||||
|
||||
if m.Shared.Values.ConvShortname != "" {
|
||||
// (re)load conversation contents
|
||||
cmds = append(cmds, m.loadConversation(m.Shared.Values.ConvShortname))
|
||||
|
||||
if m.conversation.ShortName.String != m.Shared.Values.ConvShortname {
|
||||
// clear existing messages if we're loading a new conversation
|
||||
m.messages = []api.Message{}
|
||||
m.selectedMessage = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh view
|
||||
m.rebuildMessageCache()
|
||||
m.updateContent()
|
||||
|
||||
if m.App.Conversation != nil && m.App.Conversation.ID > 0 {
|
||||
// (re)load conversation contents
|
||||
cmds = append(cmds, m.loadConversationMessages())
|
||||
}
|
||||
case tuiutil.MsgTempfileEditorClosed:
|
||||
contents := string(msg)
|
||||
switch m.editorTarget {
|
||||
case input:
|
||||
m.input.SetValue(contents)
|
||||
case selectedMessage:
|
||||
toEdit := m.messages[m.selectedMessage]
|
||||
toEdit := m.App.Messages[m.selectedMessage]
|
||||
if toEdit.Content != contents {
|
||||
toEdit.Content = contents
|
||||
m.setMessage(m.selectedMessage, toEdit)
|
||||
@@ -66,18 +61,18 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
}
|
||||
}
|
||||
case msgConversationLoaded:
|
||||
m.conversation = msg.conversation
|
||||
m.rootMessages = msg.rootMessages
|
||||
m.App.Conversation = msg.conversation
|
||||
m.App.RootMessages = msg.rootMessages
|
||||
m.selectedMessage = -1
|
||||
if len(m.rootMessages) > 0 {
|
||||
if len(m.App.RootMessages) > 0 {
|
||||
cmds = append(cmds, m.loadConversationMessages())
|
||||
}
|
||||
case msgMessagesLoaded:
|
||||
m.messages = msg
|
||||
m.App.Messages = msg
|
||||
if m.selectedMessage == -1 {
|
||||
m.selectedMessage = len(msg) - 1
|
||||
} else {
|
||||
m.selectedMessage = min(m.selectedMessage, len(m.messages))
|
||||
m.selectedMessage = min(m.selectedMessage, len(m.App.Messages))
|
||||
}
|
||||
m.rebuildMessageCache()
|
||||
m.updateContent()
|
||||
@@ -88,10 +83,10 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
break
|
||||
}
|
||||
|
||||
last := len(m.messages) - 1
|
||||
if last >= 0 && m.messages[last].Role.IsAssistant() {
|
||||
last := len(m.App.Messages) - 1
|
||||
if last >= 0 && m.App.Messages[last].Role.IsAssistant() {
|
||||
// append chunk to existing message
|
||||
m.setMessageContents(last, m.messages[last].Content+msg.Content)
|
||||
m.setMessageContents(last, m.App.Messages[last].Content+msg.Content)
|
||||
} else {
|
||||
// use chunk in a new message
|
||||
m.addMessage(api.Message{
|
||||
@@ -113,12 +108,12 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
reply := (*api.Message)(msg)
|
||||
reply.Content = strings.TrimSpace(reply.Content)
|
||||
|
||||
last := len(m.messages) - 1
|
||||
last := len(m.App.Messages) - 1
|
||||
if last < 0 {
|
||||
panic("Unexpected empty messages handling msgAssistantReply")
|
||||
}
|
||||
|
||||
if m.messages[last].Role.IsAssistant() {
|
||||
if m.App.Messages[last].Role.IsAssistant() {
|
||||
// TODO: handle continuations gracefully - some models support them well, others fail horribly.
|
||||
m.setMessage(last, *reply)
|
||||
} else {
|
||||
@@ -136,7 +131,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
cmds = append(cmds, m.persistConversation())
|
||||
}
|
||||
|
||||
if m.conversation.Title == "" {
|
||||
if m.App.Conversation.Title == "" {
|
||||
cmds = append(cmds, m.generateConversationTitle())
|
||||
}
|
||||
|
||||
@@ -149,12 +144,12 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
m.Shared.Err = error(msg)
|
||||
m.updateContent()
|
||||
case msgToolResults:
|
||||
last := len(m.messages) - 1
|
||||
last := len(m.App.Messages) - 1
|
||||
if last < 0 {
|
||||
panic("Unexpected empty messages handling msgAssistantReply")
|
||||
}
|
||||
|
||||
if m.messages[last].Role != api.MessageRoleToolCall {
|
||||
if m.App.Messages[last].Role != api.MessageRoleToolCall {
|
||||
panic("Previous message not a tool call, unexpected")
|
||||
}
|
||||
|
||||
@@ -170,29 +165,29 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
m.updateContent()
|
||||
case msgConversationTitleGenerated:
|
||||
title := string(msg)
|
||||
m.conversation.Title = title
|
||||
m.App.Conversation.Title = title
|
||||
if m.persistence {
|
||||
cmds = append(cmds, m.updateConversationTitle(m.conversation))
|
||||
cmds = append(cmds, m.updateConversationTitle(m.App.Conversation))
|
||||
}
|
||||
case cursor.BlinkMsg:
|
||||
if m.state == pendingResponse {
|
||||
// ensure we show the updated "wait for response" cursor blink state
|
||||
last := len(m.messages)-1
|
||||
last := len(m.App.Messages) - 1
|
||||
m.messageCache[last] = m.renderMessage(last)
|
||||
m.updateContent()
|
||||
}
|
||||
case msgConversationPersisted:
|
||||
m.conversation = msg.conversation
|
||||
m.messages = msg.messages
|
||||
m.App.Conversation = msg.conversation
|
||||
m.App.Messages = msg.messages
|
||||
if msg.isNew {
|
||||
m.rootMessages = []api.Message{m.messages[0]}
|
||||
m.App.RootMessages = []api.Message{m.App.Messages[0]}
|
||||
}
|
||||
m.rebuildMessageCache()
|
||||
m.updateContent()
|
||||
case msgMessageCloned:
|
||||
if msg.Parent == nil {
|
||||
m.conversation = msg.Conversation
|
||||
m.rootMessages = append(m.rootMessages, *msg)
|
||||
m.App.Conversation = msg.Conversation
|
||||
m.App.RootMessages = append(m.App.RootMessages, *msg)
|
||||
}
|
||||
cmds = append(cmds, m.loadConversationMessages())
|
||||
case msgSelectedRootCycled, msgSelectedReplyCycled, msgMessageUpdated:
|
||||
|
||||
Reference in New Issue
Block a user