Skip to content

Commit d9f2fee

Browse files
feat: return minimal code search results with text match snippets
Return a MinimalCodeSearchResult type from search_code instead of the raw GitHub API CodeSearchResult. This reduces token usage by ~4x by: - Projecting the repository object to just the full_name string instead of the full ~3KB repository payload repeated per result - Enabling the text-match Accept header so code snippets (fragments) are included in results, which were previously missing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3a4bc26 commit d9f2fee

3 files changed

Lines changed: 83 additions & 24 deletions

File tree

pkg/github/minimal_types.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,23 @@ type MinimalSearchRepositoriesResult struct {
5151
Items []MinimalRepository `json:"items"`
5252
}
5353

54+
// MinimalCodeSearchResult is the trimmed output type for code search results.
55+
type MinimalCodeSearchResult struct {
56+
TotalCount int `json:"total_count"`
57+
IncompleteResults bool `json:"incomplete_results"`
58+
Items []MinimalCodeResult `json:"items"`
59+
}
60+
61+
// MinimalCodeResult is the trimmed output type for a single code search hit.
62+
type MinimalCodeResult struct {
63+
Name string `json:"name"`
64+
Path string `json:"path"`
65+
SHA string `json:"sha"`
66+
HTMLURL string `json:"html_url"`
67+
Repository string `json:"repository"`
68+
TextMatches []*github.TextMatch `json:"text_matches,omitempty"`
69+
}
70+
5471
// MinimalCommitAuthor represents commit author information.
5572
type MinimalCommitAuthor struct {
5673
Name string `json:"name,omitempty"`

pkg/github/search.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,9 @@ func SearchCode(t translations.TranslationHelperFunc) inventory.ServerTool {
270270
}
271271

272272
opts := &github.SearchOptions{
273-
Sort: sort,
274-
Order: order,
273+
Sort: sort,
274+
Order: order,
275+
TextMatch: true,
275276
ListOptions: github.ListOptions{
276277
PerPage: pagination.PerPage,
277278
Page: pagination.Page,
@@ -301,7 +302,28 @@ func SearchCode(t translations.TranslationHelperFunc) inventory.ServerTool {
301302
return ghErrors.NewGitHubAPIStatusErrorResponse(ctx, "failed to search code", resp, body), nil, nil
302303
}
303304

304-
r, err := json.Marshal(result)
305+
minimalItems := make([]MinimalCodeResult, 0, len(result.CodeResults))
306+
for _, code := range result.CodeResults {
307+
item := MinimalCodeResult{
308+
Name: code.GetName(),
309+
Path: code.GetPath(),
310+
SHA: code.GetSHA(),
311+
HTMLURL: code.GetHTMLURL(),
312+
TextMatches: code.TextMatches,
313+
}
314+
if code.Repository != nil {
315+
item.Repository = code.Repository.GetFullName()
316+
}
317+
minimalItems = append(minimalItems, item)
318+
}
319+
320+
minimalResult := &MinimalCodeSearchResult{
321+
TotalCount: result.GetTotal(),
322+
IncompleteResults: result.GetIncompleteResults(),
323+
Items: minimalItems,
324+
}
325+
326+
r, err := json.Marshal(minimalResult)
305327
if err != nil {
306328
return utils.NewToolResultErrorFromErr("failed to marshal response", err), nil, nil
307329
}

pkg/github/search_test.go

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -430,18 +430,29 @@ func Test_SearchCode(t *testing.T) {
430430
IncompleteResults: github.Ptr(false),
431431
CodeResults: []*github.CodeResult{
432432
{
433-
Name: github.Ptr("file1.go"),
434-
Path: github.Ptr("path/to/file1.go"),
435-
SHA: github.Ptr("abc123def456"),
436-
HTMLURL: github.Ptr("https://github.com/owner/repo/blob/main/path/to/file1.go"),
437-
Repository: &github.Repository{Name: github.Ptr("repo"), FullName: github.Ptr("owner/repo")},
433+
Name: github.Ptr("file1.go"),
434+
Path: github.Ptr("path/to/file1.go"),
435+
SHA: github.Ptr("abc123def456"),
436+
HTMLURL: github.Ptr("https://github.com/owner/repo/blob/main/path/to/file1.go"),
437+
Repository: &github.Repository{
438+
Name: github.Ptr("repo"),
439+
FullName: github.Ptr("owner/repo"),
440+
},
441+
TextMatches: []*github.TextMatch{
442+
{
443+
Fragment: github.Ptr("func main() { fmt.Println(\"hello\") }"),
444+
},
445+
},
438446
},
439447
{
440-
Name: github.Ptr("file2.go"),
441-
Path: github.Ptr("path/to/file2.go"),
442-
SHA: github.Ptr("def456abc123"),
443-
HTMLURL: github.Ptr("https://github.com/owner/repo/blob/main/path/to/file2.go"),
444-
Repository: &github.Repository{Name: github.Ptr("repo"), FullName: github.Ptr("owner/repo")},
448+
Name: github.Ptr("file2.go"),
449+
Path: github.Ptr("path/to/file2.go"),
450+
SHA: github.Ptr("def456abc123"),
451+
HTMLURL: github.Ptr("https://github.com/owner/repo/blob/main/path/to/file2.go"),
452+
Repository: &github.Repository{
453+
Name: github.Ptr("repo"),
454+
FullName: github.Ptr("owner/repo"),
455+
},
445456
},
446457
},
447458
}
@@ -540,19 +551,28 @@ func Test_SearchCode(t *testing.T) {
540551
// Parse the result and get the text content if no error
541552
textContent := getTextResult(t, result)
542553

543-
// Unmarshal and verify the result
544-
var returnedResult github.CodeSearchResult
554+
// Unmarshal and verify the minimal result
555+
var returnedResult MinimalCodeSearchResult
545556
err = json.Unmarshal([]byte(textContent.Text), &returnedResult)
546557
require.NoError(t, err)
547-
assert.Equal(t, *tc.expectedResult.Total, *returnedResult.Total)
548-
assert.Equal(t, *tc.expectedResult.IncompleteResults, *returnedResult.IncompleteResults)
549-
assert.Len(t, returnedResult.CodeResults, len(tc.expectedResult.CodeResults))
550-
for i, code := range returnedResult.CodeResults {
551-
assert.Equal(t, *tc.expectedResult.CodeResults[i].Name, *code.Name)
552-
assert.Equal(t, *tc.expectedResult.CodeResults[i].Path, *code.Path)
553-
assert.Equal(t, *tc.expectedResult.CodeResults[i].SHA, *code.SHA)
554-
assert.Equal(t, *tc.expectedResult.CodeResults[i].HTMLURL, *code.HTMLURL)
555-
assert.Equal(t, *tc.expectedResult.CodeResults[i].Repository.FullName, *code.Repository.FullName)
558+
assert.Equal(t, *tc.expectedResult.Total, returnedResult.TotalCount)
559+
assert.Equal(t, *tc.expectedResult.IncompleteResults, returnedResult.IncompleteResults)
560+
assert.Len(t, returnedResult.Items, len(tc.expectedResult.CodeResults))
561+
for i, code := range returnedResult.Items {
562+
assert.Equal(t, tc.expectedResult.CodeResults[i].GetName(), code.Name)
563+
assert.Equal(t, tc.expectedResult.CodeResults[i].GetPath(), code.Path)
564+
assert.Equal(t, tc.expectedResult.CodeResults[i].GetSHA(), code.SHA)
565+
assert.Equal(t, tc.expectedResult.CodeResults[i].GetHTMLURL(), code.HTMLURL)
566+
assert.Equal(t, tc.expectedResult.CodeResults[i].Repository.GetFullName(), code.Repository)
567+
}
568+
569+
// Verify text matches are included when present
570+
if len(tc.expectedResult.CodeResults[0].TextMatches) > 0 {
571+
require.NotEmpty(t, returnedResult.Items[0].TextMatches)
572+
assert.Equal(t,
573+
tc.expectedResult.CodeResults[0].TextMatches[0].GetFragment(),
574+
returnedResult.Items[0].TextMatches[0].GetFragment(),
575+
)
556576
}
557577
})
558578
}

0 commit comments

Comments
 (0)