Initial commit (part 2)

I added some code
and comments too
it's almost set up
for me and you
This commit is contained in:
Moby von Briesen 2023-04-22 14:39:54 -04:00
parent f0893ed8b8
commit a570437b9c
6 changed files with 160 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.swp
pal

7
Makefile Normal file
View File

@ -0,0 +1,7 @@
SHELL := /bin/bash
build:
go build -v -o pal ./cmd
run:
go run ./cmd/

7
cmd/main.go Normal file
View File

@ -0,0 +1,7 @@
package main
import "fmt"
func main() {
fmt.Println("hello")
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module github.com/mobyvb/pull-pal
go 1.20

115
pullpal/common.go Normal file
View File

@ -0,0 +1,115 @@
package pullpal
import (
"bytes"
"strings"
"text/template"
)
// PullPal is the service responsible for:
// * Interacting with git server (e.g. reading issues and making PRs on Github)
// * Generating LLM prompts
// * Parsing LLM responses
// * Interacting with LLM (e.g. with GPT via OpenAI API)
type PullPal struct {
}
// File represents a file in a git repository.
type File struct {
Path string
Contents string
}
// CodeChangeRequest contains all necessary information for generating a prompt for a LLM.
type CodeChangeRequest struct {
Files []File
Subject string
Body string
}
// String is the string representation of a CodeChangeRequest. Functionally, it contains the LLM prompt.
func (req CodeChangeRequest) String() string {
prompt := req.MustGetPrompt()
return "START OF PROMPT\n" + prompt + "\nEND OF PROMPT"
}
// MustGetPrompt only returns the prompt, but panics if the data in the request cannot populate the template.
func (req CodeChangeRequest) MustGetPrompt() string {
prompt, err := req.GetPrompt()
if err != nil {
panic(err)
}
return prompt
}
// GetPrompt converts the information in the request to a prompt for an LLM.
func (req CodeChangeRequest) GetPrompt() (string, error) {
tmpl, err := template.ParseFiles("../template/code-change-request.tmpl")
if err != nil {
return "", err
}
var result bytes.Buffer
err = tmpl.Execute(&result, req)
if err != nil {
return "", err
}
return result.String(), nil
}
// CodeChangeResponse contains data derived from an LLM response to a prompt generated via a CodeChangeRequest.
type CodeChangeResponse struct {
Files []File
Notes string
}
// String is a string representation of CodeChangeResponse.
func (res CodeChangeResponse) String() string {
out := "Notes:\n"
out += res.Notes + "\n\n"
out += "Files:\n"
for _, f := range res.Files {
out += f.Path + ":\n```\n"
out += f.Contents + "\n```\n"
}
return out
}
// ParseCodeChangeResponse parses the LLM's response to CodeChangeRequest (string) into a CodeChangeResponse.
func ParseCodeChangeResponse(llmResponse string) CodeChangeResponse {
sections := strings.Split(llmResponse, "Notes:")
filesSection := sections[0]
notes := strings.TrimSpace(sections[1])
files := parseFiles(filesSection)
return CodeChangeResponse{
Files: files,
Notes: notes,
}
}
// parseFiles process the "files" subsection of the LLM's response. It is a helper for GetCodeChangeResponse.
func parseFiles(filesSection string) []File {
fileStringList := strings.Split(filesSection, "name:")
// first item in the list is just gonna be "Files:"
fileStringList = fileStringList[1:]
fileList := make([]File, len(fileStringList))
for i, f := range fileStringList {
fileParts := strings.Split(f, "contents:")
path := strings.TrimSpace(fileParts[0])
contents := strings.TrimSpace(fileParts[1])
contents = strings.Trim(contents, "```")
fileList[i] = File{
Path: path,
Contents: contents,
}
}
return fileList
}

View File

@ -0,0 +1,26 @@
Files:
{{ range $index, $file := .Files }}
- name: {{ $file.Path }}:
contents:
```
{{ $file.Contents }}
```
{{ end }}
Modify the files above to accomplish the following task:
Subject: {{ .Subject }}
Body:
{{ .Body }}
Respond in the exact format:
Files:
{{ range $index, $file := .Files }}
- name: {{ $file.Path }}
contents:
```
[new {{ $file.Path }} contents]
```
{{ end }}
Notes:
[additional context about your changes]