diff --git a/agent/agent.go b/agent/agent.go index cd46c90..072ee60 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -245,20 +245,28 @@ func (a *Agent) consumeJob(job *Job, role string) { // return } - formatResults := "" - for _, r := range results { - formatResults += fmt.Sprintf("- %s \n", r) + if len(results) != 0 { + + formatResults := "" + for _, r := range results { + formatResults += fmt.Sprintf("- %s \n", r) + } + if a.options.debugMode { + fmt.Println("Found similar strings in KB:") + fmt.Println(formatResults) + } + // a.currentConversation = append(a.currentConversation, + // openai.ChatCompletionMessage{ + // Role: "system", + // Content: fmt.Sprintf("Given the user input you have the following in memory:\n%s", formatResults), + // }, + // ) + a.currentConversation = append([]openai.ChatCompletionMessage{ + { + Role: "system", + Content: fmt.Sprintf("Given the user input you have the following in memory:\n%s", formatResults), + }}, a.currentConversation...) } - if a.options.debugMode { - fmt.Println("Found similar strings in KB:") - fmt.Println(formatResults) - } - a.currentConversation = append(a.currentConversation, - openai.ChatCompletionMessage{ - Role: "system", - Content: fmt.Sprintf("Given the user input you have the following in memory:\n%s", formatResults), - }, - ) } } diff --git a/example/webui/agentpool.go b/example/webui/agentpool.go index 0d4ac3f..287d4d0 100644 --- a/example/webui/agentpool.go +++ b/example/webui/agentpool.go @@ -136,9 +136,10 @@ const ( ActionSearch = "search" ActionGithubIssueLabeler = "github-issue-labeler" ActionGithubIssueOpener = "github-issue-opener" + ActionGithubIssueCloser = "github-issue-closer" ) -var AvailableActions = []string{ActionSearch, ActionGithubIssueLabeler, ActionGithubIssueOpener} +var AvailableActions = []string{ActionSearch, ActionGithubIssueLabeler, ActionGithubIssueOpener, ActionGithubIssueCloser} func (a *AgentConfig) availableActions(ctx context.Context) []Action { actions := []Action{} @@ -148,7 +149,7 @@ func (a *AgentConfig) availableActions(ctx context.Context) []Action { var config map[string]string if err := json.Unmarshal([]byte(action.Config), &config); err != nil { - fmt.Println("Error unmarshalling connector config", err) + fmt.Println("Error unmarshalling action config", err) continue } fmt.Println("Config", config) @@ -160,6 +161,8 @@ func (a *AgentConfig) availableActions(ctx context.Context) []Action { actions = append(actions, external.NewGithubIssueLabeler(ctx, config)) case ActionGithubIssueOpener: actions = append(actions, external.NewGithubIssueOpener(ctx, config)) + case ActionGithubIssueCloser: + actions = append(actions, external.NewGithubIssueCloser(ctx, config)) } } @@ -206,7 +209,7 @@ func (a *AgentConfig) availableConnectors() []Connector { case ConnectorDiscord: connectors = append(connectors, connector.NewDiscord(config)) case ConnectorGithubIssues: - connectors = append(connectors, connector.NewGithub(config)) + connectors = append(connectors, connector.NewGithubIssueWatcher(config)) } } return connectors @@ -407,7 +410,7 @@ func (a *AgentPool) Remove(name string) error { } func (a *AgentPool) Save() error { - data, err := json.Marshal(a.pool) + data, err := json.MarshalIndent(a.pool, "", " ") if err != nil { return err } diff --git a/example/webui/connector/githubissue.go b/example/webui/connector/githubissue.go index d38bf79..fdbda46 100644 --- a/example/webui/connector/githubissue.go +++ b/example/webui/connector/githubissue.go @@ -19,7 +19,7 @@ type GithubIssues struct { client *github.Client } -func NewGithub(config map[string]string) *GithubIssues { +func NewGithubIssueWatcher(config map[string]string) *GithubIssues { client := github.NewClient(nil).WithAuthToken(config["token"]) interval, err := time.ParseDuration(config["pollInterval"]) if err != nil { @@ -57,7 +57,7 @@ func (g *GithubIssues) Start(a *agent.Agent) { for { select { case <-ticker.C: - fmt.Println("Fire in da hole!") + fmt.Println("Looking into github issues...") g.issuesService() case <-a.Context().Done(): return @@ -86,12 +86,27 @@ func (g *GithubIssues) issuesService() { if issue.IsPullRequest() { continue } - userName := *issue.User.Name + labels := []string{} + for _, l := range issue.Labels { + labels = append(labels, l.GetName()) + } + + // Get user that opened the issue + userNameLogin := issue.GetUser().Login + userName := "" + if userNameLogin != nil { + userName = *userNameLogin + } + + if userName == user.GetLogin() { + fmt.Println("Ignoring issue opened by the bot") + continue + } messages := []openai.ChatCompletionMessage{ { Role: "system", Content: fmt.Sprintf( - `This is a conversation with an user ("%s") that opened a Github issue with title "%s" in the repository "%s" owned by "%s" .`, userName, issue.GetTitle(), g.repository, g.owner), + `This is a conversation with an user ("%s") that opened a Github issue with title "%s" in the repository "%s" owned by "%s". The issue is the issue number %d. Current labels: %+v`, userName, issue.GetTitle(), g.repository, g.owner, issue.GetNumber(), labels), }, { Role: "user", diff --git a/external/githubissuecloser.go b/external/githubissuecloser.go new file mode 100644 index 0000000..65b7597 --- /dev/null +++ b/external/githubissuecloser.go @@ -0,0 +1,90 @@ +package external + +import ( + "context" + "fmt" + + "github.com/google/go-github/v61/github" + "github.com/mudler/local-agent-framework/action" + "github.com/sashabaranov/go-openai/jsonschema" +) + +type GithubIssuesCloser struct { + token string + context context.Context + client *github.Client +} + +func NewGithubIssueCloser(ctx context.Context, config map[string]string) *GithubIssuesCloser { + client := github.NewClient(nil).WithAuthToken(config["token"]) + return &GithubIssuesCloser{ + client: client, + token: config["token"], + context: ctx, + } +} + +func (g *GithubIssuesCloser) Run(params action.ActionParams) (string, error) { + result := struct { + Repository string `json:"repository"` + Owner string `json:"owner"` + IssueNumber int `json:"issue_number"` + }{} + err := params.Unmarshal(&result) + if err != nil { + fmt.Printf("error: %v", err) + + return "", err + } + + // _, _, err = g.client.Issues.CreateComment( + // g.context, + // result.Owner, result.Repository, + // result.IssueNumber, &github.IssueComment{ + // Body: &result.Text, + // }, + // ) + // if err != nil { + // fmt.Printf("error: %v", err) + + // return "", err + // } + + _, _, err = g.client.Issues.Edit(g.context, result.Owner, result.Repository, result.IssueNumber, &github.IssueRequest{ + State: github.String("closed"), + }) + + if err != nil { + fmt.Printf("error: %v", err) + + return "", err + } + + resultString := fmt.Sprintf("Closed issue %d in repository %s/%s", result.IssueNumber, result.Owner, result.Repository) + if err != nil { + resultString = fmt.Sprintf("Error closing issue %d in repository %s/%s: %v", result.IssueNumber, result.Owner, result.Repository, err) + } + return resultString, err +} + +func (g *GithubIssuesCloser) Definition() action.ActionDefinition { + return action.ActionDefinition{ + Name: "close_github_issue", + Description: "Closes a Github issue.", + Properties: map[string]jsonschema.Definition{ + "repository": { + Type: jsonschema.String, + Description: "The repository to add the label to.", + }, + "owner": { + Type: jsonschema.String, + Description: "The owner of the repository.", + }, + "issue_number": { + Type: jsonschema.Number, + Description: "The issue number to close", + }, + }, + Required: []string{"issue_number", "repository", "owner"}, + } +} diff --git a/external/githubissuelabeler.go b/external/githubissuelabeler.go index 0c8ef52..f1ae846 100644 --- a/external/githubissuelabeler.go +++ b/external/githubissuelabeler.go @@ -66,7 +66,7 @@ func (g *GithubIssuesLabeler) Run(params action.ActionParams) (string, error) { func (g *GithubIssuesLabeler) Definition() action.ActionDefinition { return action.ActionDefinition{ Name: "add_label_to_github_issue", - Description: "Add a label to a Github issue.", + Description: "Add a label to a Github issue. You might want to assign labels to issues to categorize them.", Properties: map[string]jsonschema.Definition{ "issue_number": { Type: jsonschema.Number, diff --git a/external/githubissueopener.go b/external/githubissueopener.go index 4e72600..ea9d369 100644 --- a/external/githubissueopener.go +++ b/external/githubissueopener.go @@ -28,7 +28,7 @@ func NewGithubIssueOpener(ctx context.Context, config map[string]string) *Github func (g *GithubIssuesOpener) Run(params action.ActionParams) (string, error) { result := struct { Title string `json:"title"` - Body string `json:"body"` + Body string `json:"text"` Repository string `json:"repository"` Owner string `json:"owner"` }{} @@ -60,9 +60,9 @@ func (g *GithubIssuesOpener) Definition() action.ActionDefinition { Name: "create_github_issue", Description: "Create a new issue on a GitHub repository.", Properties: map[string]jsonschema.Definition{ - "body": { + "text": { Type: jsonschema.String, - Description: "The number of the issue to add the label to.", + Description: "The text of the new issue", }, "title": { Type: jsonschema.String, @@ -74,9 +74,9 @@ func (g *GithubIssuesOpener) Definition() action.ActionDefinition { }, "repository": { Type: jsonschema.String, - Description: "The repository to create the issue in.", + Description: "The repository where to create the issue.", }, }, - Required: []string{"title", "body", "owner", "repository"}, + Required: []string{"title", "text", "owner", "repository"}, } }