tooluniverse 1.0.10__py3-none-any.whl → 1.0.11__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.
Potentially problematic release.
This version of tooluniverse might be problematic. Click here for more details.
- tooluniverse/__init__.py +57 -1
- tooluniverse/blast_tool.py +132 -0
- tooluniverse/boltz_tool.py +2 -2
- tooluniverse/cbioportal_tool.py +42 -0
- tooluniverse/clinvar_tool.py +268 -74
- tooluniverse/compose_scripts/tool_discover.py +1941 -443
- tooluniverse/data/agentic_tools.json +0 -370
- tooluniverse/data/alphafold_tools.json +6 -6
- tooluniverse/data/blast_tools.json +112 -0
- tooluniverse/data/cbioportal_tools.json +87 -0
- tooluniverse/data/clinvar_tools.json +235 -0
- tooluniverse/data/compose_tools.json +0 -89
- tooluniverse/data/dbsnp_tools.json +275 -0
- tooluniverse/data/emdb_tools.json +61 -0
- tooluniverse/data/ensembl_tools.json +259 -0
- tooluniverse/data/file_download_tools.json +275 -0
- tooluniverse/data/geo_tools.json +200 -48
- tooluniverse/data/gnomad_tools.json +109 -0
- tooluniverse/data/gtopdb_tools.json +68 -0
- tooluniverse/data/gwas_tools.json +32 -0
- tooluniverse/data/interpro_tools.json +199 -0
- tooluniverse/data/jaspar_tools.json +70 -0
- tooluniverse/data/kegg_tools.json +356 -0
- tooluniverse/data/mpd_tools.json +87 -0
- tooluniverse/data/ols_tools.json +314 -0
- tooluniverse/data/package_discovery_tools.json +64 -0
- tooluniverse/data/packages/categorized_tools.txt +0 -1
- tooluniverse/data/packages/machine_learning_tools.json +0 -47
- tooluniverse/data/paleobiology_tools.json +91 -0
- tooluniverse/data/pride_tools.json +62 -0
- tooluniverse/data/pypi_package_inspector_tools.json +158 -0
- tooluniverse/data/python_executor_tools.json +341 -0
- tooluniverse/data/regulomedb_tools.json +50 -0
- tooluniverse/data/remap_tools.json +89 -0
- tooluniverse/data/screen_tools.json +89 -0
- tooluniverse/data/tool_discovery_agents.json +428 -0
- tooluniverse/data/tool_discovery_agents.json.backup +1343 -0
- tooluniverse/data/uniprot_tools.json +77 -0
- tooluniverse/data/web_search_tools.json +250 -0
- tooluniverse/data/worms_tools.json +55 -0
- tooluniverse/dbsnp_tool.py +196 -58
- tooluniverse/default_config.py +35 -2
- tooluniverse/emdb_tool.py +30 -0
- tooluniverse/ensembl_tool.py +140 -47
- tooluniverse/execute_function.py +74 -14
- tooluniverse/file_download_tool.py +269 -0
- tooluniverse/geo_tool.py +81 -28
- tooluniverse/gnomad_tool.py +100 -52
- tooluniverse/gtopdb_tool.py +41 -0
- tooluniverse/interpro_tool.py +72 -0
- tooluniverse/jaspar_tool.py +30 -0
- tooluniverse/kegg_tool.py +230 -0
- tooluniverse/mpd_tool.py +42 -0
- tooluniverse/ncbi_eutils_tool.py +96 -0
- tooluniverse/ols_tool.py +435 -0
- tooluniverse/package_discovery_tool.py +217 -0
- tooluniverse/paleobiology_tool.py +30 -0
- tooluniverse/pride_tool.py +30 -0
- tooluniverse/pypi_package_inspector_tool.py +593 -0
- tooluniverse/python_executor_tool.py +711 -0
- tooluniverse/regulomedb_tool.py +30 -0
- tooluniverse/remap_tool.py +44 -0
- tooluniverse/remote/depmap_24q2/depmap_24q2_mcp_tool.py +1 -1
- tooluniverse/screen_tool.py +44 -0
- tooluniverse/smcp_server.py +3 -3
- tooluniverse/tool_finder_embedding.py +3 -1
- tooluniverse/tool_finder_keyword.py +3 -1
- tooluniverse/tool_finder_llm.py +6 -2
- tooluniverse/tools/{UCSC_get_genes_by_region.py → BLAST_nucleotide_search.py} +22 -26
- tooluniverse/tools/BLAST_protein_search.py +63 -0
- tooluniverse/tools/ClinVar_search_variants.py +26 -15
- tooluniverse/tools/CodeQualityAnalyzer.py +3 -3
- tooluniverse/tools/EMDB_get_structure.py +46 -0
- tooluniverse/tools/GtoPdb_get_targets.py +52 -0
- tooluniverse/tools/InterPro_get_domain_details.py +46 -0
- tooluniverse/tools/InterPro_get_protein_domains.py +49 -0
- tooluniverse/tools/InterPro_search_domains.py +52 -0
- tooluniverse/tools/JASPAR_get_transcription_factors.py +52 -0
- tooluniverse/tools/MPD_get_phenotype_data.py +59 -0
- tooluniverse/tools/PRIDE_search_proteomics.py +52 -0
- tooluniverse/tools/PackageAnalyzer.py +55 -0
- tooluniverse/tools/Paleobiology_get_fossils.py +52 -0
- tooluniverse/tools/PyPIPackageInspector.py +59 -0
- tooluniverse/tools/ReMap_get_transcription_factor_binding.py +59 -0
- tooluniverse/tools/ReferenceInfoAnalyzer.py +55 -0
- tooluniverse/tools/RegulomeDB_query_variant.py +46 -0
- tooluniverse/tools/SCREEN_get_regulatory_elements.py +59 -0
- tooluniverse/tools/{ArgumentDescriptionOptimizer.py → TestResultsAnalyzer.py} +13 -13
- tooluniverse/tools/ToolDiscover.py +11 -11
- tooluniverse/tools/UniProt_id_mapping.py +63 -0
- tooluniverse/tools/UniProt_search.py +63 -0
- tooluniverse/tools/UnifiedToolGenerator.py +59 -0
- tooluniverse/tools/WoRMS_search_species.py +49 -0
- tooluniverse/tools/XMLToolOptimizer.py +55 -0
- tooluniverse/tools/__init__.py +119 -29
- tooluniverse/tools/alphafold_get_annotations.py +3 -3
- tooluniverse/tools/alphafold_get_prediction.py +3 -3
- tooluniverse/tools/alphafold_get_summary.py +3 -3
- tooluniverse/tools/cBioPortal_get_cancer_studies.py +46 -0
- tooluniverse/tools/cBioPortal_get_mutations.py +52 -0
- tooluniverse/tools/{gnomAD_query_variant.py → clinvar_get_clinical_significance.py} +8 -11
- tooluniverse/tools/clinvar_get_variant_details.py +49 -0
- tooluniverse/tools/dbSNP_get_variant_by_rsid.py +7 -7
- tooluniverse/tools/dbsnp_get_frequencies.py +46 -0
- tooluniverse/tools/dbsnp_search_by_gene.py +52 -0
- tooluniverse/tools/download_binary_file.py +66 -0
- tooluniverse/tools/download_file.py +71 -0
- tooluniverse/tools/download_text_content.py +55 -0
- tooluniverse/tools/dynamic_package_discovery.py +59 -0
- tooluniverse/tools/ensembl_get_sequence.py +52 -0
- tooluniverse/tools/{Ensembl_lookup_gene_by_symbol.py → ensembl_get_variants.py} +11 -11
- tooluniverse/tools/ensembl_lookup_gene.py +46 -0
- tooluniverse/tools/geo_get_dataset_info.py +46 -0
- tooluniverse/tools/geo_get_sample_info.py +46 -0
- tooluniverse/tools/geo_search_datasets.py +67 -0
- tooluniverse/tools/gnomad_get_gene_constraints.py +49 -0
- tooluniverse/tools/kegg_find_genes.py +52 -0
- tooluniverse/tools/kegg_get_gene_info.py +46 -0
- tooluniverse/tools/kegg_get_pathway_info.py +46 -0
- tooluniverse/tools/kegg_list_organisms.py +44 -0
- tooluniverse/tools/kegg_search_pathway.py +46 -0
- tooluniverse/tools/ols_find_similar_terms.py +63 -0
- tooluniverse/tools/{get_hyperopt_info.py → ols_get_ontology_info.py} +13 -10
- tooluniverse/tools/ols_get_term_ancestors.py +67 -0
- tooluniverse/tools/ols_get_term_children.py +67 -0
- tooluniverse/tools/{TestCaseGenerator.py → ols_get_term_info.py} +12 -9
- tooluniverse/tools/{CodeOptimizer.py → ols_search_ontologies.py} +22 -14
- tooluniverse/tools/ols_search_terms.py +71 -0
- tooluniverse/tools/python_code_executor.py +79 -0
- tooluniverse/tools/python_script_runner.py +79 -0
- tooluniverse/tools/web_api_documentation_search.py +63 -0
- tooluniverse/tools/web_search.py +71 -0
- tooluniverse/uniprot_tool.py +219 -16
- tooluniverse/url_tool.py +18 -0
- tooluniverse/utils.py +2 -2
- tooluniverse/web_search_tool.py +229 -0
- tooluniverse/worms_tool.py +64 -0
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.dist-info}/METADATA +3 -2
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.dist-info}/RECORD +143 -54
- tooluniverse/data/genomics_tools.json +0 -174
- tooluniverse/tools/ToolDescriptionOptimizer.py +0 -67
- tooluniverse/tools/ToolImplementationGenerator.py +0 -67
- tooluniverse/tools/ToolOptimizer.py +0 -59
- tooluniverse/tools/ToolSpecificationGenerator.py +0 -67
- tooluniverse/tools/ToolSpecificationOptimizer.py +0 -63
- tooluniverse/ucsc_tool.py +0 -60
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.dist-info}/WHEEL +0 -0
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.dist-info}/entry_points.txt +0 -0
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.dist-info}/licenses/LICENSE +0 -0
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.dist-info}/top_level.txt +0 -0
tooluniverse/default_config.py
CHANGED
|
@@ -51,6 +51,16 @@ default_tool_files = {
|
|
|
51
51
|
"fatcat": os.path.join(current_dir, "data", "fatcat_tools.json"),
|
|
52
52
|
"wikidata_sparql": os.path.join(current_dir, "data", "wikidata_sparql_tools.json"),
|
|
53
53
|
"agents": os.path.join(current_dir, "data", "agentic_tools.json"),
|
|
54
|
+
"tool_discovery_agents": os.path.join(
|
|
55
|
+
current_dir, "data", "tool_discovery_agents.json"
|
|
56
|
+
),
|
|
57
|
+
"web_search_tools": os.path.join(current_dir, "data", "web_search_tools.json"),
|
|
58
|
+
"package_discovery_tools": os.path.join(
|
|
59
|
+
current_dir, "data", "package_discovery_tools.json"
|
|
60
|
+
),
|
|
61
|
+
"pypi_package_inspector_tools": os.path.join(
|
|
62
|
+
current_dir, "data", "pypi_package_inspector_tools.json"
|
|
63
|
+
),
|
|
54
64
|
"drug_discovery_agents": os.path.join(
|
|
55
65
|
current_dir, "data", "drug_discovery_agents.json"
|
|
56
66
|
),
|
|
@@ -100,6 +110,20 @@ default_tool_files = {
|
|
|
100
110
|
"visualization_molecule_2d": os.path.join(
|
|
101
111
|
current_dir, "data", "molecule_2d_tools.json"
|
|
102
112
|
),
|
|
113
|
+
# New database tools
|
|
114
|
+
"interpro": os.path.join(current_dir, "data", "interpro_tools.json"),
|
|
115
|
+
"blast": os.path.join(current_dir, "data", "blast_tools.json"),
|
|
116
|
+
"cbioportal": os.path.join(current_dir, "data", "cbioportal_tools.json"),
|
|
117
|
+
"regulomedb": os.path.join(current_dir, "data", "regulomedb_tools.json"),
|
|
118
|
+
"jaspar": os.path.join(current_dir, "data", "jaspar_tools.json"),
|
|
119
|
+
"remap": os.path.join(current_dir, "data", "remap_tools.json"),
|
|
120
|
+
"screen": os.path.join(current_dir, "data", "screen_tools.json"),
|
|
121
|
+
"pride": os.path.join(current_dir, "data", "pride_tools.json"),
|
|
122
|
+
"emdb": os.path.join(current_dir, "data", "emdb_tools.json"),
|
|
123
|
+
"gtopdb": os.path.join(current_dir, "data", "gtopdb_tools.json"),
|
|
124
|
+
"mpd": os.path.join(current_dir, "data", "mpd_tools.json"),
|
|
125
|
+
"worms": os.path.join(current_dir, "data", "worms_tools.json"),
|
|
126
|
+
"paleobiology": os.path.join(current_dir, "data", "paleobiology_tools.json"),
|
|
103
127
|
"visualization_molecule_3d": os.path.join(
|
|
104
128
|
current_dir, "data", "molecule_3d_tools.json"
|
|
105
129
|
),
|
|
@@ -120,6 +144,7 @@ default_tool_files = {
|
|
|
120
144
|
),
|
|
121
145
|
"go": os.path.join(current_dir, "data", "gene_ontology_tools.json"),
|
|
122
146
|
"compose": os.path.join(current_dir, "data", "compose_tools.json"),
|
|
147
|
+
"python_executor": os.path.join(current_dir, "data", "python_executor_tools.json"),
|
|
123
148
|
"idmap": os.path.join(current_dir, "data", "idmap_tools.json"),
|
|
124
149
|
"disease_target_score": os.path.join(
|
|
125
150
|
current_dir, "data", "disease_target_score_tools.json"
|
|
@@ -131,6 +156,7 @@ default_tool_files = {
|
|
|
131
156
|
"xml": os.path.join(current_dir, "data", "xml_tools.json"),
|
|
132
157
|
"mcp_auto_loader_boltz": os.path.join(current_dir, "data", "boltz_tools.json"),
|
|
133
158
|
"url": os.path.join(current_dir, "data", "url_fetch_tools.json"),
|
|
159
|
+
"file_download": os.path.join(current_dir, "data", "file_download_tools.json"),
|
|
134
160
|
# 'langchain': os.path.join(current_dir, 'data', 'langchain_tools.json'),
|
|
135
161
|
"rcsb_pdb": os.path.join(current_dir, "data", "rcsb_pdb_tools.json"),
|
|
136
162
|
"tool_composition": os.path.join(
|
|
@@ -146,10 +172,17 @@ default_tool_files = {
|
|
|
146
172
|
),
|
|
147
173
|
"odphp": os.path.join(current_dir, "data", "odphp_tools.json"),
|
|
148
174
|
"markitdown": os.path.join(current_dir, "data", "markitdown_tools.json"),
|
|
149
|
-
# Genomics tools
|
|
150
|
-
"genomics": os.path.join(current_dir, "data", "genomics_tools.json"),
|
|
151
175
|
# Guideline and health policy tools
|
|
152
176
|
"guidelines": os.path.join(current_dir, "data", "unified_guideline_tools.json"),
|
|
177
|
+
# Database tools
|
|
178
|
+
"kegg": os.path.join(current_dir, "data", "kegg_tools.json"),
|
|
179
|
+
"ensembl": os.path.join(current_dir, "data", "ensembl_tools.json"),
|
|
180
|
+
"clinvar": os.path.join(current_dir, "data", "clinvar_tools.json"),
|
|
181
|
+
"geo": os.path.join(current_dir, "data", "geo_tools.json"),
|
|
182
|
+
"dbsnp": os.path.join(current_dir, "data", "dbsnp_tools.json"),
|
|
183
|
+
"gnomad": os.path.join(current_dir, "data", "gnomad_tools.json"),
|
|
184
|
+
# Ontology tools
|
|
185
|
+
"ols": os.path.join(current_dir, "data", "ols_tools.json"),
|
|
153
186
|
}
|
|
154
187
|
|
|
155
188
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
from .base_tool import BaseTool
|
|
4
|
+
from .tool_registry import register_tool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@register_tool("EMDBRESTTool")
|
|
8
|
+
class EMDBRESTTool(BaseTool):
|
|
9
|
+
def __init__(self, tool_config: Dict):
|
|
10
|
+
super().__init__(tool_config)
|
|
11
|
+
self.base_url = "https://www.ebi.ac.uk/emdb/api"
|
|
12
|
+
self.session = requests.Session()
|
|
13
|
+
self.session.headers.update({"Accept": "application/json"})
|
|
14
|
+
self.timeout = 30
|
|
15
|
+
|
|
16
|
+
def _build_url(self, args: Dict[str, Any]) -> str:
|
|
17
|
+
url = self.tool_config["fields"]["endpoint"]
|
|
18
|
+
for k, v in args.items():
|
|
19
|
+
url = url.replace(f"{{{k}}}", str(v))
|
|
20
|
+
return url
|
|
21
|
+
|
|
22
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
23
|
+
try:
|
|
24
|
+
url = self._build_url(arguments)
|
|
25
|
+
response = self.session.get(url, timeout=self.timeout)
|
|
26
|
+
response.raise_for_status()
|
|
27
|
+
data = response.json()
|
|
28
|
+
return {"status": "success", "data": data, "url": url}
|
|
29
|
+
except Exception as e:
|
|
30
|
+
return {"status": "error", "error": f"EMDB API error: {str(e)}"}
|
tooluniverse/ensembl_tool.py
CHANGED
|
@@ -1,61 +1,154 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Ensembl REST API Tool
|
|
3
|
+
|
|
4
|
+
This tool provides access to the Ensembl genome browser database for gene
|
|
5
|
+
lookup, sequence retrieval, variant information, and homology data.
|
|
6
|
+
"""
|
|
7
|
+
|
|
1
8
|
import requests
|
|
9
|
+
from typing import Dict, Any, Optional
|
|
2
10
|
from .base_tool import BaseTool
|
|
3
11
|
from .tool_registry import register_tool
|
|
4
12
|
|
|
5
13
|
|
|
6
|
-
|
|
7
|
-
class
|
|
8
|
-
"""
|
|
9
|
-
Local tool wrapper for Ensembl REST API lookups.
|
|
10
|
-
Supports symbol→gene lookup (xrefs/symbol) then lookup/id to
|
|
11
|
-
fetch metadata.
|
|
12
|
-
"""
|
|
14
|
+
class EnsemblRESTTool(BaseTool):
|
|
15
|
+
"""Base class for Ensembl REST API tools."""
|
|
13
16
|
|
|
14
17
|
def __init__(self, tool_config):
|
|
15
18
|
super().__init__(tool_config)
|
|
16
|
-
self.
|
|
19
|
+
self.base_url = "https://rest.ensembl.org"
|
|
17
20
|
self.session = requests.Session()
|
|
18
21
|
self.session.headers.update(
|
|
19
|
-
{
|
|
22
|
+
{
|
|
23
|
+
"Accept": "application/json",
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
"User-Agent": "ToolUniverse/1.0",
|
|
26
|
+
}
|
|
20
27
|
)
|
|
28
|
+
self.timeout = 30
|
|
29
|
+
|
|
30
|
+
def _make_request(
|
|
31
|
+
self, endpoint: str, params: Optional[Dict] = None
|
|
32
|
+
) -> Dict[str, Any]:
|
|
33
|
+
"""Make a request to the Ensembl API."""
|
|
34
|
+
url = f"{self.base_url}{endpoint}"
|
|
35
|
+
try:
|
|
36
|
+
response = self.session.get(url, params=params, timeout=self.timeout)
|
|
37
|
+
response.raise_for_status()
|
|
38
|
+
|
|
39
|
+
data = response.json()
|
|
40
|
+
return {
|
|
41
|
+
"status": "success",
|
|
42
|
+
"data": data,
|
|
43
|
+
"url": url,
|
|
44
|
+
"content_type": response.headers.get(
|
|
45
|
+
"content-type", "application/json"
|
|
46
|
+
),
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
except requests.exceptions.RequestException as e:
|
|
50
|
+
return {
|
|
51
|
+
"status": "error",
|
|
52
|
+
"error": f"Ensembl API request failed: {str(e)}",
|
|
53
|
+
"url": url,
|
|
54
|
+
}
|
|
21
55
|
|
|
22
|
-
def run(self, arguments):
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if not gene_id and xrefs:
|
|
39
|
-
gene_id = xrefs[0].get("id")
|
|
56
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
57
|
+
"""Execute the tool with given arguments."""
|
|
58
|
+
return self._make_request(self.endpoint, arguments)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@register_tool("EnsemblLookupGene")
|
|
62
|
+
class EnsemblLookupGene(EnsemblRESTTool):
|
|
63
|
+
"""Lookup gene information by ID or symbol."""
|
|
64
|
+
|
|
65
|
+
def __init__(self, tool_config):
|
|
66
|
+
super().__init__(tool_config)
|
|
67
|
+
self.endpoint = "/lookup/id"
|
|
68
|
+
|
|
69
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
70
|
+
"""Lookup gene by ID or symbol."""
|
|
71
|
+
gene_id = arguments.get("gene_id", "")
|
|
40
72
|
if not gene_id:
|
|
41
|
-
return {"
|
|
42
|
-
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
73
|
+
return {"status": "error", "error": "gene_id is required"}
|
|
74
|
+
|
|
75
|
+
# Ensembl API requires the ID in the URL path
|
|
76
|
+
endpoint = f"{self.endpoint}/{gene_id}"
|
|
77
|
+
params = {"expand": 1}
|
|
78
|
+
|
|
79
|
+
# Add species if specified
|
|
80
|
+
if "species" in arguments:
|
|
81
|
+
params["species"] = arguments["species"]
|
|
82
|
+
|
|
83
|
+
result = self._make_request(endpoint, params)
|
|
84
|
+
|
|
85
|
+
# Add gene_id to result for reference
|
|
86
|
+
if result.get("status") == "success":
|
|
87
|
+
result["gene_id"] = gene_id
|
|
88
|
+
|
|
89
|
+
return result
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@register_tool("EnsemblGetSequence")
|
|
93
|
+
class EnsemblGetSequence(EnsemblRESTTool):
|
|
94
|
+
"""Get DNA or protein sequences by region or gene ID."""
|
|
95
|
+
|
|
96
|
+
def __init__(self, tool_config):
|
|
97
|
+
super().__init__(tool_config)
|
|
98
|
+
self.endpoint = "/sequence/id"
|
|
99
|
+
|
|
100
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
101
|
+
"""Get sequence by gene ID or region."""
|
|
102
|
+
sequence_id = arguments.get("sequence_id", "")
|
|
103
|
+
if not sequence_id:
|
|
104
|
+
return {"status": "error", "error": "sequence_id is required"}
|
|
105
|
+
|
|
106
|
+
# Ensembl API requires the ID in the URL path
|
|
107
|
+
endpoint = f"{self.endpoint}/{sequence_id}"
|
|
108
|
+
params = {
|
|
109
|
+
"type": arguments.get("type", "genomic"), # genomic, cds, protein
|
|
110
|
+
"multiple_sequences": "true",
|
|
61
111
|
}
|
|
112
|
+
|
|
113
|
+
# Add species if specified
|
|
114
|
+
if "species" in arguments:
|
|
115
|
+
params["species"] = arguments["species"]
|
|
116
|
+
|
|
117
|
+
result = self._make_request(endpoint, params)
|
|
118
|
+
|
|
119
|
+
# Add sequence_id to result for reference
|
|
120
|
+
if result.get("status") == "success":
|
|
121
|
+
result["sequence_id"] = sequence_id
|
|
122
|
+
|
|
123
|
+
return result
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@register_tool("EnsemblGetVariants")
|
|
127
|
+
class EnsemblGetVariants(EnsemblRESTTool):
|
|
128
|
+
"""Get variant information for a genomic region."""
|
|
129
|
+
|
|
130
|
+
def __init__(self, tool_config):
|
|
131
|
+
super().__init__(tool_config)
|
|
132
|
+
self.endpoint = "/overlap/id"
|
|
133
|
+
|
|
134
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
135
|
+
"""Get variants for a region."""
|
|
136
|
+
region = arguments.get("region", "")
|
|
137
|
+
if not region:
|
|
138
|
+
return {
|
|
139
|
+
"status": "error",
|
|
140
|
+
"error": "region is required (e.g., '1:1000000..2000000')",
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# Ensembl API requires the region in the URL path with species
|
|
144
|
+
species = arguments.get("species", "human")
|
|
145
|
+
endpoint = f"/overlap/region/{species}/{region}"
|
|
146
|
+
params = {"feature": "variation", "content-type": "application/json"}
|
|
147
|
+
|
|
148
|
+
result = self._make_request(endpoint, params)
|
|
149
|
+
|
|
150
|
+
# Add region to result for reference
|
|
151
|
+
if result.get("status") == "success":
|
|
152
|
+
result["region"] = region
|
|
153
|
+
|
|
154
|
+
return result
|
tooluniverse/execute_function.py
CHANGED
|
@@ -563,8 +563,9 @@ class ToolUniverse:
|
|
|
563
563
|
for key in sorted(all_missing_keys):
|
|
564
564
|
f.write(f"{key}=your_api_key_here\n\n")
|
|
565
565
|
|
|
566
|
-
self.logger.info(
|
|
567
|
-
|
|
566
|
+
self.logger.info(
|
|
567
|
+
f"Generated API key template: {output_file}. Copy this file to .env and fill in your API keys"
|
|
568
|
+
)
|
|
568
569
|
|
|
569
570
|
def _create_hook_config_from_type(self, hook_type):
|
|
570
571
|
"""
|
|
@@ -966,8 +967,10 @@ class ToolUniverse:
|
|
|
966
967
|
|
|
967
968
|
# Generate template for missing API keys
|
|
968
969
|
if len(all_missing_keys) > 0:
|
|
969
|
-
warning(
|
|
970
|
-
|
|
970
|
+
warning(
|
|
971
|
+
f"Some tools will not be loaded due to missing API keys: {', '.join(all_missing_keys)}"
|
|
972
|
+
)
|
|
973
|
+
# info("Generating .env.template file with missing API keys...")
|
|
971
974
|
self.generate_env_template(all_missing_keys)
|
|
972
975
|
|
|
973
976
|
def _load_auto_discovered_configs(self):
|
|
@@ -2137,16 +2140,42 @@ class ToolUniverse:
|
|
|
2137
2140
|
tool_instance, arguments, stream_callback, use_cache, validate
|
|
2138
2141
|
)
|
|
2139
2142
|
else:
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2143
|
+
# Try to auto-load tools if dictionary is empty
|
|
2144
|
+
if not self._auto_load_tools_if_empty(function_name):
|
|
2145
|
+
error_msg = "Failed to auto-load tools"
|
|
2146
|
+
return self._create_dual_format_error(
|
|
2147
|
+
ToolUnavailableError(
|
|
2148
|
+
error_msg,
|
|
2149
|
+
next_steps=[
|
|
2150
|
+
"Manually run tu.load_tools()",
|
|
2151
|
+
"Check tool configuration",
|
|
2152
|
+
],
|
|
2153
|
+
)
|
|
2154
|
+
)
|
|
2155
|
+
|
|
2156
|
+
# Try to get the tool instance again after loading
|
|
2157
|
+
tool_instance = self._get_tool_instance(function_name, cache=True)
|
|
2158
|
+
if tool_instance:
|
|
2159
|
+
result, tool_arguments = self._execute_tool_with_stream(
|
|
2160
|
+
tool_instance,
|
|
2161
|
+
arguments,
|
|
2162
|
+
stream_callback,
|
|
2163
|
+
use_cache,
|
|
2164
|
+
validate,
|
|
2165
|
+
)
|
|
2166
|
+
else:
|
|
2167
|
+
error_msg = (
|
|
2168
|
+
f"Tool '{function_name}' not found even after loading tools"
|
|
2169
|
+
)
|
|
2170
|
+
return self._create_dual_format_error(
|
|
2171
|
+
ToolUnavailableError(
|
|
2172
|
+
error_msg,
|
|
2173
|
+
next_steps=[
|
|
2174
|
+
"Check tool name spelling",
|
|
2175
|
+
"Verify tool is available in loaded categories",
|
|
2176
|
+
],
|
|
2177
|
+
)
|
|
2148
2178
|
)
|
|
2149
|
-
)
|
|
2150
2179
|
except Exception as e:
|
|
2151
2180
|
# Classify and return structured error
|
|
2152
2181
|
classified_error = self._classify_exception(e, function_name, arguments)
|
|
@@ -2356,6 +2385,29 @@ class ToolUniverse:
|
|
|
2356
2385
|
|
|
2357
2386
|
return None
|
|
2358
2387
|
|
|
2388
|
+
def _auto_load_tools_if_empty(self, function_name: str = None) -> bool:
|
|
2389
|
+
"""
|
|
2390
|
+
Automatically load tools if the tools dictionary is empty.
|
|
2391
|
+
|
|
2392
|
+
Args:
|
|
2393
|
+
function_name: Optional tool name to check after loading
|
|
2394
|
+
|
|
2395
|
+
Returns:
|
|
2396
|
+
bool: True if tools were loaded successfully, False otherwise
|
|
2397
|
+
"""
|
|
2398
|
+
if not self.all_tool_dict:
|
|
2399
|
+
print(
|
|
2400
|
+
"⚠️ Warning: No tools loaded. Automatically running tu.load_tools()..."
|
|
2401
|
+
)
|
|
2402
|
+
try:
|
|
2403
|
+
self.load_tools()
|
|
2404
|
+
print("✅ Tools loaded successfully.")
|
|
2405
|
+
return True
|
|
2406
|
+
except Exception as load_error:
|
|
2407
|
+
print(f"❌ Failed to auto-load tools: {load_error}")
|
|
2408
|
+
return False
|
|
2409
|
+
return True
|
|
2410
|
+
|
|
2359
2411
|
def _make_cache_key(self, function_name: str, arguments: dict) -> str:
|
|
2360
2412
|
"""Generate cache key by delegating to BaseTool."""
|
|
2361
2413
|
tool_instance = self._get_tool_instance(function_name, cache=False)
|
|
@@ -2374,7 +2426,15 @@ class ToolUniverse:
|
|
|
2374
2426
|
) -> Optional[ToolError]:
|
|
2375
2427
|
"""Validate parameters by delegating to BaseTool."""
|
|
2376
2428
|
if function_name not in self.all_tool_dict:
|
|
2377
|
-
|
|
2429
|
+
# Try to auto-load tools if dictionary is empty
|
|
2430
|
+
if not self._auto_load_tools_if_empty(function_name):
|
|
2431
|
+
return ToolUnavailableError("Failed to auto-load tools")
|
|
2432
|
+
|
|
2433
|
+
# Check again after loading
|
|
2434
|
+
if function_name not in self.all_tool_dict:
|
|
2435
|
+
return ToolUnavailableError(
|
|
2436
|
+
f"Tool '{function_name}' not found even after loading tools"
|
|
2437
|
+
)
|
|
2378
2438
|
|
|
2379
2439
|
tool_instance = self._get_tool_instance(function_name, cache=False)
|
|
2380
2440
|
if not tool_instance:
|