Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/feature-flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ runtime behavior (such as output formatting) won't appear here.

- **update_issue_type** - Update Issue Type
- **Required OAuth Scopes**: `repo`
- `confidence`: How confident you are in this choice. Use 'high' for clear signal or explicit user request, 'medium' for reasonable inference with some ambiguity, 'low' for best guess with limited signal. (string, optional)
- `confidence`: How confident you are in this choice. Use 'HIGH' for clear signal or explicit user request, 'MEDIUM' for reasonable inference with some ambiguity, 'LOW' for best guess with limited signal. (string, optional)
- `is_suggestion`: If true, this issue type change is sent to the API as a suggestion (suggest:true) rather than an applied value. Whether the type is applied or recorded as a proposal is determined by the API. (boolean, optional)
- `issue_number`: The issue number to update (number, required)
- `issue_type`: The issue type to set (string, required)
Expand Down
8 changes: 4 additions & 4 deletions pkg/github/__toolsnaps__/set_issue_fields.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
"items": {
"properties": {
"confidence": {
"description": "How confident you are in this choice. Use 'high' for clear signal or explicit user request, 'medium' for reasonable inference with some ambiguity, 'low' for best guess with limited signal.",
"description": "How confident you are in this choice. Use 'HIGH' for clear signal or explicit user request, 'MEDIUM' for reasonable inference with some ambiguity, 'LOW' for best guess with limited signal.",
"enum": [
"low",
"medium",
"high"
"LOW",
"MEDIUM",
"HIGH"
],
"type": "string"
},
Expand Down
10 changes: 5 additions & 5 deletions pkg/github/__toolsnaps__/update_issue_labels.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"openWorldHint": true,
"title": "Update Issue Labels"
},
"description": "Update the labels of an existing issue. This replaces the current labels with the provided list. When setting values, include a confidence level (low, medium, or high) reflecting how certain you are about the choice.",
"description": "Update the labels of an existing issue. This replaces the current labels with the provided list. When setting values, include a confidence level (LOW, MEDIUM, or HIGH) reflecting how certain you are about the choice.",
"inputSchema": {
"properties": {
"issue_number": {
Expand All @@ -23,11 +23,11 @@
{
"properties": {
"confidence": {
"description": "How confident you are in this choice. Use 'high' for clear signal or explicit user request, 'medium' for reasonable inference with some ambiguity, 'low' for best guess with limited signal.",
"description": "How confident you are in this choice. Use 'HIGH' for clear signal or explicit user request, 'MEDIUM' for reasonable inference with some ambiguity, 'LOW' for best guess with limited signal.",
"enum": [
"low",
"medium",
"high"
"LOW",
"MEDIUM",
"HIGH"
],
"type": "string"
},
Expand Down
10 changes: 5 additions & 5 deletions pkg/github/__toolsnaps__/update_issue_type.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
"openWorldHint": true,
"title": "Update Issue Type"
},
"description": "Update the type of an existing issue (e.g. 'bug', 'feature'). When setting values, include a confidence level (low, medium, or high) reflecting how certain you are about the choice.",
"description": "Update the type of an existing issue (e.g. 'bug', 'feature'). When setting values, include a confidence level (LOW, MEDIUM, or HIGH) reflecting how certain you are about the choice.",
"inputSchema": {
"properties": {
"confidence": {
"description": "How confident you are in this choice. Use 'high' for clear signal or explicit user request, 'medium' for reasonable inference with some ambiguity, 'low' for best guess with limited signal.",
"description": "How confident you are in this choice. Use 'HIGH' for clear signal or explicit user request, 'MEDIUM' for reasonable inference with some ambiguity, 'LOW' for best guess with limited signal.",
"enum": [
"low",
"medium",
"high"
"LOW",
"MEDIUM",
"HIGH"
],
"type": "string"
},
Expand Down
66 changes: 49 additions & 17 deletions pkg/github/granular_tools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,12 +476,12 @@ func TestGranularUpdateIssueLabelsConfidence(t *testing.T) {
"repo": "repo",
"issue_number": float64(1),
"labels": []any{
map[string]any{"name": "bug", "confidence": "high"},
map[string]any{"name": "bug", "confidence": "HIGH"},
},
},
expectedReq: map[string]any{
"labels": []any{
map[string]any{"name": "bug", "confidence": "high"},
map[string]any{"name": "bug", "confidence": "HIGH"},
},
},
},
Expand All @@ -492,12 +492,28 @@ func TestGranularUpdateIssueLabelsConfidence(t *testing.T) {
"repo": "repo",
"issue_number": float64(1),
"labels": []any{
map[string]any{"name": "bug", "rationale": "Reports a crash", "confidence": "medium"},
map[string]any{"name": "bug", "rationale": "Reports a crash", "confidence": "MEDIUM"},
},
},
expectedReq: map[string]any{
"labels": []any{
map[string]any{"name": "bug", "rationale": "Reports a crash", "confidence": "medium"},
map[string]any{"name": "bug", "rationale": "Reports a crash", "confidence": "MEDIUM"},
},
},
},
{
name: "label confidence is normalized",
requestArgs: map[string]any{
"owner": "owner",
"repo": "repo",
"issue_number": float64(1),
"labels": []any{
map[string]any{"name": "bug", "confidence": " high\t"},
},
},
expectedReq: map[string]any{
"labels": []any{
map[string]any{"name": "bug", "confidence": "HIGH"},
},
},
},
Expand Down Expand Up @@ -528,7 +544,7 @@ func TestGranularUpdateIssueLabelsConfidence(t *testing.T) {
require.NoError(t, err)

errorContent := getErrorResult(t, result)
assert.Contains(t, errorContent.Text, "confidence must be one of: low, medium, high")
assert.Contains(t, errorContent.Text, "confidence must be one of: LOW, MEDIUM, HIGH")
return
}

Expand Down Expand Up @@ -742,12 +758,12 @@ func TestGranularUpdateIssueTypeConfidence(t *testing.T) {
"repo": "repo",
"issue_number": float64(1),
"issue_type": "bug",
"confidence": "high",
"confidence": "HIGH",
},
expectedReq: map[string]any{
"type": map[string]any{
"value": "bug",
"confidence": "high",
"confidence": "HIGH",
},
},
},
Expand All @@ -759,13 +775,13 @@ func TestGranularUpdateIssueTypeConfidence(t *testing.T) {
"issue_number": float64(1),
"issue_type": "feature",
"rationale": "Asks for dark mode support",
"confidence": "medium",
"confidence": "MEDIUM",
},
expectedReq: map[string]any{
"type": map[string]any{
"value": "feature",
"rationale": "Asks for dark mode support",
"confidence": "medium",
"confidence": "MEDIUM",
},
},
},
Expand All @@ -776,12 +792,28 @@ func TestGranularUpdateIssueTypeConfidence(t *testing.T) {
"repo": "repo",
"issue_number": float64(1),
"issue_type": "bug",
"confidence": "low",
"confidence": "LOW",
},
expectedReq: map[string]any{
"type": map[string]any{
"value": "bug",
"confidence": "LOW",
},
},
},
{
name: "type confidence is normalized",
requestArgs: map[string]any{
"owner": "owner",
"repo": "repo",
"issue_number": float64(1),
"issue_type": "bug",
"confidence": " medium ",
},
expectedReq: map[string]any{
"type": map[string]any{
"value": "bug",
"confidence": "low",
"confidence": "MEDIUM",
},
},
},
Expand Down Expand Up @@ -820,7 +852,7 @@ func TestGranularUpdateIssueTypeInvalidConfidence(t *testing.T) {
"issue_type": "bug",
"confidence": "very_high",
},
expectedErrText: "confidence must be one of: low, medium, high",
expectedErrText: "confidence must be one of: LOW, MEDIUM, HIGH",
},
{
name: "confidence wrong type",
Expand Down Expand Up @@ -1599,7 +1631,7 @@ func TestGranularSetIssueFields(t *testing.T) {
})

t.Run("successful set with confidence", func(t *testing.T) {
confidence := "high"
confidence := "HIGH"
matchers := []githubv4mock.Matcher{
githubv4mock.NewQueryMatcher(
struct {
Expand Down Expand Up @@ -1680,7 +1712,7 @@ func TestGranularSetIssueFields(t *testing.T) {
map[string]any{
"field_id": "FIELD_1",
"text_value": "hello",
"confidence": "high",
"confidence": " high ",
},
},
})
Expand Down Expand Up @@ -1709,11 +1741,11 @@ func TestGranularSetIssueFields(t *testing.T) {
result, err := handler(ContextWithDeps(context.Background(), deps), &request)
require.NoError(t, err)
textContent := getTextResult(t, result)
assert.Contains(t, textContent.Text, "confidence must be one of: low, medium, high")
assert.Contains(t, textContent.Text, "confidence must be one of: LOW, MEDIUM, HIGH")
})

t.Run("confidence is sent when supplied", func(t *testing.T) {
confidence := "high"
confidence := "HIGH"
matchers := []githubv4mock.Matcher{
githubv4mock.NewQueryMatcher(
struct {
Expand Down Expand Up @@ -1794,7 +1826,7 @@ func TestGranularSetIssueFields(t *testing.T) {
map[string]any{
"field_id": "FIELD_1",
"text_value": "hello",
"confidence": "high",
"confidence": "HIGH",
},
},
})
Expand Down
35 changes: 21 additions & 14 deletions pkg/github/issues_granular.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import (
"github.com/shurcooL/githubv4"
)

func normalizeConfidence(confidence string) string {
return strings.ToUpper(strings.TrimSpace(confidence))
}

// issueUpdateTool is a helper to create single-field issue update tools.
func issueUpdateTool(
t translations.TranslationHelperFunc,
Expand Down Expand Up @@ -281,7 +285,7 @@ func GranularUpdateIssueLabels(t translations.TranslationHelperFunc) inventory.S
ToolsetMetadataIssues,
mcp.Tool{
Name: "update_issue_labels",
Description: t("TOOL_UPDATE_ISSUE_LABELS_DESCRIPTION", "Update the labels of an existing issue. This replaces the current labels with the provided list. When setting values, include a confidence level (low, medium, or high) reflecting how certain you are about the choice."),
Description: t("TOOL_UPDATE_ISSUE_LABELS_DESCRIPTION", "Update the labels of an existing issue. This replaces the current labels with the provided list. When setting values, include a confidence level (LOW, MEDIUM, or HIGH) reflecting how certain you are about the choice."),
Annotations: &mcp.ToolAnnotations{
Title: t("TOOL_UPDATE_ISSUE_LABELS_USER_TITLE", "Update Issue Labels"),
ReadOnlyHint: false,
Expand Down Expand Up @@ -325,8 +329,8 @@ func GranularUpdateIssueLabels(t translations.TranslationHelperFunc) inventory.S
},
"confidence": {
Type: "string",
Description: "How confident you are in this choice. Use 'high' for clear signal or explicit user request, 'medium' for reasonable inference with some ambiguity, 'low' for best guess with limited signal.",
Enum: []any{"low", "medium", "high"},
Description: "How confident you are in this choice. Use 'HIGH' for clear signal or explicit user request, 'MEDIUM' for reasonable inference with some ambiguity, 'LOW' for best guess with limited signal.",
Enum: []any{"LOW", "MEDIUM", "HIGH"},
},
"is_suggestion": {
Type: "boolean",
Expand Down Expand Up @@ -398,8 +402,9 @@ func GranularUpdateIssueLabels(t translations.TranslationHelperFunc) inventory.S
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}
if confidence != "" && confidence != "low" && confidence != "medium" && confidence != "high" {
return utils.NewToolResultError("confidence must be one of: low, medium, high"), nil, nil
confidence = normalizeConfidence(confidence)
if confidence != "" && confidence != "LOW" && confidence != "MEDIUM" && confidence != "HIGH" {
return utils.NewToolResultError("confidence must be one of: LOW, MEDIUM, HIGH"), nil, nil
}
isSuggestion, err := OptionalParam[bool](v, "is_suggestion")
if err != nil {
Expand Down Expand Up @@ -505,7 +510,7 @@ func GranularUpdateIssueType(t translations.TranslationHelperFunc) inventory.Ser
ToolsetMetadataIssues,
mcp.Tool{
Name: "update_issue_type",
Description: t("TOOL_UPDATE_ISSUE_TYPE_DESCRIPTION", "Update the type of an existing issue (e.g. 'bug', 'feature'). When setting values, include a confidence level (low, medium, or high) reflecting how certain you are about the choice."),
Description: t("TOOL_UPDATE_ISSUE_TYPE_DESCRIPTION", "Update the type of an existing issue (e.g. 'bug', 'feature'). When setting values, include a confidence level (LOW, MEDIUM, or HIGH) reflecting how certain you are about the choice."),
Annotations: &mcp.ToolAnnotations{
Title: t("TOOL_UPDATE_ISSUE_TYPE_USER_TITLE", "Update Issue Type"),
ReadOnlyHint: false,
Expand Down Expand Up @@ -540,8 +545,8 @@ func GranularUpdateIssueType(t translations.TranslationHelperFunc) inventory.Ser
},
"confidence": {
Type: "string",
Description: "How confident you are in this choice. Use 'high' for clear signal or explicit user request, 'medium' for reasonable inference with some ambiguity, 'low' for best guess with limited signal.",
Enum: []any{"low", "medium", "high"},
Description: "How confident you are in this choice. Use 'HIGH' for clear signal or explicit user request, 'MEDIUM' for reasonable inference with some ambiguity, 'LOW' for best guess with limited signal.",
Enum: []any{"LOW", "MEDIUM", "HIGH"},
},
"is_suggestion": {
Type: "boolean",
Expand Down Expand Up @@ -582,8 +587,9 @@ func GranularUpdateIssueType(t translations.TranslationHelperFunc) inventory.Ser
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}
if confidence != "" && confidence != "low" && confidence != "medium" && confidence != "high" {
return utils.NewToolResultError("confidence must be one of: low, medium, high"), nil, nil
confidence = normalizeConfidence(confidence)
if confidence != "" && confidence != "LOW" && confidence != "MEDIUM" && confidence != "HIGH" {
return utils.NewToolResultError("confidence must be one of: LOW, MEDIUM, HIGH"), nil, nil
}
isSuggestion, err := OptionalParam[bool](args, "is_suggestion")
if err != nil {
Expand Down Expand Up @@ -987,8 +993,8 @@ func GranularSetIssueFields(t translations.TranslationHelperFunc) inventory.Serv
},
"confidence": {
Type: "string",
Description: "How confident you are in this choice. Use 'high' for clear signal or explicit user request, 'medium' for reasonable inference with some ambiguity, 'low' for best guess with limited signal.",
Enum: []any{"low", "medium", "high"},
Description: "How confident you are in this choice. Use 'HIGH' for clear signal or explicit user request, 'MEDIUM' for reasonable inference with some ambiguity, 'LOW' for best guess with limited signal.",
Enum: []any{"LOW", "MEDIUM", "HIGH"},
},
"is_suggestion": {
Type: "boolean",
Expand Down Expand Up @@ -1111,8 +1117,9 @@ func GranularSetIssueFields(t translations.TranslationHelperFunc) inventory.Serv
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}
if confidence != "" && confidence != "low" && confidence != "medium" && confidence != "high" {
return utils.NewToolResultError("confidence must be one of: low, medium, high"), nil, nil
confidence = normalizeConfidence(confidence)
if confidence != "" && confidence != "LOW" && confidence != "MEDIUM" && confidence != "HIGH" {
return utils.NewToolResultError("confidence must be one of: LOW, MEDIUM, HIGH"), nil, nil
}
if confidence != "" {
input.Confidence = &confidence
Expand Down
Loading