tooluniverse 0.1.4__py3-none-any.whl → 1.0.0__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 (187) hide show
  1. tooluniverse/__init__.py +340 -4
  2. tooluniverse/admetai_tool.py +84 -0
  3. tooluniverse/agentic_tool.py +563 -0
  4. tooluniverse/alphafold_tool.py +96 -0
  5. tooluniverse/base_tool.py +129 -6
  6. tooluniverse/boltz_tool.py +207 -0
  7. tooluniverse/chem_tool.py +192 -0
  8. tooluniverse/compose_scripts/__init__.py +1 -0
  9. tooluniverse/compose_scripts/biomarker_discovery.py +293 -0
  10. tooluniverse/compose_scripts/comprehensive_drug_discovery.py +186 -0
  11. tooluniverse/compose_scripts/drug_safety_analyzer.py +89 -0
  12. tooluniverse/compose_scripts/literature_tool.py +34 -0
  13. tooluniverse/compose_scripts/output_summarizer.py +279 -0
  14. tooluniverse/compose_scripts/tool_description_optimizer.py +681 -0
  15. tooluniverse/compose_scripts/tool_discover.py +705 -0
  16. tooluniverse/compose_scripts/tool_graph_composer.py +448 -0
  17. tooluniverse/compose_tool.py +371 -0
  18. tooluniverse/ctg_tool.py +1002 -0
  19. tooluniverse/custom_tool.py +81 -0
  20. tooluniverse/dailymed_tool.py +108 -0
  21. tooluniverse/data/admetai_tools.json +155 -0
  22. tooluniverse/data/agentic_tools.json +1156 -0
  23. tooluniverse/data/alphafold_tools.json +87 -0
  24. tooluniverse/data/boltz_tools.json +9 -0
  25. tooluniverse/data/chembl_tools.json +16 -0
  26. tooluniverse/data/clait_tools.json +108 -0
  27. tooluniverse/data/clinicaltrials_gov_tools.json +326 -0
  28. tooluniverse/data/compose_tools.json +202 -0
  29. tooluniverse/data/dailymed_tools.json +70 -0
  30. tooluniverse/data/dataset_tools.json +646 -0
  31. tooluniverse/data/disease_target_score_tools.json +712 -0
  32. tooluniverse/data/efo_tools.json +17 -0
  33. tooluniverse/data/embedding_tools.json +319 -0
  34. tooluniverse/data/enrichr_tools.json +31 -0
  35. tooluniverse/data/europe_pmc_tools.json +22 -0
  36. tooluniverse/data/expert_feedback_tools.json +10 -0
  37. tooluniverse/data/fda_drug_adverse_event_tools.json +491 -0
  38. tooluniverse/data/fda_drug_labeling_tools.json +544 -168
  39. tooluniverse/data/fda_drugs_with_brand_generic_names_for_tool.py +76929 -148860
  40. tooluniverse/data/finder_tools.json +209 -0
  41. tooluniverse/data/gene_ontology_tools.json +113 -0
  42. tooluniverse/data/gwas_tools.json +1082 -0
  43. tooluniverse/data/hpa_tools.json +333 -0
  44. tooluniverse/data/humanbase_tools.json +47 -0
  45. tooluniverse/data/idmap_tools.json +74 -0
  46. tooluniverse/data/mcp_client_tools_example.json +113 -0
  47. tooluniverse/data/mcpautoloadertool_defaults.json +28 -0
  48. tooluniverse/data/medlineplus_tools.json +141 -0
  49. tooluniverse/data/monarch_tools.json +1 -1
  50. tooluniverse/data/openalex_tools.json +36 -0
  51. tooluniverse/data/opentarget_tools.json +82 -58
  52. tooluniverse/data/output_summarization_tools.json +101 -0
  53. tooluniverse/data/packages/bioinformatics_core_tools.json +1756 -0
  54. tooluniverse/data/packages/categorized_tools.txt +206 -0
  55. tooluniverse/data/packages/cheminformatics_tools.json +347 -0
  56. tooluniverse/data/packages/earth_sciences_tools.json +74 -0
  57. tooluniverse/data/packages/genomics_tools.json +776 -0
  58. tooluniverse/data/packages/image_processing_tools.json +38 -0
  59. tooluniverse/data/packages/machine_learning_tools.json +789 -0
  60. tooluniverse/data/packages/neuroscience_tools.json +62 -0
  61. tooluniverse/data/packages/original_tools.txt +0 -0
  62. tooluniverse/data/packages/physics_astronomy_tools.json +62 -0
  63. tooluniverse/data/packages/scientific_computing_tools.json +560 -0
  64. tooluniverse/data/packages/single_cell_tools.json +453 -0
  65. tooluniverse/data/packages/software_tools.json +4954 -0
  66. tooluniverse/data/packages/structural_biology_tools.json +396 -0
  67. tooluniverse/data/packages/visualization_tools.json +399 -0
  68. tooluniverse/data/pubchem_tools.json +215 -0
  69. tooluniverse/data/pubtator_tools.json +68 -0
  70. tooluniverse/data/rcsb_pdb_tools.json +1332 -0
  71. tooluniverse/data/reactome_tools.json +19 -0
  72. tooluniverse/data/semantic_scholar_tools.json +26 -0
  73. tooluniverse/data/special_tools.json +2 -25
  74. tooluniverse/data/tool_composition_tools.json +88 -0
  75. tooluniverse/data/toolfinderkeyword_defaults.json +34 -0
  76. tooluniverse/data/txagent_client_tools.json +9 -0
  77. tooluniverse/data/uniprot_tools.json +211 -0
  78. tooluniverse/data/url_fetch_tools.json +94 -0
  79. tooluniverse/data/uspto_downloader_tools.json +9 -0
  80. tooluniverse/data/uspto_tools.json +811 -0
  81. tooluniverse/data/xml_tools.json +3275 -0
  82. tooluniverse/dataset_tool.py +296 -0
  83. tooluniverse/default_config.py +165 -0
  84. tooluniverse/efo_tool.py +42 -0
  85. tooluniverse/embedding_database.py +630 -0
  86. tooluniverse/embedding_sync.py +396 -0
  87. tooluniverse/enrichr_tool.py +266 -0
  88. tooluniverse/europe_pmc_tool.py +52 -0
  89. tooluniverse/execute_function.py +1775 -95
  90. tooluniverse/extended_hooks.py +444 -0
  91. tooluniverse/gene_ontology_tool.py +194 -0
  92. tooluniverse/graphql_tool.py +158 -36
  93. tooluniverse/gwas_tool.py +358 -0
  94. tooluniverse/hpa_tool.py +1645 -0
  95. tooluniverse/humanbase_tool.py +389 -0
  96. tooluniverse/logging_config.py +254 -0
  97. tooluniverse/mcp_client_tool.py +764 -0
  98. tooluniverse/mcp_integration.py +413 -0
  99. tooluniverse/mcp_tool_registry.py +925 -0
  100. tooluniverse/medlineplus_tool.py +337 -0
  101. tooluniverse/openalex_tool.py +228 -0
  102. tooluniverse/openfda_adv_tool.py +283 -0
  103. tooluniverse/openfda_tool.py +393 -160
  104. tooluniverse/output_hook.py +1122 -0
  105. tooluniverse/package_tool.py +195 -0
  106. tooluniverse/pubchem_tool.py +158 -0
  107. tooluniverse/pubtator_tool.py +168 -0
  108. tooluniverse/rcsb_pdb_tool.py +38 -0
  109. tooluniverse/reactome_tool.py +108 -0
  110. tooluniverse/remote/boltz/boltz_mcp_server.py +50 -0
  111. tooluniverse/remote/depmap_24q2/depmap_24q2_mcp_tool.py +442 -0
  112. tooluniverse/remote/expert_feedback/human_expert_mcp_tools.py +2013 -0
  113. tooluniverse/remote/expert_feedback/simple_test.py +23 -0
  114. tooluniverse/remote/expert_feedback/start_web_interface.py +188 -0
  115. tooluniverse/remote/expert_feedback/web_only_interface.py +0 -0
  116. tooluniverse/remote/expert_feedback_mcp/human_expert_mcp_server.py +1611 -0
  117. tooluniverse/remote/expert_feedback_mcp/simple_test.py +34 -0
  118. tooluniverse/remote/expert_feedback_mcp/start_web_interface.py +91 -0
  119. tooluniverse/remote/immune_compass/compass_tool.py +327 -0
  120. tooluniverse/remote/pinnacle/pinnacle_tool.py +328 -0
  121. tooluniverse/remote/transcriptformer/transcriptformer_tool.py +586 -0
  122. tooluniverse/remote/uspto_downloader/uspto_downloader_mcp_server.py +61 -0
  123. tooluniverse/remote/uspto_downloader/uspto_downloader_tool.py +120 -0
  124. tooluniverse/remote_tool.py +99 -0
  125. tooluniverse/restful_tool.py +53 -30
  126. tooluniverse/scripts/generate_tool_graph.py +408 -0
  127. tooluniverse/scripts/visualize_tool_graph.py +829 -0
  128. tooluniverse/semantic_scholar_tool.py +62 -0
  129. tooluniverse/smcp.py +2452 -0
  130. tooluniverse/smcp_server.py +975 -0
  131. tooluniverse/test/mcp_server_test.py +0 -0
  132. tooluniverse/test/test_admetai_tool.py +370 -0
  133. tooluniverse/test/test_agentic_tool.py +129 -0
  134. tooluniverse/test/test_alphafold_tool.py +71 -0
  135. tooluniverse/test/test_chem_tool.py +37 -0
  136. tooluniverse/test/test_compose_lieraturereview.py +63 -0
  137. tooluniverse/test/test_compose_tool.py +448 -0
  138. tooluniverse/test/test_dailymed.py +69 -0
  139. tooluniverse/test/test_dataset_tool.py +200 -0
  140. tooluniverse/test/test_disease_target_score.py +56 -0
  141. tooluniverse/test/test_drugbank_filter_examples.py +179 -0
  142. tooluniverse/test/test_efo.py +31 -0
  143. tooluniverse/test/test_enrichr_tool.py +21 -0
  144. tooluniverse/test/test_europe_pmc_tool.py +20 -0
  145. tooluniverse/test/test_fda_adv.py +95 -0
  146. tooluniverse/test/test_fda_drug_labeling.py +91 -0
  147. tooluniverse/test/test_gene_ontology_tools.py +66 -0
  148. tooluniverse/test/test_gwas_tool.py +139 -0
  149. tooluniverse/test/test_hpa.py +625 -0
  150. tooluniverse/test/test_humanbase_tool.py +20 -0
  151. tooluniverse/test/test_idmap_tools.py +61 -0
  152. tooluniverse/test/test_mcp_server.py +211 -0
  153. tooluniverse/test/test_mcp_tool.py +247 -0
  154. tooluniverse/test/test_medlineplus.py +220 -0
  155. tooluniverse/test/test_openalex_tool.py +32 -0
  156. tooluniverse/test/test_opentargets.py +28 -0
  157. tooluniverse/test/test_pubchem_tool.py +116 -0
  158. tooluniverse/test/test_pubtator_tool.py +37 -0
  159. tooluniverse/test/test_rcsb_pdb_tool.py +86 -0
  160. tooluniverse/test/test_reactome.py +54 -0
  161. tooluniverse/test/test_semantic_scholar_tool.py +24 -0
  162. tooluniverse/test/test_software_tools.py +147 -0
  163. tooluniverse/test/test_tool_description_optimizer.py +49 -0
  164. tooluniverse/test/test_tool_finder.py +26 -0
  165. tooluniverse/test/test_tool_finder_llm.py +252 -0
  166. tooluniverse/test/test_tools_find.py +195 -0
  167. tooluniverse/test/test_uniprot_tools.py +74 -0
  168. tooluniverse/test/test_uspto_tool.py +72 -0
  169. tooluniverse/test/test_xml_tool.py +113 -0
  170. tooluniverse/tool_finder_embedding.py +267 -0
  171. tooluniverse/tool_finder_keyword.py +693 -0
  172. tooluniverse/tool_finder_llm.py +699 -0
  173. tooluniverse/tool_graph_web_ui.py +955 -0
  174. tooluniverse/tool_registry.py +416 -0
  175. tooluniverse/uniprot_tool.py +155 -0
  176. tooluniverse/url_tool.py +253 -0
  177. tooluniverse/uspto_tool.py +240 -0
  178. tooluniverse/utils.py +369 -41
  179. tooluniverse/xml_tool.py +369 -0
  180. tooluniverse-1.0.0.dist-info/METADATA +377 -0
  181. tooluniverse-1.0.0.dist-info/RECORD +186 -0
  182. {tooluniverse-0.1.4.dist-info → tooluniverse-1.0.0.dist-info}/WHEEL +1 -1
  183. tooluniverse-1.0.0.dist-info/entry_points.txt +9 -0
  184. tooluniverse-0.1.4.dist-info/METADATA +0 -141
  185. tooluniverse-0.1.4.dist-info/RECORD +0 -18
  186. {tooluniverse-0.1.4.dist-info → tooluniverse-1.0.0.dist-info}/licenses/LICENSE +0 -0
  187. {tooluniverse-0.1.4.dist-info → tooluniverse-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Simple demo for SimpleLiteratureTool - Perfect for paper screenshots
4
+ Shows clean, minimal compose tool functionality
5
+ """
6
+
7
+ from tooluniverse import ToolUniverse
8
+
9
+
10
+ def main():
11
+ print("🔬 LiteratureReviewAgent Tool Demo")
12
+ print("=" * 40)
13
+
14
+ # Initialize ToolUniverse and load all tools
15
+ engine = ToolUniverse()
16
+ engine.load_tools() # Load all available tools
17
+
18
+ # Check available tools
19
+ all_tools = engine.return_all_loaded_tools()
20
+ print(f"Total tools loaded: {len(all_tools)}")
21
+
22
+ # Get tool names (for dictionary-based tools, extract the 'name' field)
23
+ tool_names = []
24
+ for tool in all_tools:
25
+ if isinstance(tool, dict) and "name" in tool:
26
+ tool_names.append(tool["name"])
27
+ elif isinstance(tool, str):
28
+ tool_names.append(tool)
29
+
30
+ # Look for compose tools
31
+ compose_tools = [
32
+ t for t in tool_names if "Safety" in t or "Literature" in t or "Simple" in t
33
+ ]
34
+ print(f"Compose tools available: {compose_tools}")
35
+
36
+ if "LiteratureReviewAgent" in tool_names:
37
+ # Run the simple compose tool
38
+ result = engine.run_one_function(
39
+ {
40
+ "name": "LiteratureReviewAgent",
41
+ "arguments": {"research_topic": "CRISPR gene editing"},
42
+ }
43
+ )
44
+ print(result)
45
+
46
+ # Display clean results if it's a dict
47
+ if isinstance(result, dict):
48
+ print(f"📚 Topic: {result.get('topic', 'N/A')}")
49
+ print(f"📄 Papers Found: {result.get('papers_found', 0)}")
50
+ print("🗂️ Sources: Europe PMC, OpenAlex, PubTator")
51
+ print(
52
+ f"🤖 AI Summary: {'✅ Generated' if result.get('ai_summary') else '❌ Failed'}"
53
+ )
54
+ else:
55
+ print(f"Result: {result}")
56
+ else:
57
+ print("LiteratureReviewAgent not found in loaded tools")
58
+
59
+ print("\n✅ Demo Complete!")
60
+
61
+
62
+ if __name__ == "__main__":
63
+ main()
@@ -0,0 +1,448 @@
1
+ """
2
+ ComposeTool Test File
3
+
4
+ This file tests the core functionality of ComposeTool:
5
+ 1. Basic ComposeTool creation and execution
6
+ 2. ComposeTool nested calling (one ComposeTool calling another ComposeTool)
7
+ 3. Simple mathematical operations
8
+
9
+ ComposeTool is a composable tool that supports:
10
+ - Inline code definition (write Python code directly in JSON configuration)
11
+ - External file definition (define complex logic through Python files)
12
+ - Nested calling between tools (using call_tool function)
13
+
14
+ Usage:
15
+ 1. Run the entire test: python test_compose_tool.py
16
+ 2. View test results to confirm all functionality works properly
17
+ """
18
+
19
+ import sys
20
+ import os
21
+ import json
22
+
23
+ # Add src directory to Python path to import tooluniverse modules
24
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
25
+
26
+ from tooluniverse.execute_function import ToolUniverse # noqa: E402
27
+
28
+
29
+ def test_nested_calls():
30
+ """
31
+ Test ComposeTool nested calling functionality
32
+
33
+ This test creates two ComposeTool instances:
34
+ 1. TextTool: receives text, returns uppercase text and length
35
+ 2. CallerTool: calls TextTool to process text, then wraps the result
36
+
37
+ Key verification points:
38
+ - ComposeTool can call other ComposeTool instances
39
+ - Correct usage of call_tool function
40
+ - Parameter passing and result return in nested calls
41
+ """
42
+ print("Testing ComposeTool nested calling functionality")
43
+ print("=" * 40)
44
+
45
+ # Create a simple text processing tool
46
+ # This tool receives text and returns uppercase version and length
47
+ text_tool = {
48
+ "type": "ComposeTool",
49
+ "name": "TextTool",
50
+ "description": "Simple text processing tool",
51
+ "parameter": {
52
+ "type": "object",
53
+ "properties": {"text": {"type": "string", "description": "Input text"}},
54
+ "required": ["text"],
55
+ },
56
+ "composition_code": [
57
+ "# Get text from arguments",
58
+ "text = arguments['text']",
59
+ "# Return processing result: uppercase text and length",
60
+ "result = {'processed': text.upper(), 'length': len(text)}",
61
+ ],
62
+ }
63
+
64
+ # Create a caller tool that calls the above TextTool
65
+ # This demonstrates the nested calling capability of ComposeTool
66
+ caller_tool = {
67
+ "type": "ComposeTool",
68
+ "name": "CallerTool",
69
+ "description": "Composite tool that calls text tool",
70
+ "parameter": {
71
+ "type": "object",
72
+ "properties": {"input": {"type": "string", "description": "Input text"}},
73
+ "required": ["input"],
74
+ },
75
+ "composition_code": [
76
+ "# Get input text",
77
+ "input_text = arguments['input']",
78
+ "# Use call_tool function to call TextTool",
79
+ "# call_tool(tool_name, arguments_dict) is the standard way to call other tools in ComposeTool",
80
+ "text_result = call_tool('TextTool', {'text': input_text})",
81
+ "# Wrap result, including original input and processing result",
82
+ "result = {'original': input_text, 'processed_result': text_result}",
83
+ ],
84
+ }
85
+
86
+ # Initialize ToolUniverse engine
87
+ engine = ToolUniverse()
88
+
89
+ # Register tools to engine
90
+ # Need to add to both all_tools list and all_tool_dict dictionary
91
+ engine.all_tools.extend([text_tool, caller_tool])
92
+ engine.all_tool_dict["TextTool"] = text_tool
93
+ engine.all_tool_dict["CallerTool"] = caller_tool
94
+
95
+ # Run test: call CallerTool, which will internally call TextTool
96
+ result = engine.run_one_function(
97
+ {"name": "CallerTool", "arguments": {"input": "hello world"}}
98
+ )
99
+
100
+ print("Nested calling result:")
101
+ print(json.dumps(result, indent=2, ensure_ascii=False))
102
+
103
+
104
+ def test_simple_math():
105
+ """
106
+ Test ComposeTool's mathematical operations functionality
107
+
108
+ This test creates a math tool that supports:
109
+ 1. Array summation
110
+ 2. Array element multiplication
111
+ 3. Default handling for unknown operations
112
+
113
+ Key verification points:
114
+ - Conditional logic processing in ComposeTool
115
+ - Array data processing
116
+ - Support for multiple operation types
117
+ """
118
+ print("\nTesting simple mathematical operations functionality")
119
+ print("=" * 40)
120
+
121
+ # Create a mathematical operations tool
122
+ # Supports sum or multiply operations on number arrays
123
+ math_tool = {
124
+ "type": "ComposeTool",
125
+ "name": "MathTool",
126
+ "description": "Simple mathematical operations tool",
127
+ "parameter": {
128
+ "type": "object",
129
+ "properties": {
130
+ "numbers": {"type": "array", "description": "Array of numbers"},
131
+ "op": {
132
+ "type": "string",
133
+ "description": "Operation type: sum (addition) or multiply (multiplication)",
134
+ },
135
+ },
136
+ "required": ["numbers", "op"],
137
+ },
138
+ "composition_code": [
139
+ "# Get number array and operation type from arguments",
140
+ "numbers = arguments['numbers']",
141
+ "op = arguments['op']",
142
+ "",
143
+ "# Execute different calculations based on operation type",
144
+ "if op == 'sum':",
145
+ " # Sum operation",
146
+ " result = {'result': sum(numbers), 'operation': 'sum'}",
147
+ "elif op == 'multiply':",
148
+ " # Multiply operation: start with 1, multiply sequentially",
149
+ " result = {'result': 1}",
150
+ " for n in numbers:",
151
+ " result['result'] *= n",
152
+ " result['operation'] = 'multiply'",
153
+ "else:",
154
+ " # Default handling for unknown operations",
155
+ " result = {'result': 0, 'operation': 'unknown'}",
156
+ ],
157
+ }
158
+
159
+ # Initialize engine and register math tool
160
+ engine = ToolUniverse()
161
+ engine.all_tools.append(math_tool)
162
+ engine.all_tool_dict["MathTool"] = math_tool
163
+
164
+ # Test sum functionality
165
+ print("Testing sum operation:")
166
+ result = engine.run_one_function(
167
+ {"name": "MathTool", "arguments": {"numbers": [1, 2, 3, 4], "op": "sum"}}
168
+ )
169
+ print(" Input: [1, 2, 3, 4], Operation: sum")
170
+ print(f" Result: {result}")
171
+
172
+ # Test multiply functionality
173
+ print("\nTesting multiply operation:")
174
+ result = engine.run_one_function(
175
+ {"name": "MathTool", "arguments": {"numbers": [2, 3, 4], "op": "multiply"}}
176
+ )
177
+ print(" Input: [2, 3, 4], Operation: multiply")
178
+ print(f" Result: {result}")
179
+
180
+
181
+ def test_config_file_tools():
182
+ """
183
+ Test ComposeTool loaded from configuration files
184
+
185
+ This test verifies:
186
+ 1. Loading ComposeTool from JSON configuration files
187
+ 2. Configuration file defined tools can run normally
188
+ 3. Demonstrate how to use predefined composite tools
189
+
190
+ Configuration file location: src/tooluniverse/data/compose_tools.json
191
+ """
192
+ print("\nTesting ComposeTool from configuration files")
193
+ print("=" * 40)
194
+
195
+ # Initialize ToolUniverse engine
196
+ engine = ToolUniverse()
197
+
198
+ # Load compose type tools from configuration files
199
+ # This automatically loads tools defined in src/tooluniverse/data/compose_tools.json
200
+ engine.load_tools(tool_type=["compose"])
201
+
202
+ # Test DrugSafetyAnalyzer tool from configuration file
203
+ print("Running DrugSafetyAnalyzer tool from configuration file:")
204
+ try:
205
+ result = engine.run_one_function(
206
+ {
207
+ "name": "DrugSafetyAnalyzer",
208
+ "arguments": {"drug_name": "aspirin", "serious_events_only": False},
209
+ }
210
+ )
211
+
212
+ print("DrugSafetyAnalyzer tool result:")
213
+ print(json.dumps(result, indent=2, ensure_ascii=False))
214
+ except Exception as e:
215
+ print(f"DrugSafetyAnalyzer test failed: {e}")
216
+ print("This is expected if the required atomic tools are not loaded.")
217
+
218
+ print(f"\nTotal tools loaded: {len(engine.callable_functions)}")
219
+ compose_tools = [
220
+ name
221
+ for name in engine.callable_functions.keys()
222
+ if any(
223
+ tool.get("name") == name and tool.get("type") == "ComposeTool"
224
+ for tool in engine.all_tools
225
+ )
226
+ ]
227
+ print(f"ComposeTool instances: {compose_tools}")
228
+
229
+ # Check available composite tools and test them
230
+ print(f"\nTotal tools loaded: {len(engine.all_tools)}")
231
+ compose_tools = [
232
+ name
233
+ for name in engine.callable_functions.keys()
234
+ if any(
235
+ tool.get("name") == name and tool.get("type") == "ComposeTool"
236
+ for tool in engine.all_tools
237
+ )
238
+ ]
239
+ print(f"ComposeTool instances available: {compose_tools}")
240
+
241
+
242
+ def test_external_file_tools():
243
+ """
244
+ Test additional ComposeTool functionality
245
+
246
+ This test verifies:
247
+ 1. Additional composite tools from configuration
248
+ 2. Testing ProteinFunctionAnalyzer and LiteratureMetaAnalyzer
249
+ 3. Demonstrate complex biomedical analysis workflows
250
+ """
251
+ print("\nTesting additional composite tools")
252
+ print("=" * 40)
253
+
254
+ # Initialize ToolUniverse engine
255
+ engine = ToolUniverse()
256
+
257
+ # Load compose type tools from configuration files
258
+ engine.load_tools(tool_type=["compose"])
259
+
260
+ # Only test tools that are actually loaded
261
+ compose_tools = [
262
+ tool for tool in engine.all_tools if tool.get("type") == "ComposeTool"
263
+ ]
264
+ print(f"Found {len(compose_tools)} composite tools:")
265
+ for tool in compose_tools:
266
+ print(f" - {tool['name']}: {tool['description']}")
267
+
268
+ # Test each available composite tool
269
+ for tool in compose_tools:
270
+ tool_name = tool["name"]
271
+ if tool_name in [
272
+ "DrugSafetyAnalyzer",
273
+ "SimpleExample",
274
+ "TestDependencyLoading",
275
+ ]:
276
+ # Skip these as they are tested in other functions
277
+ continue
278
+
279
+ print(f"\nTesting {tool_name}:")
280
+ try:
281
+ # Create generic test arguments based on tool requirements
282
+ test_args = {}
283
+ if "parameter" in tool and "properties" in tool["parameter"]:
284
+ for param_name, param_info in tool["parameter"]["properties"].items():
285
+ if param_info["type"] == "string":
286
+ test_args[param_name] = "test_input"
287
+ elif param_info["type"] == "number":
288
+ test_args[param_name] = 1
289
+ elif param_info["type"] == "boolean":
290
+ test_args[param_name] = True
291
+ # Add other types as needed
292
+
293
+ result = engine.run_one_function(
294
+ {"name": tool_name, "arguments": test_args}
295
+ )
296
+ print(f"{tool_name} result:")
297
+ print(json.dumps(result, indent=2, ensure_ascii=False))
298
+ except Exception as e:
299
+ print(f"{tool_name} test failed: {e}")
300
+ print("This is expected if the required atomic tools are not loaded.")
301
+
302
+
303
+ def test_dependency_auto_loading():
304
+ """
305
+ Test ComposeTool automatic dependency loading functionality
306
+
307
+ This test verifies:
308
+ 1. Automatic detection of tool dependencies
309
+ 2. Auto-loading of missing tool categories
310
+ 3. Error handling for unavailable tools
311
+ 4. Configuration options for dependency behavior
312
+ """
313
+ print("\nTesting automatic dependency loading functionality")
314
+ print("=" * 40)
315
+
316
+ # Create a ComposeTool that depends on external tools
317
+ dependent_tool = {
318
+ "type": "ComposeTool",
319
+ "name": "DependentTool",
320
+ "description": "Tool that depends on external tools",
321
+ "parameter": {
322
+ "type": "object",
323
+ "properties": {"query": {"type": "string", "description": "Search query"}},
324
+ "required": ["query"],
325
+ },
326
+ "auto_load_dependencies": True,
327
+ "fail_on_missing_tools": False,
328
+ "required_tools": ["EuropePMC_search_articles"],
329
+ "composition_code": [
330
+ "# This tool tries to call EuropePMC tool",
331
+ "query = arguments['query']",
332
+ "",
333
+ "print(f'Testing with query: {query}')",
334
+ "",
335
+ "# Try to call external tool",
336
+ "literature_result = call_tool('EuropePMC_search_articles', {",
337
+ " 'query': query,",
338
+ " 'limit': 3",
339
+ "})",
340
+ "",
341
+ "result = {",
342
+ " 'query': query,",
343
+ " 'literature_result': literature_result,",
344
+ " 'success': True,",
345
+ " 'message': 'Dependency test completed'",
346
+ "}",
347
+ "",
348
+ "print(f'Dependency test completed for query: {query}')",
349
+ ],
350
+ }
351
+
352
+ # Initialize engine without loading external tools initially
353
+ engine = ToolUniverse()
354
+ engine.all_tools.append(dependent_tool)
355
+ engine.all_tool_dict["DependentTool"] = dependent_tool
356
+
357
+ # Test the tool - it should attempt to auto-load dependencies
358
+ print("Testing tool with auto-loading enabled:")
359
+ result = engine.run_one_function(
360
+ {"name": "DependentTool", "arguments": {"query": "artificial intelligence"}}
361
+ )
362
+
363
+ print("Dependency auto-loading test result:")
364
+ print(json.dumps(result, indent=2, ensure_ascii=False))
365
+
366
+
367
+ def main():
368
+ """
369
+ Main test function with enhanced dependency management testing
370
+
371
+ Run all ComposeTool tests:
372
+ 1. Nested calling test - verify inter-tool calling capability
373
+ 2. Mathematical operations test - verify data processing capability
374
+ 3. Configuration file test - verify tool loading from files capability
375
+ 4. Dependency auto-loading test - verify automatic dependency management
376
+
377
+ Summary information will be displayed after tests complete
378
+ """
379
+ print("ComposeTool Functionality Tests (Enhanced with Dependency Management)")
380
+ print("=" * 70)
381
+ print("Test contents:")
382
+ print("1. Nested calling functionality - ComposeTool calling other ComposeTool")
383
+ print("2. Mathematical operations functionality - array sum and multiply")
384
+ print("3. Configuration file functionality - testing available composite tools:")
385
+ print(" - DrugSafetyAnalyzer: Drug safety analysis with FAERS, PubChem, ChEMBL")
386
+ print(" - SimpleExample: Simple tool with no external dependencies")
387
+ print(" - TestDependencyLoading: Tool that tests auto-loading dependencies")
388
+ print("4. Additional composite tools functionality")
389
+ print("5. Automatic dependency loading functionality")
390
+ print("=" * 70)
391
+
392
+ try:
393
+ # Run all tests
394
+ test_nested_calls()
395
+ test_simple_math()
396
+ test_config_file_tools()
397
+ test_external_file_tools()
398
+ test_dependency_auto_loading()
399
+
400
+ # Display success information
401
+ print("\n" + "=" * 70)
402
+ print("✅ All tests completed!")
403
+ print("=" * 70)
404
+ print("Enhanced dependency management features:")
405
+ print("- ✅ Automatic detection of tool dependencies from code")
406
+ print("- ✅ Auto-loading of missing tool categories")
407
+ print(
408
+ "- ✅ Configurable behavior (auto_load_dependencies, fail_on_missing_tools)"
409
+ )
410
+ print("- ✅ Graceful error handling for unavailable tools")
411
+ print("- ✅ Real-time dependency resolution during execution")
412
+ print(
413
+ "- ✅ Support for both explicit (required_tools) and implicit dependencies"
414
+ )
415
+ print("\nComposeTool capabilities:")
416
+ print("- Supports both inline code and external file definition methods")
417
+ print(
418
+ "- Can implement nested calling between tools through call_tool() function"
419
+ )
420
+ print(
421
+ "- Fully integrated into ToolUniverse framework, usage consistent with other tools"
422
+ )
423
+ print("- Supports complex data processing and logic control")
424
+ print(
425
+ "- New composite tools demonstrate real-world biomedical analysis workflows"
426
+ )
427
+
428
+ except Exception as e:
429
+ print(f"\n❌ Test failed: {e}")
430
+ import traceback
431
+
432
+ traceback.print_exc()
433
+ print("\nTroubleshooting tips:")
434
+ print("1. Ensure all dependency packages are correctly installed")
435
+ print("2. Check if src/tooluniverse/data/compose_tools.json file exists")
436
+ print(
437
+ "3. Check if the new composite tools are properly defined in compose_tools.json"
438
+ )
439
+ print(
440
+ "4. Confirm ComposeTool class is correctly integrated into execute_function.py"
441
+ )
442
+ print("5. Note: Auto-loading will attempt to load missing tools automatically")
443
+ print("6. Use auto_load_dependencies=false to disable automatic loading")
444
+ print("7. Use fail_on_missing_tools=true for strict dependency checking")
445
+
446
+
447
+ if __name__ == "__main__":
448
+ main()
@@ -0,0 +1,69 @@
1
+ # test_dailymed.py
2
+
3
+ from tooluniverse import ToolUniverse
4
+
5
+ # === test_dailymed.py ===
6
+
7
+ # Step 1: Initialize ToolUniverse and load all tools (including our DailyMed tools)
8
+ tooluni = ToolUniverse()
9
+ tooluni.load_tools()
10
+
11
+ # Step 2: Define test queries for DailyMed tools
12
+ # NOTE: Before running this script, please confirm that "DailyMed_search_spls" call returns at least one data element,
13
+ # and extract a valid setid from it. Then replace the example setid below to avoid 404 or 415 errors.
14
+
15
+ test_queries = [
16
+ # ---- Tests for DailyMed_search_spls ----
17
+ # 1. Only pass drug_name, use default pagesize=100, page=1
18
+ {
19
+ "name": "DailyMed_search_spls",
20
+ "arguments": {"drug_name": "TAMSULOSIN HYDROCHLORIDE"},
21
+ },
22
+ # 2. Specify drug_name + pagesize=2, check if returns no more than 2 records
23
+ {
24
+ "name": "DailyMed_search_spls",
25
+ "arguments": {"drug_name": "TAMSULOSIN HYDROCHLORIDE", "pagesize": 2},
26
+ },
27
+ # 3. Use published_date filter to get recent records
28
+ {
29
+ "name": "DailyMed_search_spls",
30
+ "arguments": {
31
+ "drug_name": "TAMSULOSIN HYDROCHLORIDE",
32
+ "published_date_gte": "2025-05-01",
33
+ "pagesize": 3,
34
+ },
35
+ },
36
+ # ---- Tests for DailyMed_get_spl_by_setid ----
37
+ # 4. Use setid from first record above (example setid), request XML format
38
+ {
39
+ "name": "DailyMed_get_spl_by_setid",
40
+ "arguments": {
41
+ # Example setid, please replace with actual first setid from query
42
+ "setid": "35bbb655-19e2-00c2-e063-6394a90afbe3",
43
+ "format": "xml",
44
+ },
45
+ },
46
+ ]
47
+
48
+ # Step 3: Iterate over all test queries and print results
49
+ for idx, query in enumerate(test_queries):
50
+ name = query["name"]
51
+ args = query["arguments"]
52
+ print(f"\n[{idx+1}] Running tool: {name} with arguments: {args}")
53
+ try:
54
+ result = tooluni.run(query)
55
+ # Print brief results: if dict, print first few lines; otherwise print first 500 chars
56
+ if isinstance(result, dict):
57
+ # If contains 'error' key, print complete error dict; otherwise print first 500 chars
58
+ if "error" in result:
59
+ print("❌ Error returned:", result)
60
+ else:
61
+ snippet = str(result)[:500]
62
+ print("✅ Success. Result snippet (first 500 chars):")
63
+ print(snippet)
64
+ else:
65
+ snippet = str(result)[:500]
66
+ print("✅ Success. Result snippet (first 500 chars):")
67
+ print(snippet)
68
+ except Exception as e:
69
+ print(f"❌ Exception occurred: {e}")