fix(retriever): carry a graph source's own options to the retriever

The three per-source graph options are read from the retrieval config the
Dispatcher hands over, and it only hands one over for a source it considers
overridden -- which it decided from chunks, score_threshold, rephrase_query
and prescreen alone. A source that changed only its graph options was not
"overridden", so nothing was carried and every graph source ran the defaults:
the UI toggles did nothing at all.

They count as an override now, for graphrag sources only. They mean nothing to
any other retriever, and an override also hands the source its own chunk
budget, which a classic source must not pick up from a graph setting.
This commit is contained in:
Alex committed 2026-09-20 10:45:03 +01:00
1 parent ecf02d0d60
commit 8c5a5190d9
2 files changed
+40

No files matched your search

+11
View File
@@ -185,12 +185,23 @@ class Dispatcher(BaseRetriever):
score_threshold / rephrase_query) plus an opted-in prescreen config; a
source left at defaults takes the global path so all-classic retrieval
stays byte-identical with zero extra LLM calls.
A graph source's ``graph`` options count too: they are read from the
per-source config this records, so a source that changes only those
would otherwise run the defaults and the options would do nothing.
They mean nothing to any other retriever, so they only count for
``graphrag`` -- an override hands the source its own chunk budget as
well, which a classic source must not pick up from a graph setting.
"""
return (
retrieval.chunks != _DEFAULT_RETRIEVAL.chunks
or retrieval.score_threshold != _DEFAULT_RETRIEVAL.score_threshold
or retrieval.rephrase_query != _DEFAULT_RETRIEVAL.rephrase_query
or retrieval.prescreen is not None
or (
(retrieval.retriever or "").lower() == "graphrag"
and retrieval.graph != _DEFAULT_RETRIEVAL.graph
)
)
@staticmethod
+29
View File
@@ -74,6 +74,35 @@ class TestDispatcherGrouping:
assert "b" not in retrievals
def test_graph_options_count_as_an_override(self, _patch_llm_creator):
"""A graph source that changes only its graph options still needs its
config carried over: those options live on the per-source retrieval the
Dispatcher hands the retriever, so without this the UI toggles are
no-ops and every source runs the defaults."""
sources = [
{
"id": "a",
"retrieval": RetrievalConfig(
retriever="graphrag", graph={"seed_strategy": "relationships"}
),
},
{"id": "b", "retrieval": RetrievalConfig(retriever="graphrag")},
]
d = Dispatcher(source={"question": "q", "active_docs": ["a", "b"]}, sources=sources)
retrievals = d._groups[0]["retrievals"]
assert "a" in retrievals
assert retrievals["a"].graph.seed_strategy == "relationships"
# A source on the defaults still takes the shared path.
assert "b" not in retrievals
def test_graph_options_on_a_classic_source_are_not_an_override(self, _patch_llm_creator):
# They only mean anything to the graph retriever; treating them as an
# override would hand a classic source its own chunk budget.
sources = [{"id": "a", "retrieval": RetrievalConfig(graph={"blend_vector": False})}]
d = Dispatcher(source={"question": "q", "active_docs": ["a"]}, sources=sources)
assert d._groups[0]["retrievals"] == {}
@pytest.mark.unit
class TestDispatcherSharedBudget:
def test_single_group_full_budget(self, _patch_llm_creator):