diff --git a/chat.proto b/chat.proto index f2154eb..4f50fbb 100644 --- a/chat.proto +++ b/chat.proto @@ -4,11 +4,11 @@ package chatpb; import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp -message Row { +message Row { // `autogenpb:nomutex` repeated string fields = 1; } -message Table { +message Table { // `autogenpb:nomutex` int32 columns = 1; repeated Row rows = 2; } @@ -20,7 +20,7 @@ enum Who { } // NEW: A message to hold all the details of a tool call -message ToolCall { +message ToolCall { // `autogenpb:nomutex` string name = 1; // e.g., "Shell" string input = 2; // The command that was run string description = 3; // The description for the command @@ -29,12 +29,12 @@ message ToolCall { int32 exit_code = 6; } -message CodeSnippet { +message CodeSnippet { // `autogenpb:nomutex` string filename = 1; string content = 2; } -message Chat { +message Chat { // `autogenpb:nomutex` Who from = 1; google.protobuf.Timestamp ctime = 2; string content = 3; diff --git a/config.go b/config.go index 0db21b1..0d5d3c0 100644 --- a/config.go +++ b/config.go @@ -86,7 +86,9 @@ func (all *Chats) ConfigLoad() error { // this means the gemini.pb file exists and was read if len(data) == 0 { // todo: add default data here since it's blank? // might cause nil panic? - return errors.New("chatpb.ConfigLoad() gemini.pb is empty") + all.AddGeminiComment("I like astronomy") + log.Info(errors.New("chatpb.ConfigLoad() gemini.pb is empty")) + return nil } err = all.Unmarshal(data) test := NewChats() diff --git a/helpers.go b/helpers.go index 8f63de0..7841e87 100644 --- a/helpers.go +++ b/helpers.go @@ -1,8 +1,14 @@ package chatpb import ( + "fmt" + "os" + "path/filepath" "time" + "github.com/google/uuid" + "go.wit.com/log" + "google.golang.org/protobuf/proto" timestamppb "google.golang.org/protobuf/types/known/timestamppb" ) @@ -40,3 +46,67 @@ func UnmarshalChatsTEXT(data []byte) (*Chats, error) { err := c.UnmarshalTEXT(data) return c, err } + +func (all *Chats) AddFile(filename string) error { + data, err := os.ReadFile(filename) + if err != nil { + log.Fatalf("Error reading file %s: %v", filename, err) + return err + } + + logData, err := UnmarshalChatsTEXT(data) + if err != nil { + log.Fatalf("Error unmarshaling log file %s: %v", filename, err) + return err + } + + for _, chat := range logData.GetChats() { + // make a copy + newc := proto.Clone(chat).(*Chat) + + // 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) + + 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) + } + } else { + // Fallback for older log formats. + content = chat.GetContent() + } + newc.Content = content + newc.VerifyUuid() + all.AppendByUuid(newc) + } + + return nil +} + +func (chats *Chats) VerifyUuids() bool { + var changed bool + + all := chats.SortByUuid() + for all.Scan() { + chat := all.Next() + if chat.Uuid == "" { + chat.Uuid = uuid.New().String() + changed = true + } + } + return changed +} + +func (c *Chat) VerifyUuid() bool { + if c.Uuid == "" { + c.Uuid = uuid.New().String() + return true + } + return false +}