summaryrefslogtreecommitdiff
path: root/helpers.go
diff options
context:
space:
mode:
Diffstat (limited to 'helpers.go')
-rw-r--r--helpers.go104
1 files changed, 83 insertions, 21 deletions
diff --git a/helpers.go b/helpers.go
index 5b42533..826ef48 100644
--- a/helpers.go
+++ b/helpers.go
@@ -48,6 +48,14 @@ func UnmarshalChatsTEXT(data []byte) (*Chats, error) {
}
func (all *Chats) AddFile(filename string) error {
+ // Nil checks for safety.
+ if all == nil {
+ return fmt.Errorf("cannot call AddFile on a nil *Chats object")
+ }
+ if all.Chats == nil {
+ all.Chats = make([]*Chat, 0)
+ }
+
data, err := os.ReadFile(filename)
if err != nil {
log.Fatalf("Error reading file %s: %v", filename, err)
@@ -60,35 +68,89 @@ func (all *Chats) AddFile(filename string) error {
return err
}
- for _, chat := range logData.GetChats() {
- // make a copy
- newc := proto.Clone(chat).(*Chat)
+ // Iterate through the top-level messages from the source file.
+ for _, chatGroup := range logData.GetChats() {
+ if len(chatGroup.GetEntries()) > 0 {
+ // NEW FORMAT: This is a group, process its entries.
+ for _, entry := range chatGroup.GetEntries() {
+ // Convert the ChatEntry into a new Chat object for the flat list.
+ newChat := convertEntryToChat(entry, filename)
+ if newChat != nil {
+ newChat.VerifyUuid()
+ all.AppendByUuid(newChat)
+ }
+ }
+ } else {
+ // OLD FORMAT: This is a single, flat Chat message.
+ // We still process it to handle its external content file correctly.
+ newChat := convertChatToChat(chatGroup, filename)
+ if newChat != nil {
+ newChat.VerifyUuid()
+ all.AppendByUuid(newChat)
+ }
+ }
+ }
+ return nil
+}
- // Handle content: prefer content_file, fallback to content.
- var content string
- if contentFile := chat.GetContentFile(); contentFile != "" {
- // Construct the full path relative to the log file's directory.
- logDir := filepath.Dir(filename)
- contentPath := filepath.Join(logDir, contentFile)
+// convertChatToChat handles an old-style Chat message. It creates a clean
+// copy and resolves its external content file.
+func convertChatToChat(chat *Chat, filename string) *Chat {
+ if chat == nil {
+ return nil
+ }
- contentBytes, err := os.ReadFile(contentPath)
- if err != nil {
- content = fmt.Sprintf("--- ERROR: Could not read content file %s: %v ---", contentPath, err)
- } else {
- content = string(contentBytes)
- }
+ // Manually create a ChatEntry from the Chat fields to reuse the logic.
+ entry := &ChatEntry{
+ From: chat.GetFrom(),
+ Ctime: chat.GetCtime(),
+ Content: chat.GetContent(),
+ Table: chat.GetTable(),
+ ToolCalls: chat.GetToolCalls(),
+ ContentFile: chat.GetContentFile(),
+ Uuid: chat.GetUuid(),
+ Snippets: chat.GetSnippets(),
+ }
+ return convertEntryToChat(entry, filename)
+}
+
+// convertEntryToChat creates a new Chat object from a ChatEntry's data
+// and resolves its external content file.
+func convertEntryToChat(entry *ChatEntry, filename string) *Chat {
+ if entry == nil {
+ return nil
+ }
+
+ // Create a new Chat object and copy the fields.
+ newChat := &Chat{
+ From: entry.GetFrom(),
+ Ctime: entry.GetCtime(),
+ Table: entry.GetTable(),
+ ToolCalls: entry.GetToolCalls(),
+ Snippets: entry.GetSnippets(),
+ Uuid: entry.GetUuid(),
+ }
+
+ // Handle content: prefer content_file, fallback to content.
+ var content string
+ if contentFile := entry.GetContentFile(); contentFile != "" {
+ logDir := filepath.Dir(filename)
+ contentPath := filepath.Join(logDir, contentFile)
+ contentBytes, err := os.ReadFile(contentPath)
+ if err != nil {
+ content = fmt.Sprintf("--- ERROR: Could not read content file %s: %v ---", contentPath, err)
} else {
- // Fallback for older log formats.
- content = chat.GetContent()
+ content = string(contentBytes)
}
- newc.Content = content
- newc.VerifyUuid()
- all.AppendNew(newc)
+ } else {
+ content = entry.GetContent()
}
+ newChat.Content = content
- return nil
+ return newChat
}
+
func (chats *Chats) VerifyUuids() bool {
var changed bool