tooluniverse 1.0.9.1__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.

Files changed (191) hide show
  1. tooluniverse/__init__.py +57 -1
  2. tooluniverse/admetai_tool.py +1 -1
  3. tooluniverse/agentic_tool.py +65 -17
  4. tooluniverse/base_tool.py +19 -8
  5. tooluniverse/blast_tool.py +132 -0
  6. tooluniverse/boltz_tool.py +3 -3
  7. tooluniverse/cache/result_cache_manager.py +167 -12
  8. tooluniverse/cbioportal_tool.py +42 -0
  9. tooluniverse/clinvar_tool.py +268 -74
  10. tooluniverse/compose_scripts/drug_safety_analyzer.py +1 -1
  11. tooluniverse/compose_scripts/multi_agent_literature_search.py +1 -1
  12. tooluniverse/compose_scripts/output_summarizer.py +4 -4
  13. tooluniverse/compose_scripts/tool_discover.py +1941 -443
  14. tooluniverse/compose_scripts/tool_graph_composer.py +1 -1
  15. tooluniverse/compose_scripts/tool_metadata_generator.py +1 -1
  16. tooluniverse/compose_tool.py +9 -9
  17. tooluniverse/core_tool.py +2 -2
  18. tooluniverse/ctg_tool.py +4 -4
  19. tooluniverse/custom_tool.py +1 -1
  20. tooluniverse/data/agentic_tools.json +0 -370
  21. tooluniverse/data/alphafold_tools.json +6 -6
  22. tooluniverse/data/blast_tools.json +112 -0
  23. tooluniverse/data/cbioportal_tools.json +87 -0
  24. tooluniverse/data/clinvar_tools.json +235 -0
  25. tooluniverse/data/compose_tools.json +0 -89
  26. tooluniverse/data/dbsnp_tools.json +275 -0
  27. tooluniverse/data/emdb_tools.json +61 -0
  28. tooluniverse/data/ensembl_tools.json +259 -0
  29. tooluniverse/data/file_download_tools.json +275 -0
  30. tooluniverse/data/geo_tools.json +200 -48
  31. tooluniverse/data/gnomad_tools.json +109 -0
  32. tooluniverse/data/gtopdb_tools.json +68 -0
  33. tooluniverse/data/gwas_tools.json +32 -0
  34. tooluniverse/data/interpro_tools.json +199 -0
  35. tooluniverse/data/jaspar_tools.json +70 -0
  36. tooluniverse/data/kegg_tools.json +356 -0
  37. tooluniverse/data/mpd_tools.json +87 -0
  38. tooluniverse/data/ols_tools.json +314 -0
  39. tooluniverse/data/package_discovery_tools.json +64 -0
  40. tooluniverse/data/packages/categorized_tools.txt +0 -1
  41. tooluniverse/data/packages/machine_learning_tools.json +0 -47
  42. tooluniverse/data/paleobiology_tools.json +91 -0
  43. tooluniverse/data/pride_tools.json +62 -0
  44. tooluniverse/data/pypi_package_inspector_tools.json +158 -0
  45. tooluniverse/data/python_executor_tools.json +341 -0
  46. tooluniverse/data/regulomedb_tools.json +50 -0
  47. tooluniverse/data/remap_tools.json +89 -0
  48. tooluniverse/data/screen_tools.json +89 -0
  49. tooluniverse/data/tool_discovery_agents.json +428 -0
  50. tooluniverse/data/tool_discovery_agents.json.backup +1343 -0
  51. tooluniverse/data/uniprot_tools.json +77 -0
  52. tooluniverse/data/web_search_tools.json +250 -0
  53. tooluniverse/data/worms_tools.json +55 -0
  54. tooluniverse/dataset_tool.py +2 -2
  55. tooluniverse/dbsnp_tool.py +196 -58
  56. tooluniverse/default_config.py +36 -3
  57. tooluniverse/emdb_tool.py +30 -0
  58. tooluniverse/enrichr_tool.py +14 -14
  59. tooluniverse/ensembl_tool.py +140 -47
  60. tooluniverse/execute_function.py +594 -29
  61. tooluniverse/extended_hooks.py +4 -4
  62. tooluniverse/file_download_tool.py +269 -0
  63. tooluniverse/gene_ontology_tool.py +1 -1
  64. tooluniverse/generate_tools.py +3 -3
  65. tooluniverse/geo_tool.py +81 -28
  66. tooluniverse/gnomad_tool.py +100 -52
  67. tooluniverse/gtopdb_tool.py +41 -0
  68. tooluniverse/humanbase_tool.py +10 -10
  69. tooluniverse/interpro_tool.py +72 -0
  70. tooluniverse/jaspar_tool.py +30 -0
  71. tooluniverse/kegg_tool.py +230 -0
  72. tooluniverse/logging_config.py +2 -2
  73. tooluniverse/mcp_client_tool.py +57 -129
  74. tooluniverse/mcp_integration.py +52 -49
  75. tooluniverse/mcp_tool_registry.py +147 -528
  76. tooluniverse/mpd_tool.py +42 -0
  77. tooluniverse/ncbi_eutils_tool.py +96 -0
  78. tooluniverse/ols_tool.py +435 -0
  79. tooluniverse/openalex_tool.py +8 -8
  80. tooluniverse/openfda_tool.py +2 -2
  81. tooluniverse/output_hook.py +15 -15
  82. tooluniverse/package_discovery_tool.py +217 -0
  83. tooluniverse/package_tool.py +1 -1
  84. tooluniverse/paleobiology_tool.py +30 -0
  85. tooluniverse/pmc_tool.py +2 -2
  86. tooluniverse/pride_tool.py +30 -0
  87. tooluniverse/pypi_package_inspector_tool.py +593 -0
  88. tooluniverse/python_executor_tool.py +711 -0
  89. tooluniverse/regulomedb_tool.py +30 -0
  90. tooluniverse/remap_tool.py +44 -0
  91. tooluniverse/remote/boltz/boltz_mcp_server.py +1 -1
  92. tooluniverse/remote/depmap_24q2/depmap_24q2_mcp_tool.py +3 -3
  93. tooluniverse/remote/immune_compass/compass_tool.py +3 -3
  94. tooluniverse/remote/pinnacle/pinnacle_tool.py +2 -2
  95. tooluniverse/remote/transcriptformer/transcriptformer_tool.py +3 -3
  96. tooluniverse/remote/uspto_downloader/uspto_downloader_mcp_server.py +3 -3
  97. tooluniverse/remote_tool.py +4 -4
  98. tooluniverse/screen_tool.py +44 -0
  99. tooluniverse/scripts/filter_tool_files.py +2 -2
  100. tooluniverse/smcp.py +93 -12
  101. tooluniverse/smcp_server.py +100 -21
  102. tooluniverse/space/__init__.py +46 -0
  103. tooluniverse/space/loader.py +133 -0
  104. tooluniverse/space/validator.py +353 -0
  105. tooluniverse/tool_finder_embedding.py +5 -3
  106. tooluniverse/tool_finder_keyword.py +12 -10
  107. tooluniverse/tool_finder_llm.py +12 -8
  108. tooluniverse/tools/{UCSC_get_genes_by_region.py → BLAST_nucleotide_search.py} +22 -26
  109. tooluniverse/tools/BLAST_protein_search.py +63 -0
  110. tooluniverse/tools/ClinVar_search_variants.py +26 -15
  111. tooluniverse/tools/CodeQualityAnalyzer.py +3 -3
  112. tooluniverse/tools/EMDB_get_structure.py +46 -0
  113. tooluniverse/tools/GtoPdb_get_targets.py +52 -0
  114. tooluniverse/tools/InterPro_get_domain_details.py +46 -0
  115. tooluniverse/tools/InterPro_get_protein_domains.py +49 -0
  116. tooluniverse/tools/InterPro_search_domains.py +52 -0
  117. tooluniverse/tools/JASPAR_get_transcription_factors.py +52 -0
  118. tooluniverse/tools/MPD_get_phenotype_data.py +59 -0
  119. tooluniverse/tools/PRIDE_search_proteomics.py +52 -0
  120. tooluniverse/tools/PackageAnalyzer.py +55 -0
  121. tooluniverse/tools/Paleobiology_get_fossils.py +52 -0
  122. tooluniverse/tools/PyPIPackageInspector.py +59 -0
  123. tooluniverse/tools/ReMap_get_transcription_factor_binding.py +59 -0
  124. tooluniverse/tools/ReferenceInfoAnalyzer.py +55 -0
  125. tooluniverse/tools/RegulomeDB_query_variant.py +46 -0
  126. tooluniverse/tools/SCREEN_get_regulatory_elements.py +59 -0
  127. tooluniverse/tools/{ArgumentDescriptionOptimizer.py → TestResultsAnalyzer.py} +13 -13
  128. tooluniverse/tools/ToolDiscover.py +11 -11
  129. tooluniverse/tools/UniProt_id_mapping.py +63 -0
  130. tooluniverse/tools/UniProt_search.py +63 -0
  131. tooluniverse/tools/UnifiedToolGenerator.py +59 -0
  132. tooluniverse/tools/WoRMS_search_species.py +49 -0
  133. tooluniverse/tools/XMLToolOptimizer.py +55 -0
  134. tooluniverse/tools/__init__.py +119 -29
  135. tooluniverse/tools/_shared_client.py +3 -3
  136. tooluniverse/tools/alphafold_get_annotations.py +3 -3
  137. tooluniverse/tools/alphafold_get_prediction.py +3 -3
  138. tooluniverse/tools/alphafold_get_summary.py +3 -3
  139. tooluniverse/tools/cBioPortal_get_cancer_studies.py +46 -0
  140. tooluniverse/tools/cBioPortal_get_mutations.py +52 -0
  141. tooluniverse/tools/{gnomAD_query_variant.py → clinvar_get_clinical_significance.py} +8 -11
  142. tooluniverse/tools/clinvar_get_variant_details.py +49 -0
  143. tooluniverse/tools/dbSNP_get_variant_by_rsid.py +7 -7
  144. tooluniverse/tools/dbsnp_get_frequencies.py +46 -0
  145. tooluniverse/tools/dbsnp_search_by_gene.py +52 -0
  146. tooluniverse/tools/download_binary_file.py +66 -0
  147. tooluniverse/tools/download_file.py +71 -0
  148. tooluniverse/tools/download_text_content.py +55 -0
  149. tooluniverse/tools/dynamic_package_discovery.py +59 -0
  150. tooluniverse/tools/ensembl_get_sequence.py +52 -0
  151. tooluniverse/tools/{Ensembl_lookup_gene_by_symbol.py → ensembl_get_variants.py} +11 -11
  152. tooluniverse/tools/ensembl_lookup_gene.py +46 -0
  153. tooluniverse/tools/geo_get_dataset_info.py +46 -0
  154. tooluniverse/tools/geo_get_sample_info.py +46 -0
  155. tooluniverse/tools/geo_search_datasets.py +67 -0
  156. tooluniverse/tools/gnomad_get_gene_constraints.py +49 -0
  157. tooluniverse/tools/kegg_find_genes.py +52 -0
  158. tooluniverse/tools/kegg_get_gene_info.py +46 -0
  159. tooluniverse/tools/kegg_get_pathway_info.py +46 -0
  160. tooluniverse/tools/kegg_list_organisms.py +44 -0
  161. tooluniverse/tools/kegg_search_pathway.py +46 -0
  162. tooluniverse/tools/ols_find_similar_terms.py +63 -0
  163. tooluniverse/tools/{get_hyperopt_info.py → ols_get_ontology_info.py} +13 -10
  164. tooluniverse/tools/ols_get_term_ancestors.py +67 -0
  165. tooluniverse/tools/ols_get_term_children.py +67 -0
  166. tooluniverse/tools/{TestCaseGenerator.py → ols_get_term_info.py} +12 -9
  167. tooluniverse/tools/{CodeOptimizer.py → ols_search_ontologies.py} +22 -14
  168. tooluniverse/tools/ols_search_terms.py +71 -0
  169. tooluniverse/tools/python_code_executor.py +79 -0
  170. tooluniverse/tools/python_script_runner.py +79 -0
  171. tooluniverse/tools/web_api_documentation_search.py +63 -0
  172. tooluniverse/tools/web_search.py +71 -0
  173. tooluniverse/uniprot_tool.py +219 -16
  174. tooluniverse/url_tool.py +19 -1
  175. tooluniverse/uspto_tool.py +1 -1
  176. tooluniverse/utils.py +12 -12
  177. tooluniverse/web_search_tool.py +229 -0
  178. tooluniverse/worms_tool.py +64 -0
  179. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/METADATA +8 -3
  180. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/RECORD +184 -92
  181. tooluniverse/data/genomics_tools.json +0 -174
  182. tooluniverse/tools/ToolDescriptionOptimizer.py +0 -67
  183. tooluniverse/tools/ToolImplementationGenerator.py +0 -67
  184. tooluniverse/tools/ToolOptimizer.py +0 -59
  185. tooluniverse/tools/ToolSpecificationGenerator.py +0 -67
  186. tooluniverse/tools/ToolSpecificationOptimizer.py +0 -63
  187. tooluniverse/ucsc_tool.py +0 -60
  188. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/WHEEL +0 -0
  189. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/entry_points.txt +0 -0
  190. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/licenses/LICENSE +0 -0
  191. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/top_level.txt +0 -0
@@ -65,7 +65,7 @@ class HookRule:
65
65
  arguments (Dict[str, Any]): Arguments passed to the tool
66
66
  context (Dict[str, Any]): Additional context information
67
67
 
68
- Returns:
68
+ Returns
69
69
  bool: True if conditions are met, False otherwise
70
70
  """
71
71
  # Evaluate output length conditions
@@ -158,7 +158,7 @@ class OutputHook:
158
158
  arguments (Dict[str, Any]): Arguments passed to the tool
159
159
  context (Dict[str, Any]): Additional context information
160
160
 
161
- Returns:
161
+ Returns
162
162
  bool: True if hook should trigger, False otherwise
163
163
  """
164
164
  if not self.enabled:
@@ -184,7 +184,7 @@ class OutputHook:
184
184
  arguments (Dict[str, Any]): Arguments passed to the tool
185
185
  context (Dict[str, Any]): Additional context information
186
186
 
187
- Returns:
187
+ Returns
188
188
  Any: The processed output
189
189
 
190
190
  Raises:
@@ -290,7 +290,7 @@ class SummarizationHook(OutputHook):
290
290
  arguments (Dict[str, Any]): Arguments passed to the tool
291
291
  context (Dict[str, Any]): Additional context information
292
292
 
293
- Returns:
293
+ Returns
294
294
  Any: The summarized output, or original output if summarization fails
295
295
  """
296
296
  try:
@@ -408,7 +408,7 @@ class SummarizationHook(OutputHook):
408
408
  Args:
409
409
  context (Dict[str, Any]): Execution context containing arguments and metadata
410
410
 
411
- Returns:
411
+ Returns
412
412
  str: Extracted query context or fallback description
413
413
  """
414
414
  arguments = context.get("arguments", {})
@@ -519,7 +519,7 @@ class HookManager:
519
519
  arguments (Dict[str, Any]): Arguments passed to the tool
520
520
  context (Dict[str, Any]): Additional context information
521
521
 
522
- Returns:
522
+ Returns
523
523
  Any: The processed output after applying all applicable hooks
524
524
  """
525
525
  if not self.enabled:
@@ -553,7 +553,7 @@ class HookManager:
553
553
  """
554
554
  Validate that LLM API keys are available for hook tools.
555
555
 
556
- Returns:
556
+ Returns
557
557
  bool: True if API keys are available, False otherwise
558
558
  """
559
559
  from .agentic_tool import AgenticTool
@@ -641,7 +641,7 @@ class HookManager:
641
641
  Args:
642
642
  hook_name (str): Name of the hook to retrieve
643
643
 
644
- Returns:
644
+ Returns
645
645
  Optional[OutputHook]: Hook instance if found, None otherwise
646
646
  """
647
647
  for hook in self.hooks:
@@ -684,7 +684,7 @@ class HookManager:
684
684
  """
685
685
  Get the path to the hook configuration file.
686
686
 
687
- Returns:
687
+ Returns
688
688
  Path: Path to the configuration file
689
689
  """
690
690
  try:
@@ -934,7 +934,7 @@ class HookManager:
934
934
  Args:
935
935
  tool_name (str): Name of the tool to check
936
936
 
937
- Returns:
937
+ Returns
938
938
  bool: True if the tool is a hook tool and should be excluded from hook processing
939
939
  """
940
940
  hook_tool_names = [
@@ -956,7 +956,7 @@ class HookManager:
956
956
  Args:
957
957
  hook_config (Dict[str, Any]): Hook configuration
958
958
 
959
- Returns:
959
+ Returns
960
960
  Optional[OutputHook]: Created hook instance or None if type not supported
961
961
  """
962
962
  hook_type = hook_config.get("type", "SummarizationHook")
@@ -985,7 +985,7 @@ class HookManager:
985
985
  Args:
986
986
  hook_config (Dict[str, Any]): Original hook configuration
987
987
 
988
- Returns:
988
+ Returns
989
989
  Dict[str, Any]: Enhanced configuration with defaults applied
990
990
  """
991
991
  hook_type = hook_config.get("type", "SummarizationHook")
@@ -1052,7 +1052,7 @@ class HookManager:
1052
1052
  tool_name (str): Name of the current tool
1053
1053
  context (Dict[str, Any]): Execution context
1054
1054
 
1055
- Returns:
1055
+ Returns
1056
1056
  bool: True if hook is applicable, False otherwise
1057
1057
  """
1058
1058
  # Check tool-specific hooks
@@ -1138,7 +1138,7 @@ class FileSaveHook(OutputHook):
1138
1138
  arguments (Dict[str, Any]): Arguments passed to the tool
1139
1139
  context (Dict[str, Any]): Execution context
1140
1140
 
1141
- Returns:
1141
+ Returns
1142
1142
  Dict[str, Any]: Dictionary containing file information:
1143
1143
  - file_path: Path to the saved file
1144
1144
  - data_format: Format of the data (json, text, binary, etc.)
@@ -1213,7 +1213,7 @@ class FileSaveHook(OutputHook):
1213
1213
  Args:
1214
1214
  data (Any): The data to analyze
1215
1215
 
1216
- Returns:
1216
+ Returns
1217
1217
  tuple[str, str]: (data_format, data_structure)
1218
1218
  """
1219
1219
  if isinstance(data, dict):
@@ -0,0 +1,217 @@
1
+ """Dynamic package discovery and evaluation"""
2
+
3
+ import requests
4
+ import time
5
+ from typing import Dict, Any, List
6
+ from .base_tool import BaseTool
7
+ from .tool_registry import register_tool
8
+
9
+
10
+ @register_tool("DynamicPackageDiscovery")
11
+ class DynamicPackageDiscovery(BaseTool):
12
+ """Searches PyPI and evaluates packages dynamically based on requirements"""
13
+
14
+ def __init__(self, tool_config: Dict[str, Any]):
15
+ super().__init__(tool_config)
16
+ self.pypi_search_url = "https://pypi.org/pypi/{package}/json"
17
+ self.pypi_search_api = "https://pypi.org/search/"
18
+ self.session = requests.Session()
19
+ self.session.headers.update({"User-Agent": "ToolUniverse-PackageDiscovery/1.0"})
20
+
21
+ # Initialize WebSearchTool instance
22
+ from .web_search_tool import WebSearchTool
23
+
24
+ self.web_search_tool = WebSearchTool({"name": "WebSearchTool"})
25
+
26
+ def _search_pypi_via_web(self, query: str) -> List[Dict[str, Any]]:
27
+ """Search PyPI using web search tool"""
28
+ try:
29
+ # Use pre-initialized WebSearchTool instance
30
+ result = self.web_search_tool.run(
31
+ {
32
+ "query": f"{query} site:pypi.org",
33
+ "max_results": 10,
34
+ "search_type": "python_packages",
35
+ }
36
+ )
37
+
38
+ packages = []
39
+ if result.get("status") == "success":
40
+ for item in result.get("results", []):
41
+ url = item.get("url", "")
42
+ if "pypi.org/project/" in url:
43
+ # Extract package name from URL
44
+ pkg_name = url.split("/project/")[-1].rstrip("/")
45
+ packages.append(
46
+ {
47
+ "name": pkg_name,
48
+ "source": "pypi_web",
49
+ "title": item.get("title", ""),
50
+ "snippet": item.get("snippet", ""),
51
+ "url": url,
52
+ }
53
+ )
54
+
55
+ return packages
56
+ except Exception as e:
57
+ print(f"⚠️ Web search for PyPI packages failed: {e}")
58
+ return []
59
+
60
+ def _evaluate_package(self, package_name: str) -> Dict[str, Any]:
61
+ """Evaluate a package's suitability by fetching PyPI metadata"""
62
+ try:
63
+ response = self.session.get(
64
+ self.pypi_search_url.format(package=package_name), timeout=10
65
+ )
66
+
67
+ if response.status_code == 200:
68
+ data = response.json()
69
+ info = data.get("info", {})
70
+ urls = info.get("project_urls", {})
71
+
72
+ # Extract key metrics
73
+ evaluation = {
74
+ "name": package_name,
75
+ "version": info.get("version"),
76
+ "description": info.get("summary", ""),
77
+ "author": info.get("author", ""),
78
+ "license": info.get("license", ""),
79
+ "home_page": info.get("home_page", ""),
80
+ "download_url": info.get("download_url", ""),
81
+ "requires_python": info.get("requires_python", ""),
82
+ "dependencies": info.get("requires_dist", []),
83
+ "classifiers": info.get("classifiers", []),
84
+ # Quality indicators
85
+ "has_docs": bool(urls.get("Documentation")),
86
+ "has_source": bool(urls.get("Source")),
87
+ "has_homepage": bool(info.get("home_page")),
88
+ "has_bug_tracker": bool(urls.get("Bug Reports")),
89
+ "project_urls": urls,
90
+ # Popularity indicators
91
+ "is_stable": "Development Status :: 5 - Production/Stable"
92
+ in info.get("classifiers", []),
93
+ "is_mature": "Development Status :: 6 - Mature"
94
+ in info.get("classifiers", []),
95
+ "has_tests": "Topic :: Software Development :: Testing"
96
+ in info.get("classifiers", []),
97
+ "is_typed": "Typing :: Typed" in info.get("classifiers", []),
98
+ }
99
+
100
+ # Calculate a basic quality score
101
+ quality_score = 0
102
+ if evaluation["has_docs"]:
103
+ quality_score += 20
104
+ if evaluation["has_source"]:
105
+ quality_score += 15
106
+ if evaluation["is_stable"] or evaluation["is_mature"]:
107
+ quality_score += 25
108
+ if evaluation["has_tests"]:
109
+ quality_score += 15
110
+ if evaluation["is_typed"]:
111
+ quality_score += 10
112
+ if evaluation["has_homepage"]:
113
+ quality_score += 10
114
+ if evaluation["has_bug_tracker"]:
115
+ quality_score += 5
116
+
117
+ evaluation["quality_score"] = min(quality_score, 100)
118
+
119
+ return evaluation
120
+ else:
121
+ return {
122
+ "name": package_name,
123
+ "error": f"HTTP {response.status_code}",
124
+ "quality_score": 0,
125
+ }
126
+
127
+ except Exception as e:
128
+ return {"name": package_name, "error": str(e), "quality_score": 0}
129
+
130
+ def _rank_packages(
131
+ self, packages: List[Dict[str, Any]], requirements: str, functionality: str
132
+ ) -> List[Dict[str, Any]]:
133
+ """Rank packages by relevance and quality"""
134
+ if not packages:
135
+ return []
136
+
137
+ # Filter out packages with errors
138
+ valid_packages = [pkg for pkg in packages if "error" not in pkg]
139
+
140
+ # Sort by quality score (descending)
141
+ ranked = sorted(
142
+ valid_packages, key=lambda x: x.get("quality_score", 0), reverse=True
143
+ )
144
+
145
+ # Add ranking metadata
146
+ for i, pkg in enumerate(ranked):
147
+ pkg["rank"] = i + 1
148
+ pkg["reasoning"] = f"Quality score: {pkg.get('quality_score', 0)}/100"
149
+
150
+ return ranked
151
+
152
+ def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
153
+ """
154
+ Dynamically discover and evaluate packages
155
+
156
+ Args:
157
+ requirements: Description of what's needed
158
+ functionality: Specific functionality required
159
+ constraints: Any constraints (Python version, license, etc.)
160
+ """
161
+ try:
162
+ requirements = arguments.get("requirements", "")
163
+ functionality = arguments.get("functionality", "")
164
+
165
+ # Search for candidate packages
166
+ search_query = f"{requirements} {functionality}".strip()
167
+ print(f"🔍 Searching for packages: {search_query}")
168
+
169
+ candidates = self._search_pypi_via_web(search_query)
170
+
171
+ if not candidates:
172
+ return {
173
+ "status": "success",
174
+ "candidates": [],
175
+ "recommendation": None,
176
+ "message": "No packages found",
177
+ }
178
+
179
+ print(f"📦 Found {len(candidates)} package candidates")
180
+
181
+ # Evaluate each candidate
182
+ evaluated = []
183
+ for i, pkg in enumerate(candidates):
184
+ print(f" Evaluating {i+1}/{len(candidates)}: {pkg['name']}")
185
+ evaluation = self._evaluate_package(pkg["name"])
186
+ # Merge web search info with PyPI evaluation
187
+ evaluation.update({k: v for k, v in pkg.items() if k not in evaluation})
188
+ evaluated.append(evaluation)
189
+
190
+ # Rate limiting
191
+ time.sleep(0.2)
192
+
193
+ # Rank by suitability
194
+ ranked = self._rank_packages(evaluated, requirements, functionality)
195
+
196
+ top_recommendation = ranked[0] if ranked else None
197
+
198
+ if top_recommendation:
199
+ score = top_recommendation.get("quality_score", 0)
200
+ print(
201
+ f"🏆 Top recommendation: {top_recommendation['name']} (score: {score})"
202
+ )
203
+
204
+ return {
205
+ "status": "success",
206
+ "candidates": ranked,
207
+ "recommendation": top_recommendation,
208
+ "total_evaluated": len(evaluated),
209
+ }
210
+
211
+ except Exception as e:
212
+ return {
213
+ "status": "error",
214
+ "error": str(e),
215
+ "candidates": [],
216
+ "recommendation": None,
217
+ }
@@ -27,7 +27,7 @@ class PackageTool(BaseTool):
27
27
  Args:
28
28
  arguments (dict): Optional parameters for customization
29
29
 
30
- Returns:
30
+ Returns
31
31
  dict: Package information including name, description, installation, docs, usage
32
32
  """
33
33
  include_examples = arguments.get("include_examples", True)
@@ -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("PaleobiologyRESTTool")
8
+ class PaleobiologyRESTTool(BaseTool):
9
+ def __init__(self, tool_config: Dict):
10
+ super().__init__(tool_config)
11
+ self.base_url = "https://paleobiodb.org/data1.2"
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"Paleobiology API error: {str(e)}"}
tooluniverse/pmc_tool.py CHANGED
@@ -43,7 +43,7 @@ class PMCTool(BaseTool):
43
43
  date_to: End date filter (YYYY/MM/DD)
44
44
  article_type: Article type filter (e.g., 'research-article', 'review')
45
45
 
46
- Returns:
46
+ Returns
47
47
  List of paper dictionaries
48
48
  """
49
49
  try:
@@ -158,7 +158,7 @@ class PMCTool(BaseTool):
158
158
  Args:
159
159
  tool_arguments: Dictionary containing search parameters
160
160
 
161
- Returns:
161
+ Returns
162
162
  List of paper dictionaries
163
163
  """
164
164
  query = tool_arguments.get("query", "")
@@ -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("PRIDERESTTool")
8
+ class PRIDERESTTool(BaseTool):
9
+ def __init__(self, tool_config: Dict):
10
+ super().__init__(tool_config)
11
+ self.base_url = "https://www.ebi.ac.uk/pride/ws/archive/v2"
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"PRIDE API error: {str(e)}"}