From b87c3ffc53704d669fc5285646749c805a932a2c Mon Sep 17 00:00:00 2001 From: Matt Low Date: Sun, 12 Nov 2023 23:32:12 +0000 Subject: [PATCH] Implement `lmcli view [conversation]` with completions Separate out logic to retrieve a message's "friendly" role (System, User, Assistant) --- pkg/cli/cmd.go | 32 +++++++++++++++++++++++++++++--- pkg/cli/conversation.go | 17 +++++++++++++++++ pkg/cli/store.go | 18 ++++++++++++++++++ pkg/cli/tty.go | 11 +---------- 4 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 pkg/cli/conversation.go diff --git a/pkg/cli/cmd.go b/pkg/cli/cmd.go index 157e99e..1cdc770 100644 --- a/pkg/cli/cmd.go +++ b/pkg/cli/cmd.go @@ -111,11 +111,36 @@ var lsCmd = &cobra.Command{ } var viewCmd = &cobra.Command{ - Use: "view", + Use: "view [conversation]", Short: "View messages in a conversation", - Long: `Displays all the messages in a coversation.`, + Long: `Finds a conversation by its short name and displays its contents.`, + Args: func(cmd *cobra.Command, args []string) error { + argCount := 1 + if err := cobra.MinimumNArgs(argCount)(cmd, args); err != nil { + return err + } + return nil + }, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Displaying conversation messages...") + shortName := args[0] + conversation, err := store.ConversationByShortName(shortName) + if conversation.ID == 0 { + Fatal("Conversation not found with short name: %s\n", shortName) + } + + messages, err := store.GetMessages(conversation) + if err != nil { + Fatal("Could not retrieve messages for conversation: %s\n", conversation.Title) + } + + l := len(messages) + for i, message := range messages { + message.RenderTTY(i < l-1) + } + fmt.Println() + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return store.ConverstionShortNameCompletions(toComplete), cobra.ShellCompDirectiveNoFileComp }, } @@ -239,6 +264,7 @@ func NewRootCmd() *cobra.Command { lsCmd, newCmd, promptCmd, + viewCmd, ) return rootCmd } diff --git a/pkg/cli/conversation.go b/pkg/cli/conversation.go new file mode 100644 index 0000000..7a3d1d0 --- /dev/null +++ b/pkg/cli/conversation.go @@ -0,0 +1,17 @@ +package cli + +// FriendlyRole returns a human friendly signifier for the message's role. +func (m *Message) FriendlyRole() string { + var friendlyRole string + switch m.Role { + case "user": + friendlyRole = "You" + case "system": + friendlyRole = "System" + case "assistant": + friendlyRole = "Assistant" + default: + friendlyRole = m.Role + } + return friendlyRole +} diff --git a/pkg/cli/store.go b/pkg/cli/store.go index 2bce9f4..63ce9f6 100644 --- a/pkg/cli/store.go +++ b/pkg/cli/store.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "time" sqids "github.com/sqids/sqids-go" @@ -95,6 +96,23 @@ func (s *Store) GetConversations() ([]Conversation, error) { return conversations, err } +func (s *Store) ConverstionShortNameCompletions(shortName string) []string { + var completions []string + conversations, _ := s.GetConversations() // ignore error for completions + for _, conversation := range conversations { + if shortName == "" || strings.HasPrefix(conversation.ShortName.String, shortName) { + completions = append(completions, fmt.Sprintf("%s\t%s", conversation.ShortName.String, conversation.Title)) + } + } + return completions +} + +func (s *Store) ConversationByShortName(shortName string) (*Conversation, error) { + var conversation Conversation + err := s.db.Where("short_name = ?", shortName).Find(&conversation).Error + return &conversation, err +} + func (s *Store) GetMessages(conversation *Conversation) ([]Message, error) { var messages []Message err := s.db.Where("conversation_id = ?", conversation.ID).Find(&messages).Error diff --git a/pkg/cli/tty.go b/pkg/cli/tty.go index 159da00..d25b849 100644 --- a/pkg/cli/tty.go +++ b/pkg/cli/tty.go @@ -59,16 +59,7 @@ func HandleDelayedResponse(response chan string) string { } func (m *Message) RenderTTY(paddingDown bool) { - var friendlyRole string - switch m.Role { - case "user": - friendlyRole = "You" - case "system": - friendlyRole = "System" - case "assistant": - friendlyRole = "Assistant" - } - fmt.Printf("<%s>\n\n", friendlyRole) + fmt.Printf("<%s>\n\n", m.FriendlyRole()) if m.OriginalContent != "" { fmt.Print(m.OriginalContent) }