tooluniverse 1.0.2__tar.gz → 1.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tooluniverse might be problematic. Click here for more details.
- {tooluniverse-1.0.2/src/tooluniverse.egg-info → tooluniverse-1.0.4}/PKG-INFO +7 -6
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/README.md +5 -5
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/pyproject.toml +2 -1
- tooluniverse-1.0.4/src/tooluniverse/agentic_tool.py +495 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/output_summarizer.py +21 -15
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/tool_metadata_generator.py +6 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/agentic_tools.json +1 -1
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/output_summarization_tools.json +2 -2
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/execute_function.py +185 -70
- tooluniverse-1.0.4/src/tooluniverse/llm_clients.py +369 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/output_hook.py +92 -3
- tooluniverse-1.0.4/src/tooluniverse/scripts/filter_tool_files.py +194 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/smcp_server.py +19 -13
- tooluniverse-1.0.4/src/tooluniverse/test/list_azure_openai_models.py +210 -0
- tooluniverse-1.0.4/src/tooluniverse/test/test_agentic_tool_azure_models.py +91 -0
- tooluniverse-1.0.4/src/tooluniverse/test/test_api_key_validation_min.py +64 -0
- tooluniverse-1.0.4/src/tooluniverse/test/test_global_fallback.py +288 -0
- tooluniverse-1.0.4/src/tooluniverse/test/test_hooks_direct.py +219 -0
- tooluniverse-1.0.4/src/tooluniverse/test/test_list_built_in_tools.py +33 -0
- tooluniverse-1.0.4/src/tooluniverse/test/test_stdio_hooks.py +285 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4/src/tooluniverse.egg-info}/PKG-INFO +7 -6
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse.egg-info/SOURCES.txt +9 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse.egg-info/requires.txt +1 -0
- tooluniverse-1.0.2/src/tooluniverse/agentic_tool.py +0 -563
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/LICENSE +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/setup.cfg +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/__init__.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/admetai_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/alphafold_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/base_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/boltz_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/chem_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/__init__.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/biomarker_discovery.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/comprehensive_drug_discovery.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/drug_safety_analyzer.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/literature_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/tool_description_optimizer.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/tool_discover.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/tool_graph_composer.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/tool_graph_generation.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/ctg_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/custom_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/dailymed_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/__init__.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/admetai_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/adverse_event_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/alphafold_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/boltz_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/chembl_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/clinicaltrials_gov_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/compose_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/dailymed_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/dataset_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/disease_target_score_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/efo_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/embedding_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/enrichr_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/europe_pmc_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/expert_feedback_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/fda_drug_adverse_event_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/fda_drug_labeling_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/fda_drugs_with_brand_generic_names_for_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/finder_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/gene_ontology_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/gwas_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/hpa_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/humanbase_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/idmap_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/mcp_client_tools_example.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/mcpautoloadertool_defaults.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/medlineplus_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/monarch_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/openalex_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/opentarget_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/bioinformatics_core_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/categorized_tools.txt +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/cheminformatics_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/earth_sciences_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/genomics_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/image_processing_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/machine_learning_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/neuroscience_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/original_tools.txt +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/physics_astronomy_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/scientific_computing_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/single_cell_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/structural_biology_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/packages/visualization_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/pubchem_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/pubtator_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/rcsb_pdb_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/reactome_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/semantic_scholar_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/special_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/tool_composition_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/toolfinderkeyword_defaults.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/txagent_client_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/uniprot_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/url_fetch_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/uspto_downloader_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/uspto_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/data/xml_tools.json +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/dataset_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/default_config.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/efo_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/embedding_database.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/embedding_sync.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/enrichr_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/europe_pmc_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/extended_hooks.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/gene_ontology_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/graphql_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/gwas_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/hpa_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/humanbase_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/logging_config.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/mcp_client_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/mcp_integration.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/mcp_tool_registry.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/medlineplus_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/openalex_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/openfda_adv_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/openfda_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/package_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/pubchem_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/pubtator_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/rcsb_pdb_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/reactome_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/boltz/boltz_mcp_server.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/depmap_24q2/depmap_24q2_mcp_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/expert_feedback/human_expert_mcp_tools.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/expert_feedback/simple_test.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/expert_feedback/start_web_interface.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/expert_feedback/web_only_interface.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/immune_compass/compass_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/pinnacle/pinnacle_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/transcriptformer/transcriptformer_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/uspto_downloader/uspto_downloader_mcp_server.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote/uspto_downloader/uspto_downloader_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/remote_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/restful_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/scripts/generate_tool_graph.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/scripts/visualize_tool_graph.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/semantic_scholar_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/smcp.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/mcp_server_test.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_admetai_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_agentic_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_alphafold_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_chem_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_compose_lieraturereview.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_compose_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_dailymed.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_dataset_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_disease_target_score.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_drugbank_filter_examples.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_efo.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_enrichr_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_europe_pmc_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_fda_adv.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_fda_drug_labeling.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_gene_ontology_tools.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_gwas_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_hpa.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_humanbase_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_idmap_tools.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_mcp_server.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_mcp_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_medlineplus.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_openalex_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_opentargets.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_pubchem_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_pubtator_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_rcsb_pdb_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_reactome.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_semantic_scholar_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_software_tools.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_tool_description_optimizer.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_tool_finder.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_tool_finder_llm.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_tools_find.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_uniprot_tools.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_uspto_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/test/test_xml_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/tool_finder_embedding.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/tool_finder_keyword.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/tool_finder_llm.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/tool_graph_web_ui.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/tool_registry.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/uniprot_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/url_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/uspto_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/utils.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/xml_tool.py +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse.egg-info/dependency_links.txt +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse.egg-info/entry_points.txt +0 -0
- {tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tooluniverse
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: A comprehensive collection of scientific tools for Agentic AI, offering integration with the ToolUniverse SDK and MCP Server to support advanced scientific workflows.
|
|
5
5
|
Author-email: Shanghua Gao <shanghuagao@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/mims-harvard/TxAgent
|
|
@@ -18,6 +18,7 @@ Requires-Dist: networkx>=3.4.0
|
|
|
18
18
|
Requires-Dist: openai>=1.107.0
|
|
19
19
|
Requires-Dist: pyyaml>=6.0.0
|
|
20
20
|
Requires-Dist: google-genai>=1.36.0
|
|
21
|
+
Requires-Dist: google-generativeai>=0.7.2
|
|
21
22
|
Requires-Dist: mcp[cli]>=1.9.3
|
|
22
23
|
Requires-Dist: fastmcp>=2.12.0
|
|
23
24
|
Requires-Dist: xmltodict>=1.0.0
|
|
@@ -63,7 +64,7 @@ Provides-Extra: all
|
|
|
63
64
|
Requires-Dist: tooluniverse[dev,docs,graph]; extra == "all"
|
|
64
65
|
Dynamic: license-file
|
|
65
66
|
|
|
66
|
-
# ToolUniverse: Democratizing AI scientists
|
|
67
|
+
# <img src="docs/_static/logo.png" alt="ToolUniverse Logo" height="28" style="vertical-align: middle; margin-right: 8px;" /> ToolUniverse: Democratizing AI scientists
|
|
67
68
|
|
|
68
69
|
[](https://pypi.org/project/tooluniverse/)
|
|
69
70
|
[](https://github.com/mims-harvard/ToolUniverse)
|
|
@@ -96,7 +97,7 @@ ToolUniverse is an ecosystem for creating AI scientist systems from any open or
|
|
|
96
97
|
|
|
97
98
|
|
|
98
99
|
## 🤖 Building AI Scientists with ToolUniverse in 5 minutes
|
|
99
|
-
- **[Overview](https://zitniklab.hms.harvard.edu/bioagent/guide/building_ai_scientists/index.html)**: Create AI
|
|
100
|
+
- **[Overview](https://zitniklab.hms.harvard.edu/bioagent/guide/building_ai_scientists/index.html)**: Create AI scientists from any LLM
|
|
100
101
|
- **[Claude Desktop Integration](https://zitniklab.hms.harvard.edu/bioagent/guide/building_ai_scientists/claude_desktop.html)**: Native MCP integration with Claude Desktop App
|
|
101
102
|
- **[Claude Code Integration](https://zitniklab.hms.harvard.edu/bioagent/guide/building_ai_scientists/claude_code.html)**: AI scientist development in Claude Code environment
|
|
102
103
|
- **[Gemini CLI Integration](https://zitniklab.hms.harvard.edu/bioagent/guide/building_ai_scientists/gemini_cli.html)**: Command-line scientific research with Google Gemini
|
|
@@ -109,7 +110,7 @@ ToolUniverse is an ecosystem for creating AI scientist systems from any open or
|
|
|
109
110
|
|
|
110
111
|
AI scientists are emerging computational systems that serve as collaborative partners in discovery. However, these systems remain difficult to build because they are bespoke, tied to rigid workflows, and lack shared environments that unify tools, data, and analysts into a common ecosystem.
|
|
111
112
|
|
|
112
|
-
ToolUniverse addresses this challenge by providing a standardized ecosystem that transforms any AI model into a powerful research scientist. By abstracting capabilities behind a unified interface, ToolUniverse wraps around any AI model (LLM, AI agent, or large reasoning model) and enables users to create and refine entirely custom AI
|
|
113
|
+
ToolUniverse addresses this challenge by providing a standardized ecosystem that transforms any AI model into a powerful research scientist. By abstracting capabilities behind a unified interface, ToolUniverse wraps around any AI model (LLM, AI agent, or large reasoning model) and enables users to create and refine entirely custom AI scientists without additional training or finetuning.
|
|
113
114
|
|
|
114
115
|
**Key Features:**
|
|
115
116
|
|
|
@@ -212,7 +213,7 @@ tooluniverse-smcp
|
|
|
212
213
|
|
|
213
214
|
|
|
214
215
|
---
|
|
215
|
-
**Hypercholesterolemia Drug Discovery** [[Tutorial]](
|
|
216
|
+
**Hypercholesterolemia Drug Discovery** [[Tutorial]](https://zitniklab.hms.harvard.edu/bioagent/tutorials/tooluniverse_case_study.html) [[Code]](https://colab.research.google.com/drive/1UwJ6RwyUoqI5risKQ365EeFdDQWOeOCv?usp=sharing)
|
|
216
217
|
|
|
217
218
|
---
|
|
218
219
|
|
|
@@ -316,4 +317,4 @@ ToolUniverse is developed by the [Zitnik Lab](https://zitniklab.hms.harvard.edu/
|
|
|
316
317
|
|
|
317
318
|
---
|
|
318
319
|
|
|
319
|
-
*Democratizing AI agents for science
|
|
320
|
+
*Democratizing AI agents for science with ToolUniverse.*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ToolUniverse: Democratizing AI scientists
|
|
1
|
+
# <img src="docs/_static/logo.png" alt="ToolUniverse Logo" height="28" style="vertical-align: middle; margin-right: 8px;" /> ToolUniverse: Democratizing AI scientists
|
|
2
2
|
|
|
3
3
|
[](https://pypi.org/project/tooluniverse/)
|
|
4
4
|
[](https://github.com/mims-harvard/ToolUniverse)
|
|
@@ -31,7 +31,7 @@ ToolUniverse is an ecosystem for creating AI scientist systems from any open or
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
## 🤖 Building AI Scientists with ToolUniverse in 5 minutes
|
|
34
|
-
- **[Overview](https://zitniklab.hms.harvard.edu/bioagent/guide/building_ai_scientists/index.html)**: Create AI
|
|
34
|
+
- **[Overview](https://zitniklab.hms.harvard.edu/bioagent/guide/building_ai_scientists/index.html)**: Create AI scientists from any LLM
|
|
35
35
|
- **[Claude Desktop Integration](https://zitniklab.hms.harvard.edu/bioagent/guide/building_ai_scientists/claude_desktop.html)**: Native MCP integration with Claude Desktop App
|
|
36
36
|
- **[Claude Code Integration](https://zitniklab.hms.harvard.edu/bioagent/guide/building_ai_scientists/claude_code.html)**: AI scientist development in Claude Code environment
|
|
37
37
|
- **[Gemini CLI Integration](https://zitniklab.hms.harvard.edu/bioagent/guide/building_ai_scientists/gemini_cli.html)**: Command-line scientific research with Google Gemini
|
|
@@ -44,7 +44,7 @@ ToolUniverse is an ecosystem for creating AI scientist systems from any open or
|
|
|
44
44
|
|
|
45
45
|
AI scientists are emerging computational systems that serve as collaborative partners in discovery. However, these systems remain difficult to build because they are bespoke, tied to rigid workflows, and lack shared environments that unify tools, data, and analysts into a common ecosystem.
|
|
46
46
|
|
|
47
|
-
ToolUniverse addresses this challenge by providing a standardized ecosystem that transforms any AI model into a powerful research scientist. By abstracting capabilities behind a unified interface, ToolUniverse wraps around any AI model (LLM, AI agent, or large reasoning model) and enables users to create and refine entirely custom AI
|
|
47
|
+
ToolUniverse addresses this challenge by providing a standardized ecosystem that transforms any AI model into a powerful research scientist. By abstracting capabilities behind a unified interface, ToolUniverse wraps around any AI model (LLM, AI agent, or large reasoning model) and enables users to create and refine entirely custom AI scientists without additional training or finetuning.
|
|
48
48
|
|
|
49
49
|
**Key Features:**
|
|
50
50
|
|
|
@@ -147,7 +147,7 @@ tooluniverse-smcp
|
|
|
147
147
|
|
|
148
148
|
|
|
149
149
|
---
|
|
150
|
-
**Hypercholesterolemia Drug Discovery** [[Tutorial]](
|
|
150
|
+
**Hypercholesterolemia Drug Discovery** [[Tutorial]](https://zitniklab.hms.harvard.edu/bioagent/tutorials/tooluniverse_case_study.html) [[Code]](https://colab.research.google.com/drive/1UwJ6RwyUoqI5risKQ365EeFdDQWOeOCv?usp=sharing)
|
|
151
151
|
|
|
152
152
|
---
|
|
153
153
|
|
|
@@ -251,4 +251,4 @@ ToolUniverse is developed by the [Zitnik Lab](https://zitniklab.hms.harvard.edu/
|
|
|
251
251
|
|
|
252
252
|
---
|
|
253
253
|
|
|
254
|
-
*Democratizing AI agents for science
|
|
254
|
+
*Democratizing AI agents for science with ToolUniverse.*
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tooluniverse"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.4"
|
|
8
8
|
description = "A comprehensive collection of scientific tools for Agentic AI, offering integration with the ToolUniverse SDK and MCP Server to support advanced scientific workflows."
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Shanghua Gao", email = "shanghuagao@gmail.com" }
|
|
@@ -21,6 +21,7 @@ dependencies = [
|
|
|
21
21
|
"openai>=1.107.0",
|
|
22
22
|
"pyyaml>=6.0.0",
|
|
23
23
|
"google-genai>=1.36.0",
|
|
24
|
+
"google-generativeai>=0.7.2",
|
|
24
25
|
"mcp[cli]>=1.9.3",
|
|
25
26
|
"fastmcp>=2.12.0",
|
|
26
27
|
"xmltodict>=1.0.0",
|
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import Any, Dict, List, Optional
|
|
7
|
+
|
|
8
|
+
from .base_tool import BaseTool
|
|
9
|
+
from .tool_registry import register_tool
|
|
10
|
+
from .logging_config import get_logger
|
|
11
|
+
from .llm_clients import AzureOpenAIClient, GeminiClient
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Global default fallback configuration
|
|
15
|
+
DEFAULT_FALLBACK_CHAIN = [
|
|
16
|
+
{"api_type": "CHATGPT", "model_id": "gpt-4o-1120"},
|
|
17
|
+
{"api_type": "GEMINI", "model_id": "gemini-2.0-flash"},
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
# API key environment variable mapping
|
|
21
|
+
API_KEY_ENV_VARS = {
|
|
22
|
+
"CHATGPT": ["AZURE_OPENAI_API_KEY", "AZURE_OPENAI_ENDPOINT"],
|
|
23
|
+
"GEMINI": ["GEMINI_API_KEY"],
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@register_tool("AgenticTool")
|
|
28
|
+
class AgenticTool(BaseTool):
|
|
29
|
+
"""Generic wrapper around LLM prompting supporting JSON-defined configs with prompts and input arguments."""
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def has_any_api_keys() -> bool:
|
|
33
|
+
"""
|
|
34
|
+
Check if any API keys are available across all supported API types.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
bool: True if at least one API type has all required keys, False otherwise
|
|
38
|
+
"""
|
|
39
|
+
for _api_type, required_vars in API_KEY_ENV_VARS.items():
|
|
40
|
+
all_keys_present = True
|
|
41
|
+
for var in required_vars:
|
|
42
|
+
if not os.getenv(var):
|
|
43
|
+
all_keys_present = False
|
|
44
|
+
break
|
|
45
|
+
if all_keys_present:
|
|
46
|
+
return True
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
def __init__(self, tool_config: Dict[str, Any]):
|
|
50
|
+
super().__init__(tool_config)
|
|
51
|
+
self.logger = get_logger("AgenticTool")
|
|
52
|
+
self.name: str = tool_config.get("name", "")
|
|
53
|
+
self._prompt_template: str = tool_config.get("prompt", "")
|
|
54
|
+
self._input_arguments: List[str] = tool_config.get("input_arguments", [])
|
|
55
|
+
|
|
56
|
+
# Extract required arguments from parameter schema
|
|
57
|
+
parameter_info = tool_config.get("parameter", {})
|
|
58
|
+
self._required_arguments: List[str] = parameter_info.get("required", [])
|
|
59
|
+
self._argument_defaults: Dict[str, str] = {}
|
|
60
|
+
|
|
61
|
+
# Set up default values for optional arguments
|
|
62
|
+
properties = parameter_info.get("properties", {})
|
|
63
|
+
for arg in self._input_arguments:
|
|
64
|
+
if arg not in self._required_arguments:
|
|
65
|
+
prop_info = properties.get(arg, {})
|
|
66
|
+
if "default" in prop_info:
|
|
67
|
+
self._argument_defaults[arg] = prop_info["default"]
|
|
68
|
+
|
|
69
|
+
# Get configuration from nested 'configs' dict or fallback to top-level
|
|
70
|
+
configs = tool_config.get("configs", {})
|
|
71
|
+
|
|
72
|
+
# Helper function to get config values with fallback
|
|
73
|
+
def get_config(key: str, default: Any) -> Any:
|
|
74
|
+
return configs.get(key, tool_config.get(key, default))
|
|
75
|
+
|
|
76
|
+
# LLM configuration
|
|
77
|
+
self._api_type: str = get_config("api_type", "CHATGPT")
|
|
78
|
+
self._model_id: str = get_config("model_id", "o1-mini")
|
|
79
|
+
self._temperature: Optional[float] = get_config("temperature", 0.1)
|
|
80
|
+
# Ignore configured max_new_tokens; client will resolve per model/env
|
|
81
|
+
self._max_new_tokens: Optional[int] = None
|
|
82
|
+
self._return_json: bool = get_config("return_json", False)
|
|
83
|
+
self._max_retries: int = get_config("max_retries", 5)
|
|
84
|
+
self._retry_delay: int = get_config("retry_delay", 5)
|
|
85
|
+
self.return_metadata: bool = get_config("return_metadata", True)
|
|
86
|
+
self._validate_api_key: bool = get_config("validate_api_key", True)
|
|
87
|
+
|
|
88
|
+
# API fallback configuration
|
|
89
|
+
self._fallback_api_type: Optional[str] = get_config("fallback_api_type", None)
|
|
90
|
+
self._fallback_model_id: Optional[str] = get_config("fallback_model_id", None)
|
|
91
|
+
|
|
92
|
+
# Global fallback configuration
|
|
93
|
+
self._use_global_fallback: bool = get_config("use_global_fallback", True)
|
|
94
|
+
self._global_fallback_chain: List[Dict[str, str]] = (
|
|
95
|
+
self._get_global_fallback_chain()
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Gemini model configuration (optional; env override)
|
|
99
|
+
self._gemini_model_id: str = get_config(
|
|
100
|
+
"gemini_model_id",
|
|
101
|
+
__import__("os").getenv("GEMINI_MODEL_ID", "gemini-2.0-flash"),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Validation
|
|
105
|
+
if not self._prompt_template:
|
|
106
|
+
raise ValueError("AgenticTool requires a 'prompt' in the configuration.")
|
|
107
|
+
if not self._input_arguments:
|
|
108
|
+
raise ValueError(
|
|
109
|
+
"AgenticTool requires 'input_arguments' in the configuration."
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Validate temperature range (skip if None)
|
|
113
|
+
if (
|
|
114
|
+
isinstance(self._temperature, (int, float))
|
|
115
|
+
and not 0 <= self._temperature <= 2
|
|
116
|
+
):
|
|
117
|
+
self.logger.warning(
|
|
118
|
+
f"Temperature {self._temperature} is outside recommended range [0, 2]"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Validate model compatibility
|
|
122
|
+
self._validate_model_config()
|
|
123
|
+
|
|
124
|
+
# Initialize the provider client
|
|
125
|
+
self._llm_client = None
|
|
126
|
+
self._initialization_error = None
|
|
127
|
+
self._is_available = False
|
|
128
|
+
self._current_api_type = None
|
|
129
|
+
self._current_model_id = None
|
|
130
|
+
|
|
131
|
+
# Try primary API first, then fallback if configured
|
|
132
|
+
self._try_initialize_api()
|
|
133
|
+
|
|
134
|
+
def _get_global_fallback_chain(self) -> List[Dict[str, str]]:
|
|
135
|
+
"""Get the global fallback chain from environment or use default."""
|
|
136
|
+
# Check environment variable for custom fallback chain
|
|
137
|
+
env_chain = os.getenv("AGENTIC_TOOL_FALLBACK_CHAIN")
|
|
138
|
+
if env_chain:
|
|
139
|
+
try:
|
|
140
|
+
chain = json.loads(env_chain)
|
|
141
|
+
if isinstance(chain, list) and all(
|
|
142
|
+
isinstance(item, dict) and "api_type" in item and "model_id" in item
|
|
143
|
+
for item in chain
|
|
144
|
+
):
|
|
145
|
+
return chain
|
|
146
|
+
else:
|
|
147
|
+
self.logger.warning(
|
|
148
|
+
"Invalid fallback chain format in environment variable"
|
|
149
|
+
)
|
|
150
|
+
except json.JSONDecodeError:
|
|
151
|
+
self.logger.warning(
|
|
152
|
+
"Invalid JSON in AGENTIC_TOOL_FALLBACK_CHAIN environment variable"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return DEFAULT_FALLBACK_CHAIN.copy()
|
|
156
|
+
|
|
157
|
+
def _try_initialize_api(self):
|
|
158
|
+
"""Try to initialize the primary API, fallback to secondary if configured."""
|
|
159
|
+
# Try primary API first
|
|
160
|
+
if self._try_api(self._api_type, self._model_id):
|
|
161
|
+
return
|
|
162
|
+
|
|
163
|
+
# Try explicit fallback API if configured
|
|
164
|
+
if self._fallback_api_type and self._fallback_model_id:
|
|
165
|
+
self.logger.info(
|
|
166
|
+
f"Primary API {self._api_type} failed, trying explicit fallback {self._fallback_api_type}"
|
|
167
|
+
)
|
|
168
|
+
if self._try_api(self._fallback_api_type, self._fallback_model_id):
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
# Try global fallback chain if enabled
|
|
172
|
+
if self._use_global_fallback:
|
|
173
|
+
self.logger.info(
|
|
174
|
+
f"Primary API {self._api_type} failed, trying global fallback chain"
|
|
175
|
+
)
|
|
176
|
+
for fallback_config in self._global_fallback_chain:
|
|
177
|
+
fallback_api = fallback_config["api_type"]
|
|
178
|
+
fallback_model = fallback_config["model_id"]
|
|
179
|
+
|
|
180
|
+
# Skip if it's the same as primary or explicit fallback
|
|
181
|
+
if (
|
|
182
|
+
fallback_api == self._api_type and fallback_model == self._model_id
|
|
183
|
+
) or (
|
|
184
|
+
fallback_api == self._fallback_api_type
|
|
185
|
+
and fallback_model == self._fallback_model_id
|
|
186
|
+
):
|
|
187
|
+
continue
|
|
188
|
+
|
|
189
|
+
self.logger.info(
|
|
190
|
+
f"Trying global fallback: {fallback_api} ({fallback_model})"
|
|
191
|
+
)
|
|
192
|
+
if self._try_api(fallback_api, fallback_model):
|
|
193
|
+
return
|
|
194
|
+
|
|
195
|
+
# If we get here, all APIs failed
|
|
196
|
+
self.logger.warning(
|
|
197
|
+
f"Tool '{self.name}' failed to initialize with all available APIs"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
def _try_api(self, api_type: str, model_id: str) -> bool:
|
|
201
|
+
"""Try to initialize a specific API and model."""
|
|
202
|
+
try:
|
|
203
|
+
if api_type == "CHATGPT":
|
|
204
|
+
self._llm_client = AzureOpenAIClient(model_id, None, self.logger)
|
|
205
|
+
elif api_type == "GEMINI":
|
|
206
|
+
self._llm_client = GeminiClient(model_id, self.logger)
|
|
207
|
+
else:
|
|
208
|
+
raise ValueError(f"Unsupported API type: {api_type}")
|
|
209
|
+
|
|
210
|
+
# Test API key validity after initialization (if enabled)
|
|
211
|
+
if self._validate_api_key:
|
|
212
|
+
self._llm_client.test_api()
|
|
213
|
+
self.logger.debug(
|
|
214
|
+
f"Successfully initialized {api_type} model: {model_id}"
|
|
215
|
+
)
|
|
216
|
+
else:
|
|
217
|
+
self.logger.info("API key validation skipped (validate_api_key=False)")
|
|
218
|
+
|
|
219
|
+
self._is_available = True
|
|
220
|
+
self._current_api_type = api_type
|
|
221
|
+
self._current_model_id = model_id
|
|
222
|
+
self._initialization_error = None
|
|
223
|
+
|
|
224
|
+
if api_type != self._api_type or model_id != self._model_id:
|
|
225
|
+
self.logger.info(
|
|
226
|
+
f"Using fallback API: {api_type} with model {model_id} "
|
|
227
|
+
f"(originally configured: {self._api_type} with {self._model_id})"
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
return True
|
|
231
|
+
|
|
232
|
+
except Exception as e:
|
|
233
|
+
error_msg = f"Failed to initialize {api_type} model {model_id}: {str(e)}"
|
|
234
|
+
self.logger.warning(error_msg)
|
|
235
|
+
self._initialization_error = error_msg
|
|
236
|
+
return False
|
|
237
|
+
|
|
238
|
+
# ------------------------------------------------------------------ LLM utilities -----------
|
|
239
|
+
def _validate_model_config(self):
|
|
240
|
+
supported_api_types = ["CHATGPT", "GEMINI"]
|
|
241
|
+
if self._api_type not in supported_api_types:
|
|
242
|
+
raise ValueError(
|
|
243
|
+
f"Unsupported API type: {self._api_type}. Supported types: {supported_api_types}"
|
|
244
|
+
)
|
|
245
|
+
if self._max_new_tokens is not None and self._max_new_tokens <= 0:
|
|
246
|
+
raise ValueError("max_new_tokens must be positive or None")
|
|
247
|
+
|
|
248
|
+
# ------------------------------------------------------------------ public API --------------
|
|
249
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
250
|
+
start_time = datetime.now()
|
|
251
|
+
|
|
252
|
+
# Check if tool is available before attempting to run
|
|
253
|
+
if not self._is_available:
|
|
254
|
+
error_msg = f"Tool '{self.name}' is not available due to initialization error: {self._initialization_error}"
|
|
255
|
+
self.logger.error(error_msg)
|
|
256
|
+
if self.return_metadata:
|
|
257
|
+
return {
|
|
258
|
+
"success": False,
|
|
259
|
+
"error": error_msg,
|
|
260
|
+
"error_type": "ToolUnavailable",
|
|
261
|
+
"metadata": {
|
|
262
|
+
"prompt_used": "Tool unavailable",
|
|
263
|
+
"input_arguments": {
|
|
264
|
+
arg: arguments.get(arg) for arg in self._input_arguments
|
|
265
|
+
},
|
|
266
|
+
"model_info": {
|
|
267
|
+
"api_type": self._api_type,
|
|
268
|
+
"model_id": self._model_id,
|
|
269
|
+
},
|
|
270
|
+
"execution_time_seconds": 0,
|
|
271
|
+
"timestamp": start_time.isoformat(),
|
|
272
|
+
},
|
|
273
|
+
}
|
|
274
|
+
else:
|
|
275
|
+
return f"error: {error_msg} error_type: ToolUnavailable"
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
# Validate required args
|
|
279
|
+
missing_required_args = [
|
|
280
|
+
arg for arg in self._required_arguments if arg not in arguments
|
|
281
|
+
]
|
|
282
|
+
if missing_required_args:
|
|
283
|
+
raise ValueError(
|
|
284
|
+
f"Missing required input arguments: {missing_required_args}"
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
# Fill defaults for optional args
|
|
288
|
+
for arg in self._input_arguments:
|
|
289
|
+
if arg not in arguments:
|
|
290
|
+
arguments[arg] = self._argument_defaults.get(arg, "")
|
|
291
|
+
|
|
292
|
+
self._validate_arguments(arguments)
|
|
293
|
+
formatted_prompt = self._format_prompt(arguments)
|
|
294
|
+
|
|
295
|
+
messages = [{"role": "user", "content": formatted_prompt}]
|
|
296
|
+
custom_format = arguments.get("response_format", None)
|
|
297
|
+
|
|
298
|
+
# Delegate to client; client handles provider-specific logic
|
|
299
|
+
response = self._llm_client.infer(
|
|
300
|
+
messages=messages,
|
|
301
|
+
temperature=self._temperature,
|
|
302
|
+
max_tokens=None, # client resolves per-model defaults/env
|
|
303
|
+
return_json=self._return_json,
|
|
304
|
+
custom_format=custom_format,
|
|
305
|
+
max_retries=self._max_retries,
|
|
306
|
+
retry_delay=self._retry_delay,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
end_time = datetime.now()
|
|
310
|
+
execution_time = (end_time - start_time).total_seconds()
|
|
311
|
+
|
|
312
|
+
if self.return_metadata:
|
|
313
|
+
return {
|
|
314
|
+
"success": True,
|
|
315
|
+
"result": response,
|
|
316
|
+
"metadata": {
|
|
317
|
+
"prompt_used": (
|
|
318
|
+
formatted_prompt
|
|
319
|
+
if len(formatted_prompt) < 1000
|
|
320
|
+
else f"{formatted_prompt[:1000]}..."
|
|
321
|
+
),
|
|
322
|
+
"input_arguments": {
|
|
323
|
+
arg: arguments.get(arg) for arg in self._input_arguments
|
|
324
|
+
},
|
|
325
|
+
"model_info": {
|
|
326
|
+
"api_type": self._api_type,
|
|
327
|
+
"model_id": self._model_id,
|
|
328
|
+
"temperature": self._temperature,
|
|
329
|
+
"max_new_tokens": self._max_new_tokens,
|
|
330
|
+
},
|
|
331
|
+
"execution_time_seconds": execution_time,
|
|
332
|
+
"timestamp": start_time.isoformat(),
|
|
333
|
+
},
|
|
334
|
+
}
|
|
335
|
+
else:
|
|
336
|
+
return response
|
|
337
|
+
except Exception as e:
|
|
338
|
+
end_time = datetime.now()
|
|
339
|
+
execution_time = (end_time - start_time).total_seconds()
|
|
340
|
+
self.logger.error(f"Error executing {self.name}: {str(e)}")
|
|
341
|
+
if self.return_metadata:
|
|
342
|
+
return {
|
|
343
|
+
"success": False,
|
|
344
|
+
"error": str(e),
|
|
345
|
+
"error_type": type(e).__name__,
|
|
346
|
+
"metadata": {
|
|
347
|
+
"prompt_used": (
|
|
348
|
+
formatted_prompt
|
|
349
|
+
if "formatted_prompt" in locals()
|
|
350
|
+
else "Failed to format prompt"
|
|
351
|
+
),
|
|
352
|
+
"input_arguments": {
|
|
353
|
+
arg: arguments.get(arg) for arg in self._input_arguments
|
|
354
|
+
},
|
|
355
|
+
"model_info": {
|
|
356
|
+
"api_type": self._api_type,
|
|
357
|
+
"model_id": self._model_id,
|
|
358
|
+
},
|
|
359
|
+
"execution_time_seconds": execution_time,
|
|
360
|
+
"timestamp": start_time.isoformat(),
|
|
361
|
+
},
|
|
362
|
+
}
|
|
363
|
+
else:
|
|
364
|
+
return "error: " + str(e) + " error_type: " + type(e).__name__
|
|
365
|
+
|
|
366
|
+
# ------------------------------------------------------------------ helpers -----------------
|
|
367
|
+
def _validate_arguments(self, arguments: Dict[str, Any]):
|
|
368
|
+
for arg_name, value in arguments.items():
|
|
369
|
+
if arg_name in self._input_arguments:
|
|
370
|
+
if isinstance(value, str) and not value.strip():
|
|
371
|
+
if arg_name in self._required_arguments:
|
|
372
|
+
raise ValueError(
|
|
373
|
+
f"Required argument '{arg_name}' cannot be empty"
|
|
374
|
+
)
|
|
375
|
+
if isinstance(value, str) and len(value) > 100000:
|
|
376
|
+
pass
|
|
377
|
+
|
|
378
|
+
def _format_prompt(self, arguments: Dict[str, Any]) -> str:
|
|
379
|
+
prompt = self._prompt_template
|
|
380
|
+
for arg_name in self._input_arguments:
|
|
381
|
+
placeholder = f"{{{arg_name}}}"
|
|
382
|
+
value = arguments.get(arg_name, "")
|
|
383
|
+
if placeholder in prompt:
|
|
384
|
+
prompt = prompt.replace(placeholder, str(value))
|
|
385
|
+
return prompt
|
|
386
|
+
|
|
387
|
+
def get_prompt_preview(self, arguments: Dict[str, Any]) -> str:
|
|
388
|
+
try:
|
|
389
|
+
args_copy = arguments.copy()
|
|
390
|
+
missing_required_args = [
|
|
391
|
+
arg for arg in self._required_arguments if arg not in args_copy
|
|
392
|
+
]
|
|
393
|
+
if missing_required_args:
|
|
394
|
+
raise ValueError(
|
|
395
|
+
f"Missing required input arguments: {missing_required_args}"
|
|
396
|
+
)
|
|
397
|
+
for arg in self._input_arguments:
|
|
398
|
+
if arg not in args_copy:
|
|
399
|
+
args_copy[arg] = self._argument_defaults.get(arg, "")
|
|
400
|
+
return self._format_prompt(args_copy)
|
|
401
|
+
except Exception as e:
|
|
402
|
+
return f"Error formatting prompt: {str(e)}"
|
|
403
|
+
|
|
404
|
+
def get_model_info(self) -> Dict[str, Any]:
|
|
405
|
+
return {
|
|
406
|
+
"api_type": self._api_type,
|
|
407
|
+
"model_id": self._model_id,
|
|
408
|
+
"temperature": self._temperature,
|
|
409
|
+
"max_new_tokens": self._max_new_tokens,
|
|
410
|
+
"return_json": self._return_json,
|
|
411
|
+
"max_retries": self._max_retries,
|
|
412
|
+
"retry_delay": self._retry_delay,
|
|
413
|
+
"validate_api_key": self._validate_api_key,
|
|
414
|
+
"gemini_model_id": getattr(self, "_gemini_model_id", None),
|
|
415
|
+
"is_available": self._is_available,
|
|
416
|
+
"initialization_error": self._initialization_error,
|
|
417
|
+
"current_api_type": self._current_api_type,
|
|
418
|
+
"current_model_id": self._current_model_id,
|
|
419
|
+
"fallback_api_type": self._fallback_api_type,
|
|
420
|
+
"fallback_model_id": self._fallback_model_id,
|
|
421
|
+
"use_global_fallback": self._use_global_fallback,
|
|
422
|
+
"global_fallback_chain": self._global_fallback_chain,
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
def is_available(self) -> bool:
|
|
426
|
+
"""Check if the tool is available for use."""
|
|
427
|
+
return self._is_available
|
|
428
|
+
|
|
429
|
+
def get_availability_status(self) -> Dict[str, Any]:
|
|
430
|
+
"""Get detailed availability status of the tool."""
|
|
431
|
+
return {
|
|
432
|
+
"is_available": self._is_available,
|
|
433
|
+
"initialization_error": self._initialization_error,
|
|
434
|
+
"api_type": self._api_type,
|
|
435
|
+
"model_id": self._model_id,
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
def retry_initialization(self) -> bool:
|
|
439
|
+
"""Attempt to reinitialize the tool (useful if API keys were updated)."""
|
|
440
|
+
try:
|
|
441
|
+
if self._api_type == "CHATGPT":
|
|
442
|
+
self._llm_client = AzureOpenAIClient(self._model_id, None, self.logger)
|
|
443
|
+
elif self._api_type == "GEMINI":
|
|
444
|
+
self._llm_client = GeminiClient(self._gemini_model_id, self.logger)
|
|
445
|
+
else:
|
|
446
|
+
raise ValueError(f"Unsupported API type: {self._api_type}")
|
|
447
|
+
|
|
448
|
+
if self._validate_api_key:
|
|
449
|
+
self._llm_client.test_api()
|
|
450
|
+
self.logger.info(
|
|
451
|
+
f"Successfully reinitialized {self._api_type} model: {self._model_id}"
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
self._is_available = True
|
|
455
|
+
self._initialization_error = None
|
|
456
|
+
return True
|
|
457
|
+
|
|
458
|
+
except Exception as e:
|
|
459
|
+
self._initialization_error = str(e)
|
|
460
|
+
self.logger.warning(
|
|
461
|
+
f"Retry initialization failed for {self._api_type} model {self._model_id}: {str(e)}"
|
|
462
|
+
)
|
|
463
|
+
return False
|
|
464
|
+
|
|
465
|
+
def get_prompt_template(self) -> str:
|
|
466
|
+
return self._prompt_template
|
|
467
|
+
|
|
468
|
+
def get_input_arguments(self) -> List[str]:
|
|
469
|
+
return self._input_arguments.copy()
|
|
470
|
+
|
|
471
|
+
def validate_configuration(self) -> Dict[str, Any]:
|
|
472
|
+
validation_results = {"valid": True, "warnings": [], "errors": []}
|
|
473
|
+
try:
|
|
474
|
+
self._validate_model_config()
|
|
475
|
+
except ValueError as e:
|
|
476
|
+
validation_results["valid"] = False
|
|
477
|
+
validation_results["errors"].append(str(e))
|
|
478
|
+
if not self._prompt_template:
|
|
479
|
+
validation_results["valid"] = False
|
|
480
|
+
validation_results["errors"].append("Missing prompt template")
|
|
481
|
+
return validation_results
|
|
482
|
+
|
|
483
|
+
def estimate_token_usage(self, arguments: Dict[str, Any]) -> Dict[str, int]:
|
|
484
|
+
prompt = self._format_prompt(arguments)
|
|
485
|
+
estimated_input_tokens = len(prompt) // 4
|
|
486
|
+
estimated_max_output_tokens = (
|
|
487
|
+
self._max_new_tokens if self._max_new_tokens is not None else 2048
|
|
488
|
+
)
|
|
489
|
+
estimated_total_tokens = estimated_input_tokens + estimated_max_output_tokens
|
|
490
|
+
return {
|
|
491
|
+
"estimated_input_tokens": estimated_input_tokens,
|
|
492
|
+
"max_output_tokens": estimated_max_output_tokens,
|
|
493
|
+
"estimated_total_tokens": estimated_total_tokens,
|
|
494
|
+
"prompt_length_chars": len(prompt),
|
|
495
|
+
}
|
{tooluniverse-1.0.2 → tooluniverse-1.0.4}/src/tooluniverse/compose_scripts/output_summarizer.py
RENAMED
|
@@ -81,31 +81,37 @@ def compose(arguments: Dict[str, Any], tooluniverse, call_tool) -> Dict[str, Any
|
|
|
81
81
|
else:
|
|
82
82
|
print(f"❌ Chunk {i+1} summarization failed")
|
|
83
83
|
|
|
84
|
-
# Step 3: Merge summaries
|
|
84
|
+
# Step 3: Merge summaries (or gracefully fall back)
|
|
85
85
|
if chunk_summaries:
|
|
86
86
|
final_summary = _merge_summaries(
|
|
87
87
|
chunk_summaries, query_context, tool_name, max_summary_length, call_tool
|
|
88
88
|
)
|
|
89
|
+
print(
|
|
90
|
+
f"✅ Summarization completed. Final length: {len(final_summary)} characters"
|
|
91
|
+
)
|
|
92
|
+
return {
|
|
93
|
+
"success": True,
|
|
94
|
+
"original_length": len(tool_output),
|
|
95
|
+
"summary_length": len(final_summary),
|
|
96
|
+
"chunks_processed": len(chunks),
|
|
97
|
+
"summary": final_summary,
|
|
98
|
+
"tool_name": tool_name,
|
|
99
|
+
}
|
|
89
100
|
else:
|
|
90
|
-
|
|
101
|
+
# Treat as a non-fatal failure so upstream falls back to original output
|
|
91
102
|
print("❌ No chunk summaries were generated. This usually indicates:")
|
|
92
103
|
print(" 1. ToolOutputSummarizer tool is not available")
|
|
93
104
|
print(" 2. The output_summarization tools are not loaded")
|
|
94
105
|
print(" 3. There was an error in the summarization process")
|
|
95
106
|
print(" Please check that the SMCP server is started with hooks enabled.")
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
"summary_length": len(final_summary),
|
|
105
|
-
"chunks_processed": len(chunks),
|
|
106
|
-
"summary": final_summary,
|
|
107
|
-
"tool_name": tool_name,
|
|
108
|
-
}
|
|
107
|
+
return {
|
|
108
|
+
"success": False,
|
|
109
|
+
"error": "No chunk summaries generated",
|
|
110
|
+
"original_length": len(tool_output),
|
|
111
|
+
"chunks_processed": len(chunks),
|
|
112
|
+
"original_output": tool_output,
|
|
113
|
+
"tool_name": tool_name,
|
|
114
|
+
}
|
|
109
115
|
|
|
110
116
|
except Exception as e:
|
|
111
117
|
error_msg = f"Error in output summarization: {str(e)}"
|