-
Notifications
You must be signed in to change notification settings - Fork 14
Add stream cmd #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add stream cmd #10
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
|
Comment on lines
+55
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am actually not sure if we want to silently skip this. I'd want to know if the stream is invalid somehow. You will have to deal with two special case:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note; I see you made the updates to check for 1 and 2, but we are still silently skipping everything else. If we fail to parse any other data line it should fail and not continue.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I misunderstood. Will make a new pr to address |
||
| } | ||
|
|
||
| // 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) | ||
|
Comment on lines
+70
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need |
||
|
|
||
| return nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now it's fine, we may want to think in the future of how to handle this for other SSE even types.