Part data model (#950)

This commit is contained in:
Dax
2025-07-13 17:22:11 -04:00
committed by GitHub
parent 736396fc70
commit 90d6c4ab41
27 changed files with 1447 additions and 965 deletions

View File

@@ -5,6 +5,7 @@ import (
"log/slog"
"os"
"os/exec"
"slices"
"strings"
"time"
@@ -364,55 +365,76 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case opencode.EventListResponseEventSessionDeleted:
if a.app.Session != nil && msg.Properties.Info.ID == a.app.Session.ID {
a.app.Session = &opencode.Session{}
a.app.Messages = []opencode.MessageUnion{}
a.app.Messages = []app.Message{}
}
return a, toast.NewSuccessToast("Session deleted successfully")
case opencode.EventListResponseEventSessionUpdated:
if msg.Properties.Info.ID == a.app.Session.ID {
a.app.Session = &msg.Properties.Info
}
case opencode.EventListResponseEventMessagePartUpdated:
slog.Info("message part updated", "message", msg.Properties.Part.MessageID, "part", msg.Properties.Part.ID)
if msg.Properties.Part.SessionID == a.app.Session.ID {
messageIndex := slices.IndexFunc(a.app.Messages, func(m app.Message) bool {
switch casted := m.Info.(type) {
case opencode.UserMessage:
return casted.ID == msg.Properties.Part.MessageID
case opencode.AssistantMessage:
return casted.ID == msg.Properties.Part.MessageID
}
return false
})
if messageIndex > -1 {
message := a.app.Messages[messageIndex]
partIndex := slices.IndexFunc(message.Parts, func(p opencode.PartUnion) bool {
switch casted := p.(type) {
case opencode.TextPart:
return casted.ID == msg.Properties.Part.ID
case opencode.FilePart:
return casted.ID == msg.Properties.Part.ID
case opencode.ToolPart:
return casted.ID == msg.Properties.Part.ID
case opencode.StepStartPart:
return casted.ID == msg.Properties.Part.ID
case opencode.StepFinishPart:
return casted.ID == msg.Properties.Part.ID
}
return false
})
if partIndex > -1 {
message.Parts[partIndex] = msg.Properties.Part.AsUnion()
}
if partIndex == -1 {
message.Parts = append(message.Parts, msg.Properties.Part.AsUnion())
}
a.app.Messages[messageIndex] = message
}
}
case opencode.EventListResponseEventMessageUpdated:
if msg.Properties.Info.SessionID == a.app.Session.ID {
exists := false
optimisticReplaced := false
matchIndex := slices.IndexFunc(a.app.Messages, func(m app.Message) bool {
switch casted := m.Info.(type) {
case opencode.UserMessage:
return casted.ID == msg.Properties.Info.ID
case opencode.AssistantMessage:
return casted.ID == msg.Properties.Info.ID
}
return false
})
// First check if this is replacing an optimistic message
if msg.Properties.Info.Role == opencode.MessageRoleUser {
// Look for optimistic messages to replace
for i, m := range a.app.Messages {
switch m := m.(type) {
case opencode.UserMessage:
if strings.HasPrefix(m.ID, "optimistic-") && m.Role == opencode.UserMessageRoleUser {
// Replace the optimistic message with the real one
a.app.Messages[i] = msg.Properties.Info.AsUnion()
exists = true
optimisticReplaced = true
break
}
}
if matchIndex > -1 {
match := a.app.Messages[matchIndex]
a.app.Messages[matchIndex] = app.Message{
Info: msg.Properties.Info.AsUnion(),
Parts: match.Parts,
}
}
// If not replacing optimistic, check for existing message with same ID
if !optimisticReplaced {
for i, m := range a.app.Messages {
var id string
switch m := m.(type) {
case opencode.UserMessage:
id = m.ID
case opencode.AssistantMessage:
id = m.ID
}
if id == msg.Properties.Info.ID {
a.app.Messages[i] = msg.Properties.Info.AsUnion()
exists = true
break
}
}
}
if !exists {
a.app.Messages = append(a.app.Messages, msg.Properties.Info.AsUnion())
if matchIndex == -1 {
a.app.Messages = append(a.app.Messages, app.Message{
Info: msg.Properties.Info.AsUnion(),
Parts: []opencode.PartUnion{},
})
}
}
case opencode.EventListResponseEventSessionError:
@@ -473,10 +495,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return a, toast.NewErrorToast("Failed to open session")
}
a.app.Session = msg
a.app.Messages = make([]opencode.MessageUnion, 0)
for _, message := range messages {
a.app.Messages = append(a.app.Messages, message.AsUnion())
}
a.app.Messages = messages
return a, util.CmdHandler(app.SessionLoadedMsg{})
case app.ModelSelectedMsg:
a.app.Provider = &msg.Provider
@@ -837,7 +856,7 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
return a, nil
}
a.app.Session = &opencode.Session{}
a.app.Messages = []opencode.MessageUnion{}
a.app.Messages = []app.Message{}
cmds = append(cmds, util.CmdHandler(app.SessionClearedMsg{}))
case commands.SessionListCommand:
sessionDialog := dialog.NewSessionDialog(a.app)