Fix SDE search: migrate to the current endpoint and honor min_score - #115
Fix SDE search: migrate to the current endpoint and honor min_score#115pushwithak wants to merge 3 commits into
Conversation
e09615e to
23f4f74
Compare
The SDE tools point at a retired distribution and omit min_score, so sde_search_tool and repository_search_tool return zero results for many queries against the SDE API as deployed today. The endpoints apply a server-side default of 0.55 for min_score when it is omitted, which is above the score most documents receive and silently drops the whole result set. - sde_search: default to the current SDE host (via a single DEFAULT_SDE_BASE_URL constant, resolved lazily) and send min_score on every /api/search request (config field, default 0.0). The request URL is rstripped so a trailing-slash SDE_BASE_URL can't double up. - repository_search: point the code-search endpoint (/api/code/search) at the current host and send min_score=0.0 on every request. Because results now actually flow, the GitHub-enrichment path runs for the first time, so it is hardened: the SDE call is async and reuses a single client, HTTP errors are raised (and transient ones retried) instead of silently becoming empty results, results with invalid URLs are skipped while still backfilling to the requested count, a URL that is not github.com/owner/repo yields empty metadata instead of raising, and a single enrichment failure no longer sinks the whole result set. - utils: keep first_commit_date a str so repository metadata serializes cleanly. Verified against the live endpoint: "UF universal format weather radar .uf reader python reflectivity" returns 0 results before and 385 after.
23f4f74 to
56f27e9
Compare
sanzog03
left a comment
There was a problem hiding this comment.
Code review findings from a high-effort automated pass. Two correctness items (one confirmed, one plausible) and one cleanup — see inline comments.
| repository_metadata.pulls = repo.get_pulls(state="open", sort="created", base="master").totalCount | ||
| repository_metadata.closed_pulls = repo.get_pulls(state="closed", sort="created", base="master").totalCount | ||
| repository_metadata.first_commit_date = None # The original code provided also fell back to created_at if first_commit_date was not available. And it was set to None by default. | ||
| # first_commit_date is left at its "" default: GitHub doesn't expose it cheaply, and |
There was a problem hiding this comment.
🟡 Correctness (plausible): dropping the explicit first_commit_date = None can flip reliability_score from 0.0 to null.
The field now stays at its declared default "" on success. Since None != "", a successfully-fetched repo can satisfy is_null_metadata where it previously never could. For a repo whose other fields also land at defaults (notably created_at == ""), is_null_metadata flips False → True, so calculate_reliability_score short-circuits to None instead of 0.0 — changing a reported reliability_score from 0.0 to null.
Worth confirming is_null_metadata's definition doesn't now include first_commit_date == "" as a trigger for the empty-default case.
There was a problem hiding this comment.
is_null_metadata only returns True if every field is at its default, including created_at == "". On a successful fetch created_at is always populated from repo.created_at.isoformat(), so it stays False and the score is computed (a zero-star repo scores e.g. 35.0, not null). created_at == "" only happens on the failure path, where null is correct. So no regression from leaving first_commit_date at its "" default.
56f27e9 to
c5c3a7b
Compare
repository_search consumed SDE_BASE_URL as the full endpoint, while sde_search / code_signals and .env.example treat it as a bare host. Setting SDE_BASE_URL to a host therefore made repository_search POST to the bare host -> 404 -> silent zero results. It now routes the default through the shared DEFAULT_SDE_BASE_URL constant and appends /api/code/search per request (rstrip guards a trailing slash). Adds a unit test pinning host-form URL construction.
c5c3a7b to
8452e85
Compare
sanzog03
left a comment
There was a problem hiding this comment.
Follow-up review of the fix commit. One correctness item on the new env placeholder — see inline.
| SDE_BASE_URL="https://dyejsbdumgpqz.cloudfront.net" | ||
| # Optional. Without it, GitHub throttles at 60 requests/hour and repository_search_tool | ||
| # returns null reliability_score for repositories it could not fetch metadata for. | ||
| GITHUB_ACCESS_TOKEN="xxxxxxxxxx" |
There was a problem hiding this comment.
🔴 Correctness: this bogus token placeholder actively breaks scoring — it's worse than leaving the var unset.
A user who copies .env.example verbatim (the documented setup path) keeps GITHUB_ACCESS_TOKEN="xxxxxxxxxx". repository_search_tool then authenticates every GitHub call with that invalid token → PyGithub raises 401 inside fetch_github_metadata → the exception is swallowed and an empty RepositoryMetadata is returned → is_null_metadata is True → calculate_reliability_score returns None. Every repository_search result comes back with reliability_score: null.
That's strictly worse than leaving the var unset, where unauthenticated requests (60/hr) succeed and produce real scores — and the comment just above even promises the token prevents null scores, so the placeholder misleads.
Suggest shipping it empty or commented out, e.g.:
# GITHUB_ACCESS_TOKEN=""
so an unconfigured copy falls back to working unauthenticated requests instead of failing auth.
There was a problem hiding this comment.
Confirmed and fixed. Verified the mechanism: with GITHUB_ACCESS_TOKEN="xxxxxxxxxx", fetch_github_metadata builds Auth.Token("xxxxxxxxxx") → 401 → swallowed → empty metadata → reliability_score: null for every result. Unset and empty both leave auth=None and return real scores (stars=3, score=63.64 for veda-config-ghg). Commented the variable out in .env.example so a verbatim copy falls back to unauthenticated requests, and corrected the note — the previous one blamed the token's absence when it's the invalid placeholder that nulls scores.
A copied .env.example kept GITHUB_ACCESS_TOKEN="xxxxxxxxxx", which authenticates every GitHub call with an invalid token: PyGithub raises 401, fetch_github_metadata swallows it, and repository_search returns reliability_score: null for every result. That is strictly worse than leaving the token unset, where unauthenticated requests succeed and produce real scores. Comment the variable out so a verbatim copy falls back to unauthenticated requests, and correct the note (the previous one blamed the token's absence for null scores; it is the invalid placeholder that nulls them).
Summary
sde_search_toolandrepository_search_toolreturn zero results for many queries against the SDE API as it is deployed today, for two reasons this PR fixes:SDE_BASE_URL-overridable).min_score— neither tool sentmin_score. The SDE endpoints apply a server-side default of0.55when the field is omitted, which is above the relevance score most documents receive (hybrid search scores most hits around0.01), so the whole result set is silently dropped. Both tools now sendmin_scoreon every request, default it to0.0, and expose it as config.Changes
sde_search— searches/api/search; current-host default via a singleDEFAULT_SDE_BASE_URLconstant (resolved lazily soSDE_BASE_URLset after import is honored);min_scoreon every request; request URL isrstrip'd so a trailing-slashSDE_BASE_URL(shared withcode_signals) can't producehost//api/search.repository_search— searches the code-specific/api/code/searchendpoint.SDE_BASE_URLis treated as a bare host (consistent withsde_searchandcode_signals) with/api/code/searchappended per request, routed through the sharedDEFAULT_SDE_BASE_URLconstant;min_score=0.0on every request. Because results now actually flow, the GitHub-enrichment path runs for the first time and is hardened alongside the fix:httpx.AsyncClient, one client reused across pages) instead of blockingrequests.post;raise_for_status) and transient failures retried, instead of an error body silently becoming "no results";github.com/owner/repo(an org page, another host) returns empty metadata /nullreliability score instead of raisingIndexErrorand sinking the whole query viaasyncio.gather;utils—first_commit_datestays astrso repository metadata serializes cleanly (aNonethere failed MCP output validation once results started flowing).Test plan
uv run pytest tests/tools/test_sde_search.py tests/tools/code_search/— passes (unit + live functional)min_scoreis on every request, and that a host-formSDE_BASE_URL(with a trailing slash) produces the right endpoint URLowner/repoURL returnsNone(noIndexError) and enrichment returns empty metadata for it"UF universal format weather radar .uf reader python reflectivity"returns 0 results withmin_scoreomitted vs 385 withmin_score=0.0sde_search_toolandrepository_search_tool