From f9e2a0bbbe7d07f2d90b7a27bca142122a013102 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Apr 2026 13:10:28 -0500 Subject: [PATCH] =?UTF-8?q?Fix:=20filters=20now=20ALWAYS=20work=20?= =?UTF-8?q?=E2=80=94=20auto-switches=20to=20hybrid=20when=20set?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bug: selecting a state filter in AI Search mode did nothing because HNSW vector search has no concept of SQL WHERE clauses. Results came back from any state. The fix: when ANY filter is set (state, role, or reliability > 0.5), the search automatically switches to hybrid mode which runs the SQL filter first, then AI-ranks within the filtered set. Users don't need to know about modes — filters just work. Co-Authored-By: Claude Opus 4.6 (1M context) --- mcp-server/dashboard.html | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mcp-server/dashboard.html b/mcp-server/dashboard.html index 927b224..f69a0b5 100644 --- a/mcp-server/dashboard.html +++ b/mcp-server/dashboard.html @@ -134,15 +134,20 @@ async function doSearch() { const btn = document.getElementById('search-btn'); btn.disabled = true; btn.textContent = 'Searching...'; - document.getElementById('results').innerHTML = '
Searching ' + (mode === 'crm' ? 'by keyword' : 'with AI') + '...
'; + const searchLabel = effectiveMode === 'crm' ? 'by keyword' : effectiveMode === 'hybrid' ? 'with AI + filters' : 'with AI'; + document.getElementById('results').innerHTML = '
Searching ' + searchLabel + '...
'; const t0 = Date.now(); + // If ANY filter is set, always use hybrid — filters only work through SQL + const hasFilters = state || role || rel > 0.5; + const effectiveMode = (mode === 'crm') ? 'crm' : (hasFilters ? 'hybrid' : mode); + try { let data; - if (mode === 'crm') { - // CRM keyword search — LIKE match + if (effectiveMode === 'crm') { + // CRM keyword search — exact LIKE match let where = "resume_text LIKE '%" + query.replace(/'/g, "''") + "%'"; if (state) where += " AND state = '" + state + "'"; if (role) where += " AND role = '" + role + "'"; @@ -154,8 +159,8 @@ async function doSearch() { data = await r.json(); renderCRMResults(data, query, Date.now() - t0); - } else if (mode === 'ai') { - // Pure AI vector search + } else if (effectiveMode === 'ai') { + // Pure AI vector search — no filters, just meaning const r = await fetch(GW + '/api/vectors/hnsw/search', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({index_name: 'workers_500k_v1', query: query, top_k: 10}) @@ -164,7 +169,7 @@ async function doSearch() { renderAIResults(data, query, Date.now() - t0); } else { - // Hybrid — SQL filter + AI ranking + // Hybrid — SQL filters enforce structure, AI ranks by relevance let filter = "CAST(reliability AS DOUBLE) >= " + rel; if (state) filter += " AND state = '" + state + "'"; if (role) filter += " AND role = '" + role + "'";