tooluniverse 1.0.6__py3-none-any.whl → 1.0.8__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 (862) hide show
  1. tooluniverse/__init__.py +56 -10
  2. tooluniverse/admetai_tool.py +8 -4
  3. tooluniverse/agentic_tool.py +40 -4
  4. tooluniverse/arxiv_tool.py +2 -6
  5. tooluniverse/base_tool.py +210 -25
  6. tooluniverse/biogrid_tool.py +118 -0
  7. tooluniverse/biorxiv_tool.py +35 -16
  8. tooluniverse/build_optimizer.py +87 -0
  9. tooluniverse/cache/__init__.py +3 -0
  10. tooluniverse/cache/memory_cache.py +99 -0
  11. tooluniverse/cache/result_cache_manager.py +235 -0
  12. tooluniverse/cache/sqlite_backend.py +257 -0
  13. tooluniverse/cellosaurus_tool.py +1332 -0
  14. tooluniverse/clinvar_tool.py +90 -0
  15. tooluniverse/compose_scripts/enhanced_multi_agent_literature_search.py +310 -0
  16. tooluniverse/compose_scripts/multi_agent_literature_search.py +794 -0
  17. tooluniverse/compose_scripts/tool_graph_generation.py +68 -35
  18. tooluniverse/compose_scripts/tool_metadata_generator.py +205 -105
  19. tooluniverse/compose_tool.py +93 -8
  20. tooluniverse/core_tool.py +46 -44
  21. tooluniverse/crossref_tool.py +89 -4
  22. tooluniverse/custom_tool.py +28 -0
  23. tooluniverse/data/agentic_tools.json +1271 -1179
  24. tooluniverse/data/alphafold_tools.json +356 -105
  25. tooluniverse/data/arxiv_tools.json +85 -81
  26. tooluniverse/data/biorxiv_tools.json +69 -64
  27. tooluniverse/data/cellosaurus_tools.json +260 -0
  28. tooluniverse/data/chembl_tools.json +27 -12
  29. tooluniverse/data/clinicaltrials_gov_tools.json +377 -302
  30. tooluniverse/data/compose_tools.json +123 -16
  31. tooluniverse/data/core_tools.json +104 -99
  32. tooluniverse/data/crossref_tools.json +131 -63
  33. tooluniverse/data/dailymed_tools.json +17 -3
  34. tooluniverse/data/dataset_tools.json +1031 -588
  35. tooluniverse/data/dblp_tools.json +135 -64
  36. tooluniverse/data/disease_target_score_tools.json +20 -10
  37. tooluniverse/data/doaj_tools.json +131 -87
  38. tooluniverse/data/drug_discovery_agents.json +292 -0
  39. tooluniverse/data/embedding_tools.json +362 -299
  40. tooluniverse/data/enrichr_tools.json +34 -27
  41. tooluniverse/data/europe_pmc_tools.json +107 -16
  42. tooluniverse/data/fatcat_tools.json +71 -66
  43. tooluniverse/data/fda_drug_adverse_event_tools.json +1061 -445
  44. tooluniverse/data/fda_drug_labeling_tools.json +6858 -6901
  45. tooluniverse/data/finder_tools.json +32 -37
  46. tooluniverse/data/gene_ontology_tools.json +19 -7
  47. tooluniverse/data/genomics_tools.json +174 -0
  48. tooluniverse/data/geo_tools.json +86 -0
  49. tooluniverse/data/gwas_tools.json +1720 -959
  50. tooluniverse/data/hal_tools.json +69 -64
  51. tooluniverse/data/hpa_tools.json +53 -14
  52. tooluniverse/data/humanbase_tools.json +51 -43
  53. tooluniverse/data/idmap_tools.json +76 -70
  54. tooluniverse/data/literature_search_tools.json +306 -0
  55. tooluniverse/data/markitdown_tools.json +51 -0
  56. tooluniverse/data/mcp_client_tools_example.json +122 -107
  57. tooluniverse/data/medlineplus_tools.json +50 -10
  58. tooluniverse/data/medrxiv_tools.json +69 -64
  59. tooluniverse/data/molecule_2d_tools.json +134 -0
  60. tooluniverse/data/molecule_3d_tools.json +164 -0
  61. tooluniverse/data/monarch_tools.json +112 -110
  62. tooluniverse/data/odphp_tools.json +389 -119
  63. tooluniverse/data/openaire_tools.json +89 -79
  64. tooluniverse/data/openalex_tools.json +96 -31
  65. tooluniverse/data/opentarget_tools.json +1457 -1372
  66. tooluniverse/data/osf_preprints_tools.json +77 -73
  67. tooluniverse/data/packages/bioinformatics_core_tools.json +40 -10
  68. tooluniverse/data/packages/cheminformatics_tools.json +20 -5
  69. tooluniverse/data/packages/genomics_tools.json +36 -9
  70. tooluniverse/data/packages/machine_learning_tools.json +36 -9
  71. tooluniverse/data/packages/scientific_computing_tools.json +20 -5
  72. tooluniverse/data/packages/single_cell_tools.json +20 -5
  73. tooluniverse/data/packages/structural_biology_tools.json +16 -4
  74. tooluniverse/data/packages/visualization_tools.json +20 -5
  75. tooluniverse/data/pmc_tools.json +108 -103
  76. tooluniverse/data/ppi_tools.json +139 -0
  77. tooluniverse/data/protein_structure_3d_tools.json +138 -0
  78. tooluniverse/data/pubchem_tools.json +37 -12
  79. tooluniverse/data/pubmed_tools.json +124 -58
  80. tooluniverse/data/pubtator_tools.json +68 -60
  81. tooluniverse/data/rcsb_pdb_tools.json +1532 -1221
  82. tooluniverse/data/semantic_scholar_tools.json +54 -22
  83. tooluniverse/data/special_tools.json +8 -6
  84. tooluniverse/data/tool_composition_tools.json +112 -82
  85. tooluniverse/data/unified_guideline_tools.json +909 -0
  86. tooluniverse/data/url_fetch_tools.json +102 -82
  87. tooluniverse/data/uspto_tools.json +49 -30
  88. tooluniverse/data/wikidata_sparql_tools.json +42 -39
  89. tooluniverse/data/xml_tools.json +3274 -3113
  90. tooluniverse/data/zenodo_tools.json +83 -76
  91. tooluniverse/dblp_tool.py +76 -6
  92. tooluniverse/dbsnp_tool.py +71 -0
  93. tooluniverse/default_config.py +19 -0
  94. tooluniverse/doaj_tool.py +76 -17
  95. tooluniverse/doctor.py +48 -0
  96. tooluniverse/ensembl_tool.py +61 -0
  97. tooluniverse/europe_pmc_tool.py +132 -17
  98. tooluniverse/exceptions.py +170 -0
  99. tooluniverse/execute_function.py +930 -387
  100. tooluniverse/fatcat_tool.py +0 -1
  101. tooluniverse/generate_tools.py +481 -0
  102. tooluniverse/genomics_gene_search_tool.py +56 -0
  103. tooluniverse/geo_tool.py +116 -0
  104. tooluniverse/gnomad_tool.py +63 -0
  105. tooluniverse/hal_tool.py +1 -1
  106. tooluniverse/llm_clients.py +101 -124
  107. tooluniverse/markitdown_tool.py +159 -0
  108. tooluniverse/mcp_client_tool.py +10 -5
  109. tooluniverse/mcp_tool_registry.py +4 -1
  110. tooluniverse/medrxiv_tool.py +32 -13
  111. tooluniverse/memory_manager.py +166 -0
  112. tooluniverse/molecule_2d_tool.py +274 -0
  113. tooluniverse/molecule_3d_tool.py +441 -0
  114. tooluniverse/odphp_tool.py +49 -14
  115. tooluniverse/openaire_tool.py +5 -20
  116. tooluniverse/openalex_tool.py +34 -0
  117. tooluniverse/osf_preprints_tool.py +1 -1
  118. tooluniverse/pmc_tool.py +54 -56
  119. tooluniverse/protein_structure_3d_tool.py +295 -0
  120. tooluniverse/pubmed_tool.py +69 -6
  121. tooluniverse/remote/boltz/boltz_mcp_server.py +3 -1
  122. tooluniverse/remote/uspto_downloader/uspto_downloader_mcp_server.py +3 -1
  123. tooluniverse/semantic_scholar_tool.py +40 -10
  124. tooluniverse/smcp.py +149 -213
  125. tooluniverse/smcp_server.py +97 -55
  126. tooluniverse/string_tool.py +112 -0
  127. tooluniverse/tool_registry.py +35 -3
  128. tooluniverse/tools/ADMETAI_predict_BBB_penetrance.py +46 -0
  129. tooluniverse/tools/ADMETAI_predict_CYP_interactions.py +46 -0
  130. tooluniverse/tools/ADMETAI_predict_bioavailability.py +46 -0
  131. tooluniverse/tools/ADMETAI_predict_clearance_distribution.py +49 -0
  132. tooluniverse/tools/ADMETAI_predict_nuclear_receptor_activity.py +49 -0
  133. tooluniverse/tools/ADMETAI_predict_physicochemical_properties.py +49 -0
  134. tooluniverse/tools/ADMETAI_predict_solubility_lipophilicity_hydration.py +49 -0
  135. tooluniverse/tools/ADMETAI_predict_stress_response.py +46 -0
  136. tooluniverse/tools/ADMETAI_predict_toxicity.py +46 -0
  137. tooluniverse/tools/ADMETAnalyzerAgent.py +59 -0
  138. tooluniverse/tools/AdvancedCodeQualityAnalyzer.py +63 -0
  139. tooluniverse/tools/AdverseEventICDMapper.py +46 -0
  140. tooluniverse/tools/AdverseEventPredictionQuestionGenerator.py +52 -0
  141. tooluniverse/tools/AdverseEventPredictionQuestionGeneratorWithContext.py +59 -0
  142. tooluniverse/tools/ArXiv_search_papers.py +63 -0
  143. tooluniverse/tools/ArgumentDescriptionOptimizer.py +55 -0
  144. tooluniverse/tools/BioRxiv_search_preprints.py +52 -0
  145. tooluniverse/tools/BiomarkerDiscoveryWorkflow.py +55 -0
  146. tooluniverse/tools/CMA_Guidelines_Search.py +52 -0
  147. tooluniverse/tools/CORE_search_papers.py +67 -0
  148. tooluniverse/tools/CallAgent.py +46 -0
  149. tooluniverse/tools/ChEMBL_search_similar_molecules.py +59 -0
  150. tooluniverse/tools/ClinVar_search_variants.py +52 -0
  151. tooluniverse/tools/ClinicalTrialDesignAgent.py +63 -0
  152. tooluniverse/tools/CodeOptimizer.py +55 -0
  153. tooluniverse/tools/CodeQualityAnalyzer.py +71 -0
  154. tooluniverse/tools/CompoundDiscoveryAgent.py +59 -0
  155. tooluniverse/tools/ComprehensiveDrugDiscoveryPipeline.py +49 -0
  156. tooluniverse/tools/Crossref_search_works.py +55 -0
  157. tooluniverse/tools/DBLP_search_publications.py +52 -0
  158. tooluniverse/tools/DOAJ_search_articles.py +55 -0
  159. tooluniverse/tools/DailyMed_get_spl_by_setid.py +52 -0
  160. tooluniverse/tools/DailyMed_search_spls.py +79 -0
  161. tooluniverse/tools/DataAnalysisValidityReviewer.py +49 -0
  162. tooluniverse/tools/DescriptionAnalyzer.py +55 -0
  163. tooluniverse/tools/DescriptionQualityEvaluator.py +59 -0
  164. tooluniverse/tools/DiseaseAnalyzerAgent.py +52 -0
  165. tooluniverse/tools/DomainExpertValidator.py +63 -0
  166. tooluniverse/tools/DrugInteractionAnalyzerAgent.py +52 -0
  167. tooluniverse/tools/DrugOptimizationAgent.py +63 -0
  168. tooluniverse/tools/DrugSafetyAnalyzer.py +59 -0
  169. tooluniverse/tools/Ensembl_lookup_gene_by_symbol.py +52 -0
  170. tooluniverse/tools/EthicalComplianceReviewer.py +49 -0
  171. tooluniverse/tools/EuropePMC_Guidelines_Search.py +52 -0
  172. tooluniverse/tools/EuropePMC_search_articles.py +52 -0
  173. tooluniverse/tools/ExperimentalDesignScorer.py +55 -0
  174. tooluniverse/tools/FAERS_count_additive_administration_routes.py +52 -0
  175. tooluniverse/tools/FAERS_count_additive_adverse_reactions.py +71 -0
  176. tooluniverse/tools/FAERS_count_additive_event_reports_by_country.py +63 -0
  177. tooluniverse/tools/FAERS_count_additive_reaction_outcomes.py +63 -0
  178. tooluniverse/tools/FAERS_count_additive_reports_by_reporter_country.py +63 -0
  179. tooluniverse/tools/FAERS_count_additive_seriousness_classification.py +63 -0
  180. tooluniverse/tools/FAERS_count_country_by_drug_event.py +63 -0
  181. tooluniverse/tools/FAERS_count_death_related_by_drug.py +49 -0
  182. tooluniverse/tools/FAERS_count_drug_routes_by_event.py +52 -0
  183. tooluniverse/tools/FAERS_count_drugs_by_drug_event.py +63 -0
  184. tooluniverse/tools/FAERS_count_outcomes_by_drug_event.py +63 -0
  185. tooluniverse/tools/FAERS_count_patient_age_distribution.py +49 -0
  186. tooluniverse/tools/FAERS_count_reactions_by_drug_event.py +71 -0
  187. tooluniverse/tools/FAERS_count_reportercountry_by_drug_event.py +63 -0
  188. tooluniverse/tools/FAERS_count_seriousness_by_drug_event.py +63 -0
  189. tooluniverse/tools/FDA_get_abuse_dependence_info_by_drug_name.py +55 -0
  190. tooluniverse/tools/FDA_get_abuse_info_by_drug_name.py +55 -0
  191. tooluniverse/tools/FDA_get_accessories_info_by_drug_name.py +55 -0
  192. tooluniverse/tools/FDA_get_active_ingredient_info_by_drug_name.py +55 -0
  193. tooluniverse/tools/FDA_get_adverse_reactions_by_drug_name.py +55 -0
  194. tooluniverse/tools/FDA_get_alarms_by_drug_name.py +55 -0
  195. tooluniverse/tools/FDA_get_animal_pharmacology_info_by_drug_name.py +55 -0
  196. tooluniverse/tools/FDA_get_assembly_installation_info_by_drug_name.py +55 -0
  197. tooluniverse/tools/FDA_get_boxed_warning_info_by_drug_name.py +55 -0
  198. tooluniverse/tools/FDA_get_brand_name_generic_name.py +52 -0
  199. tooluniverse/tools/FDA_get_calibration_instructions_by_drug_name.py +55 -0
  200. tooluniverse/tools/FDA_get_carcinogenic_mutagenic_fertility_by_drug_name.py +55 -0
  201. tooluniverse/tools/FDA_get_child_safety_info_by_drug_name.py +55 -0
  202. tooluniverse/tools/FDA_get_clinical_pharmacology_by_drug_name.py +55 -0
  203. tooluniverse/tools/FDA_get_clinical_studies_info_by_drug_name.py +55 -0
  204. tooluniverse/tools/FDA_get_contact_for_questions_info_by_drug_name.py +55 -0
  205. tooluniverse/tools/FDA_get_contraindications_by_drug_name.py +55 -0
  206. tooluniverse/tools/FDA_get_controlled_substance_DEA_schedule_info_by_drug_name.py +55 -0
  207. tooluniverse/tools/FDA_get_dear_health_care_provider_letter_info_by_drug_name.py +55 -0
  208. tooluniverse/tools/FDA_get_dependence_info_by_drug_name.py +55 -0
  209. tooluniverse/tools/FDA_get_disposal_info_by_drug_name.py +55 -0
  210. tooluniverse/tools/FDA_get_do_not_use_info_by_drug_name.py +55 -0
  211. tooluniverse/tools/FDA_get_document_id_by_drug_name.py +55 -0
  212. tooluniverse/tools/FDA_get_dosage_and_storage_information_by_drug_name.py +55 -0
  213. tooluniverse/tools/FDA_get_dosage_forms_and_strengths_by_drug_name.py +55 -0
  214. tooluniverse/tools/FDA_get_drug_generic_name.py +46 -0
  215. tooluniverse/tools/FDA_get_drug_interactions_by_drug_name.py +55 -0
  216. tooluniverse/tools/FDA_get_drug_name_by_SPL_ID.py +55 -0
  217. tooluniverse/tools/FDA_get_drug_name_by_adverse_reaction.py +59 -0
  218. tooluniverse/tools/FDA_get_drug_name_by_calibration_instructions.py +59 -0
  219. tooluniverse/tools/FDA_get_drug_name_by_dependence_info.py +59 -0
  220. tooluniverse/tools/FDA_get_drug_name_by_document_id.py +55 -0
  221. tooluniverse/tools/FDA_get_drug_name_by_dosage_info.py +55 -0
  222. tooluniverse/tools/FDA_get_drug_name_by_environmental_warning.py +59 -0
  223. tooluniverse/tools/FDA_get_drug_name_by_inactive_ingredient.py +59 -0
  224. tooluniverse/tools/FDA_get_drug_name_by_info_on_conditions_for_doctor_consultation.py +55 -0
  225. tooluniverse/tools/FDA_get_drug_name_by_labor_and_delivery_info.py +59 -0
  226. tooluniverse/tools/FDA_get_drug_name_by_microbiology.py +59 -0
  227. tooluniverse/tools/FDA_get_drug_name_by_other_safety_info.py +55 -0
  228. tooluniverse/tools/FDA_get_drug_name_by_pharmacodynamics.py +59 -0
  229. tooluniverse/tools/FDA_get_drug_name_by_pharmacogenomics.py +59 -0
  230. tooluniverse/tools/FDA_get_drug_name_by_precautions.py +55 -0
  231. tooluniverse/tools/FDA_get_drug_name_by_pregnancy_or_breastfeeding_info.py +59 -0
  232. tooluniverse/tools/FDA_get_drug_name_by_principal_display_panel.py +59 -0
  233. tooluniverse/tools/FDA_get_drug_name_by_reference.py +55 -0
  234. tooluniverse/tools/FDA_get_drug_name_by_set_id.py +55 -0
  235. tooluniverse/tools/FDA_get_drug_name_by_stop_use_info.py +55 -0
  236. tooluniverse/tools/FDA_get_drug_name_by_storage_and_handling_info.py +55 -0
  237. tooluniverse/tools/FDA_get_drug_name_by_warnings.py +55 -0
  238. tooluniverse/tools/FDA_get_drug_name_from_patient_package_insert.py +59 -0
  239. tooluniverse/tools/FDA_get_drug_names_by_abuse_dependence_info.py +55 -0
  240. tooluniverse/tools/FDA_get_drug_names_by_abuse_info.py +63 -0
  241. tooluniverse/tools/FDA_get_drug_names_by_accessories.py +63 -0
  242. tooluniverse/tools/FDA_get_drug_names_by_active_ingredient.py +63 -0
  243. tooluniverse/tools/FDA_get_drug_names_by_alarm.py +63 -0
  244. tooluniverse/tools/FDA_get_drug_names_by_animal_pharmacology_info.py +63 -0
  245. tooluniverse/tools/FDA_get_drug_names_by_application_number_NDC_number.py +59 -0
  246. tooluniverse/tools/FDA_get_drug_names_by_assembly_installation_info.py +63 -0
  247. tooluniverse/tools/FDA_get_drug_names_by_boxed_warning.py +63 -0
  248. tooluniverse/tools/FDA_get_drug_names_by_child_safety_info.py +63 -0
  249. tooluniverse/tools/FDA_get_drug_names_by_clinical_pharmacology.py +63 -0
  250. tooluniverse/tools/FDA_get_drug_names_by_clinical_studies.py +63 -0
  251. tooluniverse/tools/FDA_get_drug_names_by_consulting_doctor_pharmacist_info.py +63 -0
  252. tooluniverse/tools/FDA_get_drug_names_by_contraindications.py +63 -0
  253. tooluniverse/tools/FDA_get_drug_names_by_controlled_substance_DEA_schedule.py +63 -0
  254. tooluniverse/tools/FDA_get_drug_names_by_dear_health_care_provider_letter_info.py +63 -0
  255. tooluniverse/tools/FDA_get_drug_names_by_disposal_info.py +63 -0
  256. tooluniverse/tools/FDA_get_drug_names_by_dosage_forms_and_strengths_info.py +63 -0
  257. tooluniverse/tools/FDA_get_drug_names_by_drug_interactions.py +63 -0
  258. tooluniverse/tools/FDA_get_drug_names_by_effective_time.py +63 -0
  259. tooluniverse/tools/FDA_get_drug_names_by_food_safety_warnings.py +63 -0
  260. tooluniverse/tools/FDA_get_drug_names_by_general_precautions.py +63 -0
  261. tooluniverse/tools/FDA_get_drug_names_by_geriatric_use.py +63 -0
  262. tooluniverse/tools/FDA_get_drug_names_by_health_claim.py +63 -0
  263. tooluniverse/tools/FDA_get_drug_names_by_indication.py +55 -0
  264. tooluniverse/tools/FDA_get_drug_names_by_info_for_nursing_mothers.py +63 -0
  265. tooluniverse/tools/FDA_get_drug_names_by_information_for_owners_or_caregivers.py +63 -0
  266. tooluniverse/tools/FDA_get_drug_names_by_ingredient.py +63 -0
  267. tooluniverse/tools/FDA_get_drug_names_by_instructions_for_use.py +63 -0
  268. tooluniverse/tools/FDA_get_drug_names_by_lab_test_interference.py +63 -0
  269. tooluniverse/tools/FDA_get_drug_names_by_lab_tests.py +63 -0
  270. tooluniverse/tools/FDA_get_drug_names_by_mechanism_of_action.py +63 -0
  271. tooluniverse/tools/FDA_get_drug_names_by_medication_guide.py +63 -0
  272. tooluniverse/tools/FDA_get_drug_names_by_nonclinical_toxicology_info.py +63 -0
  273. tooluniverse/tools/FDA_get_drug_names_by_nonteratogenic_effects.py +63 -0
  274. tooluniverse/tools/FDA_get_drug_names_by_overdosage_info.py +63 -0
  275. tooluniverse/tools/FDA_get_drug_names_by_pediatric_use.py +63 -0
  276. tooluniverse/tools/FDA_get_drug_names_by_pharmacokinetics.py +63 -0
  277. tooluniverse/tools/FDA_get_drug_names_by_population_use.py +63 -0
  278. tooluniverse/tools/FDA_get_drug_names_by_pregnancy_effects_info.py +63 -0
  279. tooluniverse/tools/FDA_get_drug_names_by_residue_warning.py +63 -0
  280. tooluniverse/tools/FDA_get_drug_names_by_risk.py +63 -0
  281. tooluniverse/tools/FDA_get_drug_names_by_route.py +63 -0
  282. tooluniverse/tools/FDA_get_drug_names_by_safe_handling_warning.py +63 -0
  283. tooluniverse/tools/FDA_get_drug_names_by_safety_summary.py +63 -0
  284. tooluniverse/tools/FDA_get_drug_names_by_spl_indexing_data_elements.py +63 -0
  285. tooluniverse/tools/FDA_get_drug_names_by_teratogenic_effects.py +63 -0
  286. tooluniverse/tools/FDA_get_drug_names_by_user_safety_warning.py +63 -0
  287. tooluniverse/tools/FDA_get_drug_names_by_warnings_and_cautions.py +63 -0
  288. tooluniverse/tools/FDA_get_drugs_by_carcinogenic_mutagenic_fertility.py +63 -0
  289. tooluniverse/tools/FDA_get_effective_time_by_drug_name.py +55 -0
  290. tooluniverse/tools/FDA_get_environmental_warning_by_drug_name.py +55 -0
  291. tooluniverse/tools/FDA_get_general_precautions_by_drug_name.py +55 -0
  292. tooluniverse/tools/FDA_get_geriatric_use_info_by_drug_name.py +55 -0
  293. tooluniverse/tools/FDA_get_health_claims_by_drug_name.py +55 -0
  294. tooluniverse/tools/FDA_get_inactive_ingredient_info_by_drug_name.py +55 -0
  295. tooluniverse/tools/FDA_get_indications_by_drug_name.py +55 -0
  296. tooluniverse/tools/FDA_get_info_for_nursing_mothers_by_drug_name.py +55 -0
  297. tooluniverse/tools/FDA_get_info_for_patients_by_drug_name.py +55 -0
  298. tooluniverse/tools/FDA_get_info_on_conditions_for_doctor_consultation_by_drug_name.py +55 -0
  299. tooluniverse/tools/FDA_get_info_on_consulting_doctor_pharmacist_by_drug_name.py +55 -0
  300. tooluniverse/tools/FDA_get_information_for_owners_or_caregivers_by_drug_name.py +55 -0
  301. tooluniverse/tools/FDA_get_ingredients_by_drug_name.py +55 -0
  302. tooluniverse/tools/FDA_get_instructions_for_use_by_drug_name.py +55 -0
  303. tooluniverse/tools/FDA_get_lab_test_interference_info_by_drug_name.py +55 -0
  304. tooluniverse/tools/FDA_get_lab_tests_by_drug_name.py +55 -0
  305. tooluniverse/tools/FDA_get_labor_and_delivery_info_by_drug_name.py +55 -0
  306. tooluniverse/tools/FDA_get_manufacturer_name_NDC_number_by_drug_name.py +55 -0
  307. tooluniverse/tools/FDA_get_mechanism_of_action_by_drug_name.py +55 -0
  308. tooluniverse/tools/FDA_get_medication_guide_info_by_drug_name.py +55 -0
  309. tooluniverse/tools/FDA_get_microbiology_info_by_drug_name.py +55 -0
  310. tooluniverse/tools/FDA_get_nonclinical_toxicology_info_by_drug_name.py +55 -0
  311. tooluniverse/tools/FDA_get_nonteratogenic_effects_by_drug_name.py +55 -0
  312. tooluniverse/tools/FDA_get_other_safety_info_by_drug_name.py +55 -0
  313. tooluniverse/tools/FDA_get_overdosage_info_by_drug_name.py +55 -0
  314. tooluniverse/tools/FDA_get_patient_package_insert_from_drug_name.py +55 -0
  315. tooluniverse/tools/FDA_get_pediatric_use_info_by_drug_name.py +55 -0
  316. tooluniverse/tools/FDA_get_pharmacodynamics_by_drug_name.py +55 -0
  317. tooluniverse/tools/FDA_get_pharmacogenomics_info_by_drug_name.py +55 -0
  318. tooluniverse/tools/FDA_get_pharmacokinetics_by_drug_name.py +55 -0
  319. tooluniverse/tools/FDA_get_population_use_info_by_drug_name.py +55 -0
  320. tooluniverse/tools/FDA_get_precautions_by_drug_name.py +55 -0
  321. tooluniverse/tools/FDA_get_pregnancy_effects_info_by_drug_name.py +55 -0
  322. tooluniverse/tools/FDA_get_pregnancy_or_breastfeeding_info_by_drug_name.py +55 -0
  323. tooluniverse/tools/FDA_get_principal_display_panel_by_drug_name.py +55 -0
  324. tooluniverse/tools/FDA_get_purpose_info_by_drug_name.py +55 -0
  325. tooluniverse/tools/FDA_get_recent_changes_by_drug_name.py +55 -0
  326. tooluniverse/tools/FDA_get_reference_info_by_drug_name.py +55 -0
  327. tooluniverse/tools/FDA_get_residue_warning_by_drug_name.py +55 -0
  328. tooluniverse/tools/FDA_get_risk_info_by_drug_name.py +55 -0
  329. tooluniverse/tools/FDA_get_route_info_by_drug_name.py +55 -0
  330. tooluniverse/tools/FDA_get_safe_handling_warnings_by_drug_name.py +55 -0
  331. tooluniverse/tools/FDA_get_safety_summary_by_drug_name.py +55 -0
  332. tooluniverse/tools/FDA_get_spl_indexing_data_elements_by_drug_name.py +55 -0
  333. tooluniverse/tools/FDA_get_spl_unclassified_section_by_drug_name.py +55 -0
  334. tooluniverse/tools/FDA_get_stop_use_info_by_drug_name.py +55 -0
  335. tooluniverse/tools/FDA_get_storage_and_handling_info_by_drug_name.py +55 -0
  336. tooluniverse/tools/FDA_get_teratogenic_effects_by_drug_name.py +55 -0
  337. tooluniverse/tools/FDA_get_user_safety_warning_by_drug_names.py +55 -0
  338. tooluniverse/tools/FDA_get_warnings_and_cautions_by_drug_name.py +55 -0
  339. tooluniverse/tools/FDA_get_warnings_by_drug_name.py +55 -0
  340. tooluniverse/tools/FDA_get_when_using_info.py +55 -0
  341. tooluniverse/tools/FDA_retrieve_device_use_by_drug_name.py +55 -0
  342. tooluniverse/tools/FDA_retrieve_drug_name_by_device_use.py +59 -0
  343. tooluniverse/tools/FDA_retrieve_drug_names_by_patient_medication_info.py +55 -0
  344. tooluniverse/tools/FDA_retrieve_patient_medication_info_by_drug_name.py +55 -0
  345. tooluniverse/tools/Fatcat_search_scholar.py +52 -0
  346. tooluniverse/tools/Finish.py +44 -0
  347. tooluniverse/tools/GIN_Guidelines_Search.py +52 -0
  348. tooluniverse/tools/GO_get_annotations_for_gene.py +46 -0
  349. tooluniverse/tools/GO_get_genes_for_term.py +55 -0
  350. tooluniverse/tools/GO_get_term_by_id.py +46 -0
  351. tooluniverse/tools/GO_get_term_details.py +46 -0
  352. tooluniverse/tools/GO_search_terms.py +46 -0
  353. tooluniverse/tools/GWAS_search_associations_by_gene.py +52 -0
  354. tooluniverse/tools/HAL_search_archive.py +52 -0
  355. tooluniverse/tools/HPA_get_biological_processes_by_gene.py +52 -0
  356. tooluniverse/tools/HPA_get_cancer_prognostics_by_gene.py +49 -0
  357. tooluniverse/tools/HPA_get_comparative_expression_by_gene_and_cellline.py +52 -0
  358. tooluniverse/tools/HPA_get_comprehensive_gene_details_by_ensembl_id.py +63 -0
  359. tooluniverse/tools/HPA_get_contextual_biological_process_analysis.py +52 -0
  360. tooluniverse/tools/HPA_get_disease_expression_by_gene_tissue_disease.py +59 -0
  361. tooluniverse/tools/HPA_get_gene_basic_info_by_ensembl_id.py +49 -0
  362. tooluniverse/tools/HPA_get_gene_tsv_data_by_ensembl_id.py +49 -0
  363. tooluniverse/tools/HPA_get_protein_interactions_by_gene.py +49 -0
  364. tooluniverse/tools/HPA_get_rna_expression_by_source.py +59 -0
  365. tooluniverse/tools/HPA_get_rna_expression_in_specific_tissues.py +52 -0
  366. tooluniverse/tools/HPA_get_subcellular_location.py +46 -0
  367. tooluniverse/tools/HPA_search_genes_by_query.py +49 -0
  368. tooluniverse/tools/HypothesisGenerator.py +63 -0
  369. tooluniverse/tools/LabelGenerator.py +67 -0
  370. tooluniverse/tools/LiteratureContextReviewer.py +55 -0
  371. tooluniverse/tools/LiteratureSearchTool.py +49 -0
  372. tooluniverse/tools/LiteratureSynthesisAgent.py +59 -0
  373. tooluniverse/tools/MedRxiv_search_preprints.py +52 -0
  374. tooluniverse/tools/MedicalLiteratureReviewer.py +71 -0
  375. tooluniverse/tools/MedicalTermNormalizer.py +46 -0
  376. tooluniverse/tools/MedlinePlus_connect_lookup_by_code.py +67 -0
  377. tooluniverse/tools/MedlinePlus_get_genetics_condition_by_name.py +52 -0
  378. tooluniverse/tools/MedlinePlus_get_genetics_gene_by_name.py +52 -0
  379. tooluniverse/tools/MedlinePlus_get_genetics_index.py +44 -0
  380. tooluniverse/tools/MedlinePlus_search_topics_by_keyword.py +55 -0
  381. tooluniverse/tools/MethodologyRigorReviewer.py +49 -0
  382. tooluniverse/tools/MultiAgentLiteratureSearch.py +59 -0
  383. tooluniverse/tools/NICE_Clinical_Guidelines_Search.py +52 -0
  384. tooluniverse/tools/NICE_Guideline_Full_Text.py +46 -0
  385. tooluniverse/tools/NoveltySignificanceReviewer.py +59 -0
  386. tooluniverse/tools/OSF_search_preprints.py +59 -0
  387. tooluniverse/tools/OSL_get_efo_id_by_disease_name.py +46 -0
  388. tooluniverse/tools/OpenAIRE_search_publications.py +55 -0
  389. tooluniverse/tools/OpenAlex_Guidelines_Search.py +63 -0
  390. tooluniverse/tools/OpenTargets_drug_pharmacogenomics_data.py +52 -0
  391. tooluniverse/tools/OpenTargets_get_approved_indications_by_drug_chemblId.py +49 -0
  392. tooluniverse/tools/OpenTargets_get_associated_diseases_by_drug_chemblId.py +49 -0
  393. tooluniverse/tools/OpenTargets_get_associated_drugs_by_disease_efoId.py +52 -0
  394. tooluniverse/tools/OpenTargets_get_associated_drugs_by_target_ensemblID.py +55 -0
  395. tooluniverse/tools/OpenTargets_get_associated_phenotypes_by_disease_efoId.py +49 -0
  396. tooluniverse/tools/OpenTargets_get_associated_targets_by_disease_efoId.py +49 -0
  397. tooluniverse/tools/OpenTargets_get_associated_targets_by_drug_chemblId.py +49 -0
  398. tooluniverse/tools/OpenTargets_get_biological_mouse_models_by_ensemblID.py +49 -0
  399. tooluniverse/tools/OpenTargets_get_chemical_probes_by_target_ensemblID.py +49 -0
  400. tooluniverse/tools/OpenTargets_get_disease_ancestors_parents_by_efoId.py +49 -0
  401. tooluniverse/tools/OpenTargets_get_disease_descendants_children_by_efoId.py +49 -0
  402. tooluniverse/tools/OpenTargets_get_disease_description_by_efoId.py +49 -0
  403. tooluniverse/tools/OpenTargets_get_disease_id_description_by_name.py +49 -0
  404. tooluniverse/tools/OpenTargets_get_disease_ids_by_efoId.py +46 -0
  405. tooluniverse/tools/OpenTargets_get_disease_ids_by_name.py +46 -0
  406. tooluniverse/tools/OpenTargets_get_disease_locations_by_efoId.py +49 -0
  407. tooluniverse/tools/OpenTargets_get_disease_synonyms_by_efoId.py +49 -0
  408. tooluniverse/tools/OpenTargets_get_disease_therapeutic_areas_by_efoId.py +49 -0
  409. tooluniverse/tools/OpenTargets_get_diseases_phenotypes_by_target_ensembl.py +49 -0
  410. tooluniverse/tools/OpenTargets_get_drug_adverse_events_by_chemblId.py +52 -0
  411. tooluniverse/tools/OpenTargets_get_drug_approval_status_by_chemblId.py +49 -0
  412. tooluniverse/tools/OpenTargets_get_drug_chembId_by_generic_name.py +49 -0
  413. tooluniverse/tools/OpenTargets_get_drug_description_by_chemblId.py +49 -0
  414. tooluniverse/tools/OpenTargets_get_drug_id_description_by_name.py +49 -0
  415. tooluniverse/tools/OpenTargets_get_drug_indications_by_chemblId.py +49 -0
  416. tooluniverse/tools/OpenTargets_get_drug_mechanisms_of_action_by_chemblId.py +49 -0
  417. tooluniverse/tools/OpenTargets_get_drug_synonyms_by_chemblId.py +49 -0
  418. tooluniverse/tools/OpenTargets_get_drug_trade_names_by_chemblId.py +49 -0
  419. tooluniverse/tools/OpenTargets_get_drug_warnings_by_chemblId.py +49 -0
  420. tooluniverse/tools/OpenTargets_get_drug_withdrawn_blackbox_status_by_chemblId.py +49 -0
  421. tooluniverse/tools/OpenTargets_get_gene_ontology_terms_by_goID.py +49 -0
  422. tooluniverse/tools/OpenTargets_get_known_drugs_by_drug_chemblId.py +49 -0
  423. tooluniverse/tools/OpenTargets_get_parent_child_molecules_by_drug_chembl_ID.py +49 -0
  424. tooluniverse/tools/OpenTargets_get_publications_by_disease_efoId.py +71 -0
  425. tooluniverse/tools/OpenTargets_get_publications_by_drug_chemblId.py +71 -0
  426. tooluniverse/tools/OpenTargets_get_publications_by_target_ensemblID.py +71 -0
  427. tooluniverse/tools/OpenTargets_get_similar_entities_by_disease_efoId.py +55 -0
  428. tooluniverse/tools/OpenTargets_get_similar_entities_by_drug_chemblId.py +55 -0
  429. tooluniverse/tools/OpenTargets_get_similar_entities_by_target_ensemblID.py +55 -0
  430. tooluniverse/tools/OpenTargets_get_target_classes_by_ensemblID.py +49 -0
  431. tooluniverse/tools/OpenTargets_get_target_constraint_info_by_ensemblID.py +49 -0
  432. tooluniverse/tools/OpenTargets_get_target_enabling_packages_by_ensemblID.py +49 -0
  433. tooluniverse/tools/OpenTargets_get_target_gene_ontology_by_ensemblID.py +49 -0
  434. tooluniverse/tools/OpenTargets_get_target_genomic_location_by_ensemblID.py +49 -0
  435. tooluniverse/tools/OpenTargets_get_target_homologues_by_ensemblID.py +49 -0
  436. tooluniverse/tools/OpenTargets_get_target_id_description_by_name.py +49 -0
  437. tooluniverse/tools/OpenTargets_get_target_interactions_by_ensemblID.py +52 -0
  438. tooluniverse/tools/OpenTargets_get_target_safety_profile_by_ensemblID.py +49 -0
  439. tooluniverse/tools/OpenTargets_get_target_subcellular_locations_by_ensemblID.py +49 -0
  440. tooluniverse/tools/OpenTargets_get_target_synonyms_by_ensemblID.py +49 -0
  441. tooluniverse/tools/OpenTargets_get_target_tractability_by_ensemblID.py +49 -0
  442. tooluniverse/tools/OpenTargets_map_any_disease_id_to_all_other_ids.py +49 -0
  443. tooluniverse/tools/OpenTargets_multi_entity_search_by_query_string.py +59 -0
  444. tooluniverse/tools/OpenTargets_search_category_counts_by_query_string.py +49 -0
  445. tooluniverse/tools/OpenTargets_target_disease_evidence.py +52 -0
  446. tooluniverse/tools/OutputSummarizationComposer.py +71 -0
  447. tooluniverse/tools/PMC_search_papers.py +67 -0
  448. tooluniverse/tools/ProtocolOptimizer.py +49 -0
  449. tooluniverse/tools/PubChem_get_CID_by_SMILES.py +46 -0
  450. tooluniverse/tools/PubChem_get_CID_by_compound_name.py +46 -0
  451. tooluniverse/tools/PubChem_get_associated_patents_by_CID.py +46 -0
  452. tooluniverse/tools/PubChem_get_compound_2D_image_by_CID.py +52 -0
  453. tooluniverse/tools/PubChem_get_compound_properties_by_CID.py +46 -0
  454. tooluniverse/tools/PubChem_get_compound_synonyms_by_CID.py +46 -0
  455. tooluniverse/tools/PubChem_get_compound_xrefs_by_CID.py +52 -0
  456. tooluniverse/tools/PubChem_search_compounds_by_similarity.py +52 -0
  457. tooluniverse/tools/PubChem_search_compounds_by_substructure.py +49 -0
  458. tooluniverse/tools/PubMed_Guidelines_Search.py +55 -0
  459. tooluniverse/tools/PubMed_search_articles.py +55 -0
  460. tooluniverse/tools/PubTator3_EntityAutocomplete.py +59 -0
  461. tooluniverse/tools/PubTator3_LiteratureSearch.py +55 -0
  462. tooluniverse/tools/QuestionRephraser.py +52 -0
  463. tooluniverse/tools/Reactome_get_pathway_reactions.py +46 -0
  464. tooluniverse/tools/ReproducibilityTransparencyReviewer.py +49 -0
  465. tooluniverse/tools/ResultsInterpretationReviewer.py +55 -0
  466. tooluniverse/tools/ScientificTextSummarizer.py +59 -0
  467. tooluniverse/tools/SemanticScholar_search_papers.py +55 -0
  468. tooluniverse/tools/TRIP_Database_Guidelines_Search.py +55 -0
  469. tooluniverse/tools/TestCaseGenerator.py +46 -0
  470. tooluniverse/tools/ToolCompatibilityAnalyzer.py +59 -0
  471. tooluniverse/tools/ToolDescriptionOptimizer.py +67 -0
  472. tooluniverse/tools/ToolDiscover.py +63 -0
  473. tooluniverse/tools/ToolGraphComposer.py +71 -0
  474. tooluniverse/tools/ToolGraphGenerationPipeline.py +63 -0
  475. tooluniverse/tools/ToolImplementationGenerator.py +67 -0
  476. tooluniverse/tools/ToolMetadataGenerationPipeline.py +63 -0
  477. tooluniverse/tools/ToolMetadataGenerator.py +55 -0
  478. tooluniverse/tools/ToolMetadataStandardizer.py +52 -0
  479. tooluniverse/tools/ToolOptimizer.py +59 -0
  480. tooluniverse/tools/ToolOutputSummarizer.py +67 -0
  481. tooluniverse/tools/ToolQualityEvaluator.py +59 -0
  482. tooluniverse/tools/ToolRelationshipDetector.py +52 -0
  483. tooluniverse/tools/ToolSpecificationGenerator.py +67 -0
  484. tooluniverse/tools/ToolSpecificationOptimizer.py +63 -0
  485. tooluniverse/tools/Tool_Finder.py +67 -0
  486. tooluniverse/tools/Tool_Finder_Keyword.py +67 -0
  487. tooluniverse/tools/Tool_Finder_LLM.py +67 -0
  488. tooluniverse/tools/Tool_RAG.py +49 -0
  489. tooluniverse/tools/UCSC_get_genes_by_region.py +67 -0
  490. tooluniverse/tools/UniProt_get_alternative_names_by_accession.py +49 -0
  491. tooluniverse/tools/UniProt_get_disease_variants_by_accession.py +49 -0
  492. tooluniverse/tools/UniProt_get_entry_by_accession.py +49 -0
  493. tooluniverse/tools/UniProt_get_function_by_accession.py +49 -0
  494. tooluniverse/tools/UniProt_get_isoform_ids_by_accession.py +49 -0
  495. tooluniverse/tools/UniProt_get_organism_by_accession.py +49 -0
  496. tooluniverse/tools/UniProt_get_ptm_processing_by_accession.py +49 -0
  497. tooluniverse/tools/UniProt_get_recommended_name_by_accession.py +49 -0
  498. tooluniverse/tools/UniProt_get_sequence_by_accession.py +49 -0
  499. tooluniverse/tools/UniProt_get_subcellular_location_by_accession.py +49 -0
  500. tooluniverse/tools/Unpaywall_check_oa_status.py +52 -0
  501. tooluniverse/tools/WHO_Guideline_Full_Text.py +46 -0
  502. tooluniverse/tools/WHO_Guidelines_Search.py +52 -0
  503. tooluniverse/tools/Wikidata_SPARQL_query.py +52 -0
  504. tooluniverse/tools/WritingPresentationReviewer.py +49 -0
  505. tooluniverse/tools/Zenodo_search_records.py +59 -0
  506. tooluniverse/tools/__init__.py +1770 -0
  507. tooluniverse/tools/_shared_client.py +138 -0
  508. tooluniverse/tools/alphafold_get_annotations.py +52 -0
  509. tooluniverse/tools/alphafold_get_prediction.py +55 -0
  510. tooluniverse/tools/alphafold_get_summary.py +46 -0
  511. tooluniverse/tools/call_agentic_human.py +46 -0
  512. tooluniverse/tools/cancer_biomarkers_disease_target_score.py +52 -0
  513. tooluniverse/tools/cancer_gene_census_disease_target_score.py +52 -0
  514. tooluniverse/tools/cellosaurus_get_cell_line_info.py +55 -0
  515. tooluniverse/tools/cellosaurus_query_converter.py +52 -0
  516. tooluniverse/tools/cellosaurus_search_cell_lines.py +55 -0
  517. tooluniverse/tools/chembl_disease_target_score.py +52 -0
  518. tooluniverse/tools/convert_to_markdown.py +59 -0
  519. tooluniverse/tools/dbSNP_get_variant_by_rsid.py +46 -0
  520. tooluniverse/tools/dict_search.py +67 -0
  521. tooluniverse/tools/dili_search.py +67 -0
  522. tooluniverse/tools/diqt_search.py +67 -0
  523. tooluniverse/tools/disease_target_score.py +59 -0
  524. tooluniverse/tools/drugbank_filter_drugs_by_name.py +55 -0
  525. tooluniverse/tools/drugbank_full_search.py +67 -0
  526. tooluniverse/tools/drugbank_get_drug_basic_info_by_drug_name_or_drugbank_id.py +63 -0
  527. tooluniverse/tools/drugbank_get_drug_chemistry_by_drug_name_or_drugbank_id.py +63 -0
  528. tooluniverse/tools/drugbank_get_drug_interactions_by_drug_name_or_drugbank_id.py +63 -0
  529. tooluniverse/tools/drugbank_get_drug_name_and_description_by_indication.py +63 -0
  530. tooluniverse/tools/drugbank_get_drug_name_and_description_by_pathway_name.py +63 -0
  531. tooluniverse/tools/drugbank_get_drug_name_and_description_by_target_name.py +63 -0
  532. tooluniverse/tools/drugbank_get_drug_name_description_pharmacology_by_mechanism_of_action.py +63 -0
  533. tooluniverse/tools/drugbank_get_drug_pathways_and_reactions_by_drug_name_or_drugbank_id.py +63 -0
  534. tooluniverse/tools/drugbank_get_drug_products_by_name_or_drugbank_id.py +63 -0
  535. tooluniverse/tools/drugbank_get_drug_references_by_drug_name_or_drugbank_id.py +63 -0
  536. tooluniverse/tools/drugbank_get_indications_by_drug_name_or_drugbank_id.py +63 -0
  537. tooluniverse/tools/drugbank_get_pharmacology_by_drug_name_or_drugbank_id.py +63 -0
  538. tooluniverse/tools/drugbank_get_safety_by_drug_name_or_drugbank_id.py +63 -0
  539. tooluniverse/tools/drugbank_get_targets_by_drug_name_or_drugbank_id.py +63 -0
  540. tooluniverse/tools/drugbank_links_search.py +67 -0
  541. tooluniverse/tools/drugbank_vocab_filter.py +63 -0
  542. tooluniverse/tools/drugbank_vocab_search.py +67 -0
  543. tooluniverse/tools/embedding_database_add.py +63 -0
  544. tooluniverse/tools/embedding_database_create.py +71 -0
  545. tooluniverse/tools/embedding_database_load.py +63 -0
  546. tooluniverse/tools/embedding_database_search.py +67 -0
  547. tooluniverse/tools/embedding_sync_download.py +63 -0
  548. tooluniverse/tools/embedding_sync_upload.py +71 -0
  549. tooluniverse/tools/enrichr_gene_enrichment_analysis.py +52 -0
  550. tooluniverse/tools/europepmc_disease_target_score.py +52 -0
  551. tooluniverse/tools/eva_disease_target_score.py +52 -0
  552. tooluniverse/tools/eva_somatic_disease_target_score.py +52 -0
  553. tooluniverse/tools/expression_atlas_disease_target_score.py +52 -0
  554. tooluniverse/tools/extract_clinical_trial_adverse_events.py +59 -0
  555. tooluniverse/tools/extract_clinical_trial_outcomes.py +52 -0
  556. tooluniverse/tools/genomics_england_disease_target_score.py +52 -0
  557. tooluniverse/tools/get_HPO_ID_by_phenotype.py +55 -0
  558. tooluniverse/tools/get_albumentations_info.py +44 -0
  559. tooluniverse/tools/get_altair_info.py +44 -0
  560. tooluniverse/tools/get_anndata_info.py +49 -0
  561. tooluniverse/tools/get_arboreto_info.py +46 -0
  562. tooluniverse/tools/get_arxiv_info.py +46 -0
  563. tooluniverse/tools/get_ase_info.py +46 -0
  564. tooluniverse/tools/get_assembly_info_by_pdb_id.py +46 -0
  565. tooluniverse/tools/get_assembly_summary.py +46 -0
  566. tooluniverse/tools/get_astropy_info.py +44 -0
  567. tooluniverse/tools/get_binding_affinity_by_pdb_id.py +46 -0
  568. tooluniverse/tools/get_biopandas_info.py +49 -0
  569. tooluniverse/tools/get_biopython_info.py +49 -0
  570. tooluniverse/tools/get_bioservices_info.py +44 -0
  571. tooluniverse/tools/get_biotite_info.py +49 -0
  572. tooluniverse/tools/get_bokeh_info.py +44 -0
  573. tooluniverse/tools/get_brian2_info.py +44 -0
  574. tooluniverse/tools/get_cartopy_info.py +44 -0
  575. tooluniverse/tools/get_catboost_info.py +44 -0
  576. tooluniverse/tools/get_cellpose_info.py +49 -0
  577. tooluniverse/tools/get_cellrank_info.py +44 -0
  578. tooluniverse/tools/get_cellxgene_census_info.py +46 -0
  579. tooluniverse/tools/get_cftime_info.py +44 -0
  580. tooluniverse/tools/get_chem_comp_audit_info.py +46 -0
  581. tooluniverse/tools/get_chem_comp_charge_and_ambiguity.py +46 -0
  582. tooluniverse/tools/get_chembl_webresource_client_info.py +44 -0
  583. tooluniverse/tools/get_citation_info_by_pdb_id.py +46 -0
  584. tooluniverse/tools/get_clair3_info.py +46 -0
  585. tooluniverse/tools/get_clinical_trial_conditions_and_interventions.py +55 -0
  586. tooluniverse/tools/get_clinical_trial_descriptions.py +52 -0
  587. tooluniverse/tools/get_clinical_trial_eligibility_criteria.py +55 -0
  588. tooluniverse/tools/get_clinical_trial_locations.py +52 -0
  589. tooluniverse/tools/get_clinical_trial_outcome_measures.py +52 -0
  590. tooluniverse/tools/get_clinical_trial_references.py +52 -0
  591. tooluniverse/tools/get_clinical_trial_status_and_dates.py +52 -0
  592. tooluniverse/tools/get_cobra_info.py +46 -0
  593. tooluniverse/tools/get_cobrapy_info.py +46 -0
  594. tooluniverse/tools/get_cooler_info.py +49 -0
  595. tooluniverse/tools/get_core_refinement_statistics.py +46 -0
  596. tooluniverse/tools/get_cryosparc_tools_info.py +46 -0
  597. tooluniverse/tools/get_crystal_growth_conditions_by_pdb_id.py +49 -0
  598. tooluniverse/tools/get_crystallization_ph_by_pdb_id.py +46 -0
  599. tooluniverse/tools/get_crystallographic_properties_by_pdb_id.py +49 -0
  600. tooluniverse/tools/get_cupy_info.py +44 -0
  601. tooluniverse/tools/get_cyvcf2_info.py +49 -0
  602. tooluniverse/tools/get_dask_info.py +44 -0
  603. tooluniverse/tools/get_datamol_info.py +44 -0
  604. tooluniverse/tools/get_datashader_info.py +44 -0
  605. tooluniverse/tools/get_deepchem_info.py +49 -0
  606. tooluniverse/tools/get_deeppurpose_info.py +46 -0
  607. tooluniverse/tools/get_deeptools_info.py +46 -0
  608. tooluniverse/tools/get_deepxde_info.py +49 -0
  609. tooluniverse/tools/get_dendropy_info.py +44 -0
  610. tooluniverse/tools/get_descriptastorus_info.py +46 -0
  611. tooluniverse/tools/get_diffdock_info.py +46 -0
  612. tooluniverse/tools/get_dscribe_info.py +49 -0
  613. tooluniverse/tools/get_ec_number_by_entity_id.py +46 -0
  614. tooluniverse/tools/get_elephant_info.py +44 -0
  615. tooluniverse/tools/get_em_3d_fitting_and_reconstruction_details.py +49 -0
  616. tooluniverse/tools/get_emdb_ids_by_pdb_id.py +46 -0
  617. tooluniverse/tools/get_episcanpy_info.py +44 -0
  618. tooluniverse/tools/get_ete3_info.py +44 -0
  619. tooluniverse/tools/get_faiss_info.py +46 -0
  620. tooluniverse/tools/get_fanc_info.py +46 -0
  621. tooluniverse/tools/get_flask_info.py +46 -0
  622. tooluniverse/tools/get_flowio_info.py +46 -0
  623. tooluniverse/tools/get_flowkit_info.py +46 -0
  624. tooluniverse/tools/get_flowutils_info.py +46 -0
  625. tooluniverse/tools/get_freesasa_info.py +44 -0
  626. tooluniverse/tools/get_galpy_info.py +44 -0
  627. tooluniverse/tools/get_gene_name_by_entity_id.py +46 -0
  628. tooluniverse/tools/get_geopandas_info.py +44 -0
  629. tooluniverse/tools/get_gget_info.py +46 -0
  630. tooluniverse/tools/get_googlesearch_python_info.py +46 -0
  631. tooluniverse/tools/get_gseapy_info.py +49 -0
  632. tooluniverse/tools/get_h5py_info.py +46 -0
  633. tooluniverse/tools/get_harmony_pytorch_info.py +46 -0
  634. tooluniverse/tools/get_hmmlearn_info.py +46 -0
  635. tooluniverse/tools/get_holoviews_info.py +44 -0
  636. tooluniverse/tools/get_host_organism_by_pdb_id.py +46 -0
  637. tooluniverse/tools/get_htmd_info.py +44 -0
  638. tooluniverse/tools/get_hyperopt_info.py +49 -0
  639. tooluniverse/tools/get_igraph_info.py +49 -0
  640. tooluniverse/tools/get_imageio_info.py +44 -0
  641. tooluniverse/tools/get_imbalanced_learn_info.py +44 -0
  642. tooluniverse/tools/get_jcvi_info.py +46 -0
  643. tooluniverse/tools/get_joblib_info.py +44 -0
  644. tooluniverse/tools/get_joint_associated_diseases_by_HPO_ID_list.py +55 -0
  645. tooluniverse/tools/get_khmer_info.py +46 -0
  646. tooluniverse/tools/get_kipoiseq_info.py +44 -0
  647. tooluniverse/tools/get_lifelines_info.py +49 -0
  648. tooluniverse/tools/get_ligand_bond_count_by_pdb_id.py +46 -0
  649. tooluniverse/tools/get_ligand_smiles_by_chem_comp_id.py +49 -0
  650. tooluniverse/tools/get_lightgbm_info.py +44 -0
  651. tooluniverse/tools/get_loompy_info.py +46 -0
  652. tooluniverse/tools/get_mageck_info.py +46 -0
  653. tooluniverse/tools/get_matplotlib_info.py +49 -0
  654. tooluniverse/tools/get_mdanalysis_info.py +46 -0
  655. tooluniverse/tools/get_mdtraj_info.py +44 -0
  656. tooluniverse/tools/get_mne_info.py +44 -0
  657. tooluniverse/tools/get_molfeat_info.py +44 -0
  658. tooluniverse/tools/get_molvs_info.py +44 -0
  659. tooluniverse/tools/get_mordred_info.py +44 -0
  660. tooluniverse/tools/get_msprime_info.py +49 -0
  661. tooluniverse/tools/get_mudata_info.py +49 -0
  662. tooluniverse/tools/get_mutation_annotations_by_pdb_id.py +46 -0
  663. tooluniverse/tools/get_neo_info.py +44 -0
  664. tooluniverse/tools/get_netcdf4_info.py +44 -0
  665. tooluniverse/tools/get_networkx_info.py +46 -0
  666. tooluniverse/tools/get_nglview_info.py +44 -0
  667. tooluniverse/tools/get_nilearn_info.py +44 -0
  668. tooluniverse/tools/get_numba_info.py +46 -0
  669. tooluniverse/tools/get_numpy_info.py +46 -0
  670. tooluniverse/tools/get_oligosaccharide_descriptors_by_entity_id.py +49 -0
  671. tooluniverse/tools/get_openbabel_info.py +49 -0
  672. tooluniverse/tools/get_openchem_info.py +46 -0
  673. tooluniverse/tools/get_opencv_info.py +49 -0
  674. tooluniverse/tools/get_openmm_info.py +49 -0
  675. tooluniverse/tools/get_optlang_info.py +46 -0
  676. tooluniverse/tools/get_optuna_info.py +44 -0
  677. tooluniverse/tools/get_palantir_info.py +44 -0
  678. tooluniverse/tools/get_pandas_info.py +49 -0
  679. tooluniverse/tools/get_patsy_info.py +44 -0
  680. tooluniverse/tools/get_pdbfixer_info.py +46 -0
  681. tooluniverse/tools/get_phenotype_by_HPO_ID.py +46 -0
  682. tooluniverse/tools/get_pillow_info.py +44 -0
  683. tooluniverse/tools/get_plantcv_info.py +46 -0
  684. tooluniverse/tools/get_plip_info.py +46 -0
  685. tooluniverse/tools/get_plotly_info.py +44 -0
  686. tooluniverse/tools/get_poliastro_info.py +46 -0
  687. tooluniverse/tools/get_polymer_entity_annotations.py +49 -0
  688. tooluniverse/tools/get_polymer_entity_count_by_pdb_id.py +46 -0
  689. tooluniverse/tools/get_polymer_entity_ids_by_pdb_id.py +46 -0
  690. tooluniverse/tools/get_polymer_entity_type_by_entity_id.py +49 -0
  691. tooluniverse/tools/get_polymer_molecular_weight_by_entity_id.py +49 -0
  692. tooluniverse/tools/get_poretools_info.py +44 -0
  693. tooluniverse/tools/get_prody_info.py +46 -0
  694. tooluniverse/tools/get_protein_classification_by_pdb_id.py +49 -0
  695. tooluniverse/tools/get_protein_metadata_by_pdb_id.py +46 -0
  696. tooluniverse/tools/get_pubchempy_info.py +44 -0
  697. tooluniverse/tools/get_pybedtools_info.py +49 -0
  698. tooluniverse/tools/get_pybigwig_info.py +46 -0
  699. tooluniverse/tools/get_pydeseq2_info.py +46 -0
  700. tooluniverse/tools/get_pyensembl_info.py +44 -0
  701. tooluniverse/tools/get_pyephem_info.py +44 -0
  702. tooluniverse/tools/get_pyfaidx_info.py +49 -0
  703. tooluniverse/tools/get_pyfasta_info.py +44 -0
  704. tooluniverse/tools/get_pykalman_info.py +46 -0
  705. tooluniverse/tools/get_pyliftover_info.py +49 -0
  706. tooluniverse/tools/get_pymassspec_info.py +46 -0
  707. tooluniverse/tools/get_pymed_info.py +46 -0
  708. tooluniverse/tools/get_pymzml_info.py +46 -0
  709. tooluniverse/tools/get_pypdf2_info.py +46 -0
  710. tooluniverse/tools/get_pyranges_info.py +49 -0
  711. tooluniverse/tools/get_pyrosetta_info.py +44 -0
  712. tooluniverse/tools/get_pysam_info.py +46 -0
  713. tooluniverse/tools/get_pyscenic_info.py +46 -0
  714. tooluniverse/tools/get_pyscf_info.py +46 -0
  715. tooluniverse/tools/get_pyscreener_info.py +46 -0
  716. tooluniverse/tools/get_pytdc_info.py +46 -0
  717. tooluniverse/tools/get_python_libsbml_info.py +46 -0
  718. tooluniverse/tools/get_pytorch_info.py +49 -0
  719. tooluniverse/tools/get_pyvcf_info.py +44 -0
  720. tooluniverse/tools/get_pyvis_info.py +44 -0
  721. tooluniverse/tools/get_qutip_info.py +44 -0
  722. tooluniverse/tools/get_rasterio_info.py +44 -0
  723. tooluniverse/tools/get_rdkit_info.py +46 -0
  724. tooluniverse/tools/get_refinement_resolution_by_pdb_id.py +49 -0
  725. tooluniverse/tools/get_release_deposit_dates_by_pdb_id.py +49 -0
  726. tooluniverse/tools/get_reportlab_info.py +49 -0
  727. tooluniverse/tools/get_requests_info.py +49 -0
  728. tooluniverse/tools/get_ruptures_info.py +46 -0
  729. tooluniverse/tools/get_scanorama_info.py +44 -0
  730. tooluniverse/tools/get_scanpy_info.py +49 -0
  731. tooluniverse/tools/get_schnetpack_info.py +49 -0
  732. tooluniverse/tools/get_scholarly_info.py +46 -0
  733. tooluniverse/tools/get_scikit_bio_info.py +49 -0
  734. tooluniverse/tools/get_scikit_image_info.py +46 -0
  735. tooluniverse/tools/get_scikit_learn_info.py +49 -0
  736. tooluniverse/tools/get_scipy_info.py +46 -0
  737. tooluniverse/tools/get_scrublet_info.py +49 -0
  738. tooluniverse/tools/get_scvelo_info.py +49 -0
  739. tooluniverse/tools/get_scvi_tools_info.py +44 -0
  740. tooluniverse/tools/get_seaborn_info.py +49 -0
  741. tooluniverse/tools/get_sequence_by_pdb_id.py +46 -0
  742. tooluniverse/tools/get_sequence_lengths_by_pdb_id.py +46 -0
  743. tooluniverse/tools/get_sequence_positional_features_by_instance_id.py +49 -0
  744. tooluniverse/tools/get_skopt_info.py +44 -0
  745. tooluniverse/tools/get_souporcell_info.py +46 -0
  746. tooluniverse/tools/get_source_organism_by_pdb_id.py +46 -0
  747. tooluniverse/tools/get_space_group_by_pdb_id.py +46 -0
  748. tooluniverse/tools/get_statsmodels_info.py +49 -0
  749. tooluniverse/tools/get_structure_determination_software_by_pdb_id.py +49 -0
  750. tooluniverse/tools/get_structure_title_by_pdb_id.py +46 -0
  751. tooluniverse/tools/get_structure_validation_metrics_by_pdb_id.py +49 -0
  752. tooluniverse/tools/get_sunpy_info.py +44 -0
  753. tooluniverse/tools/get_sympy_info.py +46 -0
  754. tooluniverse/tools/get_target_cofactor_info.py +46 -0
  755. tooluniverse/tools/get_taxonomy_by_pdb_id.py +46 -0
  756. tooluniverse/tools/get_tiledb_info.py +46 -0
  757. tooluniverse/tools/get_tiledbsoma_info.py +46 -0
  758. tooluniverse/tools/get_torch_geometric_info.py +49 -0
  759. tooluniverse/tools/get_tqdm_info.py +46 -0
  760. tooluniverse/tools/get_trackpy_info.py +46 -0
  761. tooluniverse/tools/get_tskit_info.py +46 -0
  762. tooluniverse/tools/get_umap_learn_info.py +49 -0
  763. tooluniverse/tools/get_uniprot_accession_by_entity_id.py +49 -0
  764. tooluniverse/tools/get_velocyto_info.py +44 -0
  765. tooluniverse/tools/get_viennarna_info.py +49 -0
  766. tooluniverse/tools/get_webpage_text_from_url.py +52 -0
  767. tooluniverse/tools/get_webpage_title.py +49 -0
  768. tooluniverse/tools/get_xarray_info.py +44 -0
  769. tooluniverse/tools/get_xesmf_info.py +44 -0
  770. tooluniverse/tools/get_xgboost_info.py +44 -0
  771. tooluniverse/tools/get_zarr_info.py +44 -0
  772. tooluniverse/tools/gnomAD_query_variant.py +52 -0
  773. tooluniverse/tools/gwas_get_association_by_id.py +49 -0
  774. tooluniverse/tools/gwas_get_associations_for_snp.py +67 -0
  775. tooluniverse/tools/gwas_get_associations_for_study.py +55 -0
  776. tooluniverse/tools/gwas_get_associations_for_trait.py +55 -0
  777. tooluniverse/tools/gwas_get_snp_by_id.py +46 -0
  778. tooluniverse/tools/gwas_get_snps_for_gene.py +55 -0
  779. tooluniverse/tools/gwas_get_studies_for_trait.py +75 -0
  780. tooluniverse/tools/gwas_get_study_by_id.py +46 -0
  781. tooluniverse/tools/gwas_get_variants_for_trait.py +55 -0
  782. tooluniverse/tools/gwas_search_associations.py +75 -0
  783. tooluniverse/tools/gwas_search_snps.py +63 -0
  784. tooluniverse/tools/gwas_search_studies.py +75 -0
  785. tooluniverse/tools/humanbase_ppi_analysis.py +67 -0
  786. tooluniverse/tools/mesh_get_subjects_by_pharmacological_action.py +63 -0
  787. tooluniverse/tools/mesh_get_subjects_by_subject_id.py +63 -0
  788. tooluniverse/tools/mesh_get_subjects_by_subject_name.py +63 -0
  789. tooluniverse/tools/mesh_get_subjects_by_subject_scope_or_definition.py +63 -0
  790. tooluniverse/tools/odphp_itemlist.py +49 -0
  791. tooluniverse/tools/odphp_myhealthfinder.py +67 -0
  792. tooluniverse/tools/odphp_outlink_fetch.py +59 -0
  793. tooluniverse/tools/odphp_topicsearch.py +67 -0
  794. tooluniverse/tools/openalex_literature_search.py +67 -0
  795. tooluniverse/tools/reactome_disease_target_score.py +52 -0
  796. tooluniverse/tools/search_clinical_trials.py +67 -0
  797. tooluniverse/tools/visualize_molecule_2d.py +83 -0
  798. tooluniverse/tools/visualize_molecule_3d.py +91 -0
  799. tooluniverse/tools/visualize_protein_structure_3d.py +79 -0
  800. tooluniverse/ucsc_tool.py +60 -0
  801. tooluniverse/unified_guideline_tools.py +2328 -0
  802. tooluniverse/unpaywall_tool.py +0 -1
  803. tooluniverse/utils.py +122 -6
  804. tooluniverse/visualization_tool.py +897 -0
  805. tooluniverse/wikidata_sparql_tool.py +1 -2
  806. tooluniverse/zenodo_tool.py +3 -4
  807. {tooluniverse-1.0.6.dist-info → tooluniverse-1.0.8.dist-info}/METADATA +19 -4
  808. tooluniverse-1.0.8.dist-info/RECORD +891 -0
  809. {tooluniverse-1.0.6.dist-info → tooluniverse-1.0.8.dist-info}/entry_points.txt +3 -0
  810. tooluniverse/test/list_azure_openai_models.py +0 -210
  811. tooluniverse/test/mcp_server_test.py +0 -0
  812. tooluniverse/test/test_admetai_tool.py +0 -370
  813. tooluniverse/test/test_agentic_tool.py +0 -129
  814. tooluniverse/test/test_agentic_tool_azure_models.py +0 -91
  815. tooluniverse/test/test_alphafold_tool.py +0 -108
  816. tooluniverse/test/test_api_key_validation_min.py +0 -64
  817. tooluniverse/test/test_chem_tool.py +0 -37
  818. tooluniverse/test/test_claude_sdk.py +0 -93
  819. tooluniverse/test/test_compose_lieraturereview.py +0 -63
  820. tooluniverse/test/test_compose_tool.py +0 -448
  821. tooluniverse/test/test_dailymed.py +0 -69
  822. tooluniverse/test/test_dataset_tool.py +0 -200
  823. tooluniverse/test/test_disease_target_score.py +0 -56
  824. tooluniverse/test/test_drugbank_filter_examples.py +0 -179
  825. tooluniverse/test/test_efo.py +0 -31
  826. tooluniverse/test/test_enrichr_tool.py +0 -21
  827. tooluniverse/test/test_europe_pmc_tool.py +0 -20
  828. tooluniverse/test/test_fda_adv.py +0 -95
  829. tooluniverse/test/test_fda_drug_labeling.py +0 -91
  830. tooluniverse/test/test_gene_ontology_tools.py +0 -66
  831. tooluniverse/test/test_global_fallback.py +0 -288
  832. tooluniverse/test/test_gwas_tool.py +0 -139
  833. tooluniverse/test/test_hooks_direct.py +0 -219
  834. tooluniverse/test/test_hpa.py +0 -625
  835. tooluniverse/test/test_humanbase_tool.py +0 -20
  836. tooluniverse/test/test_idmap_tools.py +0 -61
  837. tooluniverse/test/test_list_built_in_tools.py +0 -33
  838. tooluniverse/test/test_mcp_server.py +0 -211
  839. tooluniverse/test/test_mcp_tool.py +0 -247
  840. tooluniverse/test/test_medlineplus.py +0 -220
  841. tooluniverse/test/test_odphp_tool.py +0 -166
  842. tooluniverse/test/test_openalex_tool.py +0 -32
  843. tooluniverse/test/test_openrouter_client.py +0 -288
  844. tooluniverse/test/test_opentargets.py +0 -28
  845. tooluniverse/test/test_pubchem_tool.py +0 -116
  846. tooluniverse/test/test_pubtator_tool.py +0 -37
  847. tooluniverse/test/test_rcsb_pdb_tool.py +0 -86
  848. tooluniverse/test/test_reactome.py +0 -54
  849. tooluniverse/test/test_semantic_scholar_tool.py +0 -24
  850. tooluniverse/test/test_software_tools.py +0 -147
  851. tooluniverse/test/test_stdio_hooks.py +0 -285
  852. tooluniverse/test/test_tool_description_optimizer.py +0 -49
  853. tooluniverse/test/test_tool_finder.py +0 -26
  854. tooluniverse/test/test_tool_finder_llm.py +0 -252
  855. tooluniverse/test/test_tools_find.py +0 -195
  856. tooluniverse/test/test_uniprot_tools.py +0 -74
  857. tooluniverse/test/test_uspto_tool.py +0 -72
  858. tooluniverse/test/test_xml_tool.py +0 -113
  859. tooluniverse-1.0.6.dist-info/RECORD +0 -230
  860. {tooluniverse-1.0.6.dist-info → tooluniverse-1.0.8.dist-info}/WHEEL +0 -0
  861. {tooluniverse-1.0.6.dist-info → tooluniverse-1.0.8.dist-info}/licenses/LICENSE +0 -0
  862. {tooluniverse-1.0.6.dist-info → tooluniverse-1.0.8.dist-info}/top_level.txt +0 -0
@@ -31,12 +31,26 @@ import random
31
31
  import string
32
32
  import os
33
33
  import time
34
+ import hashlib
35
+ import warnings
36
+ from pathlib import Path
37
+ from contextlib import nullcontext
38
+ from typing import Any, Dict, List, Optional
34
39
  from .utils import read_json_list, evaluate_function_call, extract_function_call_json
40
+ from .exceptions import (
41
+ ToolError,
42
+ ToolUnavailableError,
43
+ ToolValidationError,
44
+ ToolConfigError,
45
+ ToolServerError,
46
+ )
35
47
  from .tool_registry import (
36
48
  auto_discover_tools,
37
49
  get_tool_registry,
38
50
  register_external_tool,
39
51
  get_tool_class_lazy,
52
+ get_tool_errors,
53
+ mark_tool_unavailable,
40
54
  )
41
55
  from .logging_config import (
42
56
  get_logger,
@@ -46,6 +60,7 @@ from .logging_config import (
46
60
  error,
47
61
  set_log_level,
48
62
  )
63
+ from .cache.result_cache_manager import ResultCacheManager
49
64
  from .output_hook import HookManager
50
65
  from .default_config import default_tool_files, get_default_hook_config
51
66
 
@@ -81,6 +96,82 @@ for _tool_name, _tool_class in sorted(tool_type_mappings.items()):
81
96
  debug(f" - {_tool_name}: {_tool_class.__name__}")
82
97
 
83
98
 
99
+ class ToolCallable:
100
+ """
101
+ A callable wrapper for a tool that validates kwargs and calls run_one_function.
102
+
103
+ This class provides the dynamic function interface for tools, allowing
104
+ them to be called like regular Python functions with keyword arguments.
105
+ """
106
+
107
+ def __init__(self, engine: "ToolUniverse", tool_name: str):
108
+ self.engine = engine
109
+ self.tool_name = tool_name
110
+ self.schema = engine.all_tool_dict[tool_name]["parameter"]
111
+ self.__doc__ = engine.all_tool_dict[tool_name].get("description", tool_name)
112
+
113
+ def __call__(
114
+ self, *, stream_callback=None, use_cache=False, validate=True, **kwargs
115
+ ):
116
+ """
117
+ Execute the tool with the provided keyword arguments.
118
+
119
+ Args:
120
+ stream_callback: Optional callback for streaming responses
121
+ use_cache: Whether to use result caching
122
+ validate: Whether to validate parameters against schema
123
+ **kwargs: Tool-specific arguments
124
+
125
+ Returns:
126
+ Tool execution result
127
+ """
128
+ function_call = {"name": self.tool_name, "arguments": kwargs}
129
+ return self.engine.run_one_function(
130
+ function_call,
131
+ stream_callback=stream_callback,
132
+ use_cache=use_cache,
133
+ validate=validate,
134
+ )
135
+
136
+
137
+ class ToolNamespace:
138
+ """
139
+ Dynamic namespace for accessing tools as callable functions.
140
+
141
+ This class provides the `tu.tools.tool_name(**kwargs)` interface,
142
+ dynamically creating ToolCallable instances for each available tool.
143
+ """
144
+
145
+ def __init__(self, engine: "ToolUniverse"):
146
+ self.engine = engine
147
+
148
+ def __getattr__(self, name: str) -> ToolCallable:
149
+ """Return a ToolCallable for the requested tool name."""
150
+ if name in self.engine.all_tool_dict:
151
+ return ToolCallable(self.engine, name)
152
+ raise AttributeError(f"Tool '{name}' not found")
153
+
154
+ def __len__(self) -> int:
155
+ """Return the number of available tools."""
156
+ return len(self.engine.all_tool_dict)
157
+
158
+ def __iter__(self):
159
+ """Iterate over tool names."""
160
+ return iter(self.engine.all_tool_dict.keys())
161
+
162
+ def __contains__(self, name: str) -> bool:
163
+ """Check if a tool exists."""
164
+ return name in self.engine.all_tool_dict
165
+
166
+ def refresh(self):
167
+ """Refresh tool discovery (re-discover MCP/remote tools)."""
168
+ self.engine.refresh_tools()
169
+
170
+ def eager_load(self, names: Optional[List[str]] = None):
171
+ """Pre-instantiate tools to reduce first-call latency."""
172
+ self.engine.eager_load_tools(names)
173
+
174
+
84
175
  class ToolUniverse:
85
176
  """
86
177
  A comprehensive tool management system for loading, organizing, and executing various scientific and data tools.
@@ -130,9 +221,9 @@ class ToolUniverse:
130
221
  self.logger = get_logger("ToolUniverse")
131
222
 
132
223
  # Initialize any necessary attributes here FIRST
133
- self.all_tools = []
134
- self.all_tool_dict = {}
135
- self.tool_category_dicts = {}
224
+ self.all_tools: List[Dict[str, Any]] = []
225
+ self.all_tool_dict: Dict[str, Dict[str, Any]] = {}
226
+ self.tool_category_dicts: Dict[str, List[Dict[str, Any]]] = {}
136
227
  self.tool_finder = None
137
228
  if tool_files is None:
138
229
  tool_files = default_tool_files
@@ -172,6 +263,46 @@ class ToolUniverse:
172
263
  self.hook_manager = None
173
264
  self.logger.debug("Output hooks disabled")
174
265
 
266
+ # Initialize caching configuration
267
+ cache_enabled = os.getenv("TOOLUNIVERSE_CACHE_ENABLED", "true").lower() in (
268
+ "true",
269
+ "1",
270
+ "yes",
271
+ )
272
+ persistence_enabled = os.getenv(
273
+ "TOOLUNIVERSE_CACHE_PERSIST", "true"
274
+ ).lower() in ("true", "1", "yes")
275
+ memory_size = int(os.getenv("TOOLUNIVERSE_CACHE_MEMORY_SIZE", "256"))
276
+ default_ttl_env = os.getenv("TOOLUNIVERSE_CACHE_DEFAULT_TTL")
277
+ default_ttl = int(default_ttl_env) if default_ttl_env else None
278
+ singleflight_enabled = os.getenv(
279
+ "TOOLUNIVERSE_CACHE_SINGLEFLIGHT", "true"
280
+ ).lower() in ("true", "1", "yes")
281
+
282
+ cache_path = os.getenv("TOOLUNIVERSE_CACHE_PATH")
283
+ if not cache_path and persistence_enabled:
284
+ base_dir = os.getenv("TOOLUNIVERSE_CACHE_DIR")
285
+ if not base_dir:
286
+ base_dir = os.path.join(str(Path.home()), ".tooluniverse")
287
+ os.makedirs(base_dir, exist_ok=True)
288
+ cache_path = os.path.join(base_dir, "cache.sqlite")
289
+
290
+ self.cache_manager = ResultCacheManager(
291
+ memory_size=memory_size,
292
+ persistent_path=cache_path if persistence_enabled else None,
293
+ enabled=cache_enabled,
294
+ persistence_enabled=persistence_enabled,
295
+ singleflight=singleflight_enabled,
296
+ default_ttl=default_ttl,
297
+ )
298
+
299
+ self._strict_validation = os.getenv(
300
+ "TOOLUNIVERSE_STRICT_VALIDATION", "false"
301
+ ).lower() in ("true", "1", "yes")
302
+
303
+ # Initialize dynamic tools namespace
304
+ self.tools = ToolNamespace(self)
305
+
175
306
  def register_custom_tool(self, tool_class, tool_name=None, tool_config=None):
176
307
  """
177
308
  Register a custom tool class at runtime.
@@ -903,104 +1034,6 @@ class ToolUniverse:
903
1034
  )
904
1035
  self.logger.debug("_process_mcp_auto_loaders completed")
905
1036
 
906
- def select_tools(
907
- self,
908
- include_names=None,
909
- exclude_names=None,
910
- include_categories=None,
911
- exclude_categories=None,
912
- ):
913
- """
914
- Select tools based on tool names and/or categories (tool_files keys).
915
-
916
- Args:
917
- include_names (list, optional): List of tool names to include. If None, include all.
918
- exclude_names (list, optional): List of tool names to exclude.
919
- include_categories (list, optional): List of categories (tool_files keys) to include.
920
- If None, include all.
921
- exclude_categories (list, optional): List of categories (tool_files keys) to exclude.
922
-
923
- Returns:
924
- list: List of selected tool configurations.
925
- """
926
- selected_tools = []
927
- # If categories are specified, use self.tool_category_dicts to filter
928
- categories = set(self.tool_category_dicts.keys())
929
- if include_categories is not None:
930
- categories &= set(include_categories)
931
- if exclude_categories is not None:
932
- categories -= set(exclude_categories)
933
- # Gather tools from selected categories
934
- for cat in categories:
935
- selected_tools.extend(self.tool_category_dicts[cat])
936
- # Further filter by names if needed
937
- if include_names is not None:
938
- selected_tools = [
939
- tool for tool in selected_tools if tool["name"] in include_names
940
- ]
941
- if exclude_names is not None:
942
- selected_tools = [
943
- tool for tool in selected_tools if tool["name"] not in exclude_names
944
- ]
945
- return selected_tools
946
-
947
- def filter_tool_lists(
948
- self,
949
- tool_name_list,
950
- tool_desc_list,
951
- include_names=None,
952
- exclude_names=None,
953
- include_categories=None,
954
- exclude_categories=None,
955
- ):
956
- """
957
- Directly filter tool name and description lists based on names and/or categories.
958
-
959
- This method takes existing tool name and description lists and filters them according
960
- to the specified criteria using the select_tools method for category-based filtering.
961
-
962
- Args:
963
- tool_name_list (list): List of tool names to filter.
964
- tool_desc_list (list): List of tool descriptions to filter (must correspond to tool_name_list).
965
- include_names (list, optional): List of tool names to include.
966
- exclude_names (list, optional): List of tool names to exclude.
967
- include_categories (list, optional): List of categories to include.
968
- exclude_categories (list, optional): List of categories to exclude.
969
-
970
- Returns:
971
- tuple: A tuple containing (filtered_tool_name_list, filtered_tool_desc_list).
972
- """
973
- # Build a set of allowed tool names using select_tools for category filtering
974
- allowed_names = set()
975
- if any([include_names, exclude_names, include_categories, exclude_categories]):
976
- filtered_tools = self.select_tools(
977
- include_names=include_names,
978
- exclude_names=exclude_names,
979
- include_categories=include_categories,
980
- exclude_categories=exclude_categories,
981
- )
982
- allowed_names = set(tool["name"] for tool in filtered_tools)
983
- else:
984
- allowed_names = set(tool_name_list)
985
-
986
- # Filter lists by allowed_names
987
- filtered_tool_name_list = []
988
- filtered_tool_desc_list = []
989
- for name, desc in zip(tool_name_list, tool_desc_list):
990
- if name in allowed_names:
991
- filtered_tool_name_list.append(name)
992
- filtered_tool_desc_list.append(desc)
993
- return filtered_tool_name_list, filtered_tool_desc_list
994
-
995
- def return_all_loaded_tools(self):
996
- """
997
- Return a deep copy of all loaded tools.
998
-
999
- Returns:
1000
- list: A deep copy of the all_tools list to prevent external modification.
1001
- """
1002
- return copy.deepcopy(self.all_tools)
1003
-
1004
1037
  def list_built_in_tools(self, mode="config", scan_all=False):
1005
1038
  """
1006
1039
  List all built-in tool categories and their statistics with different modes.
@@ -1041,9 +1074,14 @@ class ToolUniverse:
1041
1074
  - When scan_all=True, all JSON files in data/ and subdirectories are scanned
1042
1075
  """
1043
1076
  if mode not in ["config", "type", "list_name", "list_spec"]:
1044
- raise ValueError(
1045
- "Mode must be one of: 'config', 'type', 'list_name', 'list_spec'"
1046
- )
1077
+ # Handle invalid modes gracefully
1078
+ if mode is None:
1079
+ mode = "config" # Default to config mode
1080
+ else:
1081
+ # For invalid string modes, return error info instead of raising
1082
+ return {
1083
+ "error": f"Invalid mode '{mode}'. Must be one of: 'config', 'type', 'list_name', 'list_spec'"
1084
+ }
1047
1085
 
1048
1086
  # For list_name and list_spec modes, we can return early with just the data
1049
1087
  if mode in ["list_name", "list_spec"]:
@@ -1211,6 +1249,39 @@ class ToolUniverse:
1211
1249
 
1212
1250
  return result
1213
1251
 
1252
+ def _read_tools_from_file(self, file_path):
1253
+ """
1254
+ Read tools from a single JSON file with error handling.
1255
+
1256
+ Args:
1257
+ file_path (str): Path to the JSON file
1258
+
1259
+ Returns:
1260
+ list: List of tool configurations from the file
1261
+ """
1262
+ try:
1263
+ tools_in_file = read_json_list(file_path)
1264
+
1265
+ # Handle different data formats
1266
+ if isinstance(tools_in_file, dict):
1267
+ # Convert dict of tools to list of tools
1268
+ tools_in_file = list(tools_in_file.values())
1269
+ elif not isinstance(tools_in_file, list):
1270
+ # Skip files that don't contain tool configurations
1271
+ return []
1272
+
1273
+ # Validate tools have required fields
1274
+ valid_tools = []
1275
+ for tool in tools_in_file:
1276
+ if isinstance(tool, dict) and "name" in tool:
1277
+ valid_tools.append(tool)
1278
+
1279
+ return valid_tools
1280
+
1281
+ except Exception as e:
1282
+ warning(f"Warning: Could not read tools from {file_path}: {e}")
1283
+ return []
1284
+
1214
1285
  def _scan_predefined_files(self):
1215
1286
  """
1216
1287
  Scan predefined tool files (original behavior).
@@ -1223,39 +1294,23 @@ class ToolUniverse:
1223
1294
  all_tool_names = set()
1224
1295
 
1225
1296
  # Read tools from each category file
1226
- for category, file_path in self.tool_files.items():
1227
- try:
1228
- # Read the JSON file for this category
1229
- tools_in_category = read_json_list(file_path)
1230
- all_tools.extend(tools_in_category)
1231
- all_tool_names.update([tool["name"] for tool in tools_in_category])
1232
- except Exception as e:
1233
- warning(
1234
- f"Warning: Could not read tools from {category} ({file_path}): {e}"
1235
- )
1297
+ for _category, file_path in self.tool_files.items():
1298
+ tools_in_category = self._read_tools_from_file(file_path)
1299
+ all_tools.extend(tools_in_category)
1300
+ all_tool_names.update([tool["name"] for tool in tools_in_category])
1236
1301
 
1237
1302
  # Also include remote tools
1238
1303
  try:
1239
1304
  remote_dir = os.path.join(current_dir, "data", "remote_tools")
1240
1305
  if os.path.isdir(remote_dir):
1241
- remote_tools = []
1242
1306
  for fname in os.listdir(remote_dir):
1243
1307
  if not fname.lower().endswith(".json"):
1244
1308
  continue
1245
1309
  fpath = os.path.join(remote_dir, fname)
1246
- try:
1247
- tools_in_file = read_json_list(fpath)
1248
- if isinstance(tools_in_file, dict):
1249
- tools_in_file = list(tools_in_file.values())
1250
- if isinstance(tools_in_file, list):
1251
- remote_tools.extend(tools_in_file)
1252
- except Exception as e:
1253
- warning(
1254
- f"Warning: Could not read remote tools from {fpath}: {e}"
1255
- )
1256
- if remote_tools:
1257
- all_tools.extend(remote_tools)
1258
- all_tool_names.update([tool["name"] for tool in remote_tools])
1310
+ remote_tools = self._read_tools_from_file(fpath)
1311
+ if remote_tools:
1312
+ all_tools.extend(remote_tools)
1313
+ all_tool_names.update([tool["name"] for tool in remote_tools])
1259
1314
  except Exception as e:
1260
1315
  warning(f"Warning: Failed to scan remote tools directory: {e}")
1261
1316
 
@@ -1288,31 +1343,14 @@ class ToolUniverse:
1288
1343
 
1289
1344
  self.logger.debug(f"Found {len(json_files)} JSON files to scan")
1290
1345
 
1291
- # Read tools from each JSON file
1346
+ # Read tools from each JSON file using the common method
1292
1347
  for json_file in json_files:
1293
- try:
1294
- tools_in_file = read_json_list(json_file)
1295
-
1296
- # Handle different data formats
1297
- if isinstance(tools_in_file, dict):
1298
- # Convert dict of tools to list of tools
1299
- tools_in_file = list(tools_in_file.values())
1300
- elif not isinstance(tools_in_file, list):
1301
- # Skip files that don't contain tool configurations
1302
- continue
1303
-
1304
- # Add tools to our collection
1305
- for tool in tools_in_file:
1306
- if isinstance(tool, dict) and "name" in tool:
1307
- all_tools.append(tool)
1308
- all_tool_names.add(tool["name"])
1309
-
1348
+ tools_in_file = self._read_tools_from_file(json_file)
1349
+ if tools_in_file:
1350
+ all_tools.extend(tools_in_file)
1351
+ all_tool_names.update([tool["name"] for tool in tools_in_file])
1310
1352
  self.logger.debug(f"Loaded {len(tools_in_file)} tools from {json_file}")
1311
1353
 
1312
- except Exception as e:
1313
- warning(f"Warning: Could not read tools from {json_file}: {e}")
1314
- continue
1315
-
1316
1354
  self.logger.info(
1317
1355
  f"Scanned {len(json_files)} JSON files, found {len(all_tools)} tools"
1318
1356
  )
@@ -1387,63 +1425,42 @@ class ToolUniverse:
1387
1425
  del tool[key]
1388
1426
  return tool
1389
1427
 
1390
- def prepare_tool_prompts(self, tool_list):
1391
- """
1392
- Prepare a list of tool configurations for prompt usage.
1393
-
1394
- Args:
1395
- tool_list (list): List of tool configuration dictionaries.
1396
-
1397
- Returns:
1398
- list: List of tool configurations with only essential keys for prompting.
1399
- """
1400
- copied_list = []
1401
- for tool in tool_list:
1402
- copied_list.append(self.prepare_one_tool_prompt(tool))
1403
- return copied_list
1404
-
1405
- def remove_keys(self, tool_list, invalid_keys):
1428
+ def prepare_tool_prompts(self, tool_list, mode="prompt", valid_keys=None):
1406
1429
  """
1407
- Remove specified keys from a list of tool configurations.
1430
+ Prepare a list of tool configurations for different usage modes.
1408
1431
 
1409
1432
  Args:
1410
1433
  tool_list (list): List of tool configuration dictionaries.
1411
- invalid_keys (list): List of keys to remove from each tool configuration.
1434
+ mode (str): Preparation mode. Options:
1435
+ - 'prompt': Keep essential keys for prompting (name, description, parameter, required)
1436
+ - 'example': Keep extended keys for examples (name, description, parameter, required, query_schema, fields, label, type)
1437
+ - 'custom': Use custom valid_keys parameter
1438
+ valid_keys (list, optional): Custom list of keys to keep when mode='custom'.
1412
1439
 
1413
1440
  Returns:
1414
- list: Deep copy of tool list with specified keys removed.
1415
- """
1416
- copied_list = copy.deepcopy(tool_list)
1417
- for tool in copied_list:
1418
- # Create a list of keys to avoid modifying the dictionary during iteration
1419
- for key in list(tool.keys()):
1420
- if key in invalid_keys:
1421
- del tool[key]
1422
- return copied_list
1423
-
1424
- def prepare_tool_examples(self, tool_list):
1425
- """
1426
- Prepare tool configurations for example usage by keeping extended set of keys.
1427
-
1428
- This method is similar to prepare_tool_prompts but includes additional keys
1429
- useful for examples and documentation.
1430
-
1431
- Args:
1432
- tool_list (list): List of tool configuration dictionaries.
1441
+ list: List of tool configurations with only specified keys.
1442
+ """
1443
+ if mode == "prompt":
1444
+ valid_keys = ["name", "description", "parameter", "required"]
1445
+ elif mode == "example":
1446
+ valid_keys = [
1447
+ "name",
1448
+ "description",
1449
+ "parameter",
1450
+ "required",
1451
+ "query_schema",
1452
+ "fields",
1453
+ "label",
1454
+ "type",
1455
+ ]
1456
+ elif mode == "custom":
1457
+ if valid_keys is None:
1458
+ raise ValueError("valid_keys must be provided when mode='custom'")
1459
+ else:
1460
+ raise ValueError(
1461
+ f"Invalid mode: {mode}. Must be 'prompt', 'example', or 'custom'"
1462
+ )
1433
1463
 
1434
- Returns:
1435
- list: Deep copy of tool list with only example-relevant keys.
1436
- """
1437
- valid_keys = [
1438
- "name",
1439
- "description",
1440
- "parameter",
1441
- "required",
1442
- "query_schema",
1443
- "fields",
1444
- "label",
1445
- "type",
1446
- ]
1447
1464
  copied_list = copy.deepcopy(tool_list)
1448
1465
  for tool in copied_list:
1449
1466
  # Create a list of keys to avoid modifying the dictionary during iteration
@@ -1472,21 +1489,6 @@ class ToolUniverse:
1472
1489
  picked_tool_list.append(tool_spec)
1473
1490
  return picked_tool_list
1474
1491
 
1475
- def get_tool_by_name(self, tool_names, format="default"):
1476
- """
1477
- Retrieve tool configurations by their names.
1478
-
1479
- Args:
1480
- tool_names (list): List of tool names to retrieve.
1481
- format (str, optional): Output format. Options: 'default', 'openai'.
1482
- If 'openai', returns OpenAI function calling format. Defaults to 'default'.
1483
-
1484
- Returns:
1485
- list: List of tool configurations for the specified names.
1486
- Tools not found will be reported but not included in the result.
1487
- """
1488
- return self.get_tool_specification_by_names(tool_names, format=format)
1489
-
1490
1492
  def get_one_tool_by_one_name(self, tool_name, return_prompt=True):
1491
1493
  """
1492
1494
  Retrieve a single tool specification by name, optionally prepared for prompting.
@@ -1521,65 +1523,58 @@ class ToolUniverse:
1521
1523
  Returns:
1522
1524
  dict or None: Tool configuration if found, None otherwise.
1523
1525
  """
1524
- if tool_name in self.all_tool_dict:
1525
- tool_config = self.all_tool_dict[tool_name]
1526
-
1527
- if format == "openai":
1528
- parameters = tool_config.get("parameter", {})
1529
- if isinstance(parameters, dict):
1530
- # 修复 required 字段格式
1531
- if "properties" in parameters:
1532
- for _prop_name, prop_config in parameters["properties"].items():
1533
- if (
1534
- isinstance(prop_config, dict)
1535
- and "required" in prop_config
1536
- ):
1537
- del prop_config["required"]
1538
-
1539
- if "required" in parameters and not isinstance(
1540
- parameters["required"], list
1541
- ):
1542
- if parameters["required"] is True:
1543
- required_list = []
1544
- if "properties" in parameters:
1545
- for prop_name, prop_config in parameters[
1546
- "properties"
1547
- ].items():
1548
- if (
1549
- isinstance(prop_config, dict)
1550
- and prop_config.get("required") is True
1551
- ):
1552
- required_list.append(prop_name)
1553
- parameters["required"] = required_list
1554
- else:
1555
- parameters["required"] = []
1556
-
1557
- return {
1558
- "name": tool_config["name"],
1559
- "description": tool_config["description"],
1560
- "parameters": parameters,
1561
- }
1562
- elif return_prompt:
1563
- return self.prepare_one_tool_prompt(tool_config)
1564
- else:
1565
- return tool_config
1566
- else:
1526
+ if tool_name not in self.all_tool_dict:
1567
1527
  warning(f"Tool name {tool_name} not found in the loaded tools.")
1568
1528
  return None
1569
1529
 
1570
- def get_tool_description(self, tool_name):
1571
- """
1572
- Get the description of a tool by its name.
1530
+ tool_config = self.all_tool_dict[tool_name]
1573
1531
 
1574
- This is a convenience method that calls get_one_tool_by_one_name.
1532
+ if return_prompt:
1533
+ return self.prepare_one_tool_prompt(tool_config)
1575
1534
 
1576
- Args:
1577
- tool_name (str): Name of the tool.
1535
+ # Process parameter schema based on format
1536
+ if "parameter" in tool_config and isinstance(tool_config["parameter"], dict):
1537
+ import copy
1578
1538
 
1579
- Returns:
1580
- dict or None: Tool configuration if found, None otherwise.
1581
- """
1582
- return self.get_one_tool_by_one_name(tool_name)
1539
+ processed_config = copy.deepcopy(tool_config)
1540
+ parameter_schema = processed_config["parameter"]
1541
+
1542
+ if (
1543
+ "properties" in parameter_schema
1544
+ and parameter_schema["properties"] is not None
1545
+ ):
1546
+ required_properties = parameter_schema.get("required", [])
1547
+
1548
+ if format == "openai":
1549
+ # For OpenAI format: remove property-level required fields
1550
+ for _prop_name, prop_config in parameter_schema[
1551
+ "properties"
1552
+ ].items():
1553
+ if isinstance(prop_config, dict) and "required" in prop_config:
1554
+ del prop_config["required"]
1555
+
1556
+ # Ensure required is a list
1557
+ if not isinstance(parameter_schema.get("required"), list):
1558
+ parameter_schema["required"] = (
1559
+ required_properties if required_properties else []
1560
+ )
1561
+
1562
+ return {
1563
+ "name": processed_config["name"],
1564
+ "description": processed_config["description"],
1565
+ "parameters": parameter_schema,
1566
+ }
1567
+ else:
1568
+ # For default format: add required fields to properties
1569
+ for prop_name, prop_config in parameter_schema[
1570
+ "properties"
1571
+ ].items():
1572
+ if isinstance(prop_config, dict):
1573
+ prop_config["required"] = prop_name in required_properties
1574
+
1575
+ return processed_config
1576
+
1577
+ return tool_config
1583
1578
 
1584
1579
  def get_tool_type_by_name(self, tool_name):
1585
1580
  """
@@ -1596,6 +1591,15 @@ class ToolUniverse:
1596
1591
  """
1597
1592
  return self.all_tool_dict[tool_name]["type"]
1598
1593
 
1594
+ def call_id_gen(self):
1595
+ """
1596
+ Generate a random call ID for function calls.
1597
+
1598
+ Returns:
1599
+ str: A random 9-character string composed of letters and digits.
1600
+ """
1601
+ return "".join(random.choices(string.ascii_letters + string.digits, k=9))
1602
+
1599
1603
  def tool_to_str(self, tool_list):
1600
1604
  """
1601
1605
  Convert a list of tool configurations to a formatted string.
@@ -1630,14 +1634,14 @@ class ToolUniverse:
1630
1634
  lst, return_message=return_message, verbose=verbose, format=format
1631
1635
  )
1632
1636
 
1633
- def call_id_gen(self):
1637
+ def return_all_loaded_tools(self):
1634
1638
  """
1635
- Generate a random call ID for function calls.
1639
+ Return a deep copy of all loaded tools.
1636
1640
 
1637
1641
  Returns:
1638
- str: A random 9-character string composed of letters and digits.
1642
+ list: A deep copy of the all_tools list to prevent external modification.
1639
1643
  """
1640
- return "".join(random.choices(string.ascii_letters + string.digits, k=9))
1644
+ return copy.deepcopy(self.all_tools)
1641
1645
 
1642
1646
  def run(
1643
1647
  self,
@@ -1708,7 +1712,9 @@ class ToolUniverse:
1708
1712
  error("Not a function call")
1709
1713
  return None
1710
1714
 
1711
- def run_one_function(self, function_call_json, stream_callback=None):
1715
+ def run_one_function(
1716
+ self, function_call_json, stream_callback=None, use_cache=False, validate=True
1717
+ ):
1712
1718
  """
1713
1719
  Execute a single function call.
1714
1720
 
@@ -1718,67 +1724,155 @@ class ToolUniverse:
1718
1724
 
1719
1725
  Args:
1720
1726
  function_call_json (dict): Dictionary containing function name and arguments.
1727
+ stream_callback (callable, optional): Callback for streaming responses.
1728
+ use_cache (bool, optional): Whether to use result caching. Defaults to False.
1729
+ validate (bool, optional): Whether to validate parameters against schema. Defaults to True.
1721
1730
 
1722
1731
  Returns:
1723
1732
  str or dict: Result from the tool execution, or error message if validation fails.
1724
1733
  """
1725
- check_status, check_message = self.check_function_call(function_call_json)
1726
- if check_status is False:
1727
- return (
1728
- "Invalid function call: " + check_message
1729
- ) # + " You must correct your invalid function call!"
1730
- function_name = function_call_json["name"]
1731
- arguments = function_call_json["arguments"]
1734
+ function_name = function_call_json.get("name", "")
1735
+ arguments = function_call_json.get("arguments", {})
1732
1736
 
1733
- # Execute the tool
1734
- tool_instance = None
1735
- tool_arguments = arguments
1736
- if function_name in self.callable_functions:
1737
- tool_instance = self.callable_functions[function_name]
1738
- result, tool_arguments = self._execute_tool_with_stream(
1739
- tool_instance, arguments, stream_callback
1740
- )
1741
- else:
1742
- if function_name in self.all_tool_dict:
1743
- self.logger.debug(
1744
- "Initiating callable_function from loaded tool dicts."
1745
- )
1746
- tool = self.init_tool(
1747
- self.all_tool_dict[function_name], add_to_cache=True
1737
+ # Handle malformed queries gracefully
1738
+ if not function_name:
1739
+ return {"error": "Missing or empty function name"}
1740
+
1741
+ if not isinstance(arguments, dict):
1742
+ return {
1743
+ "error": f"Arguments must be a dictionary, got {type(arguments).__name__}"
1744
+ }
1745
+
1746
+ tool_instance = None
1747
+ cache_namespace = None
1748
+ cache_version = None
1749
+ cache_key = None
1750
+ composed_cache_key = None
1751
+ cache_guard = nullcontext()
1752
+
1753
+ cache_enabled = (
1754
+ use_cache and self.cache_manager is not None and self.cache_manager.enabled
1755
+ )
1756
+
1757
+ if cache_enabled:
1758
+ tool_instance = self._get_tool_instance(function_name, cache=True)
1759
+ if tool_instance and tool_instance.supports_caching():
1760
+ cache_namespace = tool_instance.get_cache_namespace()
1761
+ cache_version = tool_instance.get_cache_version()
1762
+ cache_key = self._make_cache_key(function_name, arguments)
1763
+ composed_cache_key = self.cache_manager.compose_key(
1764
+ cache_namespace, cache_version, cache_key
1748
1765
  )
1749
- tool_instance = tool
1750
- result, tool_arguments = self._execute_tool_with_stream(
1751
- tool_instance, arguments, stream_callback
1766
+ cached_value = self.cache_manager.get(
1767
+ namespace=cache_namespace,
1768
+ version=cache_version,
1769
+ cache_key=cache_key,
1752
1770
  )
1771
+ if cached_value is not None:
1772
+ self.logger.debug(f"Cache hit for {function_name}")
1773
+ return cached_value
1774
+ cache_guard = self.cache_manager.singleflight_guard(composed_cache_key)
1753
1775
  else:
1754
- return f"Tool '{function_name}' not found"
1755
-
1756
- # Apply output hooks if enabled
1757
- if self.hook_manager:
1758
- context = {
1759
- "tool_name": function_name,
1760
- "tool_type": (
1761
- tool_instance.__class__.__name__
1762
- if tool_instance is not None
1763
- else "unknown"
1764
- ),
1765
- "execution_time": time.time(),
1766
- "arguments": tool_arguments,
1767
- }
1768
- result = self.hook_manager.apply_hooks(
1769
- result, function_name, tool_arguments, context
1770
- )
1776
+ cache_enabled = False
1777
+
1778
+ with cache_guard:
1779
+ if cache_enabled:
1780
+ cached_value = self.cache_manager.get(
1781
+ namespace=cache_namespace,
1782
+ version=cache_version,
1783
+ cache_key=cache_key,
1784
+ )
1785
+ if cached_value is not None:
1786
+ self.logger.debug(
1787
+ f"Cache hit for {function_name} (after singleflight wait)"
1788
+ )
1789
+ return cached_value
1790
+
1791
+ # Validate parameters if requested
1792
+ if validate:
1793
+ validation_error = self._validate_parameters(function_name, arguments)
1794
+ if validation_error:
1795
+ return self._create_dual_format_error(validation_error)
1796
+
1797
+ # Check function call format (existing validation)
1798
+ check_status, check_message = self.check_function_call(function_call_json)
1799
+ if check_status is False:
1800
+ error_msg = "Invalid function call: " + check_message
1801
+ return self._create_dual_format_error(
1802
+ ToolValidationError(
1803
+ error_msg, details={"check_message": check_message}
1804
+ )
1805
+ )
1771
1806
 
1772
- return result
1807
+ # Execute the tool
1808
+ tool_arguments = arguments
1809
+ try:
1810
+ if tool_instance is None:
1811
+ tool_instance = self._get_tool_instance(function_name, cache=True)
1812
+
1813
+ if tool_instance:
1814
+ result, tool_arguments = self._execute_tool_with_stream(
1815
+ tool_instance, arguments, stream_callback, use_cache, validate
1816
+ )
1817
+ else:
1818
+ error_msg = f"Tool '{function_name}' not found"
1819
+ return self._create_dual_format_error(
1820
+ ToolUnavailableError(
1821
+ error_msg,
1822
+ next_steps=[
1823
+ "Check tool name spelling",
1824
+ "Run tu.tools.refresh()",
1825
+ ],
1826
+ )
1827
+ )
1828
+ except Exception as e:
1829
+ # Classify and return structured error
1830
+ classified_error = self._classify_exception(e, function_name, arguments)
1831
+ return self._create_dual_format_error(classified_error)
1832
+
1833
+ # Apply output hooks if enabled
1834
+ if self.hook_manager:
1835
+ context = {
1836
+ "tool_name": function_name,
1837
+ "tool_type": (
1838
+ tool_instance.__class__.__name__
1839
+ if tool_instance is not None
1840
+ else "unknown"
1841
+ ),
1842
+ "execution_time": time.time(),
1843
+ "arguments": tool_arguments,
1844
+ }
1845
+ result = self.hook_manager.apply_hooks(
1846
+ result, function_name, tool_arguments, context
1847
+ )
1848
+
1849
+ # Cache result if enabled
1850
+ if cache_enabled and tool_instance and tool_instance.supports_caching():
1851
+ if cache_key is None:
1852
+ cache_key = self._make_cache_key(function_name, arguments)
1853
+ if cache_namespace is None:
1854
+ cache_namespace = tool_instance.get_cache_namespace()
1855
+ if cache_version is None:
1856
+ cache_version = tool_instance.get_cache_version()
1857
+ ttl = tool_instance.get_cache_ttl(result)
1858
+ self.cache_manager.set(
1859
+ namespace=cache_namespace,
1860
+ version=cache_version,
1861
+ cache_key=cache_key,
1862
+ value=result,
1863
+ ttl=ttl,
1864
+ )
1773
1865
 
1774
- def _execute_tool_with_stream(self, tool_instance, arguments, stream_callback):
1775
- """Invoke a tool, forwarding stream callbacks when supported."""
1866
+ return result
1867
+
1868
+ def _execute_tool_with_stream(
1869
+ self, tool_instance, arguments, stream_callback, use_cache=False, validate=True
1870
+ ):
1871
+ """Invoke a tool, forwarding stream callbacks and other parameters when supported."""
1776
1872
 
1777
1873
  tool_arguments = arguments
1778
1874
  stream_flag_key = (
1779
- getattr(tool_instance, "STREAM_FLAG_KEY", None)
1780
- if stream_callback
1781
- else None
1875
+ getattr(tool_instance, "STREAM_FLAG_KEY", None) if stream_callback else None
1782
1876
  )
1783
1877
 
1784
1878
  if isinstance(arguments, dict):
@@ -1791,24 +1885,30 @@ class ToolUniverse:
1791
1885
  ):
1792
1886
  tool_arguments[stream_flag_key] = True
1793
1887
 
1794
- if stream_callback is None:
1795
- return tool_instance.run(tool_arguments), tool_arguments
1796
-
1888
+ # Try to pass all available parameters to the tool
1797
1889
  try:
1798
1890
  signature = inspect.signature(tool_instance.run)
1799
- if "stream_callback" in signature.parameters:
1800
- return (
1801
- tool_instance.run(
1802
- tool_arguments, stream_callback=stream_callback
1803
- ),
1804
- tool_arguments,
1805
- )
1806
- except (ValueError, TypeError):
1807
- # If inspection fails, fall back to best-effort execution
1808
- pass
1809
-
1810
- # Tool doesn't support streaming yet; execute normally
1811
- return tool_instance.run(tool_arguments), tool_arguments
1891
+ params = signature.parameters
1892
+
1893
+ # Build kwargs based on what the tool accepts
1894
+ kwargs = {}
1895
+
1896
+ # Always include arguments as first positional argument
1897
+ if stream_callback is not None and "stream_callback" in params:
1898
+ kwargs["stream_callback"] = stream_callback
1899
+ if "use_cache" in params:
1900
+ kwargs["use_cache"] = use_cache
1901
+ if "validate" in params:
1902
+ kwargs["validate"] = validate
1903
+
1904
+ # Call with all supported parameters
1905
+ return tool_instance.run(tool_arguments, **kwargs), tool_arguments
1906
+
1907
+ except (ValueError, TypeError) as e:
1908
+ # If inspection fails or tool doesn't accept extra params,
1909
+ # fall back to simple execution with just arguments
1910
+ self.logger.debug(f"Falling back to simple run() call: {e}")
1911
+ return tool_instance.run(tool_arguments), tool_arguments
1812
1912
 
1813
1913
  def toggle_hooks(self, enabled: bool):
1814
1914
  """
@@ -1845,65 +1945,239 @@ class ToolUniverse:
1845
1945
  add_to_cache (bool, optional): Whether to cache the initialized tool. Defaults to True.
1846
1946
 
1847
1947
  Returns:
1848
- object: Initialized tool instance.
1948
+ object: Initialized tool instance or None if initialization fails.
1849
1949
 
1850
1950
  Raises:
1851
1951
  KeyError: If the tool type is not found in tool_type_mappings.
1852
1952
  """
1853
1953
  global tool_type_mappings
1854
1954
 
1855
- if tool_name is not None:
1856
- # Use lazy loading to get the tool class
1857
- tool_class = get_tool_class_lazy(tool_name)
1858
- if tool_class is None:
1859
- raise KeyError(f"Tool type '{tool_name}' not found in registry")
1860
- new_tool = tool_class()
1861
- else:
1862
- tool_type = tool["type"]
1863
- tool_name = tool["name"]
1864
-
1865
- # Use lazy loading to get the tool class
1866
- tool_class = get_tool_class_lazy(tool_type)
1867
- if tool_class is None:
1868
- # Fallback to old method if lazy loading fails
1869
- if tool_type not in tool_type_mappings:
1870
- # Refresh registry and try again
1871
- tool_type_mappings = get_tool_registry()
1872
- if tool_type not in tool_type_mappings:
1873
- raise KeyError(f"Tool type '{tool_type}' not found in registry")
1874
- tool_class = tool_type_mappings[tool_type]
1875
-
1876
- if "OpentargetToolDrugNameMatch" == tool_type:
1877
- if "FDADrugLabelGetDrugGenericNameTool" not in self.callable_functions:
1878
- drug_tool_class = get_tool_class_lazy(
1955
+ try:
1956
+ if tool_name is not None:
1957
+ # Use lazy loading to get the tool class
1958
+ tool_class = get_tool_class_lazy(tool_name)
1959
+ if tool_class is None:
1960
+ raise KeyError(f"Tool type '{tool_name}' not found in registry")
1961
+ new_tool = tool_class()
1962
+ else:
1963
+ tool_type = tool["type"]
1964
+ tool_name = tool["name"]
1965
+
1966
+ # Use lazy loading to get the tool class
1967
+ tool_class = get_tool_class_lazy(tool_type)
1968
+ if tool_class is None:
1969
+ # Fallback to old method if lazy loading fails
1970
+ if tool_type not in tool_type_mappings:
1971
+ # Refresh registry and try again
1972
+ tool_type_mappings = get_tool_registry()
1973
+ if tool_type not in tool_type_mappings:
1974
+ raise KeyError(f"Tool type '{tool_type}' not found in registry")
1975
+ tool_class = tool_type_mappings[tool_type]
1976
+
1977
+ if "OpentargetToolDrugNameMatch" == tool_type:
1978
+ if (
1879
1979
  "FDADrugLabelGetDrugGenericNameTool"
1880
- )
1881
- if drug_tool_class is None:
1882
- drug_tool_class = tool_type_mappings[
1980
+ not in self.callable_functions
1981
+ ):
1982
+ drug_tool_class = get_tool_class_lazy(
1883
1983
  "FDADrugLabelGetDrugGenericNameTool"
1884
- ]
1885
- self.callable_functions["FDADrugLabelGetDrugGenericNameTool"] = (
1886
- drug_tool_class()
1984
+ )
1985
+ if drug_tool_class is None:
1986
+ drug_tool_class = tool_type_mappings[
1987
+ "FDADrugLabelGetDrugGenericNameTool"
1988
+ ]
1989
+ self.callable_functions[
1990
+ "FDADrugLabelGetDrugGenericNameTool"
1991
+ ] = drug_tool_class()
1992
+ new_tool = tool_class(
1993
+ tool_config=tool,
1994
+ drug_generic_tool=self.callable_functions[
1995
+ "FDADrugLabelGetDrugGenericNameTool"
1996
+ ],
1887
1997
  )
1888
- new_tool = tool_class(
1889
- tool_config=tool,
1890
- drug_generic_tool=self.callable_functions[
1891
- "FDADrugLabelGetDrugGenericNameTool"
1892
- ],
1893
- )
1894
- elif "ToolFinderEmbedding" == tool_type:
1895
- new_tool = tool_class(tool_config=tool, tooluniverse=self)
1896
- elif "ComposeTool" == tool_type:
1897
- new_tool = tool_class(tool_config=tool, tooluniverse=self)
1898
- elif "ToolFinderLLM" == tool_type:
1899
- new_tool = tool_class(tool_config=tool, tooluniverse=self)
1900
- elif "ToolFinderKeyword" == tool_type:
1901
- new_tool = tool_class(tool_config=tool, tooluniverse=self)
1902
- else:
1903
- new_tool = tool_class(tool_config=tool)
1904
- if add_to_cache:
1905
- self.callable_functions[tool_name] = new_tool
1906
- return new_tool
1998
+ elif "ToolFinderEmbedding" == tool_type:
1999
+ new_tool = tool_class(tool_config=tool, tooluniverse=self)
2000
+ elif "ComposeTool" == tool_type:
2001
+ new_tool = tool_class(tool_config=tool, tooluniverse=self)
2002
+ elif "ToolFinderLLM" == tool_type:
2003
+ new_tool = tool_class(tool_config=tool, tooluniverse=self)
2004
+ elif "ToolFinderKeyword" == tool_type:
2005
+ new_tool = tool_class(tool_config=tool, tooluniverse=self)
2006
+ else:
2007
+ new_tool = tool_class(tool_config=tool)
2008
+
2009
+ if add_to_cache:
2010
+ self.callable_functions[tool_name] = new_tool
2011
+ return new_tool
2012
+
2013
+ except Exception as e:
2014
+ tool_type = tool_name if tool_name else tool.get("type")
2015
+ mark_tool_unavailable(tool_type, e)
2016
+ self.logger.warning(f"Failed to initialize '{tool_type}': {e}")
2017
+ return None # Return None instead of raising
2018
+
2019
+ def _get_tool_instance(self, function_name: str, cache: bool = True):
2020
+ """Get or create tool instance with optional caching."""
2021
+ # Check cache first
2022
+ if function_name in self.callable_functions:
2023
+ return self.callable_functions[function_name]
2024
+
2025
+ # Check if known unavailable
2026
+ tool_errors = get_tool_errors()
2027
+ if function_name in tool_errors:
2028
+ self.logger.debug(f"Tool {function_name} is unavailable")
2029
+ return None
2030
+
2031
+ # Try to initialize
2032
+ if function_name in self.all_tool_dict:
2033
+ return self.init_tool(self.all_tool_dict[function_name], add_to_cache=cache)
2034
+
2035
+ return None
2036
+
2037
+ def _make_cache_key(self, function_name: str, arguments: dict) -> str:
2038
+ """Generate cache key by delegating to BaseTool."""
2039
+ tool_instance = self._get_tool_instance(function_name, cache=False)
2040
+
2041
+ if tool_instance:
2042
+ return tool_instance.get_cache_key(arguments)
2043
+
2044
+ # Fallback: simple hash-based key
2045
+ serialized = json.dumps(
2046
+ {"name": function_name, "args": arguments}, sort_keys=True
2047
+ )
2048
+ return hashlib.md5(serialized.encode()).hexdigest()
2049
+
2050
+ def _validate_parameters(
2051
+ self, function_name: str, arguments: dict
2052
+ ) -> Optional[ToolError]:
2053
+ """Validate parameters by delegating to BaseTool."""
2054
+ if function_name not in self.all_tool_dict:
2055
+ return ToolUnavailableError(f"Tool '{function_name}' not found")
2056
+
2057
+ tool_instance = self._get_tool_instance(function_name, cache=False)
2058
+ if not tool_instance:
2059
+ return ToolConfigError("Failed to initialize tool for validation")
2060
+
2061
+ # Check if tool has validate_parameters method (for backward compatibility)
2062
+ if hasattr(tool_instance, "validate_parameters"):
2063
+ return tool_instance.validate_parameters(arguments)
2064
+ else:
2065
+ # Fallback for old-style tools without validate_parameters
2066
+ # Just return None (no validation) to maintain backward compatibility
2067
+ return None
2068
+
2069
+ def _check_basic_type(self, value: Any, expected_type: str) -> bool:
2070
+ """Check if value matches expected basic type."""
2071
+ type_mapping = {
2072
+ "string": str,
2073
+ "integer": int,
2074
+ "number": (int, float),
2075
+ "boolean": bool,
2076
+ "object": dict,
2077
+ "array": list,
2078
+ }
2079
+
2080
+ if expected_type not in type_mapping:
2081
+ return True # Unknown type, skip validation
2082
+
2083
+ expected_python_type = type_mapping[expected_type]
2084
+ return isinstance(value, expected_python_type)
2085
+
2086
+ def _classify_exception(
2087
+ self, exception: Exception, function_name: str, arguments: dict
2088
+ ) -> ToolError:
2089
+ """Classify exception by delegating to BaseTool."""
2090
+ tool_instance = self._get_tool_instance(function_name, cache=False)
2091
+
2092
+ if tool_instance:
2093
+ return tool_instance.handle_error(exception)
2094
+
2095
+ # Fallback for tool instance creation failure
2096
+ return ToolServerError(f"Unexpected error calling {function_name}: {exception}")
2097
+
2098
+ def _create_dual_format_error(self, error: ToolError) -> dict:
2099
+ """Create dual-format error response for backward compatibility."""
2100
+ return {
2101
+ "error": str(error), # Backward compatible string
2102
+ "error_details": error.to_dict(), # New structured format
2103
+ }
2104
+
2105
+ def refresh_tools(self):
2106
+ """Refresh tool discovery (re-discover MCP/remote tools, reload configs)."""
2107
+ # TODO: Implement MCP tool re-discovery
2108
+ # For now, just reload tool configurations
2109
+ self.logger.info("Refreshing tool configurations...")
2110
+ # This could be extended to re-discover MCP tools, reload configs, etc.
2111
+ self.logger.info("Tool refresh completed")
2112
+
2113
+ def eager_load_tools(self, names: Optional[List[str]] = None):
2114
+ """Pre-instantiate tools to reduce first-call latency."""
2115
+ tool_names = names or list(self.all_tool_dict.keys())
2116
+ self.logger.info(f"Eager loading {len(tool_names)} tools...")
2117
+
2118
+ for tool_name in tool_names:
2119
+ if (
2120
+ tool_name in self.all_tool_dict
2121
+ and tool_name not in self.callable_functions
2122
+ ):
2123
+ try:
2124
+ self.init_tool(self.all_tool_dict[tool_name], add_to_cache=True)
2125
+ self.logger.debug(f"Eager loaded: {tool_name}")
2126
+ except Exception as e:
2127
+ self.logger.warning(f"Failed to eager load {tool_name}: {e}")
2128
+
2129
+ self.logger.info(
2130
+ f"Eager loading completed. {len(self.callable_functions)} tools cached."
2131
+ )
2132
+
2133
+ def clear_cache(self):
2134
+ """Clear the result cache."""
2135
+ if self.cache_manager:
2136
+ self.cache_manager.clear()
2137
+ self.logger.info("Result cache cleared")
2138
+
2139
+ def get_cache_stats(self) -> Dict[str, Any]:
2140
+ """Return cache statistics."""
2141
+ if not self.cache_manager:
2142
+ return {"enabled": False}
2143
+ return self.cache_manager.stats()
2144
+
2145
+ def dump_cache(self, namespace: Optional[str] = None):
2146
+ """Iterate over cached entries (persistent layer only)."""
2147
+ if not self.cache_manager:
2148
+ return iter([])
2149
+ return self.cache_manager.dump(namespace=namespace)
2150
+
2151
+ def close(self):
2152
+ """Release resources."""
2153
+ if self.cache_manager:
2154
+ self.cache_manager.close()
2155
+
2156
+ def __del__(self):
2157
+ try:
2158
+ self.close()
2159
+ except Exception:
2160
+ pass
2161
+
2162
+ def get_tool_health(self, tool_name: str = None) -> dict:
2163
+ """Get health status for tool(s)."""
2164
+ tool_errors = get_tool_errors()
2165
+
2166
+ if tool_name:
2167
+ if tool_name in tool_errors:
2168
+ return tool_errors[tool_name]
2169
+ elif tool_name in self.all_tool_dict:
2170
+ return {"available": True}
2171
+ return {"available": False, "error": "Not found"}
2172
+
2173
+ # Summary for all tools
2174
+ return {
2175
+ "total": len(self.all_tool_dict),
2176
+ "available": len(self.all_tool_dict) - len(tool_errors),
2177
+ "unavailable": len(tool_errors),
2178
+ "unavailable_list": list(tool_errors.keys()),
2179
+ "details": tool_errors,
2180
+ }
1907
2181
 
1908
2182
  def check_function_call(self, fcall_str, function_config=None, format="llama"):
1909
2183
  """
@@ -1986,6 +2260,66 @@ class ToolUniverse:
1986
2260
  self.logger.error(f"Error exporting tool names to {output_file}: {e}")
1987
2261
  return []
1988
2262
 
2263
+ def filter_tools(
2264
+ self,
2265
+ include_tools=None,
2266
+ exclude_tools=None,
2267
+ include_tool_types=None,
2268
+ exclude_tool_types=None,
2269
+ ):
2270
+ """
2271
+ Filter tools based on inclusion/exclusion criteria.
2272
+
2273
+ Args:
2274
+ include_tools (set, optional): Set of tool names to include
2275
+ exclude_tools (set, optional): Set of tool names to exclude
2276
+ include_tool_types (set, optional): Set of tool types to include
2277
+ exclude_tool_types (set, optional): Set of tool types to exclude
2278
+
2279
+ Returns:
2280
+ list: Filtered list of tool configurations
2281
+ """
2282
+ if not hasattr(self, "all_tools") or not self.all_tools:
2283
+ self.logger.warning("No tools loaded. Call load_tools() first.")
2284
+ return []
2285
+
2286
+ filtered_tools = []
2287
+ for tool in self.all_tools:
2288
+ tool_name = tool.get("name", "")
2289
+ tool_type = tool.get("type", "")
2290
+
2291
+ # Check inclusion/exclusion criteria
2292
+ if include_tools and tool_name not in include_tools:
2293
+ continue
2294
+ if exclude_tools and tool_name in exclude_tools:
2295
+ continue
2296
+ if include_tool_types and tool_type not in include_tool_types:
2297
+ continue
2298
+ if exclude_tool_types and tool_type in exclude_tool_types:
2299
+ continue
2300
+
2301
+ filtered_tools.append(tool)
2302
+
2303
+ return filtered_tools
2304
+
2305
+ def get_required_parameters(self, tool_name):
2306
+ """
2307
+ Get required parameters for a specific tool.
2308
+
2309
+ Args:
2310
+ tool_name (str): Name of the tool
2311
+
2312
+ Returns:
2313
+ list: List of required parameter names
2314
+ """
2315
+ if tool_name not in self.all_tool_dict:
2316
+ self.logger.warning(f"Tool '{tool_name}' not found")
2317
+ return []
2318
+
2319
+ tool_config = self.all_tool_dict[tool_name]
2320
+ parameter_schema = tool_config.get("parameter", {})
2321
+ return parameter_schema.get("required", [])
2322
+
1989
2323
  def get_available_tools(self, category_filter=None, name_only=True):
1990
2324
  """
1991
2325
  Get available tools, optionally filtered by category.
@@ -2031,6 +2365,10 @@ class ToolUniverse:
2031
2365
  self.logger.warning("No tools loaded. Call load_tools() first.")
2032
2366
  return []
2033
2367
 
2368
+ # Handle None or empty pattern
2369
+ if pattern is None or pattern == "":
2370
+ return self.all_tools
2371
+
2034
2372
  import re
2035
2373
 
2036
2374
  flags = 0 if case_sensitive else re.IGNORECASE
@@ -2057,10 +2395,209 @@ class ToolUniverse:
2057
2395
  )
2058
2396
  return matching_tools
2059
2397
 
2398
+ # ============ DEPRECATED METHODS (Kept for backward compatibility) ============
2399
+ # These methods are deprecated and will be removed in v2.0. Use the recommended
2400
+ # alternatives instead. All methods below maintain backward compatibility but
2401
+ # issue deprecation warnings when called.
2402
+
2403
+ def get_tool_by_name(self, tool_names, format="default"):
2404
+ """
2405
+ Retrieve tool configurations by their names.
2406
+
2407
+ DEPRECATED: Use tool_specification() instead.
2408
+
2409
+ Args:
2410
+ tool_names (list): List of tool names to retrieve.
2411
+ format (str, optional): Output format. Options: 'default', 'openai'.
2412
+ If 'openai', returns OpenAI function calling format. Defaults to 'default'.
2413
+
2414
+ Returns:
2415
+ list: List of tool configurations for the specified names.
2416
+ Tools not found will be reported but not included in the result.
2417
+ """
2418
+ warnings.warn(
2419
+ "get_tool_by_name() is deprecated and will be removed in v2.0. "
2420
+ "Use tool_specification() instead.",
2421
+ DeprecationWarning,
2422
+ stacklevel=2,
2423
+ )
2424
+ return self.get_tool_specification_by_names(tool_names, format=format)
2425
+
2426
+ def get_tool_description(self, tool_name):
2427
+ """
2428
+ Get the description of a tool by its name.
2429
+
2430
+ DEPRECATED: Use tool_specification() instead.
2431
+
2432
+ Args:
2433
+ tool_name (str): Name of the tool.
2434
+
2435
+ Returns:
2436
+ dict or None: Tool configuration if found, None otherwise.
2437
+ """
2438
+ warnings.warn(
2439
+ "get_tool_description() is deprecated and will be removed in v2.0. "
2440
+ "Use tool_specification() instead.",
2441
+ DeprecationWarning,
2442
+ stacklevel=2,
2443
+ )
2444
+ return self.get_one_tool_by_one_name(tool_name)
2445
+
2446
+ def remove_keys(self, tool_list, invalid_keys):
2447
+ """
2448
+ Remove specified keys from a list of tool configurations.
2449
+
2450
+ DEPRECATED: Use prepare_tool_prompts(mode='custom', valid_keys=...) instead.
2451
+
2452
+ Args:
2453
+ tool_list (list): List of tool configuration dictionaries.
2454
+ invalid_keys (list): List of keys to remove from each tool configuration.
2455
+
2456
+ Returns:
2457
+ list: Deep copy of tool list with specified keys removed.
2458
+ """
2459
+ warnings.warn(
2460
+ "remove_keys() is deprecated and will be removed in v2.0. "
2461
+ "Use prepare_tool_prompts(mode='custom', valid_keys=...) instead.",
2462
+ DeprecationWarning,
2463
+ stacklevel=2,
2464
+ )
2465
+ copied_list = copy.deepcopy(tool_list)
2466
+ for tool in copied_list:
2467
+ # Create a list of keys to avoid modifying the dictionary during iteration
2468
+ for key in list(tool.keys()):
2469
+ if key in invalid_keys:
2470
+ del tool[key]
2471
+ return copied_list
2472
+
2473
+ def prepare_tool_examples(self, tool_list):
2474
+ """
2475
+ Prepare tool configurations for example usage by keeping extended set of keys.
2476
+
2477
+ DEPRECATED: Use prepare_tool_prompts(mode='example') instead.
2478
+
2479
+ Args:
2480
+ tool_list (list): List of tool configuration dictionaries.
2481
+
2482
+ Returns:
2483
+ list: Deep copy of tool list with only example-relevant keys.
2484
+ """
2485
+ warnings.warn(
2486
+ "prepare_tool_examples() is deprecated and will be removed in v2.0. "
2487
+ "Use prepare_tool_prompts(mode='example') instead.",
2488
+ DeprecationWarning,
2489
+ stacklevel=2,
2490
+ )
2491
+ return self.prepare_tool_prompts(tool_list, mode="example")
2492
+
2493
+ def select_tools(
2494
+ self,
2495
+ include_names=None,
2496
+ exclude_names=None,
2497
+ include_categories=None,
2498
+ exclude_categories=None,
2499
+ ):
2500
+ """
2501
+ Select tools based on tool names and/or categories (tool_files keys).
2502
+
2503
+ DEPRECATED: Use filter_tools() instead.
2504
+
2505
+ Args:
2506
+ include_names (list, optional): List of tool names to include. If None, include all.
2507
+ exclude_names (list, optional): List of tool names to exclude.
2508
+ include_categories (list, optional): List of categories (tool_files keys) to include.
2509
+ If None, include all.
2510
+ exclude_categories (list, optional): List of categories (tool_files keys) to exclude.
2511
+
2512
+ Returns:
2513
+ list: List of selected tool configurations.
2514
+ """
2515
+ warnings.warn(
2516
+ "select_tools() is deprecated and will be removed in v2.0. "
2517
+ "Use filter_tools() instead.",
2518
+ DeprecationWarning,
2519
+ stacklevel=2,
2520
+ )
2521
+ selected_tools = []
2522
+ # If categories are specified, use self.tool_category_dicts to filter
2523
+ categories = set(self.tool_category_dicts.keys())
2524
+ if include_categories is not None:
2525
+ categories &= set(include_categories)
2526
+ if exclude_categories is not None:
2527
+ categories -= set(exclude_categories)
2528
+ # Gather tools from selected categories
2529
+ for cat in categories:
2530
+ selected_tools.extend(self.tool_category_dicts[cat])
2531
+ # Further filter by names if needed
2532
+ if include_names is not None:
2533
+ selected_tools = [
2534
+ tool for tool in selected_tools if tool["name"] in include_names
2535
+ ]
2536
+ if exclude_names is not None:
2537
+ selected_tools = [
2538
+ tool for tool in selected_tools if tool["name"] not in exclude_names
2539
+ ]
2540
+ return selected_tools
2541
+
2542
+ def filter_tool_lists(
2543
+ self,
2544
+ tool_name_list,
2545
+ tool_desc_list,
2546
+ include_names=None,
2547
+ exclude_names=None,
2548
+ include_categories=None,
2549
+ exclude_categories=None,
2550
+ ):
2551
+ """
2552
+ Directly filter tool name and description lists based on names and/or categories.
2553
+
2554
+ DEPRECATED: Use filter_tools() and manual list filtering instead.
2555
+
2556
+ Args:
2557
+ tool_name_list (list): List of tool names to filter.
2558
+ tool_desc_list (list): List of tool descriptions to filter (must correspond to tool_name_list).
2559
+ include_names (list, optional): List of tool names to include.
2560
+ exclude_names (list, optional): List of tool names to exclude.
2561
+ include_categories (list, optional): List of categories to include.
2562
+ exclude_categories (list, optional): List of categories to exclude.
2563
+
2564
+ Returns:
2565
+ tuple: A tuple containing (filtered_tool_name_list, filtered_tool_desc_list).
2566
+ """
2567
+ warnings.warn(
2568
+ "filter_tool_lists() is deprecated and will be removed in v2.0. "
2569
+ "Use filter_tools() and manual list filtering instead.",
2570
+ DeprecationWarning,
2571
+ stacklevel=2,
2572
+ )
2573
+ # Build a set of allowed tool names using select_tools for category filtering
2574
+ allowed_names = set()
2575
+ if any([include_names, exclude_names, include_categories, exclude_categories]):
2576
+ filtered_tools = self.select_tools(
2577
+ include_names=include_names,
2578
+ exclude_names=exclude_names,
2579
+ include_categories=include_categories,
2580
+ exclude_categories=exclude_categories,
2581
+ )
2582
+ allowed_names = set(tool["name"] for tool in filtered_tools)
2583
+ else:
2584
+ allowed_names = set(tool_name_list)
2585
+
2586
+ # Filter lists by allowed_names
2587
+ filtered_tool_name_list = []
2588
+ filtered_tool_desc_list = []
2589
+ for name, desc in zip(tool_name_list, tool_desc_list):
2590
+ if name in allowed_names:
2591
+ filtered_tool_name_list.append(name)
2592
+ filtered_tool_desc_list.append(desc)
2593
+ return filtered_tool_name_list, filtered_tool_desc_list
2594
+
2060
2595
  def load_tools_from_names_list(self, tool_names, clear_existing=True):
2061
2596
  """
2062
2597
  Load only specific tools by their names.
2063
2598
 
2599
+ DEPRECATED: Use load_tools(include_tools=...) instead.
2600
+
2064
2601
  Args:
2065
2602
  tool_names (list): List of tool names to load
2066
2603
  clear_existing (bool): Whether to clear existing tools first
@@ -2068,6 +2605,12 @@ class ToolUniverse:
2068
2605
  Returns:
2069
2606
  int: Number of tools successfully loaded
2070
2607
  """
2608
+ warnings.warn(
2609
+ "load_tools_from_names_list() is deprecated and will be removed in v2.0. "
2610
+ "Use load_tools(include_tools=...) instead.",
2611
+ DeprecationWarning,
2612
+ stacklevel=2,
2613
+ )
2071
2614
  if clear_existing:
2072
2615
  self.all_tools = []
2073
2616
  self.all_tool_dict = {}