-
-
Notifications
You must be signed in to change notification settings - Fork 358
fix(search): address coderabbitai findings on PR #414 #521
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -211,6 +211,10 @@ export interface OrchestratorInput { | |
| * result whose title+snippet does not contain the unquoted query as a | ||
| * case-insensitive substring is dropped post-rerank. */ | ||
| exactMatch?: boolean; | ||
| /** Caller-supplied engine allowlist. When non-empty, only engines whose | ||
| * name matches an entry (case-insensitive) are dispatched. Wired from | ||
| * SearchInput.search_engines via the MCP schema and CLI --search-engines. */ | ||
| engineFilter?: string[]; | ||
| } | ||
|
|
||
| export interface OrchestratorOutput { | ||
|
|
@@ -303,6 +307,12 @@ interface RunV1SearchOptions { | |
| _isFallback?: boolean; | ||
| } | ||
|
|
||
| function applyEngineAllowlist(entries: EngineEntry[], allowlist: string[]): EngineEntry[] { | ||
| const lowered = allowlist.map((n) => n.toLowerCase()); | ||
| const filtered = entries.filter((e) => lowered.includes(e.engine.name.toLowerCase())); | ||
| return filtered; | ||
| } | ||
|
|
||
| export async function runV1Search( | ||
| input: OrchestratorInput, | ||
| opts: RunV1SearchOptions = {}, | ||
|
|
@@ -365,9 +375,21 @@ export async function runV1Search( | |
| // Probe-only engines are held back from the primary wave: they are a | ||
| // per-call latency/failure tax on the happy path but still an independent | ||
| // signal the degraded-recovery wave can pull in when the pool collapses. | ||
| const entries = allEntries.filter((e) => e.probeOnly !== true); | ||
| let entries = allEntries.filter((e) => e.probeOnly !== true); | ||
| const probeEntries = allEntries.filter((e) => e.probeOnly === true); | ||
|
|
||
| // Apply caller-supplied engine allowlist (SearchInput.search_engines). | ||
| // Case-insensitive match against engine name. For the primary wave, if no | ||
| // entries match the allowlist, fall back to the full roster (the caller | ||
| // likely made a typo or passed an unknown engine name). For recovery and | ||
| // backfill waves, an empty result means those waves run nothing — which is | ||
| // correct: if the caller explicitly filtered out all probe/backfill engines, | ||
| // we don't secretly re-introduce them. | ||
| if (input.engineFilter && input.engineFilter.length > 0) { | ||
| const allowlisted = applyEngineAllowlist(entries, input.engineFilter); | ||
| entries = allowlisted.length > 0 ? allowlisted : entries; | ||
| } | ||
|
|
||
|
Comment on lines
+378
to
+392
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Do not treat a probe-only match as an unknown engine.
Base the fallback decision on matches in 🤖 Prompt for AI Agents |
||
| const options: SearchEngineOptions = { | ||
| maxResults: input.maxResults ?? DEFAULT_MAX_RESULTS, | ||
| timeoutMs: input.timeoutMs ?? DEFAULT_TIMEOUT_MS, | ||
|
|
@@ -623,10 +645,13 @@ export async function runV1Search( | |
| const skippedPrimary = outcomes | ||
| .filter((o) => o.skipped) | ||
| .map((o) => o.engine); | ||
| const recoveryEntries = [ | ||
| let recoveryEntries = [ | ||
| ...probeEntries, | ||
| ...entries.filter((e) => skippedPrimary.includes(e.engine.name)), | ||
| ]; | ||
| if (input.engineFilter && input.engineFilter.length > 0) { | ||
| recoveryEntries = applyEngineAllowlist(recoveryEntries, input.engineFilter); | ||
| } | ||
| if ( | ||
| outcomes.length > 0 && | ||
| primaryHealthy < poolHealthFloor(outcomes.length) && | ||
|
|
@@ -684,7 +709,10 @@ export async function runV1Search( | |
| vertical !== 'images' && | ||
| !opts._isFallback | ||
| ) { | ||
| const generalEntries = getGeneralEngines(); | ||
| let generalEntries = getGeneralEngines(); | ||
| if (input.engineFilter && input.engineFilter.length > 0) { | ||
| generalEntries = applyEngineAllowlist(generalEntries, input.engineFilter); | ||
| } | ||
| if (generalEntries.length > 0) { | ||
| log.info('vertical starved below floor, backfilling from general', { | ||
| from: vertical, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win
Normalize engine names before fingerprinting.
The orchestrator matches engine names case-insensitively, but the cache fingerprint sorts raw values. Therefore,
['DuckDuckGo'],['duckduckgo'], and duplicate-name lists dispatch the same engine set but use different cache keys. Use shared normalization that trims, lowercases, deduplicates, and sorts engine names. Apply it consistently inhasAnyFilterand the fingerprint.Also applies to: 405-407
🤖 Prompt for AI Agents