pomera-ai-commander 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +680 -0
- package/bin/pomera-ai-commander.js +62 -0
- package/core/__init__.py +66 -0
- package/core/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/__pycache__/app_context.cpython-313.pyc +0 -0
- package/core/__pycache__/async_text_processor.cpython-313.pyc +0 -0
- package/core/__pycache__/backup_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/backup_recovery_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/content_hash_cache.cpython-313.pyc +0 -0
- package/core/__pycache__/context_menu.cpython-313.pyc +0 -0
- package/core/__pycache__/data_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/database_connection_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_curl_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_promera_ai_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_schema.cpython-313.pyc +0 -0
- package/core/__pycache__/database_schema_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_settings_manager_interface.cpython-313.pyc +0 -0
- package/core/__pycache__/dialog_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/efficient_line_numbers.cpython-313.pyc +0 -0
- package/core/__pycache__/error_handler.cpython-313.pyc +0 -0
- package/core/__pycache__/error_service.cpython-313.pyc +0 -0
- package/core/__pycache__/event_consolidator.cpython-313.pyc +0 -0
- package/core/__pycache__/memory_efficient_text_widget.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_test_suite.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_find_replace.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_pattern_engine.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_search_highlighter.cpython-313.pyc +0 -0
- package/core/__pycache__/performance_monitor.cpython-313.pyc +0 -0
- package/core/__pycache__/persistence_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/progressive_stats_calculator.cpython-313.pyc +0 -0
- package/core/__pycache__/regex_pattern_cache.cpython-313.pyc +0 -0
- package/core/__pycache__/regex_pattern_library.cpython-313.pyc +0 -0
- package/core/__pycache__/search_operation_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_defaults_registry.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_integrity_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_serializer.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/smart_stats_calculator.cpython-313.pyc +0 -0
- package/core/__pycache__/statistics_update_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/stats_config_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/streaming_text_handler.cpython-313.pyc +0 -0
- package/core/__pycache__/task_scheduler.cpython-313.pyc +0 -0
- package/core/__pycache__/visibility_monitor.cpython-313.pyc +0 -0
- package/core/__pycache__/widget_cache.cpython-313.pyc +0 -0
- package/core/app_context.py +482 -0
- package/core/async_text_processor.py +422 -0
- package/core/backup_manager.py +656 -0
- package/core/backup_recovery_manager.py +1034 -0
- package/core/content_hash_cache.py +509 -0
- package/core/context_menu.py +313 -0
- package/core/data_validator.py +1067 -0
- package/core/database_connection_manager.py +745 -0
- package/core/database_curl_settings_manager.py +609 -0
- package/core/database_promera_ai_settings_manager.py +447 -0
- package/core/database_schema.py +412 -0
- package/core/database_schema_manager.py +396 -0
- package/core/database_settings_manager.py +1508 -0
- package/core/database_settings_manager_interface.py +457 -0
- package/core/dialog_manager.py +735 -0
- package/core/efficient_line_numbers.py +511 -0
- package/core/error_handler.py +747 -0
- package/core/error_service.py +431 -0
- package/core/event_consolidator.py +512 -0
- package/core/mcp/__init__.py +43 -0
- package/core/mcp/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/protocol.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/schema.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/server_stdio.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/tool_registry.cpython-313.pyc +0 -0
- package/core/mcp/protocol.py +288 -0
- package/core/mcp/schema.py +251 -0
- package/core/mcp/server_stdio.py +299 -0
- package/core/mcp/tool_registry.py +2345 -0
- package/core/memory_efficient_text_widget.py +712 -0
- package/core/migration_manager.py +915 -0
- package/core/migration_test_suite.py +1086 -0
- package/core/migration_validator.py +1144 -0
- package/core/optimized_find_replace.py +715 -0
- package/core/optimized_pattern_engine.py +424 -0
- package/core/optimized_search_highlighter.py +553 -0
- package/core/performance_monitor.py +675 -0
- package/core/persistence_manager.py +713 -0
- package/core/progressive_stats_calculator.py +632 -0
- package/core/regex_pattern_cache.py +530 -0
- package/core/regex_pattern_library.py +351 -0
- package/core/search_operation_manager.py +435 -0
- package/core/settings_defaults_registry.py +1087 -0
- package/core/settings_integrity_validator.py +1112 -0
- package/core/settings_serializer.py +558 -0
- package/core/settings_validator.py +1824 -0
- package/core/smart_stats_calculator.py +710 -0
- package/core/statistics_update_manager.py +619 -0
- package/core/stats_config_manager.py +858 -0
- package/core/streaming_text_handler.py +723 -0
- package/core/task_scheduler.py +596 -0
- package/core/update_pattern_library.py +169 -0
- package/core/visibility_monitor.py +596 -0
- package/core/widget_cache.py +498 -0
- package/mcp.json +61 -0
- package/package.json +57 -0
- package/pomera.py +7483 -0
- package/pomera_mcp_server.py +144 -0
- package/tools/__init__.py +5 -0
- package/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- package/tools/__pycache__/ai_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/ascii_art_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/base64_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/base_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/case_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/column_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/cron_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_history.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_processor.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_settings.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/diff_viewer.cpython-313.pyc +0 -0
- package/tools/__pycache__/email_extraction_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/email_header_analyzer.cpython-313.pyc +0 -0
- package/tools/__pycache__/extraction_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/find_replace.cpython-313.pyc +0 -0
- package/tools/__pycache__/folder_file_reporter.cpython-313.pyc +0 -0
- package/tools/__pycache__/folder_file_reporter_adapter.cpython-313.pyc +0 -0
- package/tools/__pycache__/generator_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/hash_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/html_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/huggingface_helper.cpython-313.pyc +0 -0
- package/tools/__pycache__/jsonxml_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/line_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/list_comparator.cpython-313.pyc +0 -0
- package/tools/__pycache__/markdown_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/mcp_widget.cpython-313.pyc +0 -0
- package/tools/__pycache__/notes_widget.cpython-313.pyc +0 -0
- package/tools/__pycache__/number_base_converter.cpython-313.pyc +0 -0
- package/tools/__pycache__/regex_extractor.cpython-313.pyc +0 -0
- package/tools/__pycache__/slug_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/sorter_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/string_escape_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/text_statistics_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/text_wrapper.cpython-313.pyc +0 -0
- package/tools/__pycache__/timestamp_converter.cpython-313.pyc +0 -0
- package/tools/__pycache__/tool_loader.cpython-313.pyc +0 -0
- package/tools/__pycache__/translator_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/url_link_extractor.cpython-313.pyc +0 -0
- package/tools/__pycache__/url_parser.cpython-313.pyc +0 -0
- package/tools/__pycache__/whitespace_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/word_frequency_counter.cpython-313.pyc +0 -0
- package/tools/ai_tools.py +2892 -0
- package/tools/ascii_art_generator.py +353 -0
- package/tools/base64_tools.py +184 -0
- package/tools/base_tool.py +511 -0
- package/tools/case_tool.py +309 -0
- package/tools/column_tools.py +396 -0
- package/tools/cron_tool.py +885 -0
- package/tools/curl_history.py +601 -0
- package/tools/curl_processor.py +1208 -0
- package/tools/curl_settings.py +503 -0
- package/tools/curl_tool.py +5467 -0
- package/tools/diff_viewer.py +1072 -0
- package/tools/email_extraction_tool.py +249 -0
- package/tools/email_header_analyzer.py +426 -0
- package/tools/extraction_tools.py +250 -0
- package/tools/find_replace.py +1751 -0
- package/tools/folder_file_reporter.py +1463 -0
- package/tools/folder_file_reporter_adapter.py +480 -0
- package/tools/generator_tools.py +1217 -0
- package/tools/hash_generator.py +256 -0
- package/tools/html_tool.py +657 -0
- package/tools/huggingface_helper.py +449 -0
- package/tools/jsonxml_tool.py +730 -0
- package/tools/line_tools.py +419 -0
- package/tools/list_comparator.py +720 -0
- package/tools/markdown_tools.py +562 -0
- package/tools/mcp_widget.py +1417 -0
- package/tools/notes_widget.py +973 -0
- package/tools/number_base_converter.py +373 -0
- package/tools/regex_extractor.py +572 -0
- package/tools/slug_generator.py +311 -0
- package/tools/sorter_tools.py +459 -0
- package/tools/string_escape_tool.py +393 -0
- package/tools/text_statistics_tool.py +366 -0
- package/tools/text_wrapper.py +431 -0
- package/tools/timestamp_converter.py +422 -0
- package/tools/tool_loader.py +710 -0
- package/tools/translator_tools.py +523 -0
- package/tools/url_link_extractor.py +262 -0
- package/tools/url_parser.py +205 -0
- package/tools/whitespace_tools.py +356 -0
- package/tools/word_frequency_counter.py +147 -0
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool Loader - Centralized tool registration and lazy loading.
|
|
3
|
+
|
|
4
|
+
This module replaces the 38+ try/except import blocks in pomera.py with a cleaner
|
|
5
|
+
registry-based approach that supports lazy loading.
|
|
6
|
+
|
|
7
|
+
Author: Pomera AI Commander Team
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import importlib
|
|
11
|
+
import logging
|
|
12
|
+
from typing import Dict, Any, Optional, Callable, Type, List, Tuple
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from enum import Enum
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ToolCategory(Enum):
|
|
21
|
+
"""Tool categories for organization."""
|
|
22
|
+
CORE = "Core Tools"
|
|
23
|
+
AI = "AI Tools"
|
|
24
|
+
EXTRACTION = "Extraction Tools"
|
|
25
|
+
CONVERSION = "Conversion Tools"
|
|
26
|
+
TEXT_MANIPULATION = "Text Manipulation"
|
|
27
|
+
GENERATORS = "Generators"
|
|
28
|
+
ANALYSIS = "Analysis Tools"
|
|
29
|
+
UTILITY = "Utility Tools"
|
|
30
|
+
MCP = "MCP Tools"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class ToolSpec:
|
|
35
|
+
"""
|
|
36
|
+
Specification for a loadable tool.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
name: Display name of the tool (used in UI)
|
|
40
|
+
module_path: Python module path (e.g., "tools.case_tool")
|
|
41
|
+
class_name: Name of the class to import (e.g., "CaseTool")
|
|
42
|
+
category: Tool category for organization
|
|
43
|
+
widget_class: Optional separate widget class name
|
|
44
|
+
dependencies: Optional list of required pip packages
|
|
45
|
+
description: Tool description for UI/help
|
|
46
|
+
is_widget: True if the class is a full widget (not just a tool class)
|
|
47
|
+
available_flag: Legacy flag name for backwards compatibility
|
|
48
|
+
"""
|
|
49
|
+
name: str
|
|
50
|
+
module_path: str
|
|
51
|
+
class_name: str
|
|
52
|
+
category: ToolCategory = ToolCategory.UTILITY
|
|
53
|
+
widget_class: Optional[str] = None
|
|
54
|
+
dependencies: List[str] = field(default_factory=list)
|
|
55
|
+
description: str = ""
|
|
56
|
+
is_widget: bool = False
|
|
57
|
+
available_flag: str = "" # e.g., "CASE_TOOL_MODULE_AVAILABLE"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Complete tool specifications registry
|
|
61
|
+
TOOL_SPECS: Dict[str, ToolSpec] = {
|
|
62
|
+
# Core Tools
|
|
63
|
+
"Case Tool": ToolSpec(
|
|
64
|
+
name="Case Tool",
|
|
65
|
+
module_path="tools.case_tool",
|
|
66
|
+
class_name="CaseTool",
|
|
67
|
+
category=ToolCategory.CORE,
|
|
68
|
+
description="Transform text case (uppercase, lowercase, title case, etc.)",
|
|
69
|
+
available_flag="CASE_TOOL_MODULE_AVAILABLE"
|
|
70
|
+
),
|
|
71
|
+
"Find & Replace": ToolSpec(
|
|
72
|
+
name="Find & Replace",
|
|
73
|
+
module_path="tools.find_replace",
|
|
74
|
+
class_name="FindReplaceWidget",
|
|
75
|
+
category=ToolCategory.CORE,
|
|
76
|
+
is_widget=True,
|
|
77
|
+
description="Find and replace text with regex support",
|
|
78
|
+
available_flag="FIND_REPLACE_MODULE_AVAILABLE"
|
|
79
|
+
),
|
|
80
|
+
"Diff Viewer": ToolSpec(
|
|
81
|
+
name="Diff Viewer",
|
|
82
|
+
module_path="tools.diff_viewer",
|
|
83
|
+
class_name="DiffViewerWidget",
|
|
84
|
+
widget_class="DiffViewerSettingsWidget",
|
|
85
|
+
category=ToolCategory.CORE,
|
|
86
|
+
is_widget=True,
|
|
87
|
+
description="Compare and view differences between texts",
|
|
88
|
+
available_flag="DIFF_VIEWER_MODULE_AVAILABLE"
|
|
89
|
+
),
|
|
90
|
+
|
|
91
|
+
# AI Tools
|
|
92
|
+
"AI Tools": ToolSpec(
|
|
93
|
+
name="AI Tools",
|
|
94
|
+
module_path="tools.ai_tools",
|
|
95
|
+
class_name="AIToolsWidget",
|
|
96
|
+
category=ToolCategory.AI,
|
|
97
|
+
is_widget=True,
|
|
98
|
+
description="AI-powered text processing with multiple providers",
|
|
99
|
+
available_flag="AI_TOOLS_AVAILABLE"
|
|
100
|
+
),
|
|
101
|
+
|
|
102
|
+
# Extraction Tools
|
|
103
|
+
"Email Extraction": ToolSpec(
|
|
104
|
+
name="Email Extraction",
|
|
105
|
+
module_path="tools.email_extraction_tool",
|
|
106
|
+
class_name="EmailExtractionTool",
|
|
107
|
+
category=ToolCategory.EXTRACTION,
|
|
108
|
+
description="Extract email addresses from text",
|
|
109
|
+
available_flag="EMAIL_EXTRACTION_MODULE_AVAILABLE"
|
|
110
|
+
),
|
|
111
|
+
"Email Header Analyzer": ToolSpec(
|
|
112
|
+
name="Email Header Analyzer",
|
|
113
|
+
module_path="tools.email_header_analyzer",
|
|
114
|
+
class_name="EmailHeaderAnalyzer",
|
|
115
|
+
category=ToolCategory.EXTRACTION,
|
|
116
|
+
description="Analyze email headers for routing and authentication info",
|
|
117
|
+
available_flag="EMAIL_HEADER_ANALYZER_MODULE_AVAILABLE"
|
|
118
|
+
),
|
|
119
|
+
"URL Link Extractor": ToolSpec(
|
|
120
|
+
name="URL Link Extractor",
|
|
121
|
+
module_path="tools.url_link_extractor",
|
|
122
|
+
class_name="URLLinkExtractor",
|
|
123
|
+
category=ToolCategory.EXTRACTION,
|
|
124
|
+
description="Extract URLs and links from text",
|
|
125
|
+
available_flag="URL_LINK_EXTRACTOR_MODULE_AVAILABLE"
|
|
126
|
+
),
|
|
127
|
+
"Regex Extractor": ToolSpec(
|
|
128
|
+
name="Regex Extractor",
|
|
129
|
+
module_path="tools.regex_extractor",
|
|
130
|
+
class_name="RegexExtractor",
|
|
131
|
+
category=ToolCategory.EXTRACTION,
|
|
132
|
+
description="Extract text patterns using regular expressions",
|
|
133
|
+
available_flag="REGEX_EXTRACTOR_MODULE_AVAILABLE"
|
|
134
|
+
),
|
|
135
|
+
"URL Parser": ToolSpec(
|
|
136
|
+
name="URL Parser",
|
|
137
|
+
module_path="tools.url_parser",
|
|
138
|
+
class_name="URLParser",
|
|
139
|
+
category=ToolCategory.EXTRACTION,
|
|
140
|
+
description="Parse and analyze URL components",
|
|
141
|
+
available_flag="URL_PARSER_MODULE_AVAILABLE"
|
|
142
|
+
),
|
|
143
|
+
"HTML Tool": ToolSpec(
|
|
144
|
+
name="HTML Tool",
|
|
145
|
+
module_path="tools.html_tool",
|
|
146
|
+
class_name="HTMLExtractionTool",
|
|
147
|
+
category=ToolCategory.EXTRACTION,
|
|
148
|
+
description="Extract content from HTML",
|
|
149
|
+
available_flag="HTML_EXTRACTION_TOOL_MODULE_AVAILABLE"
|
|
150
|
+
),
|
|
151
|
+
"Extraction Tools": ToolSpec(
|
|
152
|
+
name="Extraction Tools",
|
|
153
|
+
module_path="tools.extraction_tools",
|
|
154
|
+
class_name="ExtractionTools",
|
|
155
|
+
category=ToolCategory.EXTRACTION,
|
|
156
|
+
description="General purpose extraction utilities",
|
|
157
|
+
available_flag="EXTRACTION_TOOLS_MODULE_AVAILABLE"
|
|
158
|
+
),
|
|
159
|
+
|
|
160
|
+
# Conversion Tools
|
|
161
|
+
"Base64 Tools": ToolSpec(
|
|
162
|
+
name="Base64 Tools",
|
|
163
|
+
module_path="tools.base64_tools",
|
|
164
|
+
class_name="Base64Tools",
|
|
165
|
+
widget_class="Base64ToolsWidget",
|
|
166
|
+
category=ToolCategory.CONVERSION,
|
|
167
|
+
description="Encode and decode Base64",
|
|
168
|
+
available_flag="BASE64_TOOLS_MODULE_AVAILABLE"
|
|
169
|
+
),
|
|
170
|
+
"JSON/XML Tool": ToolSpec(
|
|
171
|
+
name="JSON/XML Tool",
|
|
172
|
+
module_path="tools.jsonxml_tool",
|
|
173
|
+
class_name="JSONXMLTool",
|
|
174
|
+
category=ToolCategory.CONVERSION,
|
|
175
|
+
description="Convert between JSON and XML formats",
|
|
176
|
+
available_flag="JSONXML_TOOL_MODULE_AVAILABLE"
|
|
177
|
+
),
|
|
178
|
+
"Hash Generator": ToolSpec(
|
|
179
|
+
name="Hash Generator",
|
|
180
|
+
module_path="tools.hash_generator",
|
|
181
|
+
class_name="HashGenerator",
|
|
182
|
+
category=ToolCategory.CONVERSION,
|
|
183
|
+
description="Generate MD5, SHA1, SHA256 and other hashes",
|
|
184
|
+
available_flag="HASH_GENERATOR_MODULE_AVAILABLE"
|
|
185
|
+
),
|
|
186
|
+
"Number Base Converter": ToolSpec(
|
|
187
|
+
name="Number Base Converter",
|
|
188
|
+
module_path="tools.number_base_converter",
|
|
189
|
+
class_name="NumberBaseConverter",
|
|
190
|
+
category=ToolCategory.CONVERSION,
|
|
191
|
+
description="Convert numbers between binary, octal, decimal, hex",
|
|
192
|
+
available_flag="NUMBER_BASE_CONVERTER_MODULE_AVAILABLE"
|
|
193
|
+
),
|
|
194
|
+
"Timestamp Converter": ToolSpec(
|
|
195
|
+
name="Timestamp Converter",
|
|
196
|
+
module_path="tools.timestamp_converter",
|
|
197
|
+
class_name="TimestampConverter",
|
|
198
|
+
category=ToolCategory.CONVERSION,
|
|
199
|
+
description="Convert between timestamp formats",
|
|
200
|
+
available_flag="TIMESTAMP_CONVERTER_MODULE_AVAILABLE"
|
|
201
|
+
),
|
|
202
|
+
"String Escape Tool": ToolSpec(
|
|
203
|
+
name="String Escape Tool",
|
|
204
|
+
module_path="tools.string_escape_tool",
|
|
205
|
+
class_name="StringEscapeTool",
|
|
206
|
+
category=ToolCategory.CONVERSION,
|
|
207
|
+
description="Escape/unescape strings for various formats",
|
|
208
|
+
available_flag="STRING_ESCAPE_TOOL_MODULE_AVAILABLE"
|
|
209
|
+
),
|
|
210
|
+
|
|
211
|
+
# Text Manipulation Tools
|
|
212
|
+
"Sorter Tools": ToolSpec(
|
|
213
|
+
name="Sorter Tools",
|
|
214
|
+
module_path="tools.sorter_tools",
|
|
215
|
+
class_name="SorterTools",
|
|
216
|
+
category=ToolCategory.TEXT_MANIPULATION,
|
|
217
|
+
description="Sort lines alphabetically or numerically",
|
|
218
|
+
available_flag="SORTER_TOOLS_MODULE_AVAILABLE"
|
|
219
|
+
),
|
|
220
|
+
"Line Tools": ToolSpec(
|
|
221
|
+
name="Line Tools",
|
|
222
|
+
module_path="tools.line_tools",
|
|
223
|
+
class_name="LineTools",
|
|
224
|
+
category=ToolCategory.TEXT_MANIPULATION,
|
|
225
|
+
description="Line manipulation (remove duplicates, number lines, etc.)",
|
|
226
|
+
available_flag="LINE_TOOLS_MODULE_AVAILABLE"
|
|
227
|
+
),
|
|
228
|
+
"Whitespace Tools": ToolSpec(
|
|
229
|
+
name="Whitespace Tools",
|
|
230
|
+
module_path="tools.whitespace_tools",
|
|
231
|
+
class_name="WhitespaceTools",
|
|
232
|
+
category=ToolCategory.TEXT_MANIPULATION,
|
|
233
|
+
description="Trim, normalize whitespace and line endings",
|
|
234
|
+
available_flag="WHITESPACE_TOOLS_MODULE_AVAILABLE"
|
|
235
|
+
),
|
|
236
|
+
"Column Tools": ToolSpec(
|
|
237
|
+
name="Column Tools",
|
|
238
|
+
module_path="tools.column_tools",
|
|
239
|
+
class_name="ColumnTools",
|
|
240
|
+
category=ToolCategory.TEXT_MANIPULATION,
|
|
241
|
+
description="CSV and column manipulation",
|
|
242
|
+
available_flag="COLUMN_TOOLS_MODULE_AVAILABLE"
|
|
243
|
+
),
|
|
244
|
+
"Text Wrapper": ToolSpec(
|
|
245
|
+
name="Text Wrapper",
|
|
246
|
+
module_path="tools.text_wrapper",
|
|
247
|
+
class_name="TextWrapper",
|
|
248
|
+
category=ToolCategory.TEXT_MANIPULATION,
|
|
249
|
+
description="Wrap text to specified width",
|
|
250
|
+
available_flag="TEXT_WRAPPER_MODULE_AVAILABLE"
|
|
251
|
+
),
|
|
252
|
+
"Markdown Tools": ToolSpec(
|
|
253
|
+
name="Markdown Tools",
|
|
254
|
+
module_path="tools.markdown_tools",
|
|
255
|
+
class_name="MarkdownTools",
|
|
256
|
+
category=ToolCategory.TEXT_MANIPULATION,
|
|
257
|
+
description="Process and extract from Markdown",
|
|
258
|
+
available_flag="MARKDOWN_TOOLS_MODULE_AVAILABLE"
|
|
259
|
+
),
|
|
260
|
+
"Slug Generator": ToolSpec(
|
|
261
|
+
name="Slug Generator",
|
|
262
|
+
module_path="tools.slug_generator",
|
|
263
|
+
class_name="SlugGenerator",
|
|
264
|
+
category=ToolCategory.TEXT_MANIPULATION,
|
|
265
|
+
description="Generate URL-friendly slugs",
|
|
266
|
+
available_flag="SLUG_GENERATOR_MODULE_AVAILABLE"
|
|
267
|
+
),
|
|
268
|
+
"Translator Tools": ToolSpec(
|
|
269
|
+
name="Translator Tools",
|
|
270
|
+
module_path="tools.translator_tools",
|
|
271
|
+
class_name="TranslatorTools",
|
|
272
|
+
category=ToolCategory.TEXT_MANIPULATION,
|
|
273
|
+
description="Translate to/from Morse code and binary",
|
|
274
|
+
available_flag="TRANSLATOR_TOOLS_MODULE_AVAILABLE"
|
|
275
|
+
),
|
|
276
|
+
|
|
277
|
+
# Generator Tools
|
|
278
|
+
"Generator Tools": ToolSpec(
|
|
279
|
+
name="Generator Tools",
|
|
280
|
+
module_path="tools.generator_tools",
|
|
281
|
+
class_name="GeneratorTools",
|
|
282
|
+
widget_class="GeneratorToolsWidget",
|
|
283
|
+
category=ToolCategory.GENERATORS,
|
|
284
|
+
description="Generate passwords, UUIDs, Lorem Ipsum",
|
|
285
|
+
available_flag="GENERATOR_TOOLS_MODULE_AVAILABLE"
|
|
286
|
+
),
|
|
287
|
+
"ASCII Art Generator": ToolSpec(
|
|
288
|
+
name="ASCII Art Generator",
|
|
289
|
+
module_path="tools.ascii_art_generator",
|
|
290
|
+
class_name="ASCIIArtGenerator",
|
|
291
|
+
category=ToolCategory.GENERATORS,
|
|
292
|
+
description="Generate ASCII art from text",
|
|
293
|
+
available_flag="ASCII_ART_GENERATOR_MODULE_AVAILABLE"
|
|
294
|
+
),
|
|
295
|
+
|
|
296
|
+
# Analysis Tools
|
|
297
|
+
"Word Frequency Counter": ToolSpec(
|
|
298
|
+
name="Word Frequency Counter",
|
|
299
|
+
module_path="tools.word_frequency_counter",
|
|
300
|
+
class_name="WordFrequencyCounter",
|
|
301
|
+
category=ToolCategory.ANALYSIS,
|
|
302
|
+
description="Count word frequencies in text",
|
|
303
|
+
available_flag="WORD_FREQUENCY_COUNTER_MODULE_AVAILABLE"
|
|
304
|
+
),
|
|
305
|
+
"Text Statistics": ToolSpec(
|
|
306
|
+
name="Text Statistics",
|
|
307
|
+
module_path="tools.text_statistics_tool",
|
|
308
|
+
class_name="TextStatistics",
|
|
309
|
+
category=ToolCategory.ANALYSIS,
|
|
310
|
+
description="Calculate text statistics (chars, words, lines)",
|
|
311
|
+
available_flag="TEXT_STATISTICS_MODULE_AVAILABLE"
|
|
312
|
+
),
|
|
313
|
+
"Cron Tool": ToolSpec(
|
|
314
|
+
name="Cron Tool",
|
|
315
|
+
module_path="tools.cron_tool",
|
|
316
|
+
class_name="CronTool",
|
|
317
|
+
category=ToolCategory.ANALYSIS,
|
|
318
|
+
description="Parse and explain cron expressions",
|
|
319
|
+
available_flag="CRON_TOOL_MODULE_AVAILABLE"
|
|
320
|
+
),
|
|
321
|
+
|
|
322
|
+
# Utility Tools
|
|
323
|
+
"cURL Tool": ToolSpec(
|
|
324
|
+
name="cURL Tool",
|
|
325
|
+
module_path="tools.curl_tool",
|
|
326
|
+
class_name="CurlToolWidget",
|
|
327
|
+
category=ToolCategory.UTILITY,
|
|
328
|
+
is_widget=True,
|
|
329
|
+
description="Make HTTP requests",
|
|
330
|
+
available_flag="CURL_TOOL_MODULE_AVAILABLE"
|
|
331
|
+
),
|
|
332
|
+
"List Comparator": ToolSpec(
|
|
333
|
+
name="List Comparator",
|
|
334
|
+
module_path="tools.list_comparator",
|
|
335
|
+
class_name="DiffApp",
|
|
336
|
+
category=ToolCategory.UTILITY,
|
|
337
|
+
description="Compare two lists and find differences",
|
|
338
|
+
available_flag="LIST_COMPARATOR_MODULE_AVAILABLE"
|
|
339
|
+
),
|
|
340
|
+
"Notes Widget": ToolSpec(
|
|
341
|
+
name="Notes Widget",
|
|
342
|
+
module_path="tools.notes_widget",
|
|
343
|
+
class_name="NotesWidget",
|
|
344
|
+
category=ToolCategory.UTILITY,
|
|
345
|
+
is_widget=True,
|
|
346
|
+
description="Save and manage notes",
|
|
347
|
+
available_flag="NOTES_WIDGET_MODULE_AVAILABLE"
|
|
348
|
+
),
|
|
349
|
+
"Folder File Reporter": ToolSpec(
|
|
350
|
+
name="Folder File Reporter",
|
|
351
|
+
module_path="tools.folder_file_reporter_adapter",
|
|
352
|
+
class_name="FolderFileReporterAdapter",
|
|
353
|
+
category=ToolCategory.UTILITY,
|
|
354
|
+
description="Generate reports of folder contents",
|
|
355
|
+
available_flag="FOLDER_FILE_REPORTER_MODULE_AVAILABLE"
|
|
356
|
+
),
|
|
357
|
+
|
|
358
|
+
# MCP Tools
|
|
359
|
+
"MCP Manager": ToolSpec(
|
|
360
|
+
name="MCP Manager",
|
|
361
|
+
module_path="tools.mcp_widget",
|
|
362
|
+
class_name="MCPManager",
|
|
363
|
+
category=ToolCategory.MCP,
|
|
364
|
+
is_widget=True,
|
|
365
|
+
description="Model Context Protocol server management",
|
|
366
|
+
available_flag="MCP_WIDGET_MODULE_AVAILABLE"
|
|
367
|
+
),
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
class ToolLoader:
|
|
372
|
+
"""
|
|
373
|
+
Centralized tool loading with lazy initialization.
|
|
374
|
+
|
|
375
|
+
Benefits:
|
|
376
|
+
- Single place to manage all tool imports
|
|
377
|
+
- Lazy loading - tools only loaded when first accessed
|
|
378
|
+
- Clean availability checking
|
|
379
|
+
- Reduces startup time
|
|
380
|
+
- Caches loaded modules and classes
|
|
381
|
+
|
|
382
|
+
Usage:
|
|
383
|
+
loader = get_tool_loader()
|
|
384
|
+
|
|
385
|
+
# Check if tool is available
|
|
386
|
+
if loader.is_available("Case Tool"):
|
|
387
|
+
# Get the tool class
|
|
388
|
+
CaseTool = loader.get_tool_class("Case Tool")
|
|
389
|
+
tool = CaseTool()
|
|
390
|
+
|
|
391
|
+
# Or create instance directly
|
|
392
|
+
tool = loader.create_instance("Case Tool")
|
|
393
|
+
|
|
394
|
+
# Get all available tools
|
|
395
|
+
available = loader.get_available_tools()
|
|
396
|
+
"""
|
|
397
|
+
|
|
398
|
+
def __init__(self, tool_specs: Optional[Dict[str, ToolSpec]] = None):
|
|
399
|
+
"""
|
|
400
|
+
Initialize the tool loader.
|
|
401
|
+
|
|
402
|
+
Args:
|
|
403
|
+
tool_specs: Optional custom tool specifications (uses TOOL_SPECS if None)
|
|
404
|
+
"""
|
|
405
|
+
self._specs = tool_specs or TOOL_SPECS.copy()
|
|
406
|
+
self._loaded_modules: Dict[str, Any] = {}
|
|
407
|
+
self._loaded_classes: Dict[str, Type] = {}
|
|
408
|
+
self._availability_cache: Dict[str, bool] = {}
|
|
409
|
+
self._load_errors: Dict[str, str] = {}
|
|
410
|
+
self._widget_classes: Dict[str, Type] = {}
|
|
411
|
+
|
|
412
|
+
def register_tool(self, spec: ToolSpec) -> None:
|
|
413
|
+
"""
|
|
414
|
+
Register a new tool specification.
|
|
415
|
+
|
|
416
|
+
Args:
|
|
417
|
+
spec: Tool specification to register
|
|
418
|
+
"""
|
|
419
|
+
self._specs[spec.name] = spec
|
|
420
|
+
# Clear caches for this tool
|
|
421
|
+
self._availability_cache.pop(spec.name, None)
|
|
422
|
+
self._loaded_classes.pop(spec.name, None)
|
|
423
|
+
self._load_errors.pop(spec.name, None)
|
|
424
|
+
logger.debug(f"Registered tool: {spec.name}")
|
|
425
|
+
|
|
426
|
+
def unregister_tool(self, name: str) -> bool:
|
|
427
|
+
"""
|
|
428
|
+
Unregister a tool.
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
name: Tool name to unregister
|
|
432
|
+
|
|
433
|
+
Returns:
|
|
434
|
+
True if tool was found and removed
|
|
435
|
+
"""
|
|
436
|
+
if name in self._specs:
|
|
437
|
+
del self._specs[name]
|
|
438
|
+
self._availability_cache.pop(name, None)
|
|
439
|
+
self._loaded_classes.pop(name, None)
|
|
440
|
+
self._load_errors.pop(name, None)
|
|
441
|
+
return True
|
|
442
|
+
return False
|
|
443
|
+
|
|
444
|
+
def is_available(self, tool_name: str) -> bool:
|
|
445
|
+
"""
|
|
446
|
+
Check if a tool is available (can be imported).
|
|
447
|
+
|
|
448
|
+
Args:
|
|
449
|
+
tool_name: Name of the tool
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
True if tool module can be imported
|
|
453
|
+
"""
|
|
454
|
+
if tool_name in self._availability_cache:
|
|
455
|
+
return self._availability_cache[tool_name]
|
|
456
|
+
|
|
457
|
+
if tool_name not in self._specs:
|
|
458
|
+
self._availability_cache[tool_name] = False
|
|
459
|
+
return False
|
|
460
|
+
|
|
461
|
+
spec = self._specs[tool_name]
|
|
462
|
+
try:
|
|
463
|
+
importlib.import_module(spec.module_path)
|
|
464
|
+
self._availability_cache[tool_name] = True
|
|
465
|
+
return True
|
|
466
|
+
except ImportError as e:
|
|
467
|
+
self._availability_cache[tool_name] = False
|
|
468
|
+
self._load_errors[tool_name] = str(e)
|
|
469
|
+
logger.debug(f"Tool '{tool_name}' not available: {e}")
|
|
470
|
+
return False
|
|
471
|
+
|
|
472
|
+
def get_tool_class(self, tool_name: str) -> Optional[Type]:
|
|
473
|
+
"""
|
|
474
|
+
Get the tool class (lazy loaded).
|
|
475
|
+
|
|
476
|
+
Args:
|
|
477
|
+
tool_name: Name of the tool
|
|
478
|
+
|
|
479
|
+
Returns:
|
|
480
|
+
The tool class, or None if not available
|
|
481
|
+
"""
|
|
482
|
+
if tool_name in self._loaded_classes:
|
|
483
|
+
return self._loaded_classes[tool_name]
|
|
484
|
+
|
|
485
|
+
if not self.is_available(tool_name):
|
|
486
|
+
return None
|
|
487
|
+
|
|
488
|
+
spec = self._specs[tool_name]
|
|
489
|
+
try:
|
|
490
|
+
module = self._get_module(spec.module_path)
|
|
491
|
+
tool_class = getattr(module, spec.class_name)
|
|
492
|
+
self._loaded_classes[tool_name] = tool_class
|
|
493
|
+
logger.info(f"Loaded tool class: {tool_name}")
|
|
494
|
+
return tool_class
|
|
495
|
+
except (ImportError, AttributeError) as e:
|
|
496
|
+
self._load_errors[tool_name] = str(e)
|
|
497
|
+
logger.error(f"Failed to load tool class '{tool_name}': {e}")
|
|
498
|
+
return None
|
|
499
|
+
|
|
500
|
+
def get_widget_class(self, tool_name: str) -> Optional[Type]:
|
|
501
|
+
"""
|
|
502
|
+
Get the widget class for a tool (if it has a separate one).
|
|
503
|
+
|
|
504
|
+
Args:
|
|
505
|
+
tool_name: Name of the tool
|
|
506
|
+
|
|
507
|
+
Returns:
|
|
508
|
+
The widget class, or None if not available
|
|
509
|
+
"""
|
|
510
|
+
if tool_name in self._widget_classes:
|
|
511
|
+
return self._widget_classes[tool_name]
|
|
512
|
+
|
|
513
|
+
if tool_name not in self._specs:
|
|
514
|
+
return None
|
|
515
|
+
|
|
516
|
+
spec = self._specs[tool_name]
|
|
517
|
+
|
|
518
|
+
# If no separate widget class, return the main class
|
|
519
|
+
if not spec.widget_class:
|
|
520
|
+
return self.get_tool_class(tool_name)
|
|
521
|
+
|
|
522
|
+
try:
|
|
523
|
+
module = self._get_module(spec.module_path)
|
|
524
|
+
widget_class = getattr(module, spec.widget_class)
|
|
525
|
+
self._widget_classes[tool_name] = widget_class
|
|
526
|
+
return widget_class
|
|
527
|
+
except (ImportError, AttributeError) as e:
|
|
528
|
+
logger.error(f"Failed to load widget class for '{tool_name}': {e}")
|
|
529
|
+
return None
|
|
530
|
+
|
|
531
|
+
def create_instance(self, tool_name: str, *args, **kwargs) -> Optional[Any]:
|
|
532
|
+
"""
|
|
533
|
+
Create an instance of a tool.
|
|
534
|
+
|
|
535
|
+
Args:
|
|
536
|
+
tool_name: Name of the tool
|
|
537
|
+
*args, **kwargs: Arguments to pass to the constructor
|
|
538
|
+
|
|
539
|
+
Returns:
|
|
540
|
+
Tool instance, or None if not available
|
|
541
|
+
"""
|
|
542
|
+
tool_class = self.get_tool_class(tool_name)
|
|
543
|
+
if tool_class is None:
|
|
544
|
+
return None
|
|
545
|
+
|
|
546
|
+
try:
|
|
547
|
+
return tool_class(*args, **kwargs)
|
|
548
|
+
except Exception as e:
|
|
549
|
+
logger.error(f"Failed to instantiate tool '{tool_name}': {e}")
|
|
550
|
+
return None
|
|
551
|
+
|
|
552
|
+
def _get_module(self, module_path: str) -> Any:
|
|
553
|
+
"""Get a module (cached)."""
|
|
554
|
+
if module_path not in self._loaded_modules:
|
|
555
|
+
self._loaded_modules[module_path] = importlib.import_module(module_path)
|
|
556
|
+
return self._loaded_modules[module_path]
|
|
557
|
+
|
|
558
|
+
def get_available_tools(self) -> List[str]:
|
|
559
|
+
"""
|
|
560
|
+
Get list of all available tool names.
|
|
561
|
+
|
|
562
|
+
Returns:
|
|
563
|
+
List of tool names that can be loaded
|
|
564
|
+
"""
|
|
565
|
+
return [name for name in self._specs.keys() if self.is_available(name)]
|
|
566
|
+
|
|
567
|
+
def get_all_tool_names(self) -> List[str]:
|
|
568
|
+
"""
|
|
569
|
+
Get list of all registered tool names.
|
|
570
|
+
|
|
571
|
+
Returns:
|
|
572
|
+
List of all tool names (whether available or not)
|
|
573
|
+
"""
|
|
574
|
+
return list(self._specs.keys())
|
|
575
|
+
|
|
576
|
+
def get_tools_by_category(self, category: ToolCategory) -> List[str]:
|
|
577
|
+
"""
|
|
578
|
+
Get tools in a specific category.
|
|
579
|
+
|
|
580
|
+
Args:
|
|
581
|
+
category: Tool category
|
|
582
|
+
|
|
583
|
+
Returns:
|
|
584
|
+
List of tool names in that category
|
|
585
|
+
"""
|
|
586
|
+
return [
|
|
587
|
+
name for name, spec in self._specs.items()
|
|
588
|
+
if spec.category == category and self.is_available(name)
|
|
589
|
+
]
|
|
590
|
+
|
|
591
|
+
def get_tool_spec(self, tool_name: str) -> Optional[ToolSpec]:
|
|
592
|
+
"""
|
|
593
|
+
Get the specification for a tool.
|
|
594
|
+
|
|
595
|
+
Args:
|
|
596
|
+
tool_name: Name of the tool
|
|
597
|
+
|
|
598
|
+
Returns:
|
|
599
|
+
ToolSpec or None if not found
|
|
600
|
+
"""
|
|
601
|
+
return self._specs.get(tool_name)
|
|
602
|
+
|
|
603
|
+
def get_load_error(self, tool_name: str) -> Optional[str]:
|
|
604
|
+
"""
|
|
605
|
+
Get the error message if a tool failed to load.
|
|
606
|
+
|
|
607
|
+
Args:
|
|
608
|
+
tool_name: Name of the tool
|
|
609
|
+
|
|
610
|
+
Returns:
|
|
611
|
+
Error message, or None if no error
|
|
612
|
+
"""
|
|
613
|
+
return self._load_errors.get(tool_name)
|
|
614
|
+
|
|
615
|
+
def get_availability_report(self) -> Dict[str, Dict[str, Any]]:
|
|
616
|
+
"""
|
|
617
|
+
Get a report of all tools and their availability.
|
|
618
|
+
|
|
619
|
+
Returns:
|
|
620
|
+
Dictionary with tool availability information
|
|
621
|
+
"""
|
|
622
|
+
report = {}
|
|
623
|
+
for name, spec in self._specs.items():
|
|
624
|
+
available = self.is_available(name)
|
|
625
|
+
report[name] = {
|
|
626
|
+
'available': available,
|
|
627
|
+
'category': spec.category.value,
|
|
628
|
+
'module': spec.module_path,
|
|
629
|
+
'class': spec.class_name,
|
|
630
|
+
'is_widget': spec.is_widget,
|
|
631
|
+
'error': self._load_errors.get(name) if not available else None
|
|
632
|
+
}
|
|
633
|
+
return report
|
|
634
|
+
|
|
635
|
+
def preload_tools(self, tool_names: Optional[List[str]] = None) -> Dict[str, bool]:
|
|
636
|
+
"""
|
|
637
|
+
Preload specified tools (or all if none specified).
|
|
638
|
+
|
|
639
|
+
Args:
|
|
640
|
+
tool_names: List of tool names to preload, or None for all
|
|
641
|
+
|
|
642
|
+
Returns:
|
|
643
|
+
Dictionary of tool names to load success status
|
|
644
|
+
"""
|
|
645
|
+
names = tool_names or list(self._specs.keys())
|
|
646
|
+
results = {}
|
|
647
|
+
for name in names:
|
|
648
|
+
results[name] = self.get_tool_class(name) is not None
|
|
649
|
+
return results
|
|
650
|
+
|
|
651
|
+
def clear_cache(self) -> None:
|
|
652
|
+
"""Clear all cached modules and classes."""
|
|
653
|
+
self._loaded_modules.clear()
|
|
654
|
+
self._loaded_classes.clear()
|
|
655
|
+
self._availability_cache.clear()
|
|
656
|
+
self._load_errors.clear()
|
|
657
|
+
self._widget_classes.clear()
|
|
658
|
+
logger.debug("Tool loader cache cleared")
|
|
659
|
+
|
|
660
|
+
def get_legacy_flags(self) -> Dict[str, bool]:
|
|
661
|
+
"""
|
|
662
|
+
Get legacy availability flags for backwards compatibility.
|
|
663
|
+
|
|
664
|
+
Returns:
|
|
665
|
+
Dictionary of flag names to boolean values
|
|
666
|
+
"""
|
|
667
|
+
flags = {}
|
|
668
|
+
for name, spec in self._specs.items():
|
|
669
|
+
if spec.available_flag:
|
|
670
|
+
flags[spec.available_flag] = self.is_available(name)
|
|
671
|
+
return flags
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
# Global instance
|
|
675
|
+
_tool_loader: Optional[ToolLoader] = None
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def get_tool_loader() -> ToolLoader:
|
|
679
|
+
"""
|
|
680
|
+
Get the global tool loader instance.
|
|
681
|
+
|
|
682
|
+
Returns:
|
|
683
|
+
Global ToolLoader instance
|
|
684
|
+
"""
|
|
685
|
+
global _tool_loader
|
|
686
|
+
if _tool_loader is None:
|
|
687
|
+
_tool_loader = ToolLoader()
|
|
688
|
+
return _tool_loader
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
def init_tool_loader(tool_specs: Optional[Dict[str, ToolSpec]] = None) -> ToolLoader:
|
|
692
|
+
"""
|
|
693
|
+
Initialize the global tool loader.
|
|
694
|
+
|
|
695
|
+
Args:
|
|
696
|
+
tool_specs: Optional custom tool specifications
|
|
697
|
+
|
|
698
|
+
Returns:
|
|
699
|
+
Initialized ToolLoader
|
|
700
|
+
"""
|
|
701
|
+
global _tool_loader
|
|
702
|
+
_tool_loader = ToolLoader(tool_specs)
|
|
703
|
+
return _tool_loader
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
def reset_tool_loader() -> None:
|
|
707
|
+
"""Reset the global tool loader."""
|
|
708
|
+
global _tool_loader
|
|
709
|
+
_tool_loader = None
|
|
710
|
+
|