diff --git a/cmd/chat.go b/cmd/chat.go index e324199..e1a84e1 100644 --- a/cmd/chat.go +++ b/cmd/chat.go @@ -20,6 +20,7 @@ const ( ) var chatCmd = &cobra.Command{ + Use: "chat", Short: "Interact with your agent.", Long: `This cli tool allows you to debug your agent by chatting with it locally.`, Run: agentChat, @@ -74,10 +75,3 @@ func agentChat(cmd *cobra.Command, args []string) { fmt.Println(err) } } - -func Execute() { - err := chatCmd.Execute() - if err != nil { - os.Exit(1) - } -} diff --git a/cmd/rootCmd.go b/cmd/rootCmd.go new file mode 100644 index 0000000..64b6c1a --- /dev/null +++ b/cmd/rootCmd.go @@ -0,0 +1,31 @@ +// rootCmd.go +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "gh-debug-cli", + Short: "A CLI tool for debugging", + Long: `This CLI tool allows you to debug your agent by chatting with it locally.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Use 'gh-debug-cli --help' to see available commands") + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +func init() { + // Add subcommands to rootCmd + rootCmd.AddCommand(chatCmd) + rootCmd.AddCommand(streamCmd) +} diff --git a/cmd/stream.go b/cmd/stream.go new file mode 100644 index 0000000..24bf21b --- /dev/null +++ b/cmd/stream.go @@ -0,0 +1,38 @@ +// stream.go +package cmd + +import ( + "fmt" + "os" + + "github.com/github-technology-partners/gh-debug-cli/pkg/stream" + "github.com/spf13/cobra" +) + +const ( + streamCmdFileFlag = "file" +) + +// streamCmd represents the new command for streaming functionality +var streamCmd = &cobra.Command{ + Use: "stream [file]", + Short: "Stream data to your agent", + Long: `The stream command allows you to initiate a data stream to your agent.`, + Run: agentStream, +} + +func init() { + streamCmd.PersistentFlags().String(streamCmdFileFlag, "", "Parse agent responses from a file") +} + +func agentStream(cmd *cobra.Command, args []string) { + fmt.Println("stream command executed successfully") + + file := args[0] + + err := stream.ParseFile(file) + if err != nil { + fmt.Fprintf(os.Stderr, "Error parsing file: %v\n", err) + os.Exit(1) + } +} diff --git a/pkg/stream/parse.go b/pkg/stream/parse.go new file mode 100644 index 0000000..e1929ae --- /dev/null +++ b/pkg/stream/parse.go @@ -0,0 +1,75 @@ +package stream + +import ( + "bufio" + "encoding/json" + "fmt" + "os" + "strings" +) + +type Choice struct { + Delta struct { + Content string `json:"content"` + } `json:"delta"` +} + +type Data struct { + Choices []Choice `json:"choices"` +} + +func ParseFile(filename string) error { + // Open the file + file, err := os.Open(filename) + if err != nil { + return fmt.Errorf("could not open file: %w", err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + var contentBuilder strings.Builder + + for scanner.Scan() { + line := scanner.Text() + + // Check if the line has "data: " prefix + if strings.HasPrefix(line, "data: ") { + // Remove the "data: " prefix + line = strings.TrimPrefix(line, "data: ") + } else { + continue // skip lines without "data: " + } + + // Handle special cases + if line == "[DONE]" { + break // stop processing if we encounter [DONE] + } + if line == "" { + continue // skip empty data lines + } + + // Parse the JSON line into our `Data` struct + var data Data + err := json.Unmarshal([]byte(line), &data) + if err != nil { + // Skip this line if JSON is incomplete or malformed + continue + } + + // Extract delta.content and concatenate it + for _, choice := range data.Choices { + contentBuilder.WriteString(choice.Delta.Content) + } + } + + // Check for scanner errors + if err := scanner.Err(); err != nil { + return fmt.Errorf("error reading file: %w", err) + } + + // Print the final concatenated result + result := contentBuilder.String() + fmt.Println(result) + + return nil +}