Skip to content

fix(knowledge): repair 4 broken KB-search call sites found by #13009's audit - #13038

Merged
mrveiss merged 4 commits into
Dev_new_guifrom
issue-13024-kb-search-callsites
Jul 30, 2026
Merged

mrveiss merged 4 commits into
Dev_new_guifrom
issue-13024-kb-search-callsites

Conversation

@mrveiss

@mrveiss mrveiss commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Closes #13024, Closes #13025, Closes #13026, Closes #13027

Thinking Path

Read all four issues in full, then re-verified each premise independently against the actual code rather than trusting the filed text (this session has repeatedly found reports wrong in both directions).

All four premises held with only reachability nuance corrected (dead-code call sites called out honestly rather than folded silently into "fixed").

What Changed

Verification

  • py_compile, flake8 --max-line-length=120, black --check --line-length=120 --target-version py312: clean on all 14 touched/new files.
  • Per-site regression tests (29 new tests across agents/kb_librarian/librarian_test.py, agents/kb_librarian_agent_test.py, agents/knowledge_retrieval_agent_test.py, api/chat_knowledge_test.py, api/knowledge_mcp_test.py, tools/tool_registry_test.py, plus 1 added to the pre-existing tests/services/test_grounded_agent.py): each uses unittest.mock.create_autospec(KnowledgeBase, instance=True) (not a bare AsyncMock) so an incompatible kwarg reproduces the exact real TypeError/AttributeError these bugs caused in production, then asserts real content is returned (not just "no exception") and that the quarantine filter is threaded through.
  • cp-swapped baseline (not git stash, per worktree rules): swapped all 7 modified source files + the pre-existing test_grounded_agent.py back to origin/Dev_new_gui, ran the pre-existing test set (test_tool_registry_web_research.py, test_tool_registry_gui.py, test_knowledge_mcp_web_research.py, test_grounded_agent.py, tool_registry_debug_e2e_test.py, quarantine_test.py, test_claim_verifier.py, research/orchestrator_test.py, research/planner_test.py, research/quarantine_boundary_test.py): 141 passed, 1 pre-existing failure (tool_registry_debug_e2e_test.py::test_orchestrator_initialization -- Orchestrator has no tool_registry attribute, unrelated to this PR, filed separately as tool_registry_debug_e2e_test.py asserts Orchestrator.tool_registry, an attribute that doesn't exist #13037). Restored PR files, reran the same set + the 29 new tests: 156 passed, same 1 pre-existing failure. Identical failing set before/after.
  • tests/test_startup_imports.py: 350/350 both before and after the swap.

Model Used

Claude Sonnet 5

mrveiss added 4 commits July 30, 2026 14:27
…arch call sites (#13024)

KnowledgeBase.search() (knowledge/search.py) has no n_results or search_mode
kwargs -- every call site using them raised TypeError, swallowed by a broad
except and silently returned no/empty results. Fixed the kwarg names to the
canonical top_k, and for grounded_agent.py also dropped limit= (which routes
to the Enhanced dict-returning path this caller can't consume as a List).
Applied RESEARCH_QUARANTINE_FILTER (#13009/#12622) at the two live sites
(api/chat_knowledge.py, services/grounded_agent.py) and the KBLibrarian
tool-discovery site, since fixing the TypeError makes them real
general-purpose reads for the first time.
…ning search path (#13025)

self.knowledge_base.search(query, limit=limit) routed the canonical
search() (#10666 consolidation) to its "Enhanced" path, which returns a
Dict, not the List[Dict] this method iterates over -- iterating a dict
yields its keys, so result.get(...) raised AttributeError on every
non-empty search, silently caught and turned into []. Switched to top_k=
to stay on the Basic (List) path, and applied RESEARCH_QUARANTINE_FILTER
(#13009/#12622) now that this live path (api/kb_librarian.py, api/workflow.py,
agent_orchestration/agent_execution.py) actually returns content.
…er raises TypeError (#13026)

get_knowledge_base = lazy_singleton(lambda: KnowledgeBase(config_manager=get_config()))
raised TypeError on every call -- KnowledgeBase.__init__(self) takes no
parameters (config is read internally via SSOT config). Every route in this
file wraps the call in a broad except returning a generic error payload, so
all 10 MCP knowledge tool endpoints (search, summarize, vector similarity,
QA chain, resource read, ...) silently never worked. Fixed the factory to
lazy_singleton(KnowledgeBase), matching the dependencies.get_knowledge_base()
pattern used elsewhere, and applied RESEARCH_QUARANTINE_FILTER (#13009/#12622)
at every kb.search() call in the file now that they actually execute.
…f relying on dead constructor injection (#13027)

get_tool_registry = lazy_singleton(ToolRegistry) is constructed with no
args by every production call site (services/llm_service.py,
api/image_generation.py), so knowledge_base was permanently None and
search_knowledge_base()/get_fact() always reported "Knowledge base is not
available". Added _resolve_knowledge_base(), which falls back to the shared
knowledge_factory.get_knowledge_base_async() singleton on first use and
caches the result, regardless of construction order.

Also fixed a pre-existing #13024-class bug discovered in the same method:
search_knowledge_base() itself called .search(query, n_results=...), which
would have just traded one silent failure for another (a caught TypeError)
once the KB was wired in. Applied the same fix + RESEARCH_QUARANTINE_FILTER
(#13009/#12622) to add_file_to_knowledge_base()/store_fact(), which share
the identical dead-injection defect.
@github-actions

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No hardcoded values detected that have SSOT config equivalents!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant