🔍 Duplicate Code Pattern: Numeric Argument Extraction in restBackendCaller
Part of duplicate code analysis: #6728
Summary
In internal/proxy/proxy.go, the restBackendCaller.CallTool function contains two nearly-identical ~10-line blocks for extracting a numeric resource ID from JSON args — one for pull_request_read and one for issue_read. Both blocks extract owner, repo, and a numeric ID, with identical fallback logic for float64 JSON numbers.
Duplication Details
Pattern: Float64/string numeric ID extraction
- Severity: Medium
- Occurrences: 2 instances (expandable as more REST tools are added)
- Locations:
internal/proxy/proxy.go (lines ~225–236, pull_request_read case)
internal/proxy/proxy.go (lines ~238–249, issue_read case)
- Code Sample:
// pull_request_read case:
owner, _ := argsMap["owner"].(string)
repo, _ := argsMap["repo"].(string)
number, _ := argsMap["pullNumber"].(string)
if number == "" {
if n, ok := argsMap["pullNumber"].(float64); ok {
number = fmt.Sprintf("%d", int(n))
}
}
if owner == "" || repo == "" || number == "" {
return nil, fmt.Errorf("pull_request_read: missing owner/repo/pullNumber")
}
apiPath = fmt.Sprintf("/repos/%s/%s/pulls/%s", owner, repo, number)
// issue_read case (nearly identical):
owner, _ := argsMap["owner"].(string)
repo, _ := argsMap["repo"].(string)
number, _ := argsMap["issue_number"].(string)
if number == "" {
if n, ok := argsMap["issue_number"].(float64); ok {
number = fmt.Sprintf("%d", int(n))
}
}
if owner == "" || repo == "" || number == "" {
return nil, fmt.Errorf("issue_read: missing owner/repo/issue_number")
}
apiPath = fmt.Sprintf("/repos/%s/%s/issues/%s", owner, repo, number)
Impact Analysis
- Maintainability: Adding new resource-type tools (e.g.,
discussion_read) will likely copy-paste this pattern again
- Bug Risk: A fix to the float64 fallback logic must be applied in both places — easy to miss one
- Code Bloat: Minor now; grows with each new tool added to the switch
Refactoring Recommendations
- Extract a helper
extractOwnerRepoNumber(argsMap, ownerKey, repoKey, numberKey string) (owner, repo, number string, err error) that handles the float64 fallback and missing-field error:
func extractOwnerRepoNumber(argsMap map[string]interface{}, ownerKey, repoKey, numberKey, toolName string) (owner, repo, number string, err error) {
owner, _ = argsMap[ownerKey].(string)
repo, _ = argsMap[repoKey].(string)
number, _ = argsMap[numberKey].(string)
if number == "" {
if n, ok := argsMap[numberKey].(float64); ok {
number = fmt.Sprintf("%d", int(n))
}
}
if owner == "" || repo == "" || number == "" {
err = fmt.Errorf("%s: missing %s/%s/%s", toolName, ownerKey, repoKey, numberKey)
}
return
}
- Estimated effort: 30 minutes
- Benefits: Single fix point for float64 fallback logic, cleaner switch cases
Implementation Checklist
Parent Issue
See parent analysis report: #6728
Related to #6728
Generated by Duplicate Code Detector · sonnet46 1.7M · ◷
🔍 Duplicate Code Pattern: Numeric Argument Extraction in
restBackendCallerPart of duplicate code analysis: #6728
Summary
In
internal/proxy/proxy.go, therestBackendCaller.CallToolfunction contains two nearly-identical ~10-line blocks for extracting a numeric resource ID from JSON args — one forpull_request_readand one forissue_read. Both blocks extractowner,repo, and a numeric ID, with identical fallback logic for float64 JSON numbers.Duplication Details
Pattern: Float64/string numeric ID extraction
internal/proxy/proxy.go(lines ~225–236,pull_request_readcase)internal/proxy/proxy.go(lines ~238–249,issue_readcase)Impact Analysis
discussion_read) will likely copy-paste this pattern againRefactoring Recommendations
extractOwnerRepoNumber(argsMap, ownerKey, repoKey, numberKey string) (owner, repo, number string, err error)that handles the float64 fallback and missing-field error:Implementation Checklist
extractOwnerRepoNumberhelper ininternal/proxy/proxy.goorinternal/proxy/collaborator_permission.gopull_request_readandissue_readcases to use the helperParent Issue
See parent analysis report: #6728
Related to #6728