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
aurelian/cli.py ADDED
@@ -0,0 +1,1004 @@
1
+ """Command line interface for Aurelian agents."""
2
+
3
+ import logging
4
+ import os
5
+ from typing import Any, Awaitable, Callable, Optional, List
6
+
7
+ from aurelian.utils.async_utils import run_sync
8
+ import click
9
+ from pydantic_ai.models.openai import OpenAIModel
10
+ from pydantic_ai.providers.openai import OpenAIProvider
11
+
12
+ from aurelian import __version__
13
+
14
+ __all__ = [
15
+ "main",
16
+ ]
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ def parse_multivalued(ctx, param, value: Optional[str]) -> Optional[List]:
22
+ """Parse a comma-separated string into a list."""
23
+ if not value:
24
+ return None
25
+ return value.split(',') if isinstance(value, str) and ',' in value else [value]
26
+
27
+
28
+ # Common CLI options
29
+ model_option = click.option(
30
+ "--model",
31
+ "-m",
32
+ help="The model to use for the agent.",
33
+ )
34
+ use_cborg_option = click.option(
35
+ "--use-cborg/--no-use-cborg",
36
+ default=False,
37
+ show_default=True,
38
+ help="Use CBORG as a model proxy (LBNL account required).",
39
+ )
40
+ agent_option = click.option(
41
+ "--agent",
42
+ "-a",
43
+ help="The agent to use (if non-default).",
44
+ )
45
+ workdir_option = click.option(
46
+ "--workdir",
47
+ "-w",
48
+ default="workdir",
49
+ show_default=True,
50
+ help="The working directory for the agent.",
51
+ )
52
+ share_option = click.option(
53
+ "--share/--no-share",
54
+ default=False,
55
+ show_default=True,
56
+ help="Share the agent GradIO UI via URL.",
57
+ )
58
+ ui_option = click.option(
59
+ "--ui/--no-ui",
60
+ default=False,
61
+ show_default=True,
62
+ help="Start the agent in UI mode instead of direct query mode.",
63
+ )
64
+ run_evals_option = click.option(
65
+ "--run-evals/--no-run-evals",
66
+ default=False,
67
+ show_default=True,
68
+ help="Run the agent in evaluation mode.",
69
+ )
70
+ ontologies_option = click.option(
71
+ "--ontologies",
72
+ "-i",
73
+ callback=parse_multivalued,
74
+ help="Comma-separated list of ontologies to use for the agent.",
75
+ )
76
+ server_port_option = click.option(
77
+ "--server-port",
78
+ "-p",
79
+ default=7860,
80
+ show_default=True,
81
+ help="The port to run the UI server on.",
82
+ )
83
+ db_path_option = click.option(
84
+ "--db-path",
85
+ "-d",
86
+ help="The path to the database.",
87
+ )
88
+ collection_name_option = click.option(
89
+ "--collection-name",
90
+ "-c",
91
+ help="The name of the collection.",
92
+ )
93
+
94
+
95
+ @click.group()
96
+ @click.option("-v", "--verbose", count=True)
97
+ @click.option("-q", "--quiet")
98
+ @click.version_option(__version__)
99
+ def main(verbose: int, quiet: bool):
100
+ """Main command for Aurelian.
101
+
102
+ Aurelian provides a collection of specialized agents for various scientific and biomedical tasks.
103
+ Each agent can be run in either direct query mode or UI mode:
104
+
105
+ - Direct query mode: Run the agent with a query (e.g., `aurelian diagnosis "patient with hypotonia"`).
106
+ - UI mode: Run the agent with `--ui` flag to start a chat interface.
107
+
108
+ Some agents also provide utility commands for specific operations.
109
+
110
+ :param verbose: Verbosity while running.
111
+ :param quiet: Boolean to be quiet or verbose.
112
+ """
113
+ if verbose >= 2:
114
+ logger.setLevel(level=logging.DEBUG)
115
+ elif verbose == 1:
116
+ logger.setLevel(level=logging.INFO)
117
+ else:
118
+ logger.setLevel(level=logging.WARNING)
119
+ if quiet:
120
+ logger.setLevel(level=logging.ERROR)
121
+ import logfire
122
+
123
+ logfire.configure()
124
+
125
+
126
+ def split_options(kwargs, agent_keys: Optional[List]=None, extra_agent_keys: Optional[List] = None):
127
+ """Split options into agent and launch options."""
128
+ if agent_keys is None:
129
+ agent_keys = ["model", "workdir", "ontologies", "db_path", "collection_name"]
130
+ if extra_agent_keys is not None:
131
+ agent_keys += extra_agent_keys
132
+ agent_options = {k: v for k, v in kwargs.items() if k in agent_keys}
133
+ launch_options = {k: v for k, v in kwargs.items() if k not in agent_keys}
134
+ return agent_options, launch_options
135
+
136
+
137
+ def run_agent(
138
+ agent_name: str,
139
+ agent_module: str,
140
+ query: Optional[tuple] = None,
141
+ ui: bool = False,
142
+ specialist_agent_name: Optional[str] = None,
143
+ agent_func_name: str = "run_sync",
144
+ join_char: str = " ",
145
+ use_cborg: bool = False,
146
+ **kwargs
147
+ ) -> None:
148
+ """Run an agent in either UI or direct query mode.
149
+
150
+ Args:
151
+ agent_name: Agent's name for import paths
152
+ agent_module: Fully qualified module path to the agent
153
+ query: Text query for direct mode
154
+ ui: Whether to force UI mode
155
+ specialist_agent_name: Name of the agent class to run
156
+ agent_func_name: Name of the function to run the agent
157
+ join_char: Character to join multi-part queries with
158
+ kwargs: Additional arguments for the agent
159
+ """
160
+ # DEPRECATED: use the new agent command instead
161
+ # Import required modules
162
+ # These are imported dynamically to avoid loading all agents on startup
163
+ if not agent_module:
164
+ agent_module = f"aurelian.agents.{agent_name}"
165
+ if not specialist_agent_name:
166
+ specialist_agent_name = agent_name
167
+ gradio_module = __import__(f"{agent_module}.{agent_name}_gradio", fromlist=["chat"])
168
+ agent_class = __import__(f"{agent_module}.{agent_name}_agent", fromlist=[f"{specialist_agent_name}_agent"])
169
+ config_module = __import__(f"{agent_module}.{agent_name}_config", fromlist=["get_config"])
170
+
171
+ chat_func = gradio_module.chat
172
+ agent = getattr(agent_class, f"{specialist_agent_name}_agent")
173
+ get_config = config_module.get_config
174
+
175
+ # Process agent and UI options
176
+ agent_keys = ["model", "use_cborg", "workdir", "ontologies", "db_path", "collection_name"]
177
+ agent_options, launch_options = split_options(kwargs, agent_keys=agent_keys)
178
+
179
+ deps = get_config()
180
+
181
+ # Set workdir if provided
182
+ if 'workdir' in agent_options and agent_options['workdir']:
183
+ if hasattr(deps, 'workdir'):
184
+ deps.workdir.location = agent_options['workdir']
185
+
186
+ # Remove workdir from agent options to avoid duplicates
187
+ agent_run_options = {k: v for k, v in agent_options.items() if k != 'workdir'}
188
+
189
+ if use_cborg:
190
+ cborg_api_key = os.environ.get("CBORG_API_KEY")
191
+ model = OpenAIModel(
192
+ agent_run_options.get("model", kwargs.get("model", "openai:gpt-4o")),
193
+ provider=OpenAIProvider(
194
+ base_url="https://api.cborg.lbl.gov",
195
+ api_key=cborg_api_key),
196
+ )
197
+ print(f"CBORG model: {model}")
198
+ agent_run_options["model"] = model
199
+
200
+ # Run in appropriate mode
201
+ if not ui and query:
202
+ # Direct query mode
203
+
204
+ # Run the agent and print results
205
+ agent_run_func = getattr(agent, agent_func_name)
206
+ r = agent_run_func(join_char.join(query), deps=deps, **agent_run_options)
207
+ print(r.data)
208
+ mjb = r.all_messages_json()
209
+ # decode messages from json bytes to dict:
210
+ if isinstance(mjb, bytes):
211
+ mjb = mjb.decode()
212
+ # print the messages
213
+ import json
214
+ all_messages = json.loads(mjb)
215
+ import yaml
216
+ # print(yaml.dump(all_messages, indent=2))
217
+ else:
218
+ print(f"Running {agent_name} in UI mode, agent options: {agent_options}")
219
+ # UI mode
220
+ gradio_ui = chat_func(deps=deps, **agent_run_options)
221
+ gradio_ui.launch(**launch_options)
222
+
223
+
224
+ @main.command()
225
+ @agent_option
226
+ @model_option
227
+ @use_cborg_option
228
+ @share_option
229
+ @server_port_option
230
+ @workdir_option
231
+ @ui_option
232
+ @run_evals_option
233
+ @click.argument("query", nargs=-1, required=False)
234
+ def agent(ui, query, agent, use_cborg=False, run_evals=False, **kwargs):
235
+ """NEW: Generic agent runner.
236
+
237
+ Run with a query for direct mode or with --ui for interactive chat mode.
238
+ """
239
+ if not agent:
240
+ raise click.UsageError("Error: --agent is required")
241
+ agent_module = f"aurelian.agents.{agent}"
242
+ specialist_agent_name = agent
243
+ gradio_module = __import__(f"{agent_module}.{agent}_gradio", fromlist=["chat"])
244
+ agent_class = __import__(f"{agent_module}.{agent}_agent", fromlist=[f"{specialist_agent_name}_agent"])
245
+ config_module = __import__(f"{agent_module}.{agent}_config", fromlist=["get_config"])
246
+
247
+ chat_func = gradio_module.chat
248
+ agent_obj = getattr(agent_class, f"{specialist_agent_name}_agent")
249
+ get_config = config_module.get_config
250
+
251
+ # Process agent and UI options
252
+ agent_keys = ["model", "use_cborg", "workdir", "ontologies", "db_path", "collection_name"]
253
+ agent_options, launch_options = split_options(kwargs, agent_keys=agent_keys)
254
+
255
+ deps = get_config()
256
+
257
+ # Set workdir if provided
258
+ if hasattr(deps, 'workdir'):
259
+ deps.workdir.location = kwargs['workdir']
260
+
261
+ # Remove workdir from agent options to avoid duplicates
262
+ agent_run_options = {k: v for k, v in agent_options.items() if k != 'workdir'}
263
+
264
+ # TODO: make this generic, for any proxy model
265
+ if use_cborg:
266
+ cborg_api_key = os.environ.get("CBORG_API_KEY")
267
+ model = OpenAIModel(
268
+ agent_run_options.get("model", "openai:gpt-4o"),
269
+ provider=OpenAIProvider(
270
+ base_url="https://api.cborg.lbl.gov",
271
+ api_key=cborg_api_key),
272
+ )
273
+ agent_run_options["model"] = model
274
+
275
+ # Run in appropriate mode
276
+ if not ui and query:
277
+ # Direct query mode
278
+ join_char = " "
279
+ # Run the agent and print results
280
+ agent_run_func = getattr(agent_obj, "run_sync")
281
+ r = agent_run_func(join_char.join(query), deps=deps, **agent_run_options)
282
+ print(r.data)
283
+ mjb = r.all_messages_json()
284
+ # decode messages from json bytes to dict:
285
+ if isinstance(mjb, bytes):
286
+ mjb = mjb.decode()
287
+ # print the messages
288
+ import json
289
+ all_messages = json.loads(mjb)
290
+ import yaml
291
+ # print(yaml.dump(all_messages, indent=2))
292
+ elif run_evals:
293
+ import sys
294
+ import importlib
295
+ # TODO: make this generic
296
+ package_name = f"{agent_module}.{agent}_evals"
297
+ module = importlib.import_module(package_name)
298
+ dataset = module.create_eval_dataset()
299
+
300
+ async def run_agent(inputs: str) -> Any:
301
+ result = await agent_obj.run(inputs, deps=deps, **agent_run_options)
302
+ return result.data
303
+
304
+ eval_func: Callable[[str], Awaitable[str]] = run_agent
305
+ report = dataset.evaluate_sync(eval_func)
306
+ report.print(include_input=True, include_output=True)
307
+ else:
308
+ print(f"Running {agent} in UI mode, agent options: {agent_options}")
309
+ # UI mode
310
+ gradio_ui = chat_func(deps=deps, **agent_run_options)
311
+ gradio_ui.launch(**launch_options)
312
+
313
+
314
+
315
+ @main.command()
316
+ @click.option("--limit", "-l", default=10, show_default=True, help="Number of results to return.")
317
+ @click.argument("ontology")
318
+ @click.argument("term")
319
+ def search_ontology(ontology: str, term: str, **kwargs):
320
+ """Search the ontology for the given query term.
321
+
322
+ Also has side effect of indexing. You may want to pre-index before
323
+ starting an individual UI.
324
+ """
325
+ import aurelian.utils.ontology_utils as ontology_utils
326
+ from oaklib import get_adapter
327
+
328
+ handle = "sqlite:obo:" + ontology
329
+ adapter = get_adapter(handle)
330
+ objs = ontology_utils.search_ontology(adapter, term, **kwargs)
331
+ for id, label in objs:
332
+ print(id, label)
333
+
334
+
335
+ @main.command()
336
+ @agent_option
337
+ @model_option
338
+ @use_cborg_option
339
+ @share_option
340
+ @server_port_option
341
+ @ui_option
342
+ @click.argument("query", nargs=-1, required=False)
343
+ def gocam(ui, query, agent, **kwargs):
344
+ """Start the GO-CAM Agent for gene ontology causal activity models.
345
+
346
+ The GO-CAM Agent helps create and analyze Gene Ontology Causal Activity Models,
347
+ which describe biological systems as molecular activities connected by causal
348
+ relationships.
349
+
350
+ Run with a query for direct mode or with --ui for interactive chat mode.
351
+ """
352
+ run_agent("gocam", "aurelian.agents.gocam", query=query, ui=ui, specialist_agent_name=agent, **kwargs)
353
+
354
+
355
+
356
+ @main.command()
357
+ @model_option
358
+ @workdir_option
359
+ @share_option
360
+ @server_port_option
361
+ @ui_option
362
+ @click.argument("query", nargs=-1, required=False)
363
+ def phenopackets(ui, query, **kwargs):
364
+ """Start the Phenopackets Agent for standardized phenotype data.
365
+
366
+ The Phenopackets Agent helps work with GA4GH Phenopackets, a standard
367
+ format for sharing disease and phenotype information for genomic
368
+ medicine.
369
+
370
+ Run with a query for direct mode or with --ui for interactive chat mode.
371
+ """
372
+ run_agent("phenopackets", "aurelian.agents.phenopackets", query=query, ui=ui, **kwargs)
373
+
374
+
375
+ @main.command()
376
+ @model_option
377
+ @workdir_option
378
+ @share_option
379
+ @server_port_option
380
+ @ui_option
381
+ @click.argument("query", nargs=-1, required=False)
382
+ def diagnosis(ui, query, **kwargs):
383
+ """Start the Diagnosis Agent for rare disease diagnosis.
384
+
385
+ The Diagnosis Agent assists in diagnosing rare diseases by leveraging the
386
+ Monarch Knowledge Base. It helps clinical geneticists evaluate potential
387
+ conditions based on patient phenotypes.
388
+
389
+ Run with a query for direct mode or with --ui for interactive chat mode.
390
+ """
391
+ run_agent("diagnosis", "aurelian.agents.diagnosis", query=query, ui=ui, **kwargs)
392
+
393
+
394
+ @main.command()
395
+ @model_option
396
+ @workdir_option
397
+ @share_option
398
+ @server_port_option
399
+ @ui_option
400
+ @click.argument("query", nargs=-1, required=False)
401
+ def checklist(ui, query, **kwargs):
402
+ """Start the Checklist Agent for paper evaluation.
403
+
404
+ The Checklist Agent evaluates scientific papers against established checklists
405
+ such as STREAMS, STORMS, and ARRIVE. It helps ensure that papers conform to
406
+ relevant reporting guidelines and best practices.
407
+
408
+ Run with a query for direct mode or with --ui for interactive chat mode.
409
+ """
410
+ run_agent("checklist", "aurelian.agents.checklist", query=query, ui=ui, **kwargs)
411
+
412
+
413
+ # Keep backward compatibility
414
+ @main.command()
415
+ @model_option
416
+ @workdir_option
417
+ @share_option
418
+ @server_port_option
419
+ def aria(**kwargs):
420
+ """Start the Checklist UI (deprecated, use 'checklist' instead)."""
421
+ run_agent("checklist", "aurelian.agents.checklist", ui=True, **kwargs)
422
+
423
+
424
+ @main.command()
425
+ @model_option
426
+ @workdir_option
427
+ @share_option
428
+ @server_port_option
429
+ @ui_option
430
+ @click.argument("query", nargs=-1, required=False)
431
+ def linkml(ui, query, **kwargs):
432
+ """Start the LinkML Agent for data modeling and schema validation.
433
+
434
+ The LinkML Agent helps create and validate data models and schemas using the
435
+ Linked data Modeling Language (LinkML). It can assist in generating schemas,
436
+ validating data against schemas, and modeling domain knowledge.
437
+
438
+ Run with a query for direct mode or with --ui for interactive chat mode.
439
+ """
440
+ run_agent("linkml", "aurelian.agents.linkml", query=query, ui=ui, **kwargs)
441
+
442
+
443
+ @main.command()
444
+ @model_option
445
+ @workdir_option
446
+ @share_option
447
+ @server_port_option
448
+ @ui_option
449
+ @click.argument("query", nargs=-1, required=False)
450
+ def robot(ui, query, **kwargs):
451
+ """Start the ROBOT Agent for ontology operations.
452
+
453
+ The ROBOT Agent provides natural language access to ontology operations
454
+ and manipulations using the ROBOT tool. It can create, modify, and analyze
455
+ ontologies through a chat interface.
456
+
457
+ Run with a query for direct mode or with --ui for interactive chat mode.
458
+ """
459
+ run_agent("robot", "aurelian.agents.robot", query=query, ui=ui, agent_func_name="chat", **kwargs)
460
+
461
+
462
+ @main.command()
463
+ @model_option
464
+ @workdir_option
465
+ @share_option
466
+ @server_port_option
467
+ @ui_option
468
+ @click.argument("query", nargs=-1, required=False)
469
+ def amigo(ui, query, **kwargs):
470
+ """Start the AmiGO Agent for Gene Ontology data exploration.
471
+
472
+ The AmiGO Agent provides access to the Gene Ontology (GO) and gene
473
+ product annotations. It helps users explore gene functions and
474
+ ontology relationships.
475
+
476
+ Run with a query for direct mode or with --ui for interactive chat mode.
477
+ """
478
+ run_agent("amigo", "aurelian.agents.amigo", query=query, ui=ui, **kwargs)
479
+
480
+
481
+ @main.command()
482
+ @model_option
483
+ @workdir_option
484
+ @share_option
485
+ @server_port_option
486
+ @ui_option
487
+ @db_path_option
488
+ @collection_name_option
489
+ @click.argument("query", nargs=-1, required=False)
490
+ def rag(ui, query, db_path, collection_name, **kwargs):
491
+ """Start the RAG Agent for document retrieval and generation.
492
+
493
+ The RAG (Retrieval-Augmented Generation) Agent provides a natural language
494
+ interface for exploring and searching document collections. It uses RAG
495
+ techniques to combine search capabilities with generative AI.
496
+
497
+ Run with a query for direct mode or with --ui for interactive chat mode.
498
+ """
499
+ if not db_path:
500
+ click.echo("Error: --db-path is required")
501
+ return
502
+
503
+ # Add special parameters to kwargs
504
+ kwargs["db_path"] = db_path
505
+ if collection_name:
506
+ kwargs["collection_name"] = collection_name
507
+
508
+ run_agent("rag", "aurelian.agents.rag", query=query, ui=ui, **kwargs)
509
+
510
+
511
+ @main.command()
512
+ @model_option
513
+ @workdir_option
514
+ @share_option
515
+ @server_port_option
516
+ @ui_option
517
+ @ontologies_option
518
+ @click.argument("query", nargs=-1, required=False)
519
+ def mapper(ui, query, ontologies, **kwargs):
520
+ """Start the Ontology Mapper Agent for mapping between ontologies.
521
+
522
+ The Ontology Mapper Agent helps translate terms between different ontologies
523
+ and vocabularies. It can find equivalent concepts across ontologies and
524
+ explain relationships.
525
+
526
+ Run with a query for direct mode or with --ui for interactive chat mode.
527
+ """
528
+ # Special handling for ontologies parameter
529
+ if ontologies:
530
+ if isinstance(ontologies, str):
531
+ ontologies = [ontologies]
532
+ kwargs["ontologies"] = ontologies
533
+
534
+ run_agent("ontology_mapper", "aurelian.agents.ontology_mapper", query=query, ui=ui, join_char="\n", **kwargs)
535
+
536
+
537
+ @main.command()
538
+ @click.argument("pmid")
539
+ def fulltext(pmid):
540
+ """Download full text for a PubMed article."""
541
+ from aurelian.utils.pubmed_utils import get_pmid_text
542
+ txt = get_pmid_text(pmid)
543
+ print(txt)
544
+
545
+
546
+ @main.command()
547
+ @click.argument("term")
548
+ def websearch(term):
549
+ """Search the web for a query term."""
550
+ from aurelian.utils.search_utils import web_search
551
+ txt = web_search(term)
552
+ print(txt)
553
+
554
+ @main.command()
555
+ @click.argument("term")
556
+ def perplexity(term):
557
+ """Search the web for a query term, with citations."""
558
+ from aurelian.agents.web.web_tools import perplexity_query
559
+ result = run_sync(perplexity_query(term))
560
+ import yaml
561
+ print(yaml.dump(result.model_dump(), indent=2))
562
+
563
+ @main.command()
564
+ @click.argument("url")
565
+ def geturl(url):
566
+ """Retrieve content from a URL."""
567
+ from aurelian.utils.search_utils import retrieve_web_page
568
+ txt = retrieve_web_page(url)
569
+ print(txt)
570
+
571
+
572
+ @main.command()
573
+ @model_option
574
+ @workdir_option
575
+ @share_option
576
+ @server_port_option
577
+ @ui_option
578
+ @click.argument("url", required=False)
579
+ def datasheets(ui, url, **kwargs):
580
+ """Start the Datasheets for Datasets (D4D) Agent.
581
+
582
+ The D4D Agent extracts structured metadata from dataset documentation
583
+ according to the Datasheets for Datasets schema. It can analyze both
584
+ web pages and PDF documents describing datasets.
585
+
586
+ Run with a URL for direct mode or with --ui for interactive chat mode.
587
+ """
588
+ run_agent("d4d", "aurelian.agents.d4d", query=(url,) if url else None, ui=ui, **kwargs)
589
+
590
+
591
+ @main.command()
592
+ @model_option
593
+ @workdir_option
594
+ @share_option
595
+ @server_port_option
596
+ @ui_option
597
+ @click.argument("query", nargs=-1, required=False)
598
+ def chemistry(ui, query, **kwargs):
599
+ """Start the Chemistry Agent for chemical structure analysis.
600
+
601
+ The Chemistry Agent helps interpret and work with chemical structures,
602
+ formulas, and related information.
603
+
604
+ Run with a query for direct mode or with --ui for interactive chat mode.
605
+ """
606
+ run_agent("chemistry", "aurelian.agents.chemistry", query=query, ui=ui, **kwargs)
607
+
608
+
609
+ @main.command()
610
+ @model_option
611
+ @workdir_option
612
+ @share_option
613
+ @server_port_option
614
+ @ui_option
615
+ @click.argument("query", nargs=-1, required=False)
616
+ def literature(ui, query, **kwargs):
617
+ """Start the Literature Agent for scientific publication analysis.
618
+
619
+ The Literature Agent provides tools for analyzing scientific publications,
620
+ extracting key information, and answering questions about research articles.
621
+
622
+ Run with a query for direct mode or with --ui for interactive chat mode.
623
+ """
624
+ run_agent("literature", "aurelian.agents.literature", query=query, ui=ui, **kwargs)
625
+
626
+
627
+ @main.command()
628
+ @model_option
629
+ @workdir_option
630
+ @share_option
631
+ @server_port_option
632
+ @ui_option
633
+ @click.argument("query", nargs=-1, required=False)
634
+ def biblio(ui, query, **kwargs):
635
+ """Start the Biblio Agent for bibliographic data management.
636
+
637
+ The Biblio Agent helps organize and search bibliographic data and citations.
638
+ It provides tools for searching a bibliography database, retrieving scientific
639
+ publications, and accessing web content.
640
+
641
+ Run with a query for direct mode or with --ui for interactive chat mode.
642
+ """
643
+ run_agent("biblio", "aurelian.agents.biblio", query=query, ui=ui, **kwargs)
644
+
645
+
646
+ @main.command()
647
+ @model_option
648
+ @workdir_option
649
+ @share_option
650
+ @server_port_option
651
+ @ui_option
652
+ @click.argument("query", nargs=-1, required=False)
653
+ def monarch(ui, query, **kwargs):
654
+ """Start the Monarch Agent for biomedical knowledge exploration.
655
+
656
+ The Monarch Agent provides access to relationships between genes, diseases,
657
+ phenotypes, and other biomedical entities through the Monarch Knowledge Base.
658
+
659
+ Run with a query for direct mode or with --ui for interactive chat mode.
660
+ """
661
+ run_agent("monarch", "aurelian.agents.monarch", query=query, ui=ui, **kwargs)
662
+
663
+
664
+ @main.command()
665
+ @model_option
666
+ @workdir_option
667
+ @share_option
668
+ @server_port_option
669
+ @ui_option
670
+ @click.argument("query", nargs=-1, required=False)
671
+ def ubergraph(ui, query, **kwargs):
672
+ """Start the UberGraph Agent for SPARQL-based ontology queries.
673
+
674
+ The UberGraph Agent provides a natural language interface to query ontologies
675
+ using SPARQL through the UberGraph endpoint. It helps users formulate and execute
676
+ SPARQL queries without needing to know the full SPARQL syntax.
677
+
678
+ Run with a query for direct mode or with --ui for interactive chat mode.
679
+ """
680
+ run_agent("ubergraph", "aurelian.agents.ubergraph", query=query, ui=ui, **kwargs)
681
+
682
+
683
+ @main.command()
684
+ @model_option
685
+ @workdir_option
686
+ @share_option
687
+ @server_port_option
688
+ @ui_option
689
+ @click.argument("query", nargs=-1, required=False)
690
+ def gene(ui, query, **kwargs):
691
+ """Start the Gene Agent for retrieving gene descriptions.
692
+
693
+ The Gene Agent retrieves descriptions for gene identifiers using the UniProt API.
694
+ It can process a single gene or a list of genes and returns detailed information
695
+ about gene function, products, and associations.
696
+
697
+ Run with a query for direct mode or with --ui for interactive chat mode.
698
+ """
699
+ run_agent("gene", "aurelian.agents.gene", query=query, ui=ui, **kwargs)
700
+
701
+ @main.command()
702
+ @model_option
703
+ @use_cborg_option
704
+ @workdir_option
705
+ @share_option
706
+ @server_port_option
707
+ @ui_option
708
+ @click.argument("query", nargs=-1, required=False)
709
+ def goann(ui, query, **kwargs):
710
+ """Start the GO Annotation Review Agent for evaluating GO annotations.
711
+
712
+ The GO Annotation Review Agent helps review GO annotations for accuracy
713
+ and proper evidence. It can evaluate annotations based on evidence codes,
714
+ identify potential over-annotations, and ensure compliance with GO guidelines,
715
+ particularly for transcription factors.
716
+
717
+ Run with a query for direct mode or with --ui for interactive chat mode.
718
+ """
719
+ run_agent("goann", "aurelian.agents.goann", query=query, ui=ui, **kwargs)
720
+
721
+
722
+ @main.command()
723
+ @model_option
724
+ @workdir_option
725
+ @share_option
726
+ @server_port_option
727
+ @ui_option
728
+ @click.argument("query", nargs=-1, required=False)
729
+ def github(ui, query, **kwargs):
730
+ """Start the GitHub Agent for repository interaction.
731
+
732
+ The GitHub Agent provides a natural language interface for interacting with GitHub
733
+ repositories. It can list/view pull requests and issues, find connections between PRs
734
+ and issues, search code, clone repositories, and examine commit history.
735
+
736
+ Requires GitHub CLI (gh) to be installed and authenticated.
737
+
738
+ Run with a query for direct mode or with --ui for interactive chat mode.
739
+ """
740
+ run_agent("github", "aurelian.agents.github", query=query, ui=ui, **kwargs)
741
+
742
+
743
+ @main.command()
744
+ @model_option
745
+ @workdir_option
746
+ @share_option
747
+ @server_port_option
748
+ @ui_option
749
+ @click.argument("query", nargs=-1, required=False)
750
+ def draw(ui, query, **kwargs):
751
+ """Start the Draw Agent for creating SVG drawings.
752
+
753
+ The Draw Agent creates SVG drawings based on text descriptions and provides
754
+ feedback on drawing quality from an art critic judge. It helps generate visual
755
+ representations from textual descriptions with a focus on clarity and simplicity.
756
+
757
+ Run with a query for direct mode or with --ui for interactive chat mode.
758
+ """
759
+ run_agent("draw", "aurelian.agents.draw", query=query, ui=ui, **kwargs)
760
+
761
+
762
+ @main.command()
763
+ @ui_option
764
+ @workdir_option
765
+ @share_option
766
+ @server_port_option
767
+ @click.option("--list", "-l", help="Comma-separated list of gene identifiers")
768
+ @click.option("--taxon", "-t", help="Species/taxon the genes belong to (e.g., 'Homo sapiens', 'Desulfovibrio vulgaris')", required=True)
769
+ @click.argument("query", nargs=-1, required=False)
770
+ def talisman(ui, list, taxon, query, **kwargs):
771
+ """Start the Talisman Agent for advanced gene analysis.
772
+
773
+ The Talisman Agent retrieves descriptions for gene identifiers using UniProt and NCBI Entrez.
774
+ It can process a single gene, protein ID, or a list of genes and returns detailed information.
775
+ It also can analyze relationships between multiple genes to identify functional connections.
776
+
777
+ Run with --list and --taxon options for direct mode or with --ui for interactive chat mode.
778
+ The taxon/species parameter is required to provide proper context for gene analysis.
779
+
780
+ Examples:
781
+ aurelian talisman --list "TP53" --taxon "Homo sapiens"
782
+ aurelian talisman --list "TP53, MDM2" --taxon "Homo sapiens"
783
+ aurelian talisman --list "DVUA0001, DVUA0002" --taxon "Desulfovibrio vulgaris"
784
+ """
785
+ # Import the necessary functions from talisman_tools
786
+ from aurelian.agents.talisman.talisman_tools import (
787
+ ensure_complete_output,
788
+ GeneSetAnalysis,
789
+ FunctionalTerm,
790
+ GeneSummary
791
+ )
792
+ import re
793
+
794
+ # Convert positional argument to list option if provided
795
+ if query and not list:
796
+ list = " ".join(query)
797
+
798
+ # Inform the user if no gene list is provided
799
+ if not list and not ui:
800
+ import click
801
+ click.echo("Error: Either --list or --ui must be provided.")
802
+ return
803
+
804
+ # Prepare the prompt with the gene list and species information
805
+ if list:
806
+ list_prompt = f"Gene list: {list}\nSpecies: {taxon}"
807
+ else:
808
+ list_prompt = ""
809
+
810
+ # Create a wrapper function to post-process the output
811
+ def process_talisman_output(result):
812
+ print("=== ORIGINAL OUTPUT ===")
813
+ print(result)
814
+ print("=== END ORIGINAL OUTPUT ===")
815
+
816
+ # Force a complete rebuild of the output regardless of what's in the original result
817
+ # This ensures we always have all sections
818
+
819
+ # Extract inferred species from the result if available
820
+ inferred_species = taxon # Default to the provided taxon
821
+ organism_match = re.search(r'\|\s*\w+\s*\|\s*[^|]+\|\s*[^|]+\|\s*([^|]+)\|', result)
822
+ if organism_match:
823
+ inferred_species = organism_match.group(1).strip()
824
+
825
+ # Create gene summaries from the output
826
+ gene_summaries = []
827
+ gene_table_match = re.search(r'##?\s*Gene Summary Table.*?\n\|.*?\n\|.*?\n(.*?)(?=\n\n|\n##|\Z)',
828
+ result, re.DOTALL)
829
+ if gene_table_match:
830
+ for line in gene_table_match.group(1).split('\n'):
831
+ if '|' in line:
832
+ cols = [col.strip() for col in line.split('|')]
833
+ if len(cols) >= 6: # Account for empty first and last elements
834
+ gene_id = cols[1]
835
+ if gene_id and gene_id != '-':
836
+ gene_summaries.append(
837
+ GeneSummary(
838
+ id=cols[1],
839
+ annotation=cols[2],
840
+ genomic_context=cols[3],
841
+ organism=cols[4],
842
+ description=cols[5]
843
+ )
844
+ )
845
+
846
+ # Create default functional terms for the gene set
847
+ functional_terms = []
848
+ if gene_summaries:
849
+ gene_ids = [g.id for g in gene_summaries]
850
+
851
+ # Default functional terms based on gene descriptions
852
+ for gene in gene_summaries:
853
+ if "DNA" in gene.description or "binding" in gene.description.lower():
854
+ functional_terms.append(
855
+ FunctionalTerm(
856
+ term="DNA binding",
857
+ genes=[gene.id],
858
+ source="GO-MF"
859
+ )
860
+ )
861
+ if "stress" in gene.description.lower():
862
+ functional_terms.append(
863
+ FunctionalTerm(
864
+ term="Stress response",
865
+ genes=[gene.id],
866
+ source="GO-BP"
867
+ )
868
+ )
869
+ if "ParA" in gene.description:
870
+ functional_terms.append(
871
+ FunctionalTerm(
872
+ term="Plasmid partitioning",
873
+ genes=[gene.id],
874
+ source="GO-BP"
875
+ )
876
+ )
877
+
878
+ # Add a generic set term
879
+ functional_terms.append(
880
+ FunctionalTerm(
881
+ term="Gene set",
882
+ genes=gene_ids,
883
+ source="Analysis"
884
+ )
885
+ )
886
+
887
+ # Try to extract existing narrative text if any
888
+ narrative = "This gene set includes proteins with functions related to DNA binding, stress response, and plasmid maintenance."
889
+ # Look for any text outside of table sections
890
+ narrative_section = re.search(r'(?:^|\n\n)((?!##)[^|#].*?)(?=\n##|\Z)', result, re.DOTALL)
891
+ if narrative_section:
892
+ extracted_text = narrative_section.group(1).strip()
893
+ if len(extracted_text.split()) > 3: # Only use if it's substantial
894
+ narrative = extracted_text
895
+
896
+ # Create a properly structured analysis object
897
+ analysis = GeneSetAnalysis(
898
+ input_species=taxon,
899
+ inferred_species=inferred_species,
900
+ narrative=narrative,
901
+ functional_terms=functional_terms,
902
+ gene_summaries=gene_summaries
903
+ )
904
+
905
+ # ALWAYS rebuild the output completely to ensure proper formatting
906
+ output = ""
907
+
908
+ # 1. Add Species section
909
+ output += f"# Species\nInput: {taxon}\nInferred: {inferred_species}\n\n"
910
+
911
+ # 2. Add Gene Set Analysis header
912
+ output += "# Gene Set Analysis\n\n"
913
+
914
+ # 3. Add Narrative section (always included)
915
+ output += f"## Narrative\n{analysis.narrative}\n\n"
916
+
917
+ # 4. Add Functional Terms Table (always included)
918
+ output += "## Functional Terms Table\n"
919
+ output += "| Functional Term | Genes | Source |\n"
920
+ output += "|-----------------|-------|--------|\n"
921
+
922
+ if analysis.functional_terms:
923
+ for term in analysis.functional_terms:
924
+ genes_str = ", ".join(term.genes)
925
+ output += f"| {term.term} | {genes_str} | {term.source} |\n"
926
+ else:
927
+ output += "| No functional terms available | - | - |\n"
928
+
929
+ output += "\n"
930
+
931
+ # 5. Add Gene Summary Table (always included)
932
+ output += "## Gene Summary Table\n"
933
+ output += "| ID | Annotation | Genomic Context | Organism | Description |\n"
934
+ output += "|-------------|-------------|----------|----------------|------------|\n"
935
+
936
+ if analysis.gene_summaries:
937
+ for gene in analysis.gene_summaries:
938
+ output += f"| {gene.id} | {gene.annotation} | {gene.genomic_context} | {gene.organism} | {gene.description} |\n"
939
+ else:
940
+ output += "| No gene information available | - | - | - | - |\n"
941
+
942
+ print("=== PROCESSED OUTPUT ===")
943
+ print(output)
944
+ print("=== END PROCESSED OUTPUT ===")
945
+
946
+ return output
947
+
948
+ # Run the agent with post-processing of the output and species information
949
+ run_agent("talisman", "aurelian.agents.talisman", query=list_prompt, ui=ui,
950
+ result_processor=process_talisman_output, **kwargs)
951
+ @model_option
952
+ @workdir_option
953
+ @share_option
954
+ @server_port_option
955
+ @ui_option
956
+ @click.argument("query", nargs=-1, required=False)
957
+ def reaction(ui, query, **kwargs):
958
+ """Start the Reaction Agent for biochemical reaction query and curation.
959
+
960
+ The Reaction Agent helps query and curate biochemical reactions from various sources
961
+ including RHEA and UniProt. It can identify enzymes, substrates, products, and
962
+ extract reaction information from scientific text.
963
+
964
+ Run with a query for direct mode or with --ui for interactive chat mode.
965
+ """
966
+ run_agent("reaction", "aurelian.agents.reaction", query=query, ui=ui, **kwargs)
967
+
968
+
969
+
970
+ @main.command()
971
+ @model_option
972
+ @workdir_option
973
+ @share_option
974
+ @server_port_option
975
+ @ui_option
976
+ @click.argument("query", nargs=-1, required=False)
977
+ def paperqa(ui, query, **kwargs):
978
+ """Start the PaperQA Agent for scientific literature search and analysis.
979
+
980
+ The PaperQA Agent helps search, organize, and analyze scientific papers. It can
981
+ find papers on specific topics, add papers to your collection, and answer questions
982
+ based on the papers in your collection.
983
+
984
+ Run with a query for direct mode or with --ui for interactive chat mode.
985
+
986
+ Use `aurelian paperqa` subcommands for paper management:
987
+ - `aurelian paperqa index` to index papers for searching
988
+ - `aurelian paperqa list` to list papers in your collection
989
+ """
990
+ run_agent("paperqa", "aurelian.agents.paperqa", query=query, ui=ui, **kwargs)
991
+
992
+
993
+ # Import and register PaperQA CLI commands
994
+ from aurelian.agents.paperqa.paperqa_cli import paperqa_cli
995
+ main.add_command(paperqa_cli)
996
+
997
+ # DO NOT REMOVE THIS LINE
998
+ # added this for mkdocstrings to work
999
+ # see https://github.com/bruce-szalwinski/mkdocs-typer/issues/18
1000
+ #click_app = get_command(app)
1001
+ #click_app.name = "aurelian"
1002
+
1003
+ if __name__ == "__main__":
1004
+ main()