diff --git a/CHANGELOG.md b/CHANGELOG.md index fbae4fa4..b9a7264f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ - Simpler flow: `plan_next` → `search_one` → loop back until complete → `synthesize` - Consolidated `build_conversational_graph()` into `build_research_graph(output_mode="conversational")` +### Removed + +- **Dead config options**: Removed vestigial fields from iterative planning refactor + - `confidence_threshold` from `ResearchConfig` and `ResearchState` (LLM decides completion via `is_complete`) + - `max_sub_questions` from `QAConfig` (iterative flow uses one question at a time) + - `sub_questions` field from `ResearchContext` (no longer populated) + ## [0.27.2] - 2026-01-29 ### Added diff --git a/docs/agents.md b/docs/agents.md index 2711156e..7c946caf 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -244,7 +244,6 @@ custom_config = AppConfig( provider="openai", model="gpt-4o-mini", max_iterations=5, - confidence_threshold=0.85, max_concurrency=3, ) ) diff --git a/docs/cli.md b/docs/cli.md index 93062065..83cbead1 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -255,7 +255,7 @@ Flags: - `--context`: Background context for the research - `--context-file`: Path to a file containing background context -Research parameters like `max_iterations`, `confidence_threshold`, and `max_concurrency` are configured in your [configuration file](configuration/index.md) under the `research` section. +Research parameters like `max_iterations` and `max_concurrency` are configured in your [configuration file](configuration/index.md) under the `research` section. ## Server diff --git a/docs/configuration/index.md b/docs/configuration/index.md index 2261b103..3b313216 100644 --- a/docs/configuration/index.md +++ b/docs/configuration/index.md @@ -85,7 +85,6 @@ qa: provider: ollama name: gpt-oss enable_thinking: false - max_sub_questions: 3 max_iterations: 2 max_concurrency: 1 @@ -95,7 +94,6 @@ research: name: "" enable_thinking: false max_iterations: 3 - confidence_threshold: 0.8 max_concurrency: 1 search: diff --git a/docs/configuration/qa-research.md b/docs/configuration/qa-research.md index 611afa53..a5810e7f 100644 --- a/docs/configuration/qa-research.md +++ b/docs/configuration/qa-research.md @@ -32,17 +32,15 @@ qa: provider: ollama name: gpt-oss enable_thinking: false - max_sub_questions: 3 # Maximum sub-questions for deep QA - max_iterations: 2 # Maximum search iterations per sub-question - max_concurrency: 1 # Sub-questions processed in parallel + max_iterations: 2 # Maximum search iterations + max_concurrency: 1 # Concurrent search operations ``` - **model**: LLM configuration (see [Providers](providers.md#model-settings)) -- **max_sub_questions**: For deep QA mode, maximum number of sub-questions to generate (default: 3) -- **max_iterations**: Maximum search/evaluate cycles per sub-question (default: 2) -- **max_concurrency**: Number of sub-questions to process in parallel (default: 1) +- **max_iterations**: Maximum search iterations (default: 2) +- **max_concurrency**: Number of concurrent search operations (default: 1) -Deep QA mode (`haiku-rag ask --deep`) decomposes complex questions into sub-questions, processes them in parallel batches, and synthesizes the results. +Deep QA mode (`haiku-rag ask --deep`) uses the research graph with a single iteration for quick, focused answers. ## Research Configuration @@ -55,13 +53,11 @@ research: name: "" # Empty to use qa model enable_thinking: false max_iterations: 3 - confidence_threshold: 0.8 max_concurrency: 1 ``` - **model**: LLM configuration. Leave provider/model empty to inherit from `qa` (see [Providers](providers.md#model-settings)) -- **max_iterations**: Maximum search/evaluate cycles (default: 3) -- **confidence_threshold**: Stop when confidence score meets/exceeds this (default: 0.8) -- **max_concurrency**: Sub-questions searched in parallel per iteration (default: 1) +- **max_iterations**: Maximum planning/search iterations (default: 3) +- **max_concurrency**: Concurrent search operations (default: 1) -The research workflow plans sub-questions, searches in parallel batches, evaluates findings, and iterates until reaching the confidence threshold or max iterations. +The research workflow uses an iterative feedback loop: the planner proposes one question at a time, sees the answer, then decides whether to continue or synthesize. This continues until the planner marks research as complete or `max_iterations` is reached. diff --git a/haiku_rag_slim/haiku/rag/agents/chat/agent.py b/haiku_rag_slim/haiku/rag/agents/chat/agent.py index 109eaf62..c1081f57 100644 --- a/haiku_rag_slim/haiku/rag/agents/chat/agent.py +++ b/haiku_rag_slim/haiku/rag/agents/chat/agent.py @@ -249,7 +249,6 @@ def create_chat_agent(config: AppConfig) -> Agent[ChatDeps, str]: state = ResearchState( context=context, max_iterations=1, - confidence_threshold=0.0, search_filter=doc_filter, max_concurrency=ctx.deps.config.research.max_concurrency, ) diff --git a/haiku_rag_slim/haiku/rag/agents/research/dependencies.py b/haiku_rag_slim/haiku/rag/agents/research/dependencies.py index bcacbc7b..8a112d2a 100644 --- a/haiku_rag_slim/haiku/rag/agents/research/dependencies.py +++ b/haiku_rag_slim/haiku/rag/agents/research/dependencies.py @@ -13,9 +13,6 @@ class ResearchContext(BaseModel): """Context shared across research agents.""" original_question: str = Field(description="The original research question") - sub_questions: list[str] = Field( - default_factory=list, description="Decomposed sub-questions" - ) qa_responses: list[Any] = Field( default_factory=list, description="Structured QA pairs used during research" ) diff --git a/haiku_rag_slim/haiku/rag/agents/research/graph.py b/haiku_rag_slim/haiku/rag/agents/research/graph.py index 52d69266..18b95a9f 100644 --- a/haiku_rag_slim/haiku/rag/agents/research/graph.py +++ b/haiku_rag_slim/haiku/rag/agents/research/graph.py @@ -27,17 +27,8 @@ from haiku.rag.config.models import AppConfig from haiku.rag.utils import build_prompt, get_model -def format_context_for_prompt( - context: ResearchContext, - include_pending_questions: bool = True, -) -> str: - """Format the research context as XML for prompts. - - Args: - context: The research context to format. - include_pending_questions: Whether to include pending sub-questions. - Set to False for synthesis prompts where pending questions aren't relevant. - """ +def format_context_for_prompt(context: ResearchContext) -> str: + """Format the research context as XML for prompts.""" context_data: dict[str, object] = {} if context.session_context: @@ -45,9 +36,6 @@ def format_context_for_prompt( context_data["question"] = context.original_question - if include_pending_questions and context.sub_questions: - context_data["pending_questions"] = context.sub_questions - if context.qa_responses: context_data["prior_answers"] = [ { @@ -267,9 +255,7 @@ def build_research_graph( deps_type=ResearchDependencies, ) - context_xml = format_context_for_prompt( - state.context, include_pending_questions=False - ) + context_xml = format_context_for_prompt(state.context) prompt = ( "Generate a comprehensive research report based on all gathered information.\n\n" f"{context_xml}\n\n" @@ -301,9 +287,7 @@ def build_research_graph( deps_type=ResearchDependencies, ) - context_xml = format_context_for_prompt( - state.context, include_pending_questions=False - ) + context_xml = format_context_for_prompt(state.context) prompt = ( f"Answer the question based on the gathered evidence.\n\n{context_xml}" ) diff --git a/haiku_rag_slim/haiku/rag/agents/research/state.py b/haiku_rag_slim/haiku/rag/agents/research/state.py index e51a86b3..bc7d4f1e 100644 --- a/haiku_rag_slim/haiku/rag/agents/research/state.py +++ b/haiku_rag_slim/haiku/rag/agents/research/state.py @@ -29,9 +29,6 @@ class ResearchState(BaseModel): ) iterations: int = Field(default=0, description="Current iteration number") max_iterations: int = Field(default=3, description="Maximum allowed iterations") - confidence_threshold: float = Field( - default=0.8, description="Confidence threshold for completion", ge=0.0, le=1.0 - ) max_concurrency: int = Field( default=1, description="Maximum concurrent search operations", ge=1 ) @@ -45,7 +42,6 @@ class ResearchState(BaseModel): context: ResearchContext, config: "AppConfig", max_iterations: int | None = None, - confidence_threshold: float | None = None, ) -> "ResearchState": """Create a ResearchState from an AppConfig. @@ -53,15 +49,11 @@ class ResearchState(BaseModel): context: The ResearchContext containing the question config: The AppConfig object max_iterations: Override max iterations (None uses config default) - confidence_threshold: Override threshold (None uses config, 0.0 disables check) """ return cls( context=context, max_iterations=max_iterations if max_iterations is not None else config.research.max_iterations, - confidence_threshold=confidence_threshold - if confidence_threshold is not None - else config.research.confidence_threshold, max_concurrency=config.research.max_concurrency, ) diff --git a/haiku_rag_slim/haiku/rag/app.py b/haiku_rag_slim/haiku/rag/app.py index c47d0457..b627b694 100644 --- a/haiku_rag_slim/haiku/rag/app.py +++ b/haiku_rag_slim/haiku/rag/app.py @@ -399,7 +399,6 @@ class HaikuRAGApp: context=context, config=self.config, max_iterations=1, - confidence_threshold=0.0, ) state.search_filter = filter deps = ResearchDeps(client=self.client) diff --git a/haiku_rag_slim/haiku/rag/config/models.py b/haiku_rag_slim/haiku/rag/config/models.py index 018284f4..e5e56b2f 100644 --- a/haiku_rag_slim/haiku/rag/config/models.py +++ b/haiku_rag_slim/haiku/rag/config/models.py @@ -78,7 +78,6 @@ class QAConfig(BaseModel): enable_thinking=False, ) ) - max_sub_questions: int = 3 max_iterations: int = 2 max_concurrency: int = 1 @@ -92,7 +91,6 @@ class ResearchConfig(BaseModel): ) ) max_iterations: int = 3 - confidence_threshold: float = 0.8 max_concurrency: int = 1 diff --git a/haiku_rag_slim/haiku/rag/mcp.py b/haiku_rag_slim/haiku/rag/mcp.py index 4cbc29ab..b0d9fcf9 100644 --- a/haiku_rag_slim/haiku/rag/mcp.py +++ b/haiku_rag_slim/haiku/rag/mcp.py @@ -199,7 +199,6 @@ def create_mcp_server( context=context, config=config, max_iterations=2, - confidence_threshold=0.0, ) deps = ResearchDeps(client=rag) diff --git a/tests/agents/research/test_research_graph.py b/tests/agents/research/test_research_graph.py index 43e60246..c08e9693 100644 --- a/tests/agents/research/test_research_graph.py +++ b/tests/agents/research/test_research_graph.py @@ -30,7 +30,6 @@ async def test_graph_end_to_end(allow_model_requests, temp_db_path, qa_corpus): state = ResearchState( context=ResearchContext(original_question=doc["question"]), max_iterations=1, - confidence_threshold=0.5, max_concurrency=1, ) @@ -155,27 +154,6 @@ def test_format_context_for_prompt_with_session_context(): assert "What is Y?" in result -def test_format_context_for_prompt_excludes_pending_questions(): - """Test format_context_for_prompt can exclude pending questions.""" - from haiku.rag.agents.research.dependencies import ResearchContext - from haiku.rag.agents.research.graph import format_context_for_prompt - - context = ResearchContext( - original_question="Main question?", - sub_questions=["Sub Q1?", "Sub Q2?"], - ) - - # With pending questions (default) - with_pending = format_context_for_prompt(context, include_pending_questions=True) - assert "Sub Q1?" in with_pending - - # Without pending questions (for synthesis) - without_pending = format_context_for_prompt( - context, include_pending_questions=False - ) - assert "Sub Q1?" not in without_pending - - def test_format_context_for_prompt_with_prior_answers(): """Test format_context_for_prompt includes prior_answers.""" from haiku.rag.agents.research.dependencies import ResearchContext diff --git a/tests/agents/research/test_search_filter.py b/tests/agents/research/test_search_filter.py index d4dfefc6..67a1d1da 100644 --- a/tests/agents/research/test_search_filter.py +++ b/tests/agents/research/test_search_filter.py @@ -78,7 +78,6 @@ async def test_research_graph_uses_search_filter( state = ResearchState( context=ResearchContext(original_question="Tell me about animals"), max_iterations=1, - confidence_threshold=0.5, search_filter=filter_clause, ) @@ -116,7 +115,6 @@ async def test_search_filter_none_searches_all(allow_model_requests, client_with state = ResearchState( context=ResearchContext(original_question="Tell me about animals"), max_iterations=1, - confidence_threshold=0.5, search_filter=None, )