From f9ab2b15d803b2b1c2ac612f9ecf50159fe6cc7c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:33:40 +0000 Subject: [PATCH 1/2] Initial plan From 45a8dc81f112afac570cdde1a06e7bc4912e8a22 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:39:46 +0000 Subject: [PATCH 2/2] Add custom_instructions parameter to assign_copilot_to_issue tool - Added optional custom_instructions parameter to tool schema - Updated implementation to pass custom instructions to agent assignment - Added test case to verify custom_instructions works correctly - Updated toolsnaps and documentation The custom_instructions parameter allows users to provide additional context, constraints, or guidance to the Copilot agent beyond what's in the issue body, addressing the issue where additional context would otherwise be lost. Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com> --- README.md | 1 + .../assign_copilot_to_issue.snap | 4 + pkg/github/issues.go | 19 ++- pkg/github/issues_test.go | 111 ++++++++++++++++++ 4 files changed, 131 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6da46c00e..64b68a37a 100644 --- a/README.md +++ b/README.md @@ -752,6 +752,7 @@ The following sets of tools are available: - **assign_copilot_to_issue** - Assign Copilot to issue - **Required OAuth Scopes**: `repo` - `base_ref`: Git reference (e.g., branch) that the agent will start its work from. If not specified, defaults to the repository's default branch (string, optional) + - `custom_instructions`: Optional custom instructions to guide the agent beyond the issue body. Use this to provide additional context, constraints, or guidance that is not captured in the issue description (string, optional) - `issue_number`: Issue number (number, required) - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) diff --git a/pkg/github/__toolsnaps__/assign_copilot_to_issue.snap b/pkg/github/__toolsnaps__/assign_copilot_to_issue.snap index 7ad1922a0..81ea90e5a 100644 --- a/pkg/github/__toolsnaps__/assign_copilot_to_issue.snap +++ b/pkg/github/__toolsnaps__/assign_copilot_to_issue.snap @@ -11,6 +11,10 @@ "type": "string", "description": "Git reference (e.g., branch) that the agent will start its work from. If not specified, defaults to the repository's default branch" }, + "custom_instructions": { + "type": "string", + "description": "Optional custom instructions to guide the agent beyond the issue body. Use this to provide additional context, constraints, or guidance that is not captured in the issue description" + }, "issue_number": { "type": "number", "description": "Issue number" diff --git a/pkg/github/issues.go b/pkg/github/issues.go index 63174c9e9..3d57165d5 100644 --- a/pkg/github/issues.go +++ b/pkg/github/issues.go @@ -1650,6 +1650,10 @@ func AssignCopilotToIssue(t translations.TranslationHelperFunc) inventory.Server Type: "string", Description: "Git reference (e.g., branch) that the agent will start its work from. If not specified, defaults to the repository's default branch", }, + "custom_instructions": { + Type: "string", + Description: "Optional custom instructions to guide the agent beyond the issue body. Use this to provide additional context, constraints, or guidance that is not captured in the issue description", + }, }, Required: []string{"owner", "repo", "issue_number"}, }, @@ -1657,10 +1661,11 @@ func AssignCopilotToIssue(t translations.TranslationHelperFunc) inventory.Server []scopes.Scope{scopes.Repo}, func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) { var params struct { - Owner string `mapstructure:"owner"` - Repo string `mapstructure:"repo"` - IssueNumber int32 `mapstructure:"issue_number"` - BaseRef string `mapstructure:"base_ref"` + Owner string `mapstructure:"owner"` + Repo string `mapstructure:"repo"` + IssueNumber int32 `mapstructure:"issue_number"` + BaseRef string `mapstructure:"base_ref"` + CustomInstructions string `mapstructure:"custom_instructions"` } if err := mapstructure.Decode(args, ¶ms); err != nil { return utils.NewToolResultError(err.Error()), nil, nil @@ -1775,6 +1780,12 @@ func AssignCopilotToIssue(t translations.TranslationHelperFunc) inventory.Server agentAssignment.BaseRef = &baseRef } + // Add custom instructions if provided + if params.CustomInstructions != "" { + customInstructions := githubv4.String(params.CustomInstructions) + agentAssignment.CustomInstructions = &customInstructions + } + // Execute the updateIssue mutation with the GraphQL-Features header // This header is required for the agent assignment API which is not GA yet var updateIssueMutation struct { diff --git a/pkg/github/issues_test.go b/pkg/github/issues_test.go index 21e78874a..0d9070ace 100644 --- a/pkg/github/issues_test.go +++ b/pkg/github/issues_test.go @@ -2086,6 +2086,7 @@ func TestAssignCopilotToIssue(t *testing.T) { assert.Contains(t, tool.InputSchema.(*jsonschema.Schema).Properties, "repo") assert.Contains(t, tool.InputSchema.(*jsonschema.Schema).Properties, "issue_number") assert.Contains(t, tool.InputSchema.(*jsonschema.Schema).Properties, "base_ref") + assert.Contains(t, tool.InputSchema.(*jsonschema.Schema).Properties, "custom_instructions") assert.ElementsMatch(t, tool.InputSchema.(*jsonschema.Schema).Required, []string{"owner", "repo", "issue_number"}) // Helper function to create pointer to githubv4.String @@ -2638,6 +2639,116 @@ func TestAssignCopilotToIssue(t *testing.T) { ), ), }, + { + name: "successful assignment with custom_instructions specified", + requestArgs: map[string]any{ + "owner": "owner", + "repo": "repo", + "issue_number": float64(123), + "custom_instructions": "Please ensure all code follows PEP 8 style guidelines and includes comprehensive docstrings", + }, + mockedClient: githubv4mock.NewMockedHTTPClient( + githubv4mock.NewQueryMatcher( + struct { + Repository struct { + SuggestedActors struct { + Nodes []struct { + Bot struct { + ID githubv4.ID + Login githubv4.String + TypeName string `graphql:"__typename"` + } `graphql:"... on Bot"` + } + PageInfo struct { + HasNextPage bool + EndCursor string + } + } `graphql:"suggestedActors(first: 100, after: $endCursor, capabilities: CAN_BE_ASSIGNED)"` + } `graphql:"repository(owner: $owner, name: $name)"` + }{}, + map[string]any{ + "owner": githubv4.String("owner"), + "name": githubv4.String("repo"), + "endCursor": (*githubv4.String)(nil), + }, + githubv4mock.DataResponse(map[string]any{ + "repository": map[string]any{ + "suggestedActors": map[string]any{ + "nodes": []any{ + map[string]any{ + "id": githubv4.ID("copilot-swe-agent-id"), + "login": githubv4.String("copilot-swe-agent"), + "__typename": "Bot", + }, + }, + }, + }, + }), + ), + githubv4mock.NewQueryMatcher( + struct { + Repository struct { + ID githubv4.ID + Issue struct { + ID githubv4.ID + Assignees struct { + Nodes []struct { + ID githubv4.ID + } + } `graphql:"assignees(first: 100)"` + } `graphql:"issue(number: $number)"` + } `graphql:"repository(owner: $owner, name: $name)"` + }{}, + map[string]any{ + "owner": githubv4.String("owner"), + "name": githubv4.String("repo"), + "number": githubv4.Int(123), + }, + githubv4mock.DataResponse(map[string]any{ + "repository": map[string]any{ + "id": githubv4.ID("test-repo-id"), + "issue": map[string]any{ + "id": githubv4.ID("test-issue-id"), + "assignees": map[string]any{ + "nodes": []any{}, + }, + }, + }, + }), + ), + githubv4mock.NewMutationMatcher( + struct { + UpdateIssue struct { + Issue struct { + ID githubv4.ID + Number githubv4.Int + URL githubv4.String + } + } `graphql:"updateIssue(input: $input)"` + }{}, + UpdateIssueInput{ + ID: githubv4.ID("test-issue-id"), + AssigneeIDs: []githubv4.ID{githubv4.ID("copilot-swe-agent-id")}, + AgentAssignment: &AgentAssignmentInput{ + BaseRef: nil, + CustomAgent: ptrGitHubv4String(""), + CustomInstructions: ptrGitHubv4String("Please ensure all code follows PEP 8 style guidelines and includes comprehensive docstrings"), + TargetRepositoryID: githubv4.ID("test-repo-id"), + }, + }, + nil, + githubv4mock.DataResponse(map[string]any{ + "updateIssue": map[string]any{ + "issue": map[string]any{ + "id": githubv4.ID("test-issue-id"), + "number": githubv4.Int(123), + "url": githubv4.String("https://github.com/owner/repo/issues/123"), + }, + }, + }), + ), + ), + }, } for _, tc := range tests {