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,408 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Tool Graph Generator Script
4
+
5
+ This script generates a compatibility graph for all tools in ToolUniverse.
6
+ It uses the ToolCompatibilityAnalyzer and ToolGraphComposer to analyze tool relationships.
7
+
8
+ Usage:
9
+ python generate_tool_graph.py [options]
10
+
11
+ Examples:
12
+ # Quick analysis with limited tools
13
+ python generate_tool_graph.py --quick --max-tools 5
14
+
15
+ # Detailed analysis of specific categories
16
+ python generate_tool_graph.py --categories pubchem,chembl --analysis-depth detailed
17
+
18
+ # Full comprehensive analysis (may take hours)
19
+ python generate_tool_graph.py --analysis-depth comprehensive --force-rebuild
20
+ """
21
+
22
+ import argparse
23
+ import json
24
+ import os
25
+ import sys
26
+ import time
27
+ from datetime import datetime
28
+ from pathlib import Path
29
+
30
+ # Add parent directories to path for imports
31
+ script_dir = Path(__file__).parent
32
+ tooluniverse_dir = script_dir.parent
33
+ src_dir = tooluniverse_dir.parent
34
+ sys.path.insert(0, str(src_dir))
35
+
36
+ from tooluniverse import ToolUniverse # noqa: E402
37
+
38
+
39
+ def parse_arguments():
40
+ """Parse command line arguments."""
41
+
42
+ parser = argparse.ArgumentParser(
43
+ description="Generate tool compatibility graph for ToolUniverse",
44
+ formatter_class=argparse.RawDescriptionHelpFormatter,
45
+ epilog="""
46
+ Examples:
47
+ %(prog)s --quick --max-tools 10
48
+ %(prog)s --categories pubchem,chembl,europepmc
49
+ %(prog)s --analysis-depth comprehensive --output ./full_graph
50
+ %(prog)s --force-rebuild --min-score 80
51
+ """,
52
+ )
53
+
54
+ # Output options
55
+ parser.add_argument(
56
+ "--output",
57
+ "-o",
58
+ type=str,
59
+ default="./tool_composition_graph",
60
+ help="Output path for graph files (default: ./tool_composition_graph)",
61
+ )
62
+
63
+ parser.add_argument(
64
+ "--force-rebuild",
65
+ "-f",
66
+ action="store_true",
67
+ help="Force rebuild even if cached graph exists",
68
+ )
69
+
70
+ # Analysis options
71
+ parser.add_argument(
72
+ "--analysis-depth",
73
+ "-d",
74
+ choices=["quick", "detailed", "comprehensive"],
75
+ default="detailed",
76
+ help="Analysis depth (default: detailed)",
77
+ )
78
+
79
+ parser.add_argument(
80
+ "--min-score",
81
+ "-s",
82
+ type=int,
83
+ default=60,
84
+ help="Minimum compatibility score for edges (0-100, default: 60)",
85
+ )
86
+
87
+ # Tool selection options
88
+ parser.add_argument(
89
+ "--categories",
90
+ "-c",
91
+ type=str,
92
+ help="Comma-separated list of tool categories to include (e.g., 'pubchem,chembl')",
93
+ )
94
+
95
+ parser.add_argument(
96
+ "--exclude-categories",
97
+ "-e",
98
+ type=str,
99
+ default="tool_finder,special_tools",
100
+ help="Comma-separated list of categories to exclude (default: tool_finder,special_tools)",
101
+ )
102
+
103
+ parser.add_argument(
104
+ "--max-tools",
105
+ "-m",
106
+ type=int,
107
+ default=50,
108
+ help="Maximum tools per category (default: 50)",
109
+ )
110
+
111
+ # Convenience options
112
+ parser.add_argument(
113
+ "--quick",
114
+ "-q",
115
+ action="store_true",
116
+ help="Quick mode: use quick analysis and limit to 10 tools per category",
117
+ )
118
+
119
+ parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
120
+
121
+ parser.add_argument(
122
+ "--dry-run",
123
+ action="store_true",
124
+ help="Show what would be analyzed without actually running",
125
+ )
126
+
127
+ return parser.parse_args()
128
+
129
+
130
+ def setup_analysis_parameters(args):
131
+ """Setup analysis parameters based on arguments."""
132
+
133
+ # Handle quick mode
134
+ if args.quick:
135
+ analysis_depth = "quick"
136
+ max_tools = 10
137
+ min_score = 70 # Higher threshold for quick mode
138
+ else:
139
+ analysis_depth = args.analysis_depth
140
+ max_tools = args.max_tools
141
+ min_score = args.min_score
142
+
143
+ # Handle category selection
144
+ if args.categories:
145
+ include_categories = [cat.strip() for cat in args.categories.split(",")]
146
+ exclude_categories = []
147
+ else:
148
+ include_categories = None
149
+ exclude_categories = [cat.strip() for cat in args.exclude_categories.split(",")]
150
+
151
+ return {
152
+ "output_path": args.output,
153
+ "analysis_depth": analysis_depth,
154
+ "min_compatibility_score": min_score,
155
+ "exclude_categories": exclude_categories,
156
+ "include_categories": include_categories,
157
+ "max_tools_per_category": max_tools,
158
+ "force_rebuild": args.force_rebuild,
159
+ }
160
+
161
+
162
+ def preview_analysis(tooluniverse, parameters):
163
+ """Show what tools would be analyzed without running the analysis."""
164
+
165
+ print("Analysis Preview")
166
+ print("=" * 50)
167
+ print(f"Analysis Depth: {parameters['analysis_depth']}")
168
+ print(f"Min Compatibility Score: {parameters['min_compatibility_score']}")
169
+ print(f"Max Tools per Category: {parameters['max_tools_per_category']}")
170
+ print(f"Output Path: {parameters['output_path']}")
171
+ print()
172
+
173
+ # Show categories and tool counts
174
+ categories = tooluniverse.tool_category_dicts
175
+ exclude_set = set(parameters.get("exclude_categories", []))
176
+ include_set = (
177
+ set(parameters.get("include_categories", []))
178
+ if parameters.get("include_categories")
179
+ else None
180
+ )
181
+
182
+ total_tools = 0
183
+ selected_categories = []
184
+
185
+ for category, tools in categories.items():
186
+ # Apply category filtering
187
+ if include_set and category not in include_set:
188
+ continue
189
+ if category in exclude_set:
190
+ continue
191
+
192
+ tool_count = min(len(tools), parameters["max_tools_per_category"])
193
+ total_tools += tool_count
194
+ selected_categories.append((category, tool_count, len(tools)))
195
+
196
+ print("Selected Categories:")
197
+ for category, selected_count, total_count in selected_categories:
198
+ status = (
199
+ f"({selected_count}/{total_count})"
200
+ if selected_count < total_count
201
+ else f"({total_count})"
202
+ )
203
+ print(f" {category}: {status}")
204
+
205
+ print(f"\nTotal tools to analyze: {total_tools}")
206
+ print(f"Estimated tool pairs: {total_tools * (total_tools - 1)}")
207
+
208
+ # Time estimates
209
+ if parameters["analysis_depth"] == "quick":
210
+ est_time_per_pair = 2 # seconds
211
+ elif parameters["analysis_depth"] == "detailed":
212
+ est_time_per_pair = 5 # seconds
213
+ else: # comprehensive
214
+ est_time_per_pair = 10 # seconds
215
+
216
+ total_pairs = total_tools * (total_tools - 1)
217
+ est_total_time = total_pairs * est_time_per_pair
218
+
219
+ print("\nEstimated Analysis Time:")
220
+ print(f" Per pair: ~{est_time_per_pair} seconds")
221
+ print(f" Total: ~{est_total_time // 3600}h {(est_total_time % 3600) // 60}m")
222
+
223
+ return total_tools > 0
224
+
225
+
226
+ def run_graph_generation(tooluniverse, parameters, verbose=False):
227
+ """Run the graph generation process."""
228
+
229
+ print("Starting Tool Graph Generation")
230
+ print("=" * 50)
231
+
232
+ start_time = time.time()
233
+
234
+ try:
235
+ # Prepare arguments for ToolGraphComposer
236
+ composer_args = {
237
+ "output_path": parameters["output_path"],
238
+ "analysis_depth": parameters["analysis_depth"],
239
+ "min_compatibility_score": parameters["min_compatibility_score"],
240
+ "exclude_categories": parameters["exclude_categories"],
241
+ "max_tools_per_category": parameters["max_tools_per_category"],
242
+ "force_rebuild": parameters["force_rebuild"],
243
+ }
244
+
245
+ # Add include_categories if specified
246
+ if parameters.get("include_categories"):
247
+ # For include_categories, we need to modify exclude_categories
248
+ all_categories = set(tooluniverse.tool_category_dicts.keys())
249
+ include_set = set(parameters["include_categories"])
250
+ composer_args["exclude_categories"] = list(all_categories - include_set)
251
+
252
+ if verbose:
253
+ print("Composer arguments:")
254
+ print(json.dumps(composer_args, indent=2))
255
+ print()
256
+
257
+ # Run the composition
258
+ result = tooluniverse.run(
259
+ json.dumps([{"name": "ToolGraphComposer", "arguments": composer_args}])
260
+ )
261
+
262
+ # Handle result formatting
263
+ if isinstance(result, list) and len(result) > 0:
264
+ result = result[0]
265
+
266
+ end_time = time.time()
267
+ duration = end_time - start_time
268
+
269
+ # Display results
270
+ print("Graph Generation Complete!")
271
+ print("-" * 30)
272
+ print(
273
+ f"Duration: {duration // 3600:.0f}h {(duration % 3600) // 60:.0f}m {duration % 60:.1f}s"
274
+ )
275
+
276
+ if isinstance(result, dict):
277
+ if result.get("status") == "success":
278
+ print("✅ Status: Success")
279
+
280
+ # Show files created
281
+ if "graph_files" in result:
282
+ print("\nGenerated Files:")
283
+ for format_type, file_path in result["graph_files"].items():
284
+ if os.path.exists(file_path):
285
+ file_size = os.path.getsize(file_path)
286
+ print(
287
+ f" {format_type.upper()}: {file_path} ({file_size:,} bytes)"
288
+ )
289
+
290
+ # Show statistics
291
+ if "statistics" in result:
292
+ stats = result["statistics"]
293
+ print("\nGraph Statistics:")
294
+ print(f" Tools Analyzed: {result.get('tools_analyzed', 'N/A')}")
295
+ print(f" Nodes: {stats.get('total_nodes', 'N/A')}")
296
+ print(f" Edges: {stats.get('total_edges', 'N/A')}")
297
+ print(f" Edge Density: {stats.get('edge_density', 0):.3f}")
298
+
299
+ if "compatibility_scores" in stats:
300
+ scores = stats["compatibility_scores"]
301
+ print(
302
+ f" Avg Compatibility Score: {scores.get('average', 0):.1f}"
303
+ )
304
+ print(f" High-Quality Edges: {scores.get('count_high', 0)}")
305
+
306
+ if "automation_ready_percentage" in stats:
307
+ print(
308
+ f" Automation Ready: {stats['automation_ready_percentage']:.1f}%"
309
+ )
310
+
311
+ return True
312
+ else:
313
+ print("❌ Status: Failed")
314
+ print(f"Error: {result.get('message', 'Unknown error')}")
315
+ return False
316
+ else:
317
+ print("❌ Unexpected result format")
318
+ print(result)
319
+ return False
320
+
321
+ except Exception as e:
322
+ print(f"❌ Error during graph generation: {e}")
323
+ if verbose:
324
+ import traceback
325
+
326
+ traceback.print_exc()
327
+ return False
328
+
329
+
330
+ def main():
331
+ """Main function."""
332
+
333
+ args = parse_arguments()
334
+
335
+ print("ToolUniverse Graph Generator")
336
+ print("=" * 60)
337
+ print(f"Timestamp: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
338
+ print()
339
+
340
+ # Initialize ToolUniverse
341
+ if args.verbose:
342
+ print("Initializing ToolUniverse...")
343
+
344
+ try:
345
+ tu = ToolUniverse()
346
+ tu.load_tools()
347
+
348
+ if args.verbose:
349
+ print(f"Loaded {len(tu.all_tool_dict)} tools")
350
+ print(f"Categories: {len(tu.tool_category_dicts)}")
351
+ print()
352
+
353
+ except Exception as e:
354
+ print(f"❌ Failed to initialize ToolUniverse: {e}")
355
+ return 1
356
+
357
+ # Setup parameters
358
+ parameters = setup_analysis_parameters(args)
359
+
360
+ # Show preview
361
+ if not preview_analysis(tu, parameters):
362
+ print("❌ No tools selected for analysis. Check your category filters.")
363
+ return 1
364
+
365
+ # Dry run mode
366
+ if args.dry_run:
367
+ print(
368
+ "\n✅ Dry run complete. Use --force-rebuild to actually generate the graph."
369
+ )
370
+ return 0
371
+
372
+ # Confirmation for large analyses
373
+ total_categories = len(
374
+ [
375
+ cat
376
+ for cat in tu.tool_category_dicts.keys()
377
+ if cat not in parameters.get("exclude_categories", [])
378
+ ]
379
+ )
380
+
381
+ if (
382
+ not args.quick
383
+ and total_categories > 5
384
+ and parameters["max_tools_per_category"] > 20
385
+ ):
386
+ response = input("\nThis may take a very long time. Continue? (y/N): ")
387
+ if response.lower() != "y":
388
+ print("Cancelled.")
389
+ return 0
390
+
391
+ print("\n" + "=" * 60)
392
+
393
+ # Run the generation
394
+ success = run_graph_generation(tu, parameters, verbose=args.verbose)
395
+
396
+ if success:
397
+ print("\n🎉 Graph generation completed successfully!")
398
+ print(f"Files saved to: {parameters['output_path']}.*")
399
+ print("\nTo visualize the graph, run:")
400
+ print(f"python visualize_tool_graph.py {parameters['output_path']}.json")
401
+ return 0
402
+ else:
403
+ print("\n❌ Graph generation failed.")
404
+ return 1
405
+
406
+
407
+ if __name__ == "__main__":
408
+ sys.exit(main())