tooluniverse 0.2.0__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 (190) 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 +1 -1
  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 +1 -1
  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-1.0.0.dist-info/entry_points.txt +9 -0
  183. tooluniverse/generate_mcp_tools.py +0 -113
  184. tooluniverse/mcp_server.py +0 -3340
  185. tooluniverse-0.2.0.dist-info/METADATA +0 -139
  186. tooluniverse-0.2.0.dist-info/RECORD +0 -21
  187. tooluniverse-0.2.0.dist-info/entry_points.txt +0 -4
  188. {tooluniverse-0.2.0.dist-info → tooluniverse-1.0.0.dist-info}/WHEEL +0 -0
  189. {tooluniverse-0.2.0.dist-info → tooluniverse-1.0.0.dist-info}/licenses/LICENSE +0 -0
  190. {tooluniverse-0.2.0.dist-info → tooluniverse-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,371 @@
1
+ """
2
+ ComposeTool - A tool that composes other tools using custom code logic.
3
+ Supports intelligent dependency management with automatic tool loading.
4
+ """
5
+
6
+ import json
7
+ import copy
8
+ import traceback
9
+ import os
10
+ import importlib.util
11
+ import re
12
+ from typing import Set
13
+ from .base_tool import BaseTool
14
+ from .tool_registry import register_tool
15
+
16
+
17
+ @register_tool("ComposeTool")
18
+ class ComposeTool(BaseTool):
19
+ """
20
+ A flexible tool that can compose other tools using custom code logic.
21
+ Supports both inline composition_code and external Python files.
22
+ Features intelligent dependency management with automatic tool loading.
23
+ """
24
+
25
+ def __init__(self, tool_config, tooluniverse=None):
26
+ super().__init__(tool_config)
27
+ """
28
+ Initialize the ComposeTool.
29
+
30
+ Args:
31
+ tool_config (dict): Tool configuration containing composition code or file reference
32
+ tooluniverse (ToolUniverse): Reference to the ToolUniverse instance
33
+ """
34
+ self.tool_config = tool_config
35
+ self.name = tool_config.get("name", "unnamed_compose_tool")
36
+ self.tooluniverse = tooluniverse
37
+
38
+ # Configuration for dependency handling
39
+ self.auto_load_dependencies = tool_config.get("auto_load_dependencies", True)
40
+ self.required_tools = tool_config.get(
41
+ "required_tools", []
42
+ ) # Explicitly specified dependencies
43
+ self.fail_on_missing_tools = tool_config.get("fail_on_missing_tools", False)
44
+
45
+ # Check if using external file or inline code
46
+ self.composition_file = tool_config.get("composition_file")
47
+ self.composition_function = tool_config.get("composition_function", "compose")
48
+
49
+ if self.composition_file:
50
+ # Load code from external file
51
+ self.composition_code = self._load_code_from_file()
52
+ else:
53
+ # Use inline code (existing behavior)
54
+ composition_code_raw = tool_config.get("composition_code", "")
55
+ if isinstance(composition_code_raw, list):
56
+ self.composition_code = "\n".join(composition_code_raw)
57
+ else:
58
+ self.composition_code = composition_code_raw
59
+
60
+ # Extract tool dependencies from code
61
+ self.discovered_dependencies = self._discover_tool_dependencies()
62
+
63
+ def _discover_tool_dependencies(self):
64
+ """
65
+ Automatically discover tool dependencies from composition code.
66
+
67
+ Returns:
68
+ set: Set of tool names that this composition calls
69
+ """
70
+ dependencies = set()
71
+
72
+ if not self.composition_code:
73
+ return dependencies
74
+
75
+ # Look for call_tool patterns: call_tool('ToolName', ...)
76
+ call_tool_pattern = r"call_tool\s*\(\s*['\"]([^'\"]+)['\"]"
77
+ matches = re.findall(call_tool_pattern, self.composition_code)
78
+ dependencies.update(matches)
79
+
80
+ # Look for tooluniverse.run_one_function patterns
81
+ run_function_pattern = r"tooluniverse\.run_one_function\s*\(\s*\{\s*['\"]name['\"]:\s*['\"]([^'\"]+)['\"]"
82
+ matches = re.findall(run_function_pattern, self.composition_code)
83
+ dependencies.update(matches)
84
+
85
+ return dependencies
86
+
87
+ def _get_tool_category_mapping(self):
88
+ """
89
+ Create a mapping from tool names to their categories.
90
+
91
+ Returns:
92
+ dict: Mapping of tool names to category names
93
+ """
94
+ tool_to_category = {}
95
+
96
+ if not self.tooluniverse:
97
+ return tool_to_category
98
+
99
+ # Check all tool files to build mapping
100
+ for category, file_path in self.tooluniverse.tool_files.items():
101
+ try:
102
+ from .execute_function import read_json_list
103
+
104
+ tools_in_category = read_json_list(file_path)
105
+ for tool in tools_in_category:
106
+ tool_name = tool.get("name")
107
+ if tool_name:
108
+ tool_to_category[tool_name] = category
109
+ except Exception as e:
110
+ print(f"Warning: Could not read tool file {file_path}: {e}")
111
+
112
+ return tool_to_category
113
+
114
+ def _load_missing_dependencies(self, missing_tools: Set[str]):
115
+ """
116
+ Automatically load missing tool dependencies.
117
+
118
+ Args:
119
+ missing_tools (set): Set of missing tool names
120
+
121
+ Returns:
122
+ tuple: (successfully_loaded, failed_to_load)
123
+ """
124
+ if not self.tooluniverse or not self.auto_load_dependencies:
125
+ return set(), missing_tools
126
+
127
+ tool_to_category = self._get_tool_category_mapping()
128
+ categories_to_load = set()
129
+ successfully_loaded = set()
130
+ failed_to_load = set()
131
+
132
+ # Determine which categories need to be loaded
133
+ for tool_name in missing_tools:
134
+ category = tool_to_category.get(tool_name)
135
+ if category:
136
+ categories_to_load.add(category)
137
+ else:
138
+ failed_to_load.add(tool_name)
139
+
140
+ # Load the required categories
141
+ for category in categories_to_load:
142
+ try:
143
+ print(
144
+ f"🔄 Auto-loading category '{category}' for ComposeTool '{self.name}'"
145
+ )
146
+ self.tooluniverse.load_tools(tool_type=[category])
147
+
148
+ # Check which tools from this category are now available
149
+ for tool_name in missing_tools:
150
+ # Check both callable_functions and all_tool_dict
151
+ if (
152
+ tool_name in self.tooluniverse.callable_functions
153
+ or tool_name in self.tooluniverse.all_tool_dict
154
+ ):
155
+ successfully_loaded.add(tool_name)
156
+
157
+ except Exception as e:
158
+ print(f"❌ Failed to auto-load category '{category}': {e}")
159
+
160
+ failed_to_load = missing_tools - successfully_loaded
161
+
162
+ if successfully_loaded:
163
+ print(
164
+ f"✅ Successfully auto-loaded tools: {', '.join(successfully_loaded)}"
165
+ )
166
+ if failed_to_load:
167
+ print(f"❌ Failed to load tools: {', '.join(failed_to_load)}")
168
+
169
+ return successfully_loaded, failed_to_load
170
+
171
+ def _load_code_from_file(self):
172
+ """
173
+ Load composition code from external Python file.
174
+
175
+ Returns:
176
+ str: The composition code as a string
177
+ """
178
+ if not self.composition_file:
179
+ return ""
180
+
181
+ # Resolve file path relative to the tool configuration file
182
+ current_dir = os.path.dirname(os.path.abspath(__file__))
183
+ file_path = os.path.join(current_dir, "compose_scripts", self.composition_file)
184
+
185
+ try:
186
+ # Load the Python file as a module
187
+ spec = importlib.util.spec_from_file_location("compose_module", file_path)
188
+ compose_module = importlib.util.module_from_spec(spec)
189
+ spec.loader.exec_module(compose_module)
190
+
191
+ # Get the composition function
192
+ if hasattr(compose_module, self.composition_function):
193
+ compose_func = getattr(compose_module, self.composition_function)
194
+ # Extract the function code
195
+ import inspect
196
+
197
+ return inspect.getsource(compose_func)
198
+ else:
199
+ raise AttributeError(
200
+ f"Function '{self.composition_function}' not found in {self.composition_file}"
201
+ )
202
+
203
+ except Exception as e:
204
+ print(f"Error loading composition file {self.composition_file}: {e}")
205
+ return f"# Error loading file: {e}\nresult = {{'error': 'Failed to load composition code'}}"
206
+
207
+ def run(self, arguments):
208
+ """
209
+ Execute the composed tool with custom code logic.
210
+
211
+ Args:
212
+ arguments (dict): Input arguments for the composition
213
+
214
+ Returns:
215
+ Any: Result from the composition execution
216
+ """
217
+ if not self.tooluniverse:
218
+ return {"error": "ToolUniverse reference is required for ComposeTool"}
219
+
220
+ if not self.composition_code:
221
+ return {"error": "No composition code provided"}
222
+
223
+ # Check for missing dependencies
224
+ all_dependencies = self.discovered_dependencies.union(set(self.required_tools))
225
+ missing_tools = set()
226
+
227
+ for tool_name in all_dependencies:
228
+ # Check both callable_functions and all_tool_dict
229
+ if (
230
+ tool_name not in self.tooluniverse.callable_functions
231
+ and tool_name not in self.tooluniverse.all_tool_dict
232
+ ):
233
+ missing_tools.add(tool_name)
234
+
235
+ # Handle missing dependencies
236
+ if missing_tools:
237
+ if self.auto_load_dependencies:
238
+ print(
239
+ f"🔍 ComposeTool '{self.name}' detected missing dependencies: {', '.join(missing_tools)}"
240
+ )
241
+ successfully_loaded, still_missing = self._load_missing_dependencies(
242
+ missing_tools
243
+ )
244
+
245
+ if still_missing:
246
+ if self.fail_on_missing_tools:
247
+ return {
248
+ "error": f"Required tools not available: {', '.join(still_missing)}",
249
+ "missing_tools": list(still_missing),
250
+ "auto_loaded": list(successfully_loaded),
251
+ }
252
+ else:
253
+ print(
254
+ f"⚠️ Continuing execution despite missing tools: {', '.join(still_missing)}"
255
+ )
256
+ else:
257
+ if self.fail_on_missing_tools:
258
+ return {
259
+ "error": f"Required tools not available: {', '.join(missing_tools)}",
260
+ "missing_tools": list(missing_tools),
261
+ "auto_load_disabled": True,
262
+ }
263
+ else:
264
+ print(
265
+ f"⚠️ ComposeTool '{self.name}' has missing dependencies but continuing: {', '.join(missing_tools)}"
266
+ )
267
+
268
+ try:
269
+ if self.composition_file:
270
+ # Execute function from external file
271
+ return self._execute_from_file(arguments)
272
+ else:
273
+ # Execute inline code (existing behavior)
274
+ return self._execute_inline_code(arguments)
275
+
276
+ except Exception as e:
277
+ error_msg = f"Error in ComposeTool '{self.name}': {str(e)}"
278
+ traceback.print_exc() # 打印完整堆栈
279
+ print(f"\033[91m{error_msg}\033[0m")
280
+
281
+ return {"error": error_msg, "traceback": traceback.format_exc()}
282
+
283
+ def _execute_from_file(self, arguments):
284
+ """
285
+ Execute composition code from external file.
286
+
287
+ Args:
288
+ arguments (dict): Input arguments
289
+
290
+ Returns:
291
+ Any: Result from the composition execution
292
+ """
293
+ # Resolve file path
294
+ current_dir = os.path.dirname(os.path.abspath(__file__))
295
+ file_path = os.path.join(current_dir, "compose_scripts", self.composition_file)
296
+
297
+ # Load the Python file as a module
298
+ spec = importlib.util.spec_from_file_location("compose_module", file_path)
299
+ compose_module = importlib.util.module_from_spec(spec)
300
+ spec.loader.exec_module(compose_module)
301
+
302
+ # Get the composition function
303
+ compose_func = getattr(compose_module, self.composition_function)
304
+
305
+ # Execute the function with context
306
+ return compose_func(arguments, self.tooluniverse, self._call_tool)
307
+
308
+ def _execute_inline_code(self, arguments):
309
+ """
310
+ Execute inline composition code (existing behavior).
311
+
312
+ Args:
313
+ arguments (dict): Input arguments
314
+
315
+ Returns:
316
+ Any: Result from the composition execution
317
+ """
318
+ # Initialize execution context
319
+ context = {
320
+ "arguments": arguments,
321
+ "tooluniverse": self.tooluniverse,
322
+ "call_tool": self._call_tool,
323
+ "json": json,
324
+ "copy": copy,
325
+ "result": None, # The code should set this variable
326
+ }
327
+
328
+ # Execute the composition code
329
+ exec_globals = {"__builtins__": __builtins__, **context}
330
+
331
+ exec(self.composition_code, exec_globals)
332
+
333
+ # Return the result variable set by the code
334
+ return exec_globals.get(
335
+ "result", {"error": "No result variable set in composition code"}
336
+ )
337
+
338
+ def _call_tool(self, tool_name, arguments):
339
+ """
340
+ Helper function to call other tools from within composition code.
341
+
342
+ Args:
343
+ tool_name (str): Name of the tool to call
344
+ arguments (dict): Arguments to pass to the tool
345
+
346
+ Returns:
347
+ Any: Result from the tool execution
348
+ """
349
+ # Check if tool is available (check both callable_functions and all_tool_dict)
350
+ if (
351
+ tool_name not in self.tooluniverse.callable_functions
352
+ and tool_name not in self.tooluniverse.all_tool_dict
353
+ ):
354
+ if self.auto_load_dependencies:
355
+ # Try to load the tool
356
+ missing_tools = {tool_name}
357
+ successfully_loaded, still_missing = self._load_missing_dependencies(
358
+ missing_tools
359
+ )
360
+
361
+ if (
362
+ tool_name in still_missing
363
+ and tool_name not in self.tooluniverse.all_tool_dict
364
+ ):
365
+ return f"Invalid function call: Function name {tool_name} not found in loaded tools."
366
+ else:
367
+ return f"Invalid function call: Function name {tool_name} not found in loaded tools."
368
+
369
+ function_call = {"name": tool_name, "arguments": arguments}
370
+
371
+ return self.tooluniverse.run_one_function(function_call)