aurelian 0.3.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.
- aurelian/__init__.py +9 -0
- aurelian/agents/__init__.py +0 -0
- aurelian/agents/amigo/__init__.py +3 -0
- aurelian/agents/amigo/amigo_agent.py +77 -0
- aurelian/agents/amigo/amigo_config.py +85 -0
- aurelian/agents/amigo/amigo_evals.py +73 -0
- aurelian/agents/amigo/amigo_gradio.py +52 -0
- aurelian/agents/amigo/amigo_mcp.py +152 -0
- aurelian/agents/amigo/amigo_tools.py +152 -0
- aurelian/agents/biblio/__init__.py +42 -0
- aurelian/agents/biblio/biblio_agent.py +94 -0
- aurelian/agents/biblio/biblio_config.py +40 -0
- aurelian/agents/biblio/biblio_gradio.py +67 -0
- aurelian/agents/biblio/biblio_mcp.py +115 -0
- aurelian/agents/biblio/biblio_tools.py +164 -0
- aurelian/agents/biblio_agent.py +46 -0
- aurelian/agents/checklist/__init__.py +44 -0
- aurelian/agents/checklist/checklist_agent.py +85 -0
- aurelian/agents/checklist/checklist_config.py +28 -0
- aurelian/agents/checklist/checklist_gradio.py +70 -0
- aurelian/agents/checklist/checklist_mcp.py +86 -0
- aurelian/agents/checklist/checklist_tools.py +141 -0
- aurelian/agents/checklist/content/checklists.yaml +7 -0
- aurelian/agents/checklist/content/streams.csv +136 -0
- aurelian/agents/checklist_agent.py +40 -0
- aurelian/agents/chemistry/__init__.py +3 -0
- aurelian/agents/chemistry/chemistry_agent.py +46 -0
- aurelian/agents/chemistry/chemistry_config.py +71 -0
- aurelian/agents/chemistry/chemistry_evals.py +79 -0
- aurelian/agents/chemistry/chemistry_gradio.py +50 -0
- aurelian/agents/chemistry/chemistry_mcp.py +120 -0
- aurelian/agents/chemistry/chemistry_tools.py +121 -0
- aurelian/agents/chemistry/image_agent.py +15 -0
- aurelian/agents/d4d/__init__.py +30 -0
- aurelian/agents/d4d/d4d_agent.py +72 -0
- aurelian/agents/d4d/d4d_config.py +46 -0
- aurelian/agents/d4d/d4d_gradio.py +58 -0
- aurelian/agents/d4d/d4d_mcp.py +71 -0
- aurelian/agents/d4d/d4d_tools.py +157 -0
- aurelian/agents/d4d_agent.py +64 -0
- aurelian/agents/diagnosis/__init__.py +33 -0
- aurelian/agents/diagnosis/diagnosis_agent.py +53 -0
- aurelian/agents/diagnosis/diagnosis_config.py +48 -0
- aurelian/agents/diagnosis/diagnosis_evals.py +76 -0
- aurelian/agents/diagnosis/diagnosis_gradio.py +52 -0
- aurelian/agents/diagnosis/diagnosis_mcp.py +141 -0
- aurelian/agents/diagnosis/diagnosis_tools.py +204 -0
- aurelian/agents/diagnosis_agent.py +28 -0
- aurelian/agents/draw/__init__.py +3 -0
- aurelian/agents/draw/draw_agent.py +39 -0
- aurelian/agents/draw/draw_config.py +26 -0
- aurelian/agents/draw/draw_gradio.py +50 -0
- aurelian/agents/draw/draw_mcp.py +94 -0
- aurelian/agents/draw/draw_tools.py +100 -0
- aurelian/agents/draw/judge_agent.py +18 -0
- aurelian/agents/filesystem/__init__.py +0 -0
- aurelian/agents/filesystem/filesystem_config.py +27 -0
- aurelian/agents/filesystem/filesystem_gradio.py +49 -0
- aurelian/agents/filesystem/filesystem_mcp.py +89 -0
- aurelian/agents/filesystem/filesystem_tools.py +95 -0
- aurelian/agents/filesystem/py.typed +0 -0
- aurelian/agents/github/__init__.py +0 -0
- aurelian/agents/github/github_agent.py +83 -0
- aurelian/agents/github/github_cli.py +248 -0
- aurelian/agents/github/github_config.py +22 -0
- aurelian/agents/github/github_gradio.py +152 -0
- aurelian/agents/github/github_mcp.py +252 -0
- aurelian/agents/github/github_tools.py +408 -0
- aurelian/agents/github/github_tools.py.tmp +413 -0
- aurelian/agents/goann/__init__.py +13 -0
- aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines.md +1000 -0
- aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines.pdf +0 -0
- aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines_Paper.md +693 -0
- aurelian/agents/goann/documents/Transcription_Factors_Annotation_Guidelines_Paper.pdf +0 -0
- aurelian/agents/goann/goann_agent.py +90 -0
- aurelian/agents/goann/goann_config.py +90 -0
- aurelian/agents/goann/goann_evals.py +104 -0
- aurelian/agents/goann/goann_gradio.py +62 -0
- aurelian/agents/goann/goann_mcp.py +0 -0
- aurelian/agents/goann/goann_tools.py +65 -0
- aurelian/agents/gocam/__init__.py +43 -0
- aurelian/agents/gocam/documents/DNA-binding transcription factor activity annotation guidelines.docx +0 -0
- aurelian/agents/gocam/documents/DNA-binding transcription factor activity annotation guidelines.pdf +0 -0
- aurelian/agents/gocam/documents/DNA-binding_transcription_factor_activity_annotation_guidelines.md +100 -0
- aurelian/agents/gocam/documents/E3 ubiquitin ligases.docx +0 -0
- aurelian/agents/gocam/documents/E3 ubiquitin ligases.pdf +0 -0
- aurelian/agents/gocam/documents/E3_ubiquitin_ligases.md +134 -0
- aurelian/agents/gocam/documents/GO-CAM annotation guidelines README.docx +0 -0
- aurelian/agents/gocam/documents/GO-CAM annotation guidelines README.pdf +0 -0
- aurelian/agents/gocam/documents/GO-CAM modelling guidelines TO DO.docx +0 -0
- aurelian/agents/gocam/documents/GO-CAM modelling guidelines TO DO.pdf +0 -0
- aurelian/agents/gocam/documents/GO-CAM_annotation_guidelines_README.md +1 -0
- aurelian/agents/gocam/documents/GO-CAM_modelling_guidelines_TO_DO.md +3 -0
- aurelian/agents/gocam/documents/How to annotate complexes in GO-CAM.docx +0 -0
- aurelian/agents/gocam/documents/How to annotate complexes in GO-CAM.pdf +0 -0
- aurelian/agents/gocam/documents/How to annotate molecular adaptors.docx +0 -0
- aurelian/agents/gocam/documents/How to annotate molecular adaptors.pdf +0 -0
- aurelian/agents/gocam/documents/How to annotate sequestering proteins.docx +0 -0
- aurelian/agents/gocam/documents/How to annotate sequestering proteins.pdf +0 -0
- aurelian/agents/gocam/documents/How_to_annotate_complexes_in_GO-CAM.md +29 -0
- aurelian/agents/gocam/documents/How_to_annotate_molecular_adaptors.md +31 -0
- aurelian/agents/gocam/documents/How_to_annotate_sequestering_proteins.md +42 -0
- aurelian/agents/gocam/documents/Molecular adaptor activity.docx +0 -0
- aurelian/agents/gocam/documents/Molecular adaptor activity.pdf +0 -0
- aurelian/agents/gocam/documents/Molecular carrier activity.docx +0 -0
- aurelian/agents/gocam/documents/Molecular carrier activity.pdf +0 -0
- aurelian/agents/gocam/documents/Molecular_adaptor_activity.md +51 -0
- aurelian/agents/gocam/documents/Molecular_carrier_activity.md +41 -0
- aurelian/agents/gocam/documents/Protein sequestering activity.docx +0 -0
- aurelian/agents/gocam/documents/Protein sequestering activity.pdf +0 -0
- aurelian/agents/gocam/documents/Protein_sequestering_activity.md +50 -0
- aurelian/agents/gocam/documents/Signaling receptor activity annotation guidelines.docx +0 -0
- aurelian/agents/gocam/documents/Signaling receptor activity annotation guidelines.pdf +0 -0
- aurelian/agents/gocam/documents/Signaling_receptor_activity_annotation_guidelines.md +187 -0
- aurelian/agents/gocam/documents/Transcription coregulator activity.docx +0 -0
- aurelian/agents/gocam/documents/Transcription coregulator activity.pdf +0 -0
- aurelian/agents/gocam/documents/Transcription_coregulator_activity.md +36 -0
- aurelian/agents/gocam/documents/Transporter activity annotation annotation guidelines.docx +0 -0
- aurelian/agents/gocam/documents/Transporter activity annotation annotation guidelines.pdf +0 -0
- aurelian/agents/gocam/documents/Transporter_activity_annotation_annotation_guidelines.md +43 -0
- Regulatory Processes in GO-CAM.docx +0 -0
- Regulatory Processes in GO-CAM.pdf +0 -0
- aurelian/agents/gocam/documents/WIP_-_Regulation_and_Regulatory_Processes_in_GO-CAM.md +31 -0
- aurelian/agents/gocam/documents/md/DNA-binding_transcription_factor_activity_annotation_guidelines.md +131 -0
- aurelian/agents/gocam/documents/md/E3_ubiquitin_ligases.md +166 -0
- aurelian/agents/gocam/documents/md/GO-CAM_annotation_guidelines_README.md +1 -0
- aurelian/agents/gocam/documents/md/GO-CAM_modelling_guidelines_TO_DO.md +5 -0
- aurelian/agents/gocam/documents/md/How_to_annotate_complexes_in_GO-CAM.md +28 -0
- aurelian/agents/gocam/documents/md/How_to_annotate_molecular_adaptors.md +19 -0
- aurelian/agents/gocam/documents/md/How_to_annotate_sequestering_proteins.md +38 -0
- aurelian/agents/gocam/documents/md/Molecular_adaptor_activity.md +52 -0
- aurelian/agents/gocam/documents/md/Molecular_carrier_activity.md +59 -0
- aurelian/agents/gocam/documents/md/Protein_sequestering_activity.md +52 -0
- aurelian/agents/gocam/documents/md/Signaling_receptor_activity_annotation_guidelines.md +271 -0
- aurelian/agents/gocam/documents/md/Transcription_coregulator_activity.md +54 -0
- aurelian/agents/gocam/documents/md/Transporter_activity_annotation_annotation_guidelines.md +38 -0
- aurelian/agents/gocam/documents/md/WIP_-_Regulation_and_Regulatory_Processes_in_GO-CAM.md +39 -0
- aurelian/agents/gocam/documents/pandoc_md/Signaling_receptor_activity_annotation_guidelines.md +334 -0
- aurelian/agents/gocam/gocam_agent.py +240 -0
- aurelian/agents/gocam/gocam_config.py +85 -0
- aurelian/agents/gocam/gocam_curator_agent.py +46 -0
- aurelian/agents/gocam/gocam_evals.py +67 -0
- aurelian/agents/gocam/gocam_gradio.py +89 -0
- aurelian/agents/gocam/gocam_mcp.py +224 -0
- aurelian/agents/gocam/gocam_tools.py +294 -0
- aurelian/agents/linkml/__init__.py +0 -0
- aurelian/agents/linkml/linkml_agent.py +62 -0
- aurelian/agents/linkml/linkml_config.py +48 -0
- aurelian/agents/linkml/linkml_evals.py +66 -0
- aurelian/agents/linkml/linkml_gradio.py +45 -0
- aurelian/agents/linkml/linkml_mcp.py +186 -0
- aurelian/agents/linkml/linkml_tools.py +102 -0
- aurelian/agents/literature/__init__.py +3 -0
- aurelian/agents/literature/literature_agent.py +55 -0
- aurelian/agents/literature/literature_config.py +35 -0
- aurelian/agents/literature/literature_gradio.py +52 -0
- aurelian/agents/literature/literature_mcp.py +174 -0
- aurelian/agents/literature/literature_tools.py +182 -0
- aurelian/agents/monarch/__init__.py +25 -0
- aurelian/agents/monarch/monarch_agent.py +44 -0
- aurelian/agents/monarch/monarch_config.py +45 -0
- aurelian/agents/monarch/monarch_gradio.py +51 -0
- aurelian/agents/monarch/monarch_mcp.py +65 -0
- aurelian/agents/monarch/monarch_tools.py +113 -0
- aurelian/agents/oak/__init__.py +0 -0
- aurelian/agents/oak/oak_config.py +27 -0
- aurelian/agents/oak/oak_gradio.py +57 -0
- aurelian/agents/ontology_mapper/__init__.py +31 -0
- aurelian/agents/ontology_mapper/ontology_mapper_agent.py +56 -0
- aurelian/agents/ontology_mapper/ontology_mapper_config.py +50 -0
- aurelian/agents/ontology_mapper/ontology_mapper_evals.py +108 -0
- aurelian/agents/ontology_mapper/ontology_mapper_gradio.py +58 -0
- aurelian/agents/ontology_mapper/ontology_mapper_mcp.py +81 -0
- aurelian/agents/ontology_mapper/ontology_mapper_tools.py +147 -0
- aurelian/agents/phenopackets/__init__.py +3 -0
- aurelian/agents/phenopackets/phenopackets_agent.py +58 -0
- aurelian/agents/phenopackets/phenopackets_config.py +72 -0
- aurelian/agents/phenopackets/phenopackets_evals.py +99 -0
- aurelian/agents/phenopackets/phenopackets_gradio.py +55 -0
- aurelian/agents/phenopackets/phenopackets_mcp.py +178 -0
- aurelian/agents/phenopackets/phenopackets_tools.py +127 -0
- aurelian/agents/rag/__init__.py +40 -0
- aurelian/agents/rag/rag_agent.py +83 -0
- aurelian/agents/rag/rag_config.py +80 -0
- aurelian/agents/rag/rag_gradio.py +67 -0
- aurelian/agents/rag/rag_mcp.py +107 -0
- aurelian/agents/rag/rag_tools.py +189 -0
- aurelian/agents/rag_agent.py +54 -0
- aurelian/agents/robot/__init__.py +0 -0
- aurelian/agents/robot/assets/__init__.py +3 -0
- aurelian/agents/robot/assets/template.md +384 -0
- aurelian/agents/robot/robot_config.py +25 -0
- aurelian/agents/robot/robot_gradio.py +46 -0
- aurelian/agents/robot/robot_mcp.py +100 -0
- aurelian/agents/robot/robot_ontology_agent.py +139 -0
- aurelian/agents/robot/robot_tools.py +50 -0
- aurelian/agents/talisman/__init__.py +3 -0
- aurelian/agents/talisman/talisman_agent.py +126 -0
- aurelian/agents/talisman/talisman_config.py +66 -0
- aurelian/agents/talisman/talisman_gradio.py +50 -0
- aurelian/agents/talisman/talisman_mcp.py +168 -0
- aurelian/agents/talisman/talisman_tools.py +720 -0
- aurelian/agents/ubergraph/__init__.py +40 -0
- aurelian/agents/ubergraph/ubergraph_agent.py +71 -0
- aurelian/agents/ubergraph/ubergraph_config.py +79 -0
- aurelian/agents/ubergraph/ubergraph_gradio.py +48 -0
- aurelian/agents/ubergraph/ubergraph_mcp.py +69 -0
- aurelian/agents/ubergraph/ubergraph_tools.py +118 -0
- aurelian/agents/uniprot/__init__.py +37 -0
- aurelian/agents/uniprot/uniprot_agent.py +43 -0
- aurelian/agents/uniprot/uniprot_config.py +43 -0
- aurelian/agents/uniprot/uniprot_evals.py +99 -0
- aurelian/agents/uniprot/uniprot_gradio.py +48 -0
- aurelian/agents/uniprot/uniprot_mcp.py +168 -0
- aurelian/agents/uniprot/uniprot_tools.py +136 -0
- aurelian/agents/web/__init__.py +0 -0
- aurelian/agents/web/web_config.py +27 -0
- aurelian/agents/web/web_gradio.py +48 -0
- aurelian/agents/web/web_mcp.py +50 -0
- aurelian/agents/web/web_tools.py +108 -0
- aurelian/chat.py +23 -0
- aurelian/cli.py +800 -0
- aurelian/dependencies/__init__.py +0 -0
- aurelian/dependencies/workdir.py +78 -0
- aurelian/mcp/__init__.py +0 -0
- aurelian/mcp/amigo_mcp_test.py +86 -0
- aurelian/mcp/config_generator.py +123 -0
- aurelian/mcp/example_config.json +43 -0
- aurelian/mcp/generate_sample_config.py +37 -0
- aurelian/mcp/gocam_mcp_test.py +126 -0
- aurelian/mcp/linkml_mcp_tools.py +190 -0
- aurelian/mcp/mcp_discovery.py +87 -0
- aurelian/mcp/mcp_test.py +31 -0
- aurelian/mcp/phenopackets_mcp_test.py +103 -0
- aurelian/tools/__init__.py +0 -0
- aurelian/tools/web/__init__.py +0 -0
- aurelian/tools/web/url_download.py +51 -0
- aurelian/utils/__init__.py +0 -0
- aurelian/utils/async_utils.py +15 -0
- aurelian/utils/data_utils.py +32 -0
- aurelian/utils/documentation_manager.py +59 -0
- aurelian/utils/doi_fetcher.py +238 -0
- aurelian/utils/ontology_utils.py +68 -0
- aurelian/utils/pdf_fetcher.py +23 -0
- aurelian/utils/process_logs.py +100 -0
- aurelian/utils/pubmed_utils.py +238 -0
- aurelian/utils/pytest_report_to_markdown.py +67 -0
- aurelian/utils/robot_ontology_utils.py +112 -0
- aurelian/utils/search_utils.py +95 -0
- aurelian-0.3.2.dist-info/LICENSE +22 -0
- aurelian-0.3.2.dist-info/METADATA +105 -0
- aurelian-0.3.2.dist-info/RECORD +254 -0
- aurelian-0.3.2.dist-info/WHEEL +4 -0
- aurelian-0.3.2.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
"""
|
2
|
+
Agent for working with bibliographies and citation data.
|
3
|
+
"""
|
4
|
+
from pydantic_ai import Agent, RunContext
|
5
|
+
|
6
|
+
from .biblio_config import BiblioDependencies
|
7
|
+
from .biblio_tools import search_bibliography, lookup_pmid, search_web, retrieve_web_page
|
8
|
+
|
9
|
+
|
10
|
+
biblio_agent = Agent(
|
11
|
+
model="openai:gpt-4o",
|
12
|
+
deps_type=BiblioDependencies,
|
13
|
+
result_type=str,
|
14
|
+
system_prompt=(
|
15
|
+
"You are an AI assistant that help organize a bibliography."
|
16
|
+
" You can use different functions to access the store, for example:"
|
17
|
+
" - `search` to find biblio by text query"
|
18
|
+
" - `lookup_phenopacket` to retrieve a specific phenopacket by ID"
|
19
|
+
"You can also use `lookup_pmid` to retrieve the text of a PubMed ID, or `search_web` to search the web."
|
20
|
+
"While you are knowledgeable about clinical genetics, you should always use the store and "
|
21
|
+
"functions provided to answer questions, rather than providing your own opinion or knowledge,"
|
22
|
+
" unless explicitly asked. For example, if you are asked to 'review' something then you "
|
23
|
+
"can add your own perspective and understanding. "
|
24
|
+
"You should endeavour to provide answers in narrative form that would be understood "
|
25
|
+
"by a clinical geneticists, but provide backup using assertions from the store."
|
26
|
+
" providing IDs of terms alongside labels is encouraged, unless asked not to."
|
27
|
+
"Stick to markdown, and all prefixed IDs should by hyperlinked with bioregistry,"
|
28
|
+
" i.e https://bioregistry.io/{curie}."
|
29
|
+
"tables are a good way of summarizing or comparing multiple patients, use markdown"
|
30
|
+
" tables for this. Use your judgment in how to roll up tables, and whether values"
|
31
|
+
" should be present/absent, increased/decreased, or more specific."
|
32
|
+
),
|
33
|
+
)
|
34
|
+
|
35
|
+
|
36
|
+
@biblio_agent.tool
|
37
|
+
async def search_bibliography_tool(ctx: RunContext[BiblioDependencies], query: str):
|
38
|
+
"""
|
39
|
+
Performs a retrieval search over the biblio database.
|
40
|
+
|
41
|
+
The query can be any text, such as name of a disease, phenotype, gene, etc.
|
42
|
+
|
43
|
+
The objects returned are "biblio" which is a structured representation
|
44
|
+
of a patient. Each is uniquely identified by a phenopacket ID (essentially
|
45
|
+
the patient ID).
|
46
|
+
|
47
|
+
The objects returned are summaries of biblio; omit some details such
|
48
|
+
as phenotypes. Use `lookup_biblio` to retrieve full details of a phenopacket.
|
49
|
+
|
50
|
+
Note that the phenopacket store may not be complete, and the retrieval
|
51
|
+
method may be imperfect
|
52
|
+
"""
|
53
|
+
return await search_bibliography(ctx, query)
|
54
|
+
|
55
|
+
|
56
|
+
@biblio_agent.tool
|
57
|
+
async def lookup_pmid_tool(ctx: RunContext[BiblioDependencies], pmid: str):
|
58
|
+
"""
|
59
|
+
Lookup the text of a PubMed ID, using its PMID.
|
60
|
+
|
61
|
+
A PMID should be of the form "PMID:nnnnnnn" (no underscores).
|
62
|
+
|
63
|
+
NOTE: Phenopacket IDs are typically of the form PMID_nnn_PatientNumber,
|
64
|
+
but this should be be assumed. To reliably get PMIDs for a phenopacket,
|
65
|
+
use `lookup_phenopacket` to retrieve examine the `externalReferences`
|
66
|
+
field.
|
67
|
+
|
68
|
+
Returns: full text if available, otherwise abstract
|
69
|
+
"""
|
70
|
+
return await lookup_pmid(ctx, pmid)
|
71
|
+
|
72
|
+
|
73
|
+
@biblio_agent.tool
|
74
|
+
async def search_web_tool(ctx: RunContext[BiblioDependencies], query: str):
|
75
|
+
"""
|
76
|
+
Search the web using a text query.
|
77
|
+
|
78
|
+
Note, this will not retrieve the full content, for that you
|
79
|
+
should use `retrieve_web_page`.
|
80
|
+
|
81
|
+
Returns: matching web pages plus summaries
|
82
|
+
"""
|
83
|
+
return await search_web(ctx, query)
|
84
|
+
|
85
|
+
|
86
|
+
@biblio_agent.tool
|
87
|
+
async def retrieve_web_page_tool(ctx: RunContext[BiblioDependencies], url: str):
|
88
|
+
"""
|
89
|
+
Fetch the contents of a web page.
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
The contents of the web page.
|
93
|
+
"""
|
94
|
+
return await retrieve_web_page(ctx, url)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
"""
|
2
|
+
Configuration for the Biblio agent.
|
3
|
+
"""
|
4
|
+
from dataclasses import dataclass, field
|
5
|
+
from typing import Optional
|
6
|
+
|
7
|
+
from linkml_store import Client
|
8
|
+
from linkml_store.api import Collection
|
9
|
+
|
10
|
+
from aurelian.dependencies.workdir import HasWorkdir, WorkDir
|
11
|
+
from . import HANDLE, DB_NAME, COLLECTION_NAME
|
12
|
+
|
13
|
+
|
14
|
+
@dataclass
|
15
|
+
class BiblioDependencies(HasWorkdir):
|
16
|
+
"""Configuration for the Biblio agent."""
|
17
|
+
|
18
|
+
max_results: int = field(default=10)
|
19
|
+
_collection: Optional[Collection] = None
|
20
|
+
|
21
|
+
def __post_init__(self):
|
22
|
+
"""Initialize the config with default values."""
|
23
|
+
# HasWorkdir doesn't have a __post_init__ method, so we don't call super()
|
24
|
+
if self.workdir is None:
|
25
|
+
self.workdir = WorkDir()
|
26
|
+
|
27
|
+
@property
|
28
|
+
def collection(self) -> Collection:
|
29
|
+
"""Get the database collection, initializing it if needed."""
|
30
|
+
if self._collection is None:
|
31
|
+
client = Client()
|
32
|
+
client.attach_database(HANDLE, alias=DB_NAME)
|
33
|
+
db = client.databases[DB_NAME]
|
34
|
+
self._collection = db.get_collection(COLLECTION_NAME)
|
35
|
+
return self._collection
|
36
|
+
|
37
|
+
|
38
|
+
def get_config() -> BiblioDependencies:
|
39
|
+
"""Get the Biblio configuration with default settings."""
|
40
|
+
return BiblioDependencies()
|
@@ -0,0 +1,67 @@
|
|
1
|
+
"""
|
2
|
+
Gradio interface for the Biblio agent.
|
3
|
+
"""
|
4
|
+
from typing import List, Optional
|
5
|
+
|
6
|
+
import gradio as gr
|
7
|
+
|
8
|
+
from .biblio_agent import biblio_agent
|
9
|
+
from .biblio_config import BiblioDependencies, get_config
|
10
|
+
|
11
|
+
|
12
|
+
async def get_info(query: str, history: List[str], deps: BiblioDependencies) -> str:
|
13
|
+
"""
|
14
|
+
Process a query using the biblio agent.
|
15
|
+
|
16
|
+
Args:
|
17
|
+
query: The user query
|
18
|
+
history: The conversation history
|
19
|
+
deps: The dependencies for the agent
|
20
|
+
|
21
|
+
Returns:
|
22
|
+
The agent's response
|
23
|
+
"""
|
24
|
+
print(f"QUERY: {query}")
|
25
|
+
print(f"HISTORY: {history}")
|
26
|
+
|
27
|
+
# Add history to the query if available
|
28
|
+
if history:
|
29
|
+
query += "## History"
|
30
|
+
for h in history:
|
31
|
+
query += f"\n{h}"
|
32
|
+
|
33
|
+
# Run the agent
|
34
|
+
result = await biblio_agent.run(query, deps=deps)
|
35
|
+
return result.data
|
36
|
+
|
37
|
+
|
38
|
+
def chat(deps: Optional[BiblioDependencies] = None, **kwargs):
|
39
|
+
"""
|
40
|
+
Create a Gradio chat interface for the Biblio agent.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
deps: Optional dependencies configuration
|
44
|
+
kwargs: Additional keyword arguments for the agent
|
45
|
+
|
46
|
+
Returns:
|
47
|
+
A Gradio ChatInterface
|
48
|
+
"""
|
49
|
+
if deps is None:
|
50
|
+
deps = get_config()
|
51
|
+
|
52
|
+
def get_info_wrapper(query: str, history: List[str]) -> str:
|
53
|
+
# Use run_sync to handle the async function
|
54
|
+
from aurelian.utils.async_utils import run_sync
|
55
|
+
return run_sync(lambda: get_info(query, history, deps))
|
56
|
+
|
57
|
+
return gr.ChatInterface(
|
58
|
+
fn=get_info_wrapper,
|
59
|
+
type="messages",
|
60
|
+
title="Biblio AI Assistant",
|
61
|
+
examples=[
|
62
|
+
["What patients have liver disease?"],
|
63
|
+
["What biblio involve genes from metabolic pathways"],
|
64
|
+
["How does the type of variant affect phenotype in peroxisomal disorders?"],
|
65
|
+
["Examine biblio for skeletal dysplasias, check them against publications"],
|
66
|
+
],
|
67
|
+
)
|
@@ -0,0 +1,115 @@
|
|
1
|
+
"""
|
2
|
+
MCP tools for working with bibliographies and citation data.
|
3
|
+
"""
|
4
|
+
import os
|
5
|
+
from typing import Dict, List
|
6
|
+
|
7
|
+
from mcp.server.fastmcp import FastMCP
|
8
|
+
|
9
|
+
import aurelian.agents.biblio.biblio_tools as bt
|
10
|
+
from aurelian.agents.biblio.biblio_agent import biblio_agent
|
11
|
+
from aurelian.agents.biblio.biblio_config import BiblioDependencies
|
12
|
+
from pydantic_ai import RunContext
|
13
|
+
|
14
|
+
# Initialize FastMCP server
|
15
|
+
mcp = FastMCP("biblio", instructions=biblio_agent.system_prompt)
|
16
|
+
|
17
|
+
|
18
|
+
from aurelian.dependencies.workdir import WorkDir
|
19
|
+
|
20
|
+
def deps() -> BiblioDependencies:
|
21
|
+
deps = BiblioDependencies()
|
22
|
+
# Set the location from environment variable or default
|
23
|
+
loc = os.getenv("AURELIAN_WORKDIR", "/tmp/aurelian")
|
24
|
+
deps.workdir = WorkDir(loc)
|
25
|
+
return deps
|
26
|
+
|
27
|
+
def ctx() -> RunContext[BiblioDependencies]:
|
28
|
+
rc: RunContext[BiblioDependencies] = RunContext[BiblioDependencies](
|
29
|
+
deps=deps(),
|
30
|
+
model=None, usage=None, prompt=None,
|
31
|
+
)
|
32
|
+
return rc
|
33
|
+
|
34
|
+
|
35
|
+
@mcp.tool()
|
36
|
+
async def search_bibliography(query: str) -> List[Dict]:
|
37
|
+
"""
|
38
|
+
Performs a retrieval search over the biblio database.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
query: The search query (disease, phenotype, gene, etc.)
|
42
|
+
|
43
|
+
Returns:
|
44
|
+
A list of biblio objects matching the query
|
45
|
+
|
46
|
+
The query can be any text, such as name of a disease, phenotype, gene, etc.
|
47
|
+
|
48
|
+
The objects returned are "biblio" which is a structured representation
|
49
|
+
of a patient. Each is uniquely identified by a phenopacket ID (essentially
|
50
|
+
the patient ID).
|
51
|
+
|
52
|
+
The objects returned are summaries of biblio; omit some details such
|
53
|
+
as phenotypes. Use `lookup_biblio` to retrieve full details of a phenopacket.
|
54
|
+
|
55
|
+
Note that the phenopacket store may not be complete, and the retrieval
|
56
|
+
method may be imperfect
|
57
|
+
"""
|
58
|
+
return await bt.search_bibliography(ctx(), query)
|
59
|
+
|
60
|
+
|
61
|
+
@mcp.tool()
|
62
|
+
async def lookup_pmid(pmid: str) -> str:
|
63
|
+
"""
|
64
|
+
Lookup the text of a PubMed ID, using its PMID.
|
65
|
+
|
66
|
+
Args:
|
67
|
+
pmid: The PubMed ID to look up (format: "PMID:nnnnnnn")
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
The full text if available, otherwise abstract
|
71
|
+
|
72
|
+
A PMID should be of the form "PMID:nnnnnnn" (no underscores).
|
73
|
+
|
74
|
+
NOTE: Phenopacket IDs are typically of the form PMID_nnn_PatientNumber,
|
75
|
+
but this should be assumed. To reliably get PMIDs for a phenopacket,
|
76
|
+
use `lookup_phenopacket` to retrieve examine the `externalReferences`
|
77
|
+
field.
|
78
|
+
"""
|
79
|
+
return await bt.lookup_pmid(ctx(), pmid)
|
80
|
+
|
81
|
+
|
82
|
+
@mcp.tool()
|
83
|
+
async def search_web(query: str) -> str:
|
84
|
+
"""
|
85
|
+
Search the web using a text query.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
query: The search query
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
Matching web pages plus summaries
|
92
|
+
|
93
|
+
Note, this will not retrieve the full content, for that you
|
94
|
+
should use `retrieve_web_page`.
|
95
|
+
"""
|
96
|
+
return await bt.search_web(ctx(), query)
|
97
|
+
|
98
|
+
|
99
|
+
@mcp.tool()
|
100
|
+
async def retrieve_web_page(url: str) -> str:
|
101
|
+
"""
|
102
|
+
Fetch the contents of a web page.
|
103
|
+
|
104
|
+
Args:
|
105
|
+
url: The URL to fetch
|
106
|
+
|
107
|
+
Returns:
|
108
|
+
The contents of the web page
|
109
|
+
"""
|
110
|
+
return await bt.retrieve_web_page(ctx(), url)
|
111
|
+
|
112
|
+
|
113
|
+
if __name__ == "__main__":
|
114
|
+
# Initialize and run the server
|
115
|
+
mcp.run(transport='stdio')
|
@@ -0,0 +1,164 @@
|
|
1
|
+
"""
|
2
|
+
Tools for the Biblio agent for working with bibliographic data.
|
3
|
+
"""
|
4
|
+
import asyncio
|
5
|
+
from typing import Dict, List
|
6
|
+
|
7
|
+
from pydantic_ai import RunContext, ModelRetry
|
8
|
+
|
9
|
+
from aurelian.utils.data_utils import flatten
|
10
|
+
from aurelian.utils.pubmed_utils import get_pmid_text
|
11
|
+
from aurelian.utils.search_utils import web_search, retrieve_web_page as fetch_web_page
|
12
|
+
from .biblio_config import BiblioDependencies
|
13
|
+
|
14
|
+
|
15
|
+
async def search_bibliography(
|
16
|
+
ctx: RunContext[BiblioDependencies],
|
17
|
+
query: str
|
18
|
+
) -> List[Dict]:
|
19
|
+
"""
|
20
|
+
Performs a retrieval search over the biblio database.
|
21
|
+
|
22
|
+
Args:
|
23
|
+
ctx: The run context
|
24
|
+
query: The search query (disease, phenotype, gene, etc.)
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
A list of biblio objects matching the query
|
28
|
+
|
29
|
+
The query can be any text, such as name of a disease, phenotype, gene, etc.
|
30
|
+
|
31
|
+
The objects returned are "biblio" which is a structured representation
|
32
|
+
of a patient. Each is uniquely identified by a phenopacket ID (essentially
|
33
|
+
the patient ID).
|
34
|
+
|
35
|
+
The objects returned are summaries of biblio; omit some details such
|
36
|
+
as phenotypes. Use `lookup_biblio` to retrieve full details of a phenopacket.
|
37
|
+
|
38
|
+
Note that the phenopacket store may not be complete, and the retrieval
|
39
|
+
method may be imperfect
|
40
|
+
"""
|
41
|
+
try:
|
42
|
+
print(f"SEARCH: {query}")
|
43
|
+
|
44
|
+
# Execute the potentially blocking operation in a thread pool
|
45
|
+
def _search():
|
46
|
+
qr = ctx.deps.collection.search(query, index_name="llm", limit=ctx.deps.max_results)
|
47
|
+
objs = []
|
48
|
+
for score, row in qr.ranked_rows:
|
49
|
+
obj = flatten(row, preserve_keys=["interpretations", "diseases"])
|
50
|
+
obj["relevancy_score"] = score
|
51
|
+
objs.append(obj)
|
52
|
+
print(f"RESULT: {obj}")
|
53
|
+
return objs
|
54
|
+
|
55
|
+
objs = await asyncio.to_thread(_search)
|
56
|
+
|
57
|
+
if not objs:
|
58
|
+
raise ModelRetry(f"No results found for query: {query}")
|
59
|
+
|
60
|
+
return objs
|
61
|
+
except Exception as e:
|
62
|
+
if "ModelRetry" in str(type(e)):
|
63
|
+
raise e
|
64
|
+
raise ModelRetry(f"Error searching bibliography: {str(e)}")
|
65
|
+
|
66
|
+
|
67
|
+
async def lookup_pmid(
|
68
|
+
ctx: RunContext[BiblioDependencies],
|
69
|
+
pmid: str
|
70
|
+
) -> str:
|
71
|
+
"""
|
72
|
+
Lookup the text of a PubMed ID, using its PMID.
|
73
|
+
|
74
|
+
Args:
|
75
|
+
ctx: The run context
|
76
|
+
pmid: The PubMed ID to look up (format: "PMID:nnnnnnn")
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
The full text if available, otherwise abstract
|
80
|
+
|
81
|
+
A PMID should be of the form "PMID:nnnnnnn" (no underscores).
|
82
|
+
|
83
|
+
NOTE: Phenopacket IDs are typically of the form PMID_nnn_PatientNumber,
|
84
|
+
but this should be be assumed. To reliably get PMIDs for a phenopacket,
|
85
|
+
use `lookup_phenopacket` to retrieve examine the `externalReferences`
|
86
|
+
field.
|
87
|
+
"""
|
88
|
+
try:
|
89
|
+
print(f"LOOKUP PMID: {pmid}")
|
90
|
+
|
91
|
+
# Execute the potentially blocking operation in a thread pool
|
92
|
+
text = await asyncio.to_thread(get_pmid_text, pmid)
|
93
|
+
|
94
|
+
if not text or text.strip() == "":
|
95
|
+
raise ModelRetry(f"No text found for PMID: {pmid}")
|
96
|
+
|
97
|
+
return text
|
98
|
+
except Exception as e:
|
99
|
+
if "ModelRetry" in str(type(e)):
|
100
|
+
raise e
|
101
|
+
raise ModelRetry(f"Error retrieving text from PMID: {str(e)}")
|
102
|
+
|
103
|
+
|
104
|
+
async def search_web(
|
105
|
+
ctx: RunContext[BiblioDependencies],
|
106
|
+
query: str
|
107
|
+
) -> str:
|
108
|
+
"""
|
109
|
+
Search the web using a text query.
|
110
|
+
|
111
|
+
Args:
|
112
|
+
ctx: The run context
|
113
|
+
query: The search query
|
114
|
+
|
115
|
+
Returns:
|
116
|
+
Matching web pages plus summaries
|
117
|
+
|
118
|
+
Note, this will not retrieve the full content, for that you
|
119
|
+
should use `retrieve_web_page`.
|
120
|
+
"""
|
121
|
+
try:
|
122
|
+
print(f"Web Search: {query}")
|
123
|
+
|
124
|
+
# Execute the potentially blocking operation in a thread pool
|
125
|
+
results = await asyncio.to_thread(web_search, query)
|
126
|
+
|
127
|
+
if not results or results.strip() == "":
|
128
|
+
raise ModelRetry(f"No web search results found for query: {query}")
|
129
|
+
|
130
|
+
return results
|
131
|
+
except Exception as e:
|
132
|
+
if "ModelRetry" in str(type(e)):
|
133
|
+
raise e
|
134
|
+
raise ModelRetry(f"Error searching web: {str(e)}")
|
135
|
+
|
136
|
+
|
137
|
+
async def retrieve_web_page(
|
138
|
+
ctx: RunContext[BiblioDependencies],
|
139
|
+
url: str
|
140
|
+
) -> str:
|
141
|
+
"""
|
142
|
+
Fetch the contents of a web page.
|
143
|
+
|
144
|
+
Args:
|
145
|
+
ctx: The run context
|
146
|
+
url: The URL to fetch
|
147
|
+
|
148
|
+
Returns:
|
149
|
+
The contents of the web page
|
150
|
+
"""
|
151
|
+
try:
|
152
|
+
print(f"Fetch URL: {url}")
|
153
|
+
|
154
|
+
# Execute the potentially blocking operation in a thread pool
|
155
|
+
content = await asyncio.to_thread(fetch_web_page, url)
|
156
|
+
|
157
|
+
if not content or content.strip() == "":
|
158
|
+
raise ModelRetry(f"No content found for URL: {url}")
|
159
|
+
|
160
|
+
return content
|
161
|
+
except Exception as e:
|
162
|
+
if "ModelRetry" in str(type(e)):
|
163
|
+
raise e
|
164
|
+
raise ModelRetry(f"Error retrieving web page: {str(e)}")
|
@@ -0,0 +1,46 @@
|
|
1
|
+
"""
|
2
|
+
Agent for working with bibliographies
|
3
|
+
|
4
|
+
This module re-exports components from the biblio/ package for backward compatibility.
|
5
|
+
"""
|
6
|
+
from typing import Dict, List
|
7
|
+
|
8
|
+
# Re-export from biblio package
|
9
|
+
from aurelian.agents.biblio import (
|
10
|
+
biblio_agent,
|
11
|
+
BiblioDependencies,
|
12
|
+
get_config,
|
13
|
+
search_bibliography,
|
14
|
+
lookup_pmid,
|
15
|
+
search_web,
|
16
|
+
retrieve_web_page,
|
17
|
+
chat,
|
18
|
+
)
|
19
|
+
|
20
|
+
# Re-export the older synchronous versions of functions for compatibility
|
21
|
+
@biblio_agent.tool
|
22
|
+
def search_bibliography_sync(ctx, query: str) -> List[Dict]:
|
23
|
+
"""Legacy synchronous version of search_bibliography"""
|
24
|
+
import asyncio
|
25
|
+
return asyncio.run(search_bibliography(ctx, query))
|
26
|
+
|
27
|
+
|
28
|
+
@biblio_agent.tool
|
29
|
+
def lookup_pmid_sync(ctx, pmid: str) -> str:
|
30
|
+
"""Legacy synchronous version of lookup_pmid"""
|
31
|
+
import asyncio
|
32
|
+
return asyncio.run(lookup_pmid(ctx, pmid))
|
33
|
+
|
34
|
+
|
35
|
+
@biblio_agent.tool
|
36
|
+
def search_web_sync(ctx, query: str) -> str:
|
37
|
+
"""Legacy synchronous version of search_web"""
|
38
|
+
import asyncio
|
39
|
+
return asyncio.run(search_web(ctx, query))
|
40
|
+
|
41
|
+
|
42
|
+
@biblio_agent.tool
|
43
|
+
def retrieve_web_page_sync(ctx, url: str) -> str:
|
44
|
+
"""Legacy synchronous version of retrieve_web_page"""
|
45
|
+
import asyncio
|
46
|
+
return asyncio.run(retrieve_web_page(ctx, url))
|
@@ -0,0 +1,44 @@
|
|
1
|
+
"""
|
2
|
+
Checklist agent package for validating papers against checklists (e.g., STREAMS).
|
3
|
+
"""
|
4
|
+
from pathlib import Path
|
5
|
+
|
6
|
+
THIS_DIR = Path(__file__).parent
|
7
|
+
CONTENT_DIR = THIS_DIR / "content"
|
8
|
+
CONTENT_METADATA_PATH = CONTENT_DIR / "checklists.yaml"
|
9
|
+
|
10
|
+
# These imports must be after constants are defined
|
11
|
+
# isort: skip_file
|
12
|
+
from .checklist_agent import checklist_agent, add_checklists # noqa: E402
|
13
|
+
from .checklist_config import ChecklistDependencies, get_config # noqa: E402
|
14
|
+
from .checklist_gradio import chat # noqa: E402
|
15
|
+
from .checklist_tools import ( # noqa: E402
|
16
|
+
all_checklists,
|
17
|
+
retrieve_text_from_pmid,
|
18
|
+
retrieve_text_from_doi,
|
19
|
+
fetch_checklist,
|
20
|
+
)
|
21
|
+
|
22
|
+
__all__ = [
|
23
|
+
# Constants
|
24
|
+
"THIS_DIR",
|
25
|
+
"CONTENT_DIR",
|
26
|
+
"CONTENT_METADATA_PATH",
|
27
|
+
|
28
|
+
# Agent
|
29
|
+
"checklist_agent",
|
30
|
+
"add_checklists",
|
31
|
+
|
32
|
+
# Config
|
33
|
+
"ChecklistDependencies",
|
34
|
+
"get_config",
|
35
|
+
|
36
|
+
# Tools
|
37
|
+
"all_checklists",
|
38
|
+
"retrieve_text_from_pmid",
|
39
|
+
"retrieve_text_from_doi",
|
40
|
+
"fetch_checklist",
|
41
|
+
|
42
|
+
# Gradio
|
43
|
+
"chat",
|
44
|
+
]
|
@@ -0,0 +1,85 @@
|
|
1
|
+
"""
|
2
|
+
Agent for validating papers against checklists, e.g STREAMS
|
3
|
+
"""
|
4
|
+
from pydantic_ai import Agent, RunContext
|
5
|
+
|
6
|
+
from .checklist_config import ChecklistDependencies
|
7
|
+
from .checklist_tools import all_checklists, retrieve_text_from_pmid, retrieve_text_from_doi, fetch_checklist
|
8
|
+
|
9
|
+
|
10
|
+
checklist_agent = Agent(
|
11
|
+
model="openai:gpt-4o",
|
12
|
+
system_prompt=(
|
13
|
+
"Your role is to evaluate papers to ensure they conform to relevant checklists."
|
14
|
+
"When asked to look at or review a paper, you should first select the "
|
15
|
+
"appropriate checklist from the list of available checklists. Retrieve the checklist."
|
16
|
+
" evaluate the paper according to the checklist, and return results that include both"
|
17
|
+
" complete evaluation for each checklist item, and a general summary."
|
18
|
+
" if a particular checklist item succeeds, say PASS and then any relevant details."
|
19
|
+
" Include examples if relevant. If a particular checklist item fails, say FAIL and provide"
|
20
|
+
" Explanation. If unclear state OTHER and provide an explanation."
|
21
|
+
" Return this as a markdown table."
|
22
|
+
"\nThe available checklists are:"
|
23
|
+
),
|
24
|
+
deps_type=ChecklistDependencies,
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
@checklist_agent.system_prompt
|
29
|
+
def add_checklists(ctx: RunContext[ChecklistDependencies]) -> str:
|
30
|
+
"""
|
31
|
+
Add available checklists to the system prompt.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
ctx: The run context
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
A string containing the list of available checklists
|
38
|
+
"""
|
39
|
+
meta = all_checklists()
|
40
|
+
return "\n".join([f"- {c['id']}: {c['title']}" for c in meta["checklists"]])
|
41
|
+
|
42
|
+
|
43
|
+
@checklist_agent.tool
|
44
|
+
async def retrieve_text_from_pmid_tool(ctx: RunContext[ChecklistDependencies], pmid: str) -> str:
|
45
|
+
"""
|
46
|
+
Lookup the text of a PubMed ID, using its PMID.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
ctx: The run context
|
50
|
+
pmid: The PubMed ID to look up
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
Full text if available, otherwise abstract
|
54
|
+
"""
|
55
|
+
return await retrieve_text_from_pmid(ctx, pmid)
|
56
|
+
|
57
|
+
|
58
|
+
@checklist_agent.tool
|
59
|
+
async def retrieve_text_from_doi_tool(ctx: RunContext[ChecklistDependencies], doi: str) -> str:
|
60
|
+
"""
|
61
|
+
Lookup the text of a DOI.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
ctx: The run context
|
65
|
+
doi: The DOI to look up
|
66
|
+
|
67
|
+
Returns:
|
68
|
+
Full text if available, otherwise abstract
|
69
|
+
"""
|
70
|
+
return await retrieve_text_from_doi(ctx, doi)
|
71
|
+
|
72
|
+
|
73
|
+
@checklist_agent.tool
|
74
|
+
async def fetch_checklist_tool(ctx: RunContext[ChecklistDependencies], checklist_id: str) -> str:
|
75
|
+
"""
|
76
|
+
Lookup the checklist entry for a given checklist accession number.
|
77
|
+
|
78
|
+
Args:
|
79
|
+
ctx: The run context
|
80
|
+
checklist_id: The checklist ID (e.g. STREAM, STORMS, ARRIVE)
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
The content of the checklist
|
84
|
+
"""
|
85
|
+
return await fetch_checklist(ctx, checklist_id)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
"""
|
2
|
+
Configuration for the Checklist agent.
|
3
|
+
"""
|
4
|
+
from dataclasses import dataclass
|
5
|
+
import os
|
6
|
+
|
7
|
+
from aurelian.dependencies.workdir import HasWorkdir, WorkDir
|
8
|
+
|
9
|
+
|
10
|
+
@dataclass
|
11
|
+
class ChecklistDependencies(HasWorkdir):
|
12
|
+
"""Configuration for the Checklist agent."""
|
13
|
+
|
14
|
+
def __post_init__(self):
|
15
|
+
"""Initialize the config with default values."""
|
16
|
+
# HasWorkdir doesn't have a __post_init__ method, so we don't call super()
|
17
|
+
if self.workdir is None:
|
18
|
+
self.workdir = WorkDir()
|
19
|
+
|
20
|
+
|
21
|
+
def get_config() -> ChecklistDependencies:
|
22
|
+
"""Get the Checklist configuration from environment variables or defaults."""
|
23
|
+
workdir_path = os.environ.get("AURELIAN_WORKDIR", None)
|
24
|
+
workdir = WorkDir(location=workdir_path) if workdir_path else None
|
25
|
+
|
26
|
+
return ChecklistDependencies(
|
27
|
+
workdir=workdir,
|
28
|
+
)
|