aurelian 0.1.0__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.
Files changed (266) hide show
  1. aurelian/__init__.py +9 -0
  2. aurelian/agents/__init__.py +0 -0
  3. aurelian/agents/amigo/__init__.py +3 -0
  4. aurelian/agents/amigo/amigo_agent.py +77 -0
  5. aurelian/agents/amigo/amigo_config.py +85 -0
  6. aurelian/agents/amigo/amigo_evals.py +73 -0
  7. aurelian/agents/amigo/amigo_gradio.py +52 -0
  8. aurelian/agents/amigo/amigo_mcp.py +152 -0
  9. aurelian/agents/amigo/amigo_tools.py +152 -0
  10. aurelian/agents/biblio/__init__.py +42 -0
  11. aurelian/agents/biblio/biblio_agent.py +95 -0
  12. aurelian/agents/biblio/biblio_config.py +40 -0
  13. aurelian/agents/biblio/biblio_gradio.py +67 -0
  14. aurelian/agents/biblio/biblio_mcp.py +115 -0
  15. aurelian/agents/biblio/biblio_tools.py +164 -0
  16. aurelian/agents/biblio_agent.py +46 -0
  17. aurelian/agents/checklist/__init__.py +44 -0
  18. aurelian/agents/checklist/checklist_agent.py +86 -0
  19. aurelian/agents/checklist/checklist_config.py +28 -0
  20. aurelian/agents/checklist/checklist_gradio.py +70 -0
  21. aurelian/agents/checklist/checklist_mcp.py +86 -0
  22. aurelian/agents/checklist/checklist_tools.py +141 -0
  23. aurelian/agents/checklist/content/checklists.yaml +7 -0
  24. aurelian/agents/checklist/content/streams.csv +136 -0
  25. aurelian/agents/checklist_agent.py +40 -0
  26. aurelian/agents/chemistry/__init__.py +3 -0
  27. aurelian/agents/chemistry/chemistry_agent.py +47 -0
  28. aurelian/agents/chemistry/chemistry_config.py +71 -0
  29. aurelian/agents/chemistry/chemistry_evals.py +79 -0
  30. aurelian/agents/chemistry/chemistry_gradio.py +50 -0
  31. aurelian/agents/chemistry/chemistry_mcp.py +120 -0
  32. aurelian/agents/chemistry/chemistry_tools.py +121 -0
  33. aurelian/agents/chemistry/image_agent.py +15 -0
  34. aurelian/agents/d4d/__init__.py +30 -0
  35. aurelian/agents/d4d/d4d_agent.py +73 -0
  36. aurelian/agents/d4d/d4d_config.py +46 -0
  37. aurelian/agents/d4d/d4d_gradio.py +58 -0
  38. aurelian/agents/d4d/d4d_mcp.py +71 -0
  39. aurelian/agents/d4d/d4d_tools.py +157 -0
  40. aurelian/agents/d4d_agent.py +64 -0
  41. aurelian/agents/diagnosis/__init__.py +33 -0
  42. aurelian/agents/diagnosis/diagnosis_agent.py +54 -0
  43. aurelian/agents/diagnosis/diagnosis_config.py +48 -0
  44. aurelian/agents/diagnosis/diagnosis_evals.py +76 -0
  45. aurelian/agents/diagnosis/diagnosis_gradio.py +52 -0
  46. aurelian/agents/diagnosis/diagnosis_mcp.py +141 -0
  47. aurelian/agents/diagnosis/diagnosis_tools.py +204 -0
  48. aurelian/agents/diagnosis_agent.py +28 -0
  49. aurelian/agents/draw/__init__.py +3 -0
  50. aurelian/agents/draw/draw_agent.py +39 -0
  51. aurelian/agents/draw/draw_config.py +26 -0
  52. aurelian/agents/draw/draw_gradio.py +50 -0
  53. aurelian/agents/draw/draw_mcp.py +94 -0
  54. aurelian/agents/draw/draw_tools.py +100 -0
  55. aurelian/agents/draw/judge_agent.py +18 -0
  56. aurelian/agents/filesystem/__init__.py +0 -0
  57. aurelian/agents/filesystem/filesystem_config.py +27 -0
  58. aurelian/agents/filesystem/filesystem_gradio.py +49 -0
  59. aurelian/agents/filesystem/filesystem_mcp.py +89 -0
  60. aurelian/agents/filesystem/filesystem_tools.py +95 -0
  61. aurelian/agents/filesystem/py.typed +0 -0
  62. aurelian/agents/github/__init__.py +0 -0
  63. aurelian/agents/github/github_agent.py +83 -0
  64. aurelian/agents/github/github_cli.py +248 -0
  65. aurelian/agents/github/github_config.py +22 -0
  66. aurelian/agents/github/github_gradio.py +152 -0
  67. aurelian/agents/github/github_mcp.py +252 -0
  68. aurelian/agents/github/github_tools.py +408 -0
  69. aurelian/agents/github/github_tools.py.tmp +413 -0
  70. aurelian/agents/goann/__init__.py +13 -0
  71. aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines.md +1000 -0
  72. aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines.pdf +0 -0
  73. aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines_Paper.md +693 -0
  74. aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines_Paper.pdf +0 -0
  75. aurelian/agents/goann/goann_agent.py +90 -0
  76. aurelian/agents/goann/goann_config.py +90 -0
  77. aurelian/agents/goann/goann_evals.py +104 -0
  78. aurelian/agents/goann/goann_gradio.py +62 -0
  79. aurelian/agents/goann/goann_mcp.py +0 -0
  80. aurelian/agents/goann/goann_tools.py +65 -0
  81. aurelian/agents/gocam/__init__.py +52 -0
  82. aurelian/agents/gocam/documents/DNA-binding transcription factor activity annotation guidelines.docx +0 -0
  83. aurelian/agents/gocam/documents/DNA-binding transcription factor activity annotation guidelines.pdf +0 -0
  84. aurelian/agents/gocam/documents/DNA-binding_transcription_factor_activity_annotation_guidelines.md +100 -0
  85. aurelian/agents/gocam/documents/E3 ubiquitin ligases.docx +0 -0
  86. aurelian/agents/gocam/documents/E3 ubiquitin ligases.pdf +0 -0
  87. aurelian/agents/gocam/documents/E3_ubiquitin_ligases.md +134 -0
  88. aurelian/agents/gocam/documents/GO-CAM annotation guidelines README.docx +0 -0
  89. aurelian/agents/gocam/documents/GO-CAM annotation guidelines README.pdf +0 -0
  90. aurelian/agents/gocam/documents/GO-CAM modelling guidelines TO DO.docx +0 -0
  91. aurelian/agents/gocam/documents/GO-CAM modelling guidelines TO DO.pdf +0 -0
  92. aurelian/agents/gocam/documents/GO-CAM_annotation_guidelines_README.md +1 -0
  93. aurelian/agents/gocam/documents/GO-CAM_modelling_guidelines_TO_DO.md +3 -0
  94. aurelian/agents/gocam/documents/How to annotate complexes in GO-CAM.docx +0 -0
  95. aurelian/agents/gocam/documents/How to annotate complexes in GO-CAM.pdf +0 -0
  96. aurelian/agents/gocam/documents/How to annotate molecular adaptors.docx +0 -0
  97. aurelian/agents/gocam/documents/How to annotate molecular adaptors.pdf +0 -0
  98. aurelian/agents/gocam/documents/How to annotate sequestering proteins.docx +0 -0
  99. aurelian/agents/gocam/documents/How to annotate sequestering proteins.pdf +0 -0
  100. aurelian/agents/gocam/documents/How_to_annotate_complexes_in_GO-CAM.md +29 -0
  101. aurelian/agents/gocam/documents/How_to_annotate_molecular_adaptors.md +31 -0
  102. aurelian/agents/gocam/documents/How_to_annotate_sequestering_proteins.md +42 -0
  103. aurelian/agents/gocam/documents/Molecular adaptor activity.docx +0 -0
  104. aurelian/agents/gocam/documents/Molecular adaptor activity.pdf +0 -0
  105. aurelian/agents/gocam/documents/Molecular carrier activity.docx +0 -0
  106. aurelian/agents/gocam/documents/Molecular carrier activity.pdf +0 -0
  107. aurelian/agents/gocam/documents/Molecular_adaptor_activity.md +51 -0
  108. aurelian/agents/gocam/documents/Molecular_carrier_activity.md +41 -0
  109. aurelian/agents/gocam/documents/Protein sequestering activity.docx +0 -0
  110. aurelian/agents/gocam/documents/Protein sequestering activity.pdf +0 -0
  111. aurelian/agents/gocam/documents/Protein_sequestering_activity.md +50 -0
  112. aurelian/agents/gocam/documents/Signaling receptor activity annotation guidelines.docx +0 -0
  113. aurelian/agents/gocam/documents/Signaling receptor activity annotation guidelines.pdf +0 -0
  114. aurelian/agents/gocam/documents/Signaling_receptor_activity_annotation_guidelines.md +187 -0
  115. aurelian/agents/gocam/documents/Transcription coregulator activity.docx +0 -0
  116. aurelian/agents/gocam/documents/Transcription coregulator activity.pdf +0 -0
  117. aurelian/agents/gocam/documents/Transcription_coregulator_activity.md +36 -0
  118. aurelian/agents/gocam/documents/Transporter activity annotation annotation guidelines.docx +0 -0
  119. aurelian/agents/gocam/documents/Transporter activity annotation annotation guidelines.pdf +0 -0
  120. aurelian/agents/gocam/documents/Transporter_activity_annotation_annotation_guidelines.md +43 -0
  121. Regulatory Processes in GO-CAM.docx +0 -0
  122. Regulatory Processes in GO-CAM.pdf +0 -0
  123. aurelian/agents/gocam/documents/WIP_-_Regulation_and_Regulatory_Processes_in_GO-CAM.md +31 -0
  124. aurelian/agents/gocam/documents/md/DNA-binding_transcription_factor_activity_annotation_guidelines.md +131 -0
  125. aurelian/agents/gocam/documents/md/E3_ubiquitin_ligases.md +166 -0
  126. aurelian/agents/gocam/documents/md/GO-CAM_annotation_guidelines_README.md +1 -0
  127. aurelian/agents/gocam/documents/md/GO-CAM_modelling_guidelines_TO_DO.md +5 -0
  128. aurelian/agents/gocam/documents/md/How_to_annotate_complexes_in_GO-CAM.md +28 -0
  129. aurelian/agents/gocam/documents/md/How_to_annotate_molecular_adaptors.md +19 -0
  130. aurelian/agents/gocam/documents/md/How_to_annotate_sequestering_proteins.md +38 -0
  131. aurelian/agents/gocam/documents/md/Molecular_adaptor_activity.md +52 -0
  132. aurelian/agents/gocam/documents/md/Molecular_carrier_activity.md +59 -0
  133. aurelian/agents/gocam/documents/md/Protein_sequestering_activity.md +52 -0
  134. aurelian/agents/gocam/documents/md/Signaling_receptor_activity_annotation_guidelines.md +271 -0
  135. aurelian/agents/gocam/documents/md/Transcription_coregulator_activity.md +54 -0
  136. aurelian/agents/gocam/documents/md/Transporter_activity_annotation_annotation_guidelines.md +38 -0
  137. aurelian/agents/gocam/documents/md/WIP_-_Regulation_and_Regulatory_Processes_in_GO-CAM.md +39 -0
  138. aurelian/agents/gocam/documents/pandoc_md/Signaling_receptor_activity_annotation_guidelines.md +334 -0
  139. aurelian/agents/gocam/gocam_agent.py +243 -0
  140. aurelian/agents/gocam/gocam_config.py +85 -0
  141. aurelian/agents/gocam/gocam_curator_agent.py +46 -0
  142. aurelian/agents/gocam/gocam_evals.py +64 -0
  143. aurelian/agents/gocam/gocam_gradio.py +89 -0
  144. aurelian/agents/gocam/gocam_mcp.py +224 -0
  145. aurelian/agents/gocam/gocam_tools.py +294 -0
  146. aurelian/agents/linkml/__init__.py +0 -0
  147. aurelian/agents/linkml/linkml_agent.py +62 -0
  148. aurelian/agents/linkml/linkml_config.py +48 -0
  149. aurelian/agents/linkml/linkml_evals.py +66 -0
  150. aurelian/agents/linkml/linkml_gradio.py +45 -0
  151. aurelian/agents/linkml/linkml_mcp.py +181 -0
  152. aurelian/agents/linkml/linkml_tools.py +102 -0
  153. aurelian/agents/literature/__init__.py +3 -0
  154. aurelian/agents/literature/literature_agent.py +75 -0
  155. aurelian/agents/literature/literature_config.py +35 -0
  156. aurelian/agents/literature/literature_gradio.py +52 -0
  157. aurelian/agents/literature/literature_mcp.py +174 -0
  158. aurelian/agents/literature/literature_tools.py +182 -0
  159. aurelian/agents/monarch/__init__.py +0 -0
  160. aurelian/agents/monarch/monarch_agent.py +45 -0
  161. aurelian/agents/monarch/monarch_config.py +45 -0
  162. aurelian/agents/monarch/monarch_gradio.py +51 -0
  163. aurelian/agents/monarch/monarch_mcp.py +65 -0
  164. aurelian/agents/monarch/monarch_tools.py +112 -0
  165. aurelian/agents/oak/__init__.py +0 -0
  166. aurelian/agents/oak/oak_config.py +27 -0
  167. aurelian/agents/oak/oak_gradio.py +57 -0
  168. aurelian/agents/ontology_mapper/__init__.py +31 -0
  169. aurelian/agents/ontology_mapper/ontology_mapper_agent.py +57 -0
  170. aurelian/agents/ontology_mapper/ontology_mapper_config.py +50 -0
  171. aurelian/agents/ontology_mapper/ontology_mapper_evals.py +108 -0
  172. aurelian/agents/ontology_mapper/ontology_mapper_gradio.py +58 -0
  173. aurelian/agents/ontology_mapper/ontology_mapper_mcp.py +81 -0
  174. aurelian/agents/ontology_mapper/ontology_mapper_tools.py +147 -0
  175. aurelian/agents/paperqa/__init__.py +27 -0
  176. aurelian/agents/paperqa/paperqa_agent.py +66 -0
  177. aurelian/agents/paperqa/paperqa_cli.py +305 -0
  178. aurelian/agents/paperqa/paperqa_config.py +142 -0
  179. aurelian/agents/paperqa/paperqa_gradio.py +90 -0
  180. aurelian/agents/paperqa/paperqa_mcp.py +155 -0
  181. aurelian/agents/paperqa/paperqa_tools.py +566 -0
  182. aurelian/agents/phenopackets/__init__.py +3 -0
  183. aurelian/agents/phenopackets/phenopackets_agent.py +58 -0
  184. aurelian/agents/phenopackets/phenopackets_config.py +72 -0
  185. aurelian/agents/phenopackets/phenopackets_evals.py +99 -0
  186. aurelian/agents/phenopackets/phenopackets_gradio.py +55 -0
  187. aurelian/agents/phenopackets/phenopackets_mcp.py +178 -0
  188. aurelian/agents/phenopackets/phenopackets_tools.py +127 -0
  189. aurelian/agents/rag/__init__.py +40 -0
  190. aurelian/agents/rag/rag_agent.py +84 -0
  191. aurelian/agents/rag/rag_config.py +80 -0
  192. aurelian/agents/rag/rag_gradio.py +67 -0
  193. aurelian/agents/rag/rag_mcp.py +107 -0
  194. aurelian/agents/rag/rag_tools.py +189 -0
  195. aurelian/agents/rag_agent.py +54 -0
  196. aurelian/agents/robot/__init__.py +0 -0
  197. aurelian/agents/robot/assets/__init__.py +3 -0
  198. aurelian/agents/robot/assets/template.md +384 -0
  199. aurelian/agents/robot/robot_config.py +25 -0
  200. aurelian/agents/robot/robot_gradio.py +46 -0
  201. aurelian/agents/robot/robot_mcp.py +100 -0
  202. aurelian/agents/robot/robot_ontology_agent.py +139 -0
  203. aurelian/agents/robot/robot_tools.py +50 -0
  204. aurelian/agents/talisman/__init__.py +3 -0
  205. aurelian/agents/talisman/__main__.py +17 -0
  206. aurelian/agents/talisman/cli.py +70 -0
  207. aurelian/agents/talisman/run_talisman.py +18 -0
  208. aurelian/agents/talisman/talisman_agent.py +143 -0
  209. aurelian/agents/talisman/talisman_config.py +66 -0
  210. aurelian/agents/talisman/talisman_gradio.py +50 -0
  211. aurelian/agents/talisman/talisman_mcp.py +75 -0
  212. aurelian/agents/talisman/talisman_tools.py +962 -0
  213. aurelian/agents/ubergraph/__init__.py +40 -0
  214. aurelian/agents/ubergraph/ubergraph_agent.py +72 -0
  215. aurelian/agents/ubergraph/ubergraph_config.py +79 -0
  216. aurelian/agents/ubergraph/ubergraph_gradio.py +48 -0
  217. aurelian/agents/ubergraph/ubergraph_mcp.py +69 -0
  218. aurelian/agents/ubergraph/ubergraph_tools.py +118 -0
  219. aurelian/agents/uniprot/__init__.py +0 -0
  220. aurelian/agents/uniprot/uniprot_agent.py +43 -0
  221. aurelian/agents/uniprot/uniprot_config.py +43 -0
  222. aurelian/agents/uniprot/uniprot_evals.py +99 -0
  223. aurelian/agents/uniprot/uniprot_gradio.py +48 -0
  224. aurelian/agents/uniprot/uniprot_mcp.py +168 -0
  225. aurelian/agents/uniprot/uniprot_tools.py +136 -0
  226. aurelian/agents/web/__init__.py +0 -0
  227. aurelian/agents/web/web_config.py +27 -0
  228. aurelian/agents/web/web_gradio.py +48 -0
  229. aurelian/agents/web/web_mcp.py +50 -0
  230. aurelian/agents/web/web_tools.py +121 -0
  231. aurelian/chat.py +23 -0
  232. aurelian/cli.py +1004 -0
  233. aurelian/dependencies/__init__.py +0 -0
  234. aurelian/dependencies/workdir.py +78 -0
  235. aurelian/evaluators/model.py +9 -0
  236. aurelian/evaluators/substring_evaluator.py +30 -0
  237. aurelian/mcp/__init__.py +0 -0
  238. aurelian/mcp/amigo_mcp_test.py +86 -0
  239. aurelian/mcp/config_generator.py +123 -0
  240. aurelian/mcp/example_config.json +43 -0
  241. aurelian/mcp/generate_sample_config.py +37 -0
  242. aurelian/mcp/gocam_mcp_test.py +126 -0
  243. aurelian/mcp/linkml_mcp_tools.py +190 -0
  244. aurelian/mcp/mcp_discovery.py +87 -0
  245. aurelian/mcp/mcp_test.py +31 -0
  246. aurelian/mcp/phenopackets_mcp_test.py +103 -0
  247. aurelian/tools/__init__.py +0 -0
  248. aurelian/tools/web/__init__.py +0 -0
  249. aurelian/tools/web/url_download.py +51 -0
  250. aurelian/utils/__init__.py +0 -0
  251. aurelian/utils/async_utils.py +18 -0
  252. aurelian/utils/data_utils.py +32 -0
  253. aurelian/utils/documentation_manager.py +59 -0
  254. aurelian/utils/doi_fetcher.py +238 -0
  255. aurelian/utils/ontology_utils.py +68 -0
  256. aurelian/utils/pdf_fetcher.py +23 -0
  257. aurelian/utils/process_logs.py +100 -0
  258. aurelian/utils/pubmed_utils.py +238 -0
  259. aurelian/utils/pytest_report_to_markdown.py +67 -0
  260. aurelian/utils/robot_ontology_utils.py +112 -0
  261. aurelian/utils/search_utils.py +95 -0
  262. aurelian-0.1.0.dist-info/LICENSE +22 -0
  263. aurelian-0.1.0.dist-info/METADATA +109 -0
  264. aurelian-0.1.0.dist-info/RECORD +266 -0
  265. aurelian-0.1.0.dist-info/WHEEL +4 -0
  266. aurelian-0.1.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,99 @@
1
+ """
2
+ Evaluation module for the Phenopackets agent.
3
+
4
+ This module implements evaluations for the Phenopackets agent using the pydantic-ai-evals framework.
5
+ """
6
+ import asyncio
7
+ import sys
8
+ from typing import Optional, Any, Dict, Callable, Awaitable
9
+
10
+ from aurelian.evaluators.model import MetadataDict, metadata
11
+ from aurelian.evaluators.substring_evaluator import SubstringEvaluator
12
+ from pydantic_evals import Case, Dataset
13
+ from pydantic_evals.evaluators import LLMJudge
14
+
15
+ from aurelian.agents.phenopackets.phenopackets_agent import phenopackets_agent
16
+ from aurelian.agents.phenopackets.phenopackets_config import PhenopacketsDependencies
17
+
18
+ class PhenopacketsMetadata(Dict[str, Any]):
19
+ """Simple metadata dictionary for Phenopackets evaluations."""
20
+ pass
21
+
22
+ # Define individual evaluation cases
23
+ case1 = Case(
24
+ name="liver_disease_patients",
25
+ inputs="What patients have liver disease?",
26
+ expected_output="hepat", # Should mention hepatic/liver terms
27
+ metadata=metadata("medium", "phenotype_query")
28
+ )
29
+
30
+ case2 = Case(
31
+ name="metabolic_pathway_genes",
32
+ inputs="What phenopackets involve genes from metabolic pathways?",
33
+ expected_output="metabol", # Should mention metabolic genes/pathways
34
+ metadata=metadata("hard", "gene_pathway_query"),
35
+ evaluators=[
36
+ LLMJudge(
37
+ rubric="""
38
+ Answer should:
39
+ 1. Identify phenopackets containing genes involved in metabolic pathways
40
+ 2. Link the metabolic genes to their corresponding phenotypes
41
+ 3. Explain how these genes relate to metabolic pathways
42
+ 4. Provide patient/case IDs where applicable
43
+ """,
44
+ include_input=True
45
+ )
46
+ ]
47
+ )
48
+
49
+ case3 = Case(
50
+ name="variant_effect_peroxisomal",
51
+ inputs="How does the type of variant affect phenotype in peroxisomal disorders?",
52
+ expected_output="peroxisom", # Should discuss peroxisomal disorders
53
+ metadata=metadata("hard", "variant_phenotype_correlation")
54
+ )
55
+
56
+ case4 = Case(
57
+ name="skeletal_dysplasia_comparison",
58
+ inputs="Examine phenopackets for skeletal dysplasias and compare their phenotypes",
59
+ expected_output="skeletal", # Should discuss skeletal terms
60
+ metadata=metadata("medium", "comparative_phenotype_analysis")
61
+ )
62
+
63
+ case5 = Case(
64
+ name="pnpla6_mutations",
65
+ inputs="Look up any patients with mutations in the PNPLA6 gene",
66
+ expected_output="PNPLA6", # Should mention the PNPLA6 gene
67
+ metadata=metadata("easy", "gene_mutation_query")
68
+ )
69
+
70
+ def create_eval_dataset() -> Dataset[str, str, MetadataDict]:
71
+ """
72
+ Create a dataset for evaluating the Phenopackets agent.
73
+
74
+ Returns:
75
+ Dataset of Phenopackets evaluation cases with appropriate evaluators
76
+ """
77
+ # Collect all cases
78
+ cases = [case1, case2, case3, case4, case5]
79
+
80
+ # Dataset-level evaluators
81
+ evaluators = [
82
+ SubstringEvaluator(),
83
+ LLMJudge(
84
+ rubric="""
85
+ Evaluate the answer based on:
86
+ 1. Accuracy in identifying relevant phenopackets based on the query
87
+ 2. Correct interpretation of phenotype-genotype relationships
88
+ 3. Proper use of HPO terms and gene identifiers
89
+ 4. Comprehensive analysis of phenotypic data when requested
90
+ 5. Clear presentation of results including patient/case identifiers when appropriate
91
+ """,
92
+ model="anthropic:claude-3-7-sonnet-latest"
93
+ )
94
+ ]
95
+
96
+ return Dataset(
97
+ cases=cases,
98
+ evaluators=evaluators
99
+ )
@@ -0,0 +1,55 @@
1
+ """
2
+ Gradio UI for the phenopackets agent.
3
+ """
4
+ from typing import List, Optional
5
+
6
+ import gradio as gr
7
+
8
+ from aurelian.agents.phenopackets.phenopackets_agent import phenopackets_agent
9
+ from aurelian.agents.phenopackets.phenopackets_config import PhenopacketsDependencies
10
+ from aurelian.utils.async_utils import run_sync
11
+
12
+
13
+ def chat(deps: Optional[PhenopacketsDependencies] = None, db_path: Optional[str] = None, collection_name: Optional[str] = None, **kwargs):
14
+ """
15
+ Initialize a chat interface for the phenopackets agent.
16
+
17
+ Args:
18
+ deps: Optional dependencies configuration
19
+ db_path: Optional database path, defaults to MongoDB localhost
20
+ collection_name: Optional collection name, defaults to "main"
21
+ **kwargs: Additional arguments to pass to the agent
22
+
23
+ Returns:
24
+ A Gradio chat interface
25
+ """
26
+ if deps is None:
27
+ deps = PhenopacketsDependencies()
28
+
29
+ if db_path:
30
+ deps.db_path = db_path
31
+ if collection_name:
32
+ deps.collection_name = collection_name
33
+
34
+ def get_info(query: str, history: List[str]) -> str:
35
+ print(f"QUERY: {query}")
36
+ print(f"HISTORY: {history}")
37
+ if history:
38
+ query += "## History"
39
+ for h in history:
40
+ query += f"\n{h}"
41
+ result = run_sync(lambda: phenopackets_agent.run_sync(query, deps=deps, **kwargs))
42
+ return result.data
43
+
44
+ return gr.ChatInterface(
45
+ fn=get_info,
46
+ type="messages",
47
+ title="Phenopackets AI Assistant",
48
+ examples=[
49
+ ["What patients have liver disease?"],
50
+ ["What phenopackets involve genes from metabolic pathways?"],
51
+ ["How does the type of variant affect phenotype in peroxisomal disorders?"],
52
+ ["Examine phenopackets for skeletal dysplasias and compare their phenotypes"],
53
+ ["Look up any patients with mutations in the PNPLA6 gene"]
54
+ ]
55
+ )
@@ -0,0 +1,178 @@
1
+ """
2
+ MCP tools for working with phenopacket databases.
3
+ """
4
+ import os
5
+ from typing import Dict, List
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+ import aurelian.agents.filesystem.filesystem_tools as fst
10
+ from aurelian.agents.phenopackets.phenopackets_agent import SYSTEM
11
+ import aurelian.agents.phenopackets.phenopackets_tools as pt
12
+ from aurelian.agents.phenopackets.phenopackets_config import PhenopacketsDependencies
13
+ from pydantic_ai import RunContext
14
+
15
+ # Initialize FastMCP server
16
+ mcp = FastMCP("phenopackets", instructions=SYSTEM)
17
+
18
+
19
+ from aurelian.dependencies.workdir import WorkDir
20
+
21
+ def deps() -> PhenopacketsDependencies:
22
+ deps = PhenopacketsDependencies()
23
+ # Set the location from environment variable or default
24
+ loc = os.getenv("AURELIAN_WORKDIR", "/tmp/aurelian")
25
+ deps.workdir = WorkDir(loc)
26
+
27
+ # Get database connection parameters from environment if available
28
+ db_path = os.getenv("PHENOPACKETS_DB_PATH")
29
+ db_name = os.getenv("PHENOPACKETS_DB_NAME")
30
+ collection_name = os.getenv("PHENOPACKETS_COLLECTION_NAME")
31
+
32
+ if db_path:
33
+ deps.db_path = db_path
34
+ if db_name:
35
+ deps.db_name = db_name
36
+ if collection_name:
37
+ deps.collection_name = collection_name
38
+
39
+ return deps
40
+
41
+ def ctx() -> RunContext[PhenopacketsDependencies]:
42
+ rc: RunContext[PhenopacketsDependencies] = RunContext[PhenopacketsDependencies](
43
+ deps=deps(),
44
+ model=None, usage=None, prompt=None,
45
+ )
46
+ return rc
47
+
48
+
49
+ @mcp.tool()
50
+ async def search_phenopackets(query: str) -> List[Dict]:
51
+ """
52
+ Performs a retrieval search over the Phenopackets database.
53
+
54
+ The query can be any text, such as name of a disease, phenotype, gene, etc.
55
+
56
+ The objects returned are "Phenopackets" which is a structured representation
57
+ of a patient. Each is uniquely identified by a phenopacket ID (essentially
58
+ the patient ID).
59
+
60
+ The objects returned are summaries of Phenopackets; some details such
61
+ as phenotypes are omitted. Use `lookup_phenopacket` to retrieve full details.
62
+
63
+ Args:
64
+ query: The search query text
65
+
66
+ Returns:
67
+ List[Dict]: List of phenopackets matching the query
68
+ """
69
+ return await pt.search_phenopackets(ctx(), query)
70
+
71
+
72
+ @mcp.tool()
73
+ async def lookup_phenopacket(phenopacket_id: str) -> Dict:
74
+ """
75
+ Performs a lookup of an individual Phenopacket by its ID.
76
+
77
+ IDs are typically of the form PMID_nnn_PatientNumber, but this should not be assumed.
78
+
79
+ Args:
80
+ phenopacket_id: The ID of the Phenopacket to look up
81
+
82
+ Returns:
83
+ Dict: The phenopacket data
84
+ """
85
+ return await pt.lookup_phenopacket(ctx(), phenopacket_id)
86
+
87
+
88
+ @mcp.tool()
89
+ async def lookup_pmid(pmid: str) -> str:
90
+ """
91
+ Lookup the text of a PubMed article by its PMID.
92
+
93
+ A PMID should be of the form "PMID:nnnnnnn" (no underscores).
94
+
95
+ NOTE: Phenopacket IDs are typically of the form PMID_nnn_PatientNumber,
96
+ but this should not be assumed. To reliably get PMIDs for a phenopacket,
97
+ use `lookup_phenopacket` to retrieve and examine the `externalReferences` field.
98
+
99
+ Args:
100
+ pmid: The PubMed ID to look up
101
+
102
+ Returns:
103
+ str: Full text if available, otherwise abstract
104
+ """
105
+ return await pt.lookup_pmid(pmid)
106
+
107
+
108
+ @mcp.tool()
109
+ async def search_web(query: str) -> str:
110
+ """
111
+ Search the web using a text query.
112
+
113
+ Args:
114
+ query: The search query
115
+
116
+ Returns:
117
+ str: Search results with summaries
118
+ """
119
+ return await pt.search_web(query)
120
+
121
+
122
+ @mcp.tool()
123
+ async def retrieve_web_page(url: str) -> str:
124
+ """
125
+ Fetch the contents of a web page.
126
+
127
+ Args:
128
+ url: The URL to fetch
129
+
130
+ Returns:
131
+ str: The contents of the web page
132
+ """
133
+ return await pt.retrieve_web_page(url)
134
+
135
+
136
+ @mcp.tool()
137
+ async def inspect_file(data_file: str) -> str:
138
+ """
139
+ Inspect a file in the working directory.
140
+
141
+ Args:
142
+ data_file: name of file
143
+
144
+ Returns:
145
+ str: Contents of the file
146
+ """
147
+ return await fst.inspect_file(ctx(), data_file)
148
+
149
+
150
+ @mcp.tool()
151
+ async def list_files() -> str:
152
+ """
153
+ List files in the working directory.
154
+
155
+ Returns:
156
+ str: List of files in the working directory
157
+ """
158
+ return await fst.list_files(ctx())
159
+
160
+
161
+ @mcp.tool()
162
+ async def write_to_file(file_name: str, data: str) -> str:
163
+ """
164
+ Write data to a file in the working directory.
165
+
166
+ Args:
167
+ file_name: Name of the file to write
168
+ data: Data to write to the file
169
+
170
+ Returns:
171
+ str: Confirmation message
172
+ """
173
+ return await fst.write_to_file(ctx(), file_name, data)
174
+
175
+
176
+ if __name__ == "__main__":
177
+ # Initialize and run the server
178
+ mcp.run(transport='stdio')
@@ -0,0 +1,127 @@
1
+ """
2
+ Tools for the phenopackets agent.
3
+ """
4
+ from typing import List, Dict, Optional
5
+
6
+ from pydantic_ai import RunContext, ModelRetry
7
+
8
+ from aurelian.agents.phenopackets.phenopackets_config import PhenopacketsDependencies
9
+ from aurelian.utils.data_utils import flatten
10
+ from aurelian.agents.literature.literature_tools import (
11
+ lookup_pmid as literature_lookup_pmid,
12
+ search_literature_web,
13
+ retrieve_literature_page
14
+ )
15
+
16
+
17
+ async def search_phenopackets(ctx: RunContext[PhenopacketsDependencies], query: str) -> List[Dict]:
18
+ """
19
+ Performs a retrieval search over the Phenopackets database.
20
+
21
+ The query can be any text, such as name of a disease, phenotype, gene, etc.
22
+
23
+ The objects returned are "Phenopackets" which is a structured representation
24
+ of a patient. Each is uniquely identified by a phenopacket ID (essentially
25
+ the patient ID).
26
+
27
+ The objects returned are summaries of Phenopackets; some details such
28
+ as phenotypes are omitted. Use `lookup_phenopacket` to retrieve full details.
29
+
30
+ Args:
31
+ ctx: The run context
32
+ query: The search query text
33
+
34
+ Returns:
35
+ List[Dict]: List of phenopackets matching the query
36
+ """
37
+ print(f"SEARCH PHENOPACKETS: {query} // {ctx.deps}")
38
+ try:
39
+ qr = ctx.deps.collection.search(query, index_name="llm", limit=ctx.deps.max_results)
40
+ objs = []
41
+ for score, row in qr.ranked_rows:
42
+ obj = flatten(row, preserve_keys=["interpretations", "diseases"])
43
+ obj["relevancy_score"] = score
44
+ objs.append(obj)
45
+ print(f"RESULT: {obj}")
46
+
47
+ if not objs:
48
+ raise ModelRetry(f"No phenopackets found matching the query: {query}. Try a different search term.")
49
+
50
+ return objs
51
+ except Exception as e:
52
+ if "ModelRetry" in str(type(e)):
53
+ raise e
54
+ raise ModelRetry(f"Error searching phenopackets: {str(e)}")
55
+
56
+
57
+ async def lookup_phenopacket(ctx: RunContext[PhenopacketsDependencies], phenopacket_id: str) -> Dict:
58
+ """
59
+ Performs a lookup of an individual Phenopacket by its ID.
60
+
61
+ IDs are typically of the form PMID_nnn_PatientNumber, but this should not be assumed.
62
+
63
+ Args:
64
+ ctx: The run context
65
+ phenopacket_id: The ID of the Phenopacket to look up
66
+
67
+ Returns:
68
+ Dict: The phenopacket data
69
+ """
70
+ print(f"LOOKUP PHENOPACKET: {phenopacket_id}")
71
+ try:
72
+ qr = ctx.deps.collection.find({"id": phenopacket_id})
73
+ if not qr.rows:
74
+ raise ModelRetry(f"Could not find phenopacket with ID {phenopacket_id}. The ID may be incorrect.")
75
+ return qr.rows[0]
76
+ except Exception as e:
77
+ if "ModelRetry" in str(type(e)):
78
+ raise e
79
+ raise ModelRetry(f"Error looking up phenopacket {phenopacket_id}: {str(e)}")
80
+
81
+
82
+ async def lookup_pmid(pmid: str) -> str:
83
+ """
84
+ Lookup the text of a PubMed article by its PMID.
85
+
86
+ A PMID should be of the form "PMID:nnnnnnn" (no underscores).
87
+
88
+ NOTE: Phenopacket IDs are typically of the form PMID_nnn_PatientNumber,
89
+ but this should not be assumed. To reliably get PMIDs for a phenopacket,
90
+ use `lookup_phenopacket` to retrieve and examine the `externalReferences` field.
91
+
92
+ Args:
93
+ pmid: The PubMed ID to look up
94
+
95
+ Returns:
96
+ str: Full text if available, otherwise abstract
97
+ """
98
+ print(f"LOOKUP PMID FOR PHENOPACKET: {pmid}")
99
+ return await literature_lookup_pmid(pmid)
100
+
101
+
102
+ async def search_web(query: str) -> str:
103
+ """
104
+ Search the web using a text query.
105
+
106
+ Args:
107
+ query: The search query
108
+
109
+ Returns:
110
+ str: Search results with summaries
111
+ """
112
+ print(f"PHENOPACKET WEB SEARCH: {query}")
113
+ return await search_literature_web(query)
114
+
115
+
116
+ async def retrieve_web_page(url: str) -> str:
117
+ """
118
+ Fetch the contents of a web page.
119
+
120
+ Args:
121
+ url: The URL to fetch
122
+
123
+ Returns:
124
+ str: The contents of the web page
125
+ """
126
+ print(f"FETCH WEB PAGE FOR PHENOPACKET: {url}")
127
+ return await retrieve_literature_page(url)
@@ -0,0 +1,40 @@
1
+ """
2
+ RAG agent package for retrieval-augmented generation against document collections.
3
+ """
4
+
5
+ # Constants
6
+ COLLECTION_NAME = "main"
7
+
8
+ # isort: skip_file
9
+ from .rag_agent import rag_agent # noqa: E402
10
+ from .rag_config import RagDependencies, get_config # noqa: E402
11
+ from .rag_gradio import chat # noqa: E402
12
+ from .rag_tools import ( # noqa: E402
13
+ search_documents,
14
+ inspect_document,
15
+ lookup_pmid,
16
+ search_web,
17
+ retrieve_web_page,
18
+ )
19
+
20
+ __all__ = [
21
+ # Constants
22
+ "COLLECTION_NAME",
23
+
24
+ # Agent
25
+ "rag_agent",
26
+
27
+ # Config
28
+ "RagDependencies",
29
+ "get_config",
30
+
31
+ # Tools
32
+ "search_documents",
33
+ "inspect_document",
34
+ "lookup_pmid",
35
+ "search_web",
36
+ "retrieve_web_page",
37
+
38
+ # Gradio
39
+ "chat",
40
+ ]
@@ -0,0 +1,84 @@
1
+ """
2
+ Agent for retrieval-augmented generation (RAG) against document collections.
3
+ """
4
+ from pydantic_ai import Agent, RunContext
5
+
6
+ from .rag_config import RagDependencies
7
+ from .rag_tools import search_documents, inspect_document, lookup_pmid, search_web, retrieve_web_page
8
+
9
+
10
+ rag_agent = Agent(
11
+ model="openai:gpt-4o",
12
+ deps_type=RagDependencies,
13
+ result_type=str,
14
+ system_prompt=(
15
+ "You are an AI assistant that help explore a literature collection via RAG."
16
+ " You can use different functions to access the store, for example:"
17
+ " - `search_documents` to find documents by text query"
18
+ " - `inspect_document` to retrieve a specific document (by title/name)"
19
+ "You can also use `lookup_pmid` to retrieve the text of a PubMed ID, or `search_web` to search the web."
20
+ ),
21
+ defer_model_check=True,
22
+ )
23
+
24
+
25
+ @rag_agent.tool
26
+ async def search_documents_tool(ctx: RunContext[RagDependencies], query: str):
27
+ """
28
+ Performs a retrieval search over the RAG database.
29
+
30
+ The query can be any text, such as name of a disease, phenotype, gene, etc.
31
+ """
32
+ return await search_documents(ctx, query)
33
+
34
+
35
+ @rag_agent.tool
36
+ async def inspect_document_tool(ctx: RunContext[RagDependencies], query: str):
37
+ """
38
+ Returns the content of the document.
39
+
40
+ Args:
41
+ query: E.g. title
42
+ """
43
+ return await inspect_document(ctx, query)
44
+
45
+
46
+ @rag_agent.tool
47
+ async def lookup_pmid_tool(ctx: RunContext[RagDependencies], pmid: str):
48
+ """
49
+ Lookup the text of a PubMed ID, using its PMID.
50
+
51
+ A PMID should be of the form "PMID:nnnnnnn" (no underscores).
52
+
53
+ NOTE: Phenopacket IDs are typically of the form PMID_nnn_PatientNumber,
54
+ but this should be be assumed. To reliably get PMIDs for a phenopacket,
55
+ use `lookup_phenopacket` to retrieve examine the `externalReferences`
56
+ field.
57
+
58
+ Returns: full text if available, otherwise abstract
59
+ """
60
+ return await lookup_pmid(ctx, pmid)
61
+
62
+
63
+ @rag_agent.tool
64
+ async def search_web_tool(ctx: RunContext[RagDependencies], query: str):
65
+ """
66
+ Search the web using a text query.
67
+
68
+ Note, this will not retrieve the full content, for that you
69
+ should use `retrieve_web_page`.
70
+
71
+ Returns: matching web pages plus summaries
72
+ """
73
+ return await search_web(ctx, query)
74
+
75
+
76
+ @rag_agent.tool
77
+ async def retrieve_web_page_tool(ctx: RunContext[RagDependencies], url: str):
78
+ """
79
+ Fetch the contents of a web page.
80
+
81
+ Returns:
82
+ The contents of the web page.
83
+ """
84
+ return await retrieve_web_page(ctx, url)
@@ -0,0 +1,80 @@
1
+ """
2
+ Configuration for the RAG agent.
3
+ """
4
+ from dataclasses import dataclass, field
5
+ import os
6
+ from typing import Optional
7
+
8
+ from linkml_store import Client
9
+ from linkml_store.api import Collection
10
+
11
+ from aurelian.dependencies.workdir import HasWorkdir, WorkDir
12
+ from . import COLLECTION_NAME
13
+
14
+
15
+ @dataclass
16
+ class RagDependencies:
17
+ """Configuration for the RAG agent."""
18
+
19
+ # Required fields
20
+ db_path: str
21
+
22
+ # Optional fields with defaults
23
+ collection_name: str = COLLECTION_NAME
24
+ max_results: int = 10
25
+ max_content_len: int = 5000
26
+ workdir: Optional[WorkDir] = None
27
+ _collection: Optional[Collection] = None
28
+
29
+ def __post_init__(self):
30
+ """Initialize the config with default values."""
31
+ if self.workdir is None:
32
+ self.workdir = WorkDir()
33
+
34
+ @property
35
+ def collection(self) -> Collection:
36
+ """Get the database collection, initializing it if needed."""
37
+ if self._collection is None:
38
+ client = Client()
39
+ db_path = self.db_path
40
+ client.attach_database(db_path)
41
+ db = client.databases[db_path]
42
+ self._collection = db.get_collection(self.collection_name)
43
+ return self._collection
44
+
45
+
46
+ def get_config(db_path: Optional[str] = None, collection_name: Optional[str] = None) -> RagDependencies:
47
+ """
48
+ Get the RAG configuration from environment variables or defaults.
49
+
50
+ Args:
51
+ db_path: The database path to use (overrides environment variable)
52
+ collection_name: The collection name to use (overrides environment variable)
53
+
54
+ Returns:
55
+ A RagDependencies instance
56
+ """
57
+ # Try to get from environment, then use provided values or defaults
58
+ env_db_path = os.environ.get("AURELIAN_RAG_DB_PATH", None)
59
+ env_collection = os.environ.get("AURELIAN_RAG_COLLECTION", COLLECTION_NAME)
60
+
61
+ # Use provided values first, then environment, then defaults
62
+ final_db_path = db_path or env_db_path
63
+ final_collection = collection_name or env_collection
64
+
65
+ # For testing purposes, if no DB path is provided, use a default one
66
+ # This is only used for running basic smoke tests
67
+ if not final_db_path:
68
+ if os.environ.get("TESTING", "0") == "1":
69
+ final_db_path = "memory://test"
70
+ else:
71
+ raise ValueError("Database path must be provided either as parameter or via AURELIAN_RAG_DB_PATH environment variable")
72
+
73
+ workdir_path = os.environ.get("AURELIAN_WORKDIR", None)
74
+ workdir = WorkDir(location=workdir_path) if workdir_path else None
75
+
76
+ return RagDependencies(
77
+ db_path=final_db_path,
78
+ collection_name=final_collection,
79
+ workdir=workdir,
80
+ )