haiku.rag 0.9.0__py3-none-any.whl → 0.9.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
haiku/rag/app.py CHANGED
@@ -122,12 +122,7 @@ class HaikuRAGApp:
122
122
  self.console.print(f"• {finding}")
123
123
  self.console.print()
124
124
 
125
- # Themes
126
- if report.themes:
127
- self.console.print("[bold cyan]Key Themes:[/bold cyan]")
128
- for theme, explanation in report.themes.items():
129
- self.console.print(f"• [bold]{theme}[/bold]: {explanation}")
130
- self.console.print()
125
+ # (Themes section removed)
131
126
 
132
127
  # Conclusions
133
128
  if report.conclusions:
@@ -261,7 +256,7 @@ class HaikuRAGApp:
261
256
  elif transport == "sse":
262
257
  await server.run_sse_async()
263
258
  else:
264
- await server.run_http_async("streamable-http")
259
+ await server.run_http_async(transport="streamable-http")
265
260
  except KeyboardInterrupt:
266
261
  pass
267
262
  finally:
haiku/rag/qa/agent.py CHANGED
@@ -49,6 +49,9 @@ class QuestionAnswerAgent:
49
49
  limit: int = 3,
50
50
  ) -> list[SearchResult]:
51
51
  """Search the knowledge base for relevant documents."""
52
+
53
+ # Remove quotes from queries as this requires positional indexing in lancedb
54
+ query = query.replace('"', "")
52
55
  search_results = await ctx.deps.client.search(query, limit=limit)
53
56
  expanded_results = await ctx.deps.client.expand_context(search_results)
54
57
 
@@ -12,6 +12,7 @@ from haiku.rag.research.evaluation_agent import (
12
12
  EvaluationResult,
13
13
  )
14
14
  from haiku.rag.research.orchestrator import ResearchOrchestrator, ResearchPlan
15
+ from haiku.rag.research.presearch_agent import PresearchSurveyAgent
15
16
  from haiku.rag.research.search_agent import SearchSpecialistAgent
16
17
  from haiku.rag.research.synthesis_agent import ResearchReport, SynthesisAgent
17
18
 
@@ -25,6 +26,7 @@ __all__ = [
25
26
  # Specialized agents
26
27
  "SearchAnswer",
27
28
  "SearchSpecialistAgent",
29
+ "PresearchSurveyAgent",
28
30
  "AnalysisEvaluationAgent",
29
31
  "EvaluationResult",
30
32
  "SynthesisAgent",
@@ -33,10 +33,18 @@ class BaseResearchAgent[T](ABC):
33
33
  # Import deps type lazily to avoid circular import during module load
34
34
  from haiku.rag.research.dependencies import ResearchDependencies
35
35
 
36
+ # If the agent is expected to return plain text, pass `str` directly.
37
+ # Otherwise, wrap the model with ToolOutput for robust tool-handling retries.
38
+ agent_output_type: Any
39
+ if self.output_type is str: # plain text output
40
+ agent_output_type = str
41
+ else:
42
+ agent_output_type = ToolOutput(self.output_type, max_retries=3)
43
+
36
44
  self._agent = Agent(
37
45
  model=model_obj,
38
46
  deps_type=ResearchDependencies,
39
- output_type=ToolOutput(self.output_type, max_retries=3),
47
+ output_type=agent_output_type,
40
48
  system_prompt=self.get_system_prompt(),
41
49
  )
42
50
 
@@ -73,7 +81,7 @@ class BaseResearchAgent[T](ABC):
73
81
  pass
74
82
 
75
83
  async def run(
76
- self, prompt: str, deps: ResearchDependencies, **kwargs
84
+ self, prompt: str, deps: "ResearchDependencies", **kwargs
77
85
  ) -> AgentRunResult[T]:
78
86
  """Execute the agent."""
79
87
  return await self._agent.run(prompt, deps=deps, **kwargs)
@@ -11,7 +11,9 @@ class EvaluationResult(BaseModel):
11
11
  description="Main insights extracted from the research so far"
12
12
  )
13
13
  new_questions: list[str] = Field(
14
- description="New sub-questions to add to the research (max 3)", max_length=3
14
+ description="New sub-questions to add to the research (max 3)",
15
+ max_length=3,
16
+ default=[],
15
17
  )
16
18
  confidence_score: float = Field(
17
19
  description="Confidence level in the completeness of research (0-1)",
@@ -12,6 +12,7 @@ from haiku.rag.research.evaluation_agent import (
12
12
  AnalysisEvaluationAgent,
13
13
  EvaluationResult,
14
14
  )
15
+ from haiku.rag.research.presearch_agent import PresearchSurveyAgent
15
16
  from haiku.rag.research.prompts import ORCHESTRATOR_PROMPT
16
17
  from haiku.rag.research.search_agent import SearchSpecialistAgent
17
18
  from haiku.rag.research.synthesis_agent import ResearchReport, SynthesisAgent
@@ -41,6 +42,9 @@ class ResearchOrchestrator(BaseResearchAgent[ResearchPlan]):
41
42
  self.search_agent: SearchSpecialistAgent = SearchSpecialistAgent(
42
43
  provider, model
43
44
  )
45
+ self.presearch_agent: PresearchSurveyAgent = PresearchSurveyAgent(
46
+ provider, model
47
+ )
44
48
  self.evaluation_agent: AnalysisEvaluationAgent = AnalysisEvaluationAgent(
45
49
  provider, model
46
50
  )
@@ -61,7 +65,12 @@ class ResearchOrchestrator(BaseResearchAgent[ResearchPlan]):
61
65
  "original_question": context.original_question,
62
66
  "unanswered_questions": context.sub_questions,
63
67
  "qa_responses": [
64
- {"question": qa.query, "answer": qa.answer}
68
+ {
69
+ "question": qa.query,
70
+ "answer": qa.answer,
71
+ "context_snippets": qa.context,
72
+ "sources": qa.sources,
73
+ }
65
74
  for qa in context.qa_responses
66
75
  ],
67
76
  "insights": context.insights,
@@ -99,12 +108,38 @@ class ResearchOrchestrator(BaseResearchAgent[ResearchPlan]):
99
108
  # Use provided console or create a new one
100
109
  console = console or Console() if verbose else None
101
110
 
111
+ # Run a simple presearch survey to summarize KB context
112
+ if console:
113
+ console.print(
114
+ "\n[bold cyan]🔎 Presearch: summarizing KB context...[/bold cyan]"
115
+ )
116
+
117
+ presearch_result = await self.presearch_agent.run(question, deps=deps)
118
+
102
119
  # Create initial research plan
103
120
  if console:
104
121
  console.print("\n[bold cyan]📋 Creating research plan...[/bold cyan]")
105
122
 
123
+ # Include the presearch summary to ground the planning step.
124
+
125
+ planning_context_xml = format_as_xml(
126
+ {
127
+ "original_question": question,
128
+ "presearch_summary": presearch_result.output or "",
129
+ },
130
+ root_tag="planning_context",
131
+ )
132
+
133
+ plan_prompt = (
134
+ "Create a research plan for the main question below.\n\n"
135
+ f"Main question: {question}\n\n"
136
+ "Use this brief presearch summary to inform the plan. Focus the 3 sub-questions "
137
+ "on the most important aspects not already obvious from the current KB context.\n\n"
138
+ f"{planning_context_xml}"
139
+ )
140
+
106
141
  plan_result: AgentRunResult[ResearchPlan] = await self.run(
107
- f"Create a research plan for: {question}", deps=deps
142
+ plan_prompt, deps=deps
108
143
  )
109
144
 
110
145
  context.sub_questions = plan_result.output.sub_questions
@@ -0,0 +1,34 @@
1
+ from pydantic_ai import RunContext
2
+ from pydantic_ai.run import AgentRunResult
3
+
4
+ from haiku.rag.research.base import BaseResearchAgent
5
+ from haiku.rag.research.dependencies import ResearchDependencies
6
+ from haiku.rag.research.prompts import PRESEARCH_AGENT_PROMPT
7
+
8
+
9
+ class PresearchSurveyAgent(BaseResearchAgent[str]):
10
+ """Presearch agent that gathers verbatim context and summarizes it."""
11
+
12
+ def __init__(self, provider: str, model: str) -> None:
13
+ super().__init__(provider, model, str)
14
+
15
+ async def run(
16
+ self, prompt: str, deps: ResearchDependencies, **kwargs
17
+ ) -> AgentRunResult[str]:
18
+ return await super().run(prompt, deps, **kwargs)
19
+
20
+ def get_system_prompt(self) -> str:
21
+ return PRESEARCH_AGENT_PROMPT
22
+
23
+ def register_tools(self) -> None:
24
+ @self.agent.tool
25
+ async def gather_context(
26
+ ctx: RunContext[ResearchDependencies],
27
+ query: str,
28
+ limit: int = 6,
29
+ ) -> str:
30
+ """Return verbatim concatenation of relevant chunk texts."""
31
+ query = query.replace('"', "")
32
+ results = await ctx.deps.client.search(query, limit=limit)
33
+ expanded = await ctx.deps.client.expand_context(results)
34
+ return "\n\n".join(chunk.content for chunk, _ in expanded)
@@ -114,3 +114,16 @@ Focus on creating a report that provides clear value to the reader by:
114
114
  - Highlighting the most important findings
115
115
  - Explaining the implications of the research
116
116
  - Suggesting concrete next steps"""
117
+
118
+ PRESEARCH_AGENT_PROMPT = """You are a rapid research surveyor.
119
+
120
+ Task:
121
+ - Call the gather_context tool once with the main question to obtain a
122
+ relevant texts from the Knowledge Base (KB).
123
+ - Read that context and produce a brief natural-language summary describing
124
+ what the KB appears to contain relative to the question.
125
+
126
+ Rules:
127
+ - Base the summary strictly on the provided text; do not invent.
128
+ - Output only the summary as plain text (one short paragraph).
129
+ """
@@ -42,6 +42,7 @@ class SearchSpecialistAgent(BaseResearchAgent[SearchAnswer]):
42
42
  ) -> str:
43
43
  """Search the KB and return a concise context pack."""
44
44
  # Remove quotes from queries as this requires positional indexing in lancedb
45
+ # XXX: Investigate how to do that with lancedb
45
46
  query = query.replace('"', "")
46
47
  search_results = await ctx.deps.client.search(query, limit=limit)
47
48
  expanded = await ctx.deps.client.expand_context(search_results)
@@ -12,11 +12,12 @@ class ResearchReport(BaseModel):
12
12
  main_findings: list[str] = Field(
13
13
  description="Primary research findings with supporting evidence"
14
14
  )
15
- themes: dict[str, str] = Field(description="Major themes and their explanations")
16
15
  conclusions: list[str] = Field(description="Evidence-based conclusions")
17
- limitations: list[str] = Field(description="Limitations of the current research")
16
+ limitations: list[str] = Field(
17
+ description="Limitations of the current research", default=[]
18
+ )
18
19
  recommendations: list[str] = Field(
19
- description="Actionable recommendations based on findings"
20
+ description="Actionable recommendations based on findings", default=[]
20
21
  )
21
22
  sources_summary: str = Field(
22
23
  description="Summary of sources used and their reliability"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: haiku.rag
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: Agentic Retrieval Augmented Generation (RAG) with LanceDB
5
5
  Author-email: Yiorgis Gozadinos <ggozadinos@gmail.com>
6
6
  License: MIT
@@ -1,5 +1,5 @@
1
1
  haiku/rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- haiku/rag/app.py,sha256=Smof7ZIe-oRGkDTap81VaKZGIeborD2X-oXKgBoJs9I,11763
2
+ haiku/rag/app.py,sha256=o64L7aj5V8lYHxWhAKBNj1tGfXiN6xr0_Cc1dEYd3As,11483
3
3
  haiku/rag/chunker.py,sha256=PVe6ysv8UlacUd4Zb3_8RFWIaWDXnzBAy2VDJ4TaUsE,1555
4
4
  haiku/rag/cli.py,sha256=3nlzrT5FPCyfnu51KHchLG4Cj2eVv9YsuGHMShBnVb0,9845
5
5
  haiku/rag/client.py,sha256=NJVGXzVzpoVy1sttz_xEU7mXWtObKT8pGpvo5pZyzwc,21288
@@ -17,21 +17,22 @@ haiku/rag/embeddings/openai.py,sha256=fIFCk-jpUtaW0xsnrQnJ824O0UCjaGG2sgvBzREhil
17
17
  haiku/rag/embeddings/vllm.py,sha256=vhaUnCn6VMkfSluLhWKtSV-sekFaPsp4pKo2N7-SBCY,626
18
18
  haiku/rag/embeddings/voyageai.py,sha256=UW-MW4tJKnPB6Fs2P7A3yt-ZeRm46H9npckchSriPX8,661
19
19
  haiku/rag/qa/__init__.py,sha256=Sl7Kzrg9CuBOcMF01wc1NtQhUNWjJI0MhIHfCWrb8V4,434
20
- haiku/rag/qa/agent.py,sha256=f7hGWhjgzJKwa5BJkAO0KCxbgpwigPz5E9a26S9TUYI,2948
20
+ haiku/rag/qa/agent.py,sha256=f4Keh-ESgctNbTg96QL95HYjINVLOcxa8t8crx92MMk,3081
21
21
  haiku/rag/qa/prompts.py,sha256=LhRfDtO8Pb06lpr4PpwEaKUYItZ5OiIkeqcCogcssHY,3347
22
22
  haiku/rag/reranking/__init__.py,sha256=IRXHs4qPu6VbGJQpzSwhgtVWWumURH_vEoVFE-extlo,894
23
23
  haiku/rag/reranking/base.py,sha256=LM9yUSSJ414UgBZhFTgxGprlRqzfTe4I1vgjricz2JY,405
24
24
  haiku/rag/reranking/cohere.py,sha256=1iTdiaa8vvb6oHVB2qpWzUOVkyfUcimVSZp6Qr4aq4c,1049
25
25
  haiku/rag/reranking/mxbai.py,sha256=46sVTsTIkzIX9THgM3u8HaEmgY7evvEyB-N54JTHvK8,867
26
26
  haiku/rag/reranking/vllm.py,sha256=xVGH9ss-ISWdJ5SKUUHUbTqBo7PIEmA_SQv0ScdJ6XA,1479
27
- haiku/rag/research/__init__.py,sha256=hwCVV8fxnHTrLV2KCJ_Clqe_pPrCwTz-RW2b0BeGHeE,982
28
- haiku/rag/research/base.py,sha256=IW_VbeRlXTUfqh--jBS0dtIgSVXsbifPxZl8bfTLkDA,3686
27
+ haiku/rag/research/__init__.py,sha256=qLF41YayAxW_VeHhuTceVuz9hw1FNbuRV9VMhonUMW0,1078
28
+ haiku/rag/research/base.py,sha256=ZUvqh-IxU8r4mOPRKjwZcHciKcIfrTnP6Q_9jVElelQ,4041
29
29
  haiku/rag/research/dependencies.py,sha256=vZctKC5donqhm8LFO6hQdXZZXzjdW1__4eUlhyZn058,1573
30
- haiku/rag/research/evaluation_agent.py,sha256=3YWAdfC6n27wAIdla7M72IE1aS4GqoL9DbnW4K1b35M,1357
31
- haiku/rag/research/orchestrator.py,sha256=AnDXCoJBbt4nYqaDKk5hiMi8WW1e8NwpRvzHLLnY3WY,10478
32
- haiku/rag/research/prompts.py,sha256=C_d9OGNgHfwSUY6n5L2c2J6OpCeBHwxtMjrLQOkdcxU,5221
33
- haiku/rag/research/search_agent.py,sha256=mYn3GlxoIPEle2NLkBqHI-VRV5PanoHxhjttVozsVis,2405
34
- haiku/rag/research/synthesis_agent.py,sha256=E7Iwfe0EAlmglIRMmRQ3kaNmEWIyEMpVFK3k4SPC5BM,1559
30
+ haiku/rag/research/evaluation_agent.py,sha256=yyBobKr8MRwiox59I2Jqycp02ju9EGVaI9FceRGL188,1386
31
+ haiku/rag/research/orchestrator.py,sha256=LrxRG74BWun0T4uOxhc9AuitxbPioS_eG_nE098ftyY,11765
32
+ haiku/rag/research/presearch_agent.py,sha256=vf-WlY46g5tuuLKMBuPXXYYffynsBw7KVLr8LoTNHnU,1292
33
+ haiku/rag/research/prompts.py,sha256=pVRB7_b_p3JaLF1bC3ANTbSFY78ypSjDhoq6peoU6jo,5685
34
+ haiku/rag/research/search_agent.py,sha256=0iK7vCd9w7h8pWJgB6VUSPOdjlzB8peboNSXxuEGBK0,2464
35
+ haiku/rag/research/synthesis_agent.py,sha256=jo5rg7aL4zGXLQP105cANqRPIiwJLqYe2unO5BQkNvE,1511
35
36
  haiku/rag/store/__init__.py,sha256=hq0W0DAC7ysqhWSP2M2uHX8cbG6kbr-sWHxhq6qQcY0,103
36
37
  haiku/rag/store/engine.py,sha256=fNrykqMX7PRSCt4LSRfuJ66OLrb8BVYq2bpbfI2iaWU,8455
37
38
  haiku/rag/store/models/__init__.py,sha256=s0E72zneGlowvZrFWaNxHYjOAUjgWdLxzdYsnvNRVlY,88
@@ -42,8 +43,8 @@ haiku/rag/store/repositories/chunk.py,sha256=1RmPyEYRYOFbrALbmLOo62t3f-xO2KgxUjc
42
43
  haiku/rag/store/repositories/document.py,sha256=XoLCrMrZqs0iCZoHlDOfRDaVUux77Vdu5iZczduF1rY,7812
43
44
  haiku/rag/store/repositories/settings.py,sha256=wx3fuP_5CpPflZHRrIkeoer6ml-iD0qXERh5k6MQRzI,5291
44
45
  haiku/rag/store/upgrades/__init__.py,sha256=wUiEoSiHTahvuagx93E4FB07v123AhdbOjwUkPusiIg,14
45
- haiku_rag-0.9.0.dist-info/METADATA,sha256=ab5orVjoWGdapwaoPnwPdtuyetnErIxAvwDjl--9hfo,4681
46
- haiku_rag-0.9.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
47
- haiku_rag-0.9.0.dist-info/entry_points.txt,sha256=G1U3nAkNd5YDYd4v0tuYFbriz0i-JheCsFuT9kIoGCI,48
48
- haiku_rag-0.9.0.dist-info/licenses/LICENSE,sha256=eXZrWjSk9PwYFNK9yUczl3oPl95Z4V9UXH7bPN46iPo,1065
49
- haiku_rag-0.9.0.dist-info/RECORD,,
46
+ haiku_rag-0.9.2.dist-info/METADATA,sha256=IM9tGvye83CRTj2wOFtPP7oD9KtJvp3RXh4QdCFknD4,4681
47
+ haiku_rag-0.9.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
48
+ haiku_rag-0.9.2.dist-info/entry_points.txt,sha256=G1U3nAkNd5YDYd4v0tuYFbriz0i-JheCsFuT9kIoGCI,48
49
+ haiku_rag-0.9.2.dist-info/licenses/LICENSE,sha256=eXZrWjSk9PwYFNK9yUczl3oPl95Z4V9UXH7bPN46iPo,1065
50
+ haiku_rag-0.9.2.dist-info/RECORD,,