feat: include file content in llm prompt context (#13)
This commit is contained in:
parent
a49254c9ed
commit
93ef37bba6
@ -18,14 +18,28 @@ type Forge struct {
|
|||||||
client *gitea.Client
|
client *gitea.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProject implements port.Forge.
|
// GetFile implements port.Forge.
|
||||||
func (f *Forge) GetProject(ctx context.Context, rawProjectID string) (*model.Project, error) {
|
func (f *Forge) GetFile(ctx context.Context, rawProjectID string, path string) ([]byte, error) {
|
||||||
projectID, err := strconv.ParseInt(rawProjectID, 10, 64)
|
project, err := f.getProject(rawProjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithStack(err)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
project, _, err := f.client.GetRepoByID(projectID)
|
data, res, err := f.client.GetFile(project.Owner.UserName, project.Name, project.DefaultBranch, path)
|
||||||
|
if err != nil {
|
||||||
|
if res.StatusCode == http.StatusNotFound {
|
||||||
|
return nil, errors.WithStack(port.ErrFileNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProject implements port.Forge.
|
||||||
|
func (f *Forge) GetProject(ctx context.Context, rawProjectID string) (*model.Project, error) {
|
||||||
|
project, err := f.getProject(rawProjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithStack(err)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
@ -39,12 +53,7 @@ func (f *Forge) GetProject(ctx context.Context, rawProjectID string) (*model.Pro
|
|||||||
|
|
||||||
// GetProjectLanguages implements port.Forge.
|
// GetProjectLanguages implements port.Forge.
|
||||||
func (f *Forge) GetProjectLanguages(ctx context.Context, rawProjectID string) ([]string, error) {
|
func (f *Forge) GetProjectLanguages(ctx context.Context, rawProjectID string) ([]string, error) {
|
||||||
projectID, err := strconv.ParseInt(rawProjectID, 10, 64)
|
project, err := f.getProject(rawProjectID)
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
project, _, err := f.client.GetRepoByID(projectID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithStack(err)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
@ -65,12 +74,7 @@ func (f *Forge) GetProjectLanguages(ctx context.Context, rawProjectID string) ([
|
|||||||
|
|
||||||
// CreateIssue implements port.Forge.
|
// CreateIssue implements port.Forge.
|
||||||
func (f *Forge) CreateIssue(ctx context.Context, rawProjectID string, title string, body string) (string, error) {
|
func (f *Forge) CreateIssue(ctx context.Context, rawProjectID string, title string, body string) (string, error) {
|
||||||
projectID, err := strconv.ParseInt(rawProjectID, 10, 64)
|
project, err := f.getProject(rawProjectID)
|
||||||
if err != nil {
|
|
||||||
return "", errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
project, _, err := f.client.GetRepoByID(projectID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.WithStack(err)
|
return "", errors.WithStack(err)
|
||||||
}
|
}
|
||||||
@ -88,36 +92,17 @@ func (f *Forge) CreateIssue(ctx context.Context, rawProjectID string, title stri
|
|||||||
|
|
||||||
// GetIssueTemplate implements port.Forge.
|
// GetIssueTemplate implements port.Forge.
|
||||||
func (f *Forge) GetIssueTemplate(ctx context.Context, rawProjectID string) (string, error) {
|
func (f *Forge) GetIssueTemplate(ctx context.Context, rawProjectID string) (string, error) {
|
||||||
projectID, err := strconv.ParseInt(rawProjectID, 10, 64)
|
data, err := f.GetFile(ctx, rawProjectID, ".gitea/issue_template.md")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.WithStack(err)
|
return "", errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
project, _, err := f.client.GetRepoByID(projectID)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
data, res, err := f.client.GetFile(project.Owner.UserName, project.Name, project.DefaultBranch, ".gitea/issue_template.md")
|
|
||||||
if err != nil {
|
|
||||||
if res.StatusCode == http.StatusNotFound {
|
|
||||||
return "", errors.WithStack(port.ErrFileNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(data), nil
|
return string(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssues implements port.Forge.
|
// GetIssues implements port.Forge.
|
||||||
func (f *Forge) GetIssues(ctx context.Context, rawProjectID string, issueIDs ...string) ([]*model.Issue, error) {
|
func (f *Forge) GetIssues(ctx context.Context, rawProjectID string, issueIDs ...string) ([]*model.Issue, error) {
|
||||||
projectID, err := strconv.ParseInt(rawProjectID, 10, 64)
|
project, err := f.getProject(rawProjectID)
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
project, _, err := f.client.GetRepoByID(projectID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithStack(err)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
@ -186,6 +171,20 @@ func (f *Forge) GetAllProjects(ctx context.Context) ([]*model.Project, error) {
|
|||||||
return projects, nil
|
return projects, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Forge) getProject(rawProjectID string) (*gitea.Repository, error) {
|
||||||
|
projectID, err := strconv.ParseInt(rawProjectID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
project, _, err := f.client.GetRepoByID(projectID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return project, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewForge(client *gitea.Client) *Forge {
|
func NewForge(client *gitea.Client) *Forge {
|
||||||
return &Forge{client: client}
|
return &Forge{client: client}
|
||||||
}
|
}
|
||||||
|
@ -18,4 +18,5 @@ type Forge interface {
|
|||||||
GetIssueTemplate(ctx context.Context, projectID string) (string, error)
|
GetIssueTemplate(ctx context.Context, projectID string) (string, error)
|
||||||
GetProjectLanguages(ctx context.Context, projectID string) ([]string, error)
|
GetProjectLanguages(ctx context.Context, projectID string) ([]string, error)
|
||||||
GetProject(ctx context.Context, projectID string) (*model.Project, error)
|
GetProject(ctx context.Context, projectID string) (*model.Project, error)
|
||||||
|
GetFile(ctx context.Context, projectID string, path string) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -220,6 +221,13 @@ func (m *IssueManager) extractResources(ctx context.Context, forge port.Forge, p
|
|||||||
|
|
||||||
resources = append(resources, issues...)
|
resources = append(resources, issues...)
|
||||||
|
|
||||||
|
files, err := m.extractFiles(ctx, forge, projectID, issueSummary)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not extract files")
|
||||||
|
}
|
||||||
|
|
||||||
|
resources = append(resources, files...)
|
||||||
|
|
||||||
return resources, nil
|
return resources, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,6 +264,36 @@ func (m *IssueManager) extractIssues(ctx context.Context, forge port.Forge, proj
|
|||||||
return resources, nil
|
return resources, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fileRefRegExp = regexp.MustCompile(`(?i)(?:\/[^\/]+)+\/?[^\s]+(?:\.[^\s]+)+|[^\s]+(?:\.[^\s]+)+`)
|
||||||
|
|
||||||
|
func (m *IssueManager) extractFiles(ctx context.Context, forge port.Forge, projectID string, issueSummary string) ([]*model.Resource, error) {
|
||||||
|
fileRefMatches := fileRefRegExp.FindAllStringSubmatch(issueSummary, -1)
|
||||||
|
|
||||||
|
paths := make([]string, 0, len(fileRefMatches))
|
||||||
|
for _, m := range fileRefMatches {
|
||||||
|
paths = append(paths, m[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
resources := make([]*model.Resource, 0)
|
||||||
|
|
||||||
|
for _, p := range paths {
|
||||||
|
data, err := forge.GetFile(ctx, projectID, p)
|
||||||
|
if err != nil {
|
||||||
|
slog.ErrorContext(ctx, "could not retrieve file", slog.Any("error", errors.WithStack(err)), slog.String("path", p))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
resources = append(resources, &model.Resource{
|
||||||
|
Name: p,
|
||||||
|
Type: "File",
|
||||||
|
Syntax: strings.TrimPrefix(filepath.Ext(p), "."),
|
||||||
|
Content: string(data),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return resources, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewIssueManager(llmClient llm.Client, forgeFactories ...ForgeFactory) *IssueManager {
|
func NewIssueManager(llmClient llm.Client, forgeFactories ...ForgeFactory) *IssueManager {
|
||||||
return &IssueManager{
|
return &IssueManager{
|
||||||
llmClient: llmClient,
|
llmClient: llmClient,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user