quantalogic 0.33.4__py3-none-any.whl → 0.40.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.
- quantalogic/__init__.py +0 -4
- quantalogic/agent.py +603 -362
- quantalogic/agent_config.py +260 -28
- quantalogic/agent_factory.py +43 -17
- quantalogic/coding_agent.py +20 -12
- quantalogic/config.py +7 -4
- quantalogic/console_print_events.py +4 -8
- quantalogic/console_print_token.py +2 -2
- quantalogic/docs_cli.py +15 -10
- quantalogic/event_emitter.py +258 -83
- quantalogic/flow/__init__.py +23 -0
- quantalogic/flow/flow.py +595 -0
- quantalogic/flow/flow_extractor.py +672 -0
- quantalogic/flow/flow_generator.py +89 -0
- quantalogic/flow/flow_manager.py +407 -0
- quantalogic/flow/flow_manager_schema.py +169 -0
- quantalogic/flow/flow_yaml.md +419 -0
- quantalogic/generative_model.py +109 -77
- quantalogic/get_model_info.py +6 -6
- quantalogic/interactive_text_editor.py +100 -73
- quantalogic/main.py +36 -23
- quantalogic/model_info_list.py +12 -0
- quantalogic/model_info_litellm.py +14 -14
- quantalogic/prompts.py +2 -1
- quantalogic/{llm.py → quantlitellm.py} +29 -39
- quantalogic/search_agent.py +4 -4
- quantalogic/server/models.py +4 -1
- quantalogic/task_file_reader.py +5 -5
- quantalogic/task_runner.py +21 -20
- quantalogic/tool_manager.py +10 -21
- quantalogic/tools/__init__.py +98 -68
- quantalogic/tools/composio/composio.py +416 -0
- quantalogic/tools/{generate_database_report_tool.py → database/generate_database_report_tool.py} +4 -9
- quantalogic/tools/database/sql_query_tool_advanced.py +261 -0
- quantalogic/tools/document_tools/markdown_to_docx_tool.py +620 -0
- quantalogic/tools/document_tools/markdown_to_epub_tool.py +438 -0
- quantalogic/tools/document_tools/markdown_to_html_tool.py +362 -0
- quantalogic/tools/document_tools/markdown_to_ipynb_tool.py +319 -0
- quantalogic/tools/document_tools/markdown_to_latex_tool.py +420 -0
- quantalogic/tools/document_tools/markdown_to_pdf_tool.py +623 -0
- quantalogic/tools/document_tools/markdown_to_pptx_tool.py +319 -0
- quantalogic/tools/duckduckgo_search_tool.py +2 -4
- quantalogic/tools/finance/alpha_vantage_tool.py +440 -0
- quantalogic/tools/finance/ccxt_tool.py +373 -0
- quantalogic/tools/finance/finance_llm_tool.py +387 -0
- quantalogic/tools/finance/google_finance.py +192 -0
- quantalogic/tools/finance/market_intelligence_tool.py +520 -0
- quantalogic/tools/finance/technical_analysis_tool.py +491 -0
- quantalogic/tools/finance/tradingview_tool.py +336 -0
- quantalogic/tools/finance/yahoo_finance.py +236 -0
- quantalogic/tools/git/bitbucket_clone_repo_tool.py +181 -0
- quantalogic/tools/git/bitbucket_operations_tool.py +326 -0
- quantalogic/tools/git/clone_repo_tool.py +189 -0
- quantalogic/tools/git/git_operations_tool.py +532 -0
- quantalogic/tools/google_packages/google_news_tool.py +480 -0
- quantalogic/tools/grep_app_tool.py +123 -186
- quantalogic/tools/{dalle_e.py → image_generation/dalle_e.py} +37 -27
- quantalogic/tools/jinja_tool.py +6 -10
- quantalogic/tools/language_handlers/__init__.py +22 -9
- quantalogic/tools/list_directory_tool.py +131 -42
- quantalogic/tools/llm_tool.py +45 -15
- quantalogic/tools/llm_vision_tool.py +59 -7
- quantalogic/tools/markitdown_tool.py +17 -5
- quantalogic/tools/nasa_packages/models.py +47 -0
- quantalogic/tools/nasa_packages/nasa_apod_tool.py +232 -0
- quantalogic/tools/nasa_packages/nasa_neows_tool.py +147 -0
- quantalogic/tools/nasa_packages/services.py +82 -0
- quantalogic/tools/presentation_tools/presentation_llm_tool.py +396 -0
- quantalogic/tools/product_hunt/product_hunt_tool.py +258 -0
- quantalogic/tools/product_hunt/services.py +63 -0
- quantalogic/tools/rag_tool/__init__.py +48 -0
- quantalogic/tools/rag_tool/document_metadata.py +15 -0
- quantalogic/tools/rag_tool/query_response.py +20 -0
- quantalogic/tools/rag_tool/rag_tool.py +566 -0
- quantalogic/tools/rag_tool/rag_tool_beta.py +264 -0
- quantalogic/tools/read_html_tool.py +24 -38
- quantalogic/tools/replace_in_file_tool.py +10 -10
- quantalogic/tools/safe_python_interpreter_tool.py +10 -24
- quantalogic/tools/search_definition_names.py +2 -2
- quantalogic/tools/sequence_tool.py +14 -23
- quantalogic/tools/sql_query_tool.py +17 -19
- quantalogic/tools/tool.py +39 -15
- quantalogic/tools/unified_diff_tool.py +1 -1
- quantalogic/tools/utilities/csv_processor_tool.py +234 -0
- quantalogic/tools/utilities/download_file_tool.py +179 -0
- quantalogic/tools/utilities/mermaid_validator_tool.py +661 -0
- quantalogic/tools/utils/__init__.py +1 -4
- quantalogic/tools/utils/create_sample_database.py +24 -38
- quantalogic/tools/utils/generate_database_report.py +74 -82
- quantalogic/tools/wikipedia_search_tool.py +17 -21
- quantalogic/utils/ask_user_validation.py +1 -1
- quantalogic/utils/async_utils.py +35 -0
- quantalogic/utils/check_version.py +3 -5
- quantalogic/utils/get_all_models.py +2 -1
- quantalogic/utils/git_ls.py +21 -7
- quantalogic/utils/lm_studio_model_info.py +9 -7
- quantalogic/utils/python_interpreter.py +113 -43
- quantalogic/utils/xml_utility.py +178 -0
- quantalogic/version_check.py +1 -1
- quantalogic/welcome_message.py +7 -7
- quantalogic/xml_parser.py +0 -1
- {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/METADATA +44 -1
- quantalogic-0.40.0.dist-info/RECORD +148 -0
- quantalogic-0.33.4.dist-info/RECORD +0 -102
- {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/LICENSE +0 -0
- {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/WHEEL +0 -0
- {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,416 @@
|
|
1
|
+
"""Tool for interacting with Composio API services."""
|
2
|
+
|
3
|
+
import json
|
4
|
+
import os
|
5
|
+
import traceback
|
6
|
+
from datetime import datetime
|
7
|
+
from typing import Any, Dict, Optional
|
8
|
+
|
9
|
+
from composio import Action, ComposioToolSet
|
10
|
+
from loguru import logger
|
11
|
+
from pydantic import BaseModel, ConfigDict, Field
|
12
|
+
|
13
|
+
from quantalogic.tools.tool import Tool, ToolArgument
|
14
|
+
|
15
|
+
|
16
|
+
def setup_logger():
|
17
|
+
"""Configure Loguru logger with custom format and levels."""
|
18
|
+
config = {
|
19
|
+
"handlers": [
|
20
|
+
{
|
21
|
+
"sink": os.path.join(os.path.dirname(__file__), "composio_tool.log"),
|
22
|
+
"format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} | {message}",
|
23
|
+
"level": "DEBUG",
|
24
|
+
"rotation": "1 day",
|
25
|
+
"retention": "7 days",
|
26
|
+
"compression": "zip",
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"sink": lambda msg: print(msg),
|
30
|
+
"format": "<blue>{time:HH:mm:ss}</blue> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | <level>{message}</level>",
|
31
|
+
"level": "INFO",
|
32
|
+
}
|
33
|
+
],
|
34
|
+
}
|
35
|
+
logger.configure(**config)
|
36
|
+
|
37
|
+
|
38
|
+
setup_logger()
|
39
|
+
|
40
|
+
|
41
|
+
class ActionSchema(BaseModel):
|
42
|
+
"""Schema for Composio actions with validation."""
|
43
|
+
name: str
|
44
|
+
description: str
|
45
|
+
parameters: Dict[str, Any]
|
46
|
+
response: Dict[str, Any]
|
47
|
+
version: str
|
48
|
+
enabled: bool = True
|
49
|
+
|
50
|
+
model_config = ConfigDict(extra="allow")
|
51
|
+
|
52
|
+
def __str__(self) -> str:
|
53
|
+
"""String representation for logging purposes."""
|
54
|
+
return f"ActionSchema(name={self.name}, version={self.version}, enabled={self.enabled})"
|
55
|
+
|
56
|
+
|
57
|
+
class ComposioTool(Tool):
|
58
|
+
"""Tool for executing Composio actions with proper validation and error handling."""
|
59
|
+
|
60
|
+
model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
|
61
|
+
|
62
|
+
# Tool configuration
|
63
|
+
name: str = Field(default="composio_tool")
|
64
|
+
description: str = Field(default="")
|
65
|
+
need_validation: bool = False
|
66
|
+
arguments: list = Field(default_factory=list)
|
67
|
+
|
68
|
+
# Composio-specific fields
|
69
|
+
api_key: Optional[str] = Field(
|
70
|
+
default_factory=lambda: os.getenv("COMPOSIO_API_KEY"),
|
71
|
+
description="Composio API key for authentication",
|
72
|
+
)
|
73
|
+
action: str = Field(default="") # Single action per tool instance
|
74
|
+
action_schema: Optional[ActionSchema] = None
|
75
|
+
toolset: Optional[ComposioToolSet] = None
|
76
|
+
|
77
|
+
# Performance tracking
|
78
|
+
_last_execution_time: Optional[datetime] = None
|
79
|
+
_execution_count: int = 0
|
80
|
+
_error_count: int = 0
|
81
|
+
|
82
|
+
def __init__(
|
83
|
+
self,
|
84
|
+
action: str,
|
85
|
+
name: Optional[str] = None,
|
86
|
+
description: Optional[str] = None,
|
87
|
+
need_validation: Optional[bool] = None,
|
88
|
+
**data: Any
|
89
|
+
):
|
90
|
+
"""Initialize a Composio tool for a specific action.
|
91
|
+
|
92
|
+
Args:
|
93
|
+
action: Name of the Composio action to handle
|
94
|
+
name: Custom name for this tool instance
|
95
|
+
description: Custom description for this tool instance
|
96
|
+
need_validation: Whether this specific instance needs validation
|
97
|
+
**data: Additional data for tool initialization
|
98
|
+
"""
|
99
|
+
logger.info(f"Initializing ComposioTool for action: {action}")
|
100
|
+
start_time = datetime.now()
|
101
|
+
|
102
|
+
try:
|
103
|
+
# Set instance-specific attributes
|
104
|
+
super().__init__(**data)
|
105
|
+
self.action = action.upper()
|
106
|
+
|
107
|
+
if name:
|
108
|
+
self.name = name
|
109
|
+
else:
|
110
|
+
self.name = f"composio_{self.action.lower()}"
|
111
|
+
|
112
|
+
# Validate API key
|
113
|
+
if not self.api_key:
|
114
|
+
logger.error("COMPOSIO_API_KEY environment variable is missing")
|
115
|
+
raise ValueError("COMPOSIO_API_KEY environment variable is required")
|
116
|
+
|
117
|
+
# Initialize toolset and get action schema
|
118
|
+
logger.debug(f"Setting up toolset with API key: {'*' * len(self.api_key)}")
|
119
|
+
self.toolset = ComposioToolSet(api_key=self.api_key)
|
120
|
+
self._setup_action()
|
121
|
+
|
122
|
+
# Set description if provided
|
123
|
+
if description:
|
124
|
+
self.description = description
|
125
|
+
|
126
|
+
if need_validation is not None:
|
127
|
+
self.need_validation = need_validation
|
128
|
+
|
129
|
+
init_time = datetime.now() - start_time
|
130
|
+
logger.info(f"ComposioTool initialization completed in {init_time.total_seconds():.2f}s")
|
131
|
+
logger.debug(f"Tool configuration: {self._get_tool_info()}")
|
132
|
+
|
133
|
+
except Exception as e:
|
134
|
+
logger.error(f"Failed to initialize ComposioTool: {str(e)}")
|
135
|
+
logger.debug(f"Stack trace:\n{traceback.format_exc()}")
|
136
|
+
raise
|
137
|
+
|
138
|
+
def _get_tool_info(self) -> Dict[str, Any]:
|
139
|
+
"""Get tool configuration for logging purposes."""
|
140
|
+
return {
|
141
|
+
"name": self.name,
|
142
|
+
"action": self.action,
|
143
|
+
"need_validation": self.need_validation,
|
144
|
+
"schema_loaded": self.action_schema is not None,
|
145
|
+
"toolset_initialized": self.toolset is not None,
|
146
|
+
"execution_count": self._execution_count,
|
147
|
+
"error_count": self._error_count,
|
148
|
+
"last_execution": self._last_execution_time.isoformat() if self._last_execution_time else None
|
149
|
+
}
|
150
|
+
|
151
|
+
def _setup_action(self) -> None:
|
152
|
+
"""Set up the Composio action with its schema and parameters."""
|
153
|
+
logger.debug(f"Setting up action: {self.action}")
|
154
|
+
start_time = datetime.now()
|
155
|
+
|
156
|
+
try:
|
157
|
+
# Get action schema
|
158
|
+
logger.debug("Fetching action schema from Composio")
|
159
|
+
(schema,) = self.toolset.get_action_schemas(actions=[self.action])
|
160
|
+
schema_dict = schema.model_dump()
|
161
|
+
|
162
|
+
# For GOOGLECALENDAR_CREATE_EVENT, ensure summary is a required parameter
|
163
|
+
if self.action == "GOOGLECALENDAR_CREATE_EVENT":
|
164
|
+
parameters = schema_dict.get("parameters", {})
|
165
|
+
properties = parameters.get("properties", {})
|
166
|
+
required_params = parameters.get("required", [])
|
167
|
+
|
168
|
+
# Add summary to properties if not present
|
169
|
+
if "summary" not in properties:
|
170
|
+
properties["summary"] = {
|
171
|
+
"type": "string",
|
172
|
+
"description": "Title of the calendar event"
|
173
|
+
}
|
174
|
+
|
175
|
+
# Add summary to required parameters if not present
|
176
|
+
if "summary" not in required_params:
|
177
|
+
required_params.append("summary")
|
178
|
+
|
179
|
+
# Update the schema
|
180
|
+
parameters["properties"] = properties
|
181
|
+
parameters["required"] = required_params
|
182
|
+
schema_dict["parameters"] = parameters
|
183
|
+
|
184
|
+
# Store schema
|
185
|
+
self.action_schema = ActionSchema(**schema_dict)
|
186
|
+
logger.debug(f"Loaded schema: {self.action_schema}")
|
187
|
+
|
188
|
+
# Log schema version and metadata
|
189
|
+
logger.debug(f"Schema version: {schema_dict.get('version', 'unknown')}")
|
190
|
+
logger.debug(f"Schema description: {schema_dict.get('description', 'No description')}")
|
191
|
+
|
192
|
+
# Set up tool description and arguments
|
193
|
+
self._update_tool_info()
|
194
|
+
|
195
|
+
setup_time = datetime.now() - start_time
|
196
|
+
logger.info(f"Action setup completed in {setup_time.total_seconds():.2f}s")
|
197
|
+
|
198
|
+
except Exception as e:
|
199
|
+
logger.error(f"Error setting up action {self.action}: {str(e)}")
|
200
|
+
logger.debug(f"Stack trace:\n{traceback.format_exc()}")
|
201
|
+
raise RuntimeError(f"Failed to set up action: {str(e)}")
|
202
|
+
|
203
|
+
def _update_tool_info(self) -> None:
|
204
|
+
"""Update tool description and arguments based on the action schema."""
|
205
|
+
logger.debug("Updating tool information from schema")
|
206
|
+
|
207
|
+
if not self.action_schema:
|
208
|
+
logger.warning("No schema available for tool info update")
|
209
|
+
return
|
210
|
+
|
211
|
+
try:
|
212
|
+
# Get parameters info
|
213
|
+
schema_dict = self.action_schema.model_dump()
|
214
|
+
parameters = schema_dict.get("parameters", {})
|
215
|
+
required_params = parameters.get("required", [])
|
216
|
+
properties = parameters.get("properties", {})
|
217
|
+
|
218
|
+
logger.debug(f"Found {len(properties)} parameters in schema")
|
219
|
+
logger.debug(f"Required parameters: {required_params}")
|
220
|
+
|
221
|
+
# Build parameter details
|
222
|
+
param_details = []
|
223
|
+
total_required = 0
|
224
|
+
total_optional = 0
|
225
|
+
|
226
|
+
logger.info(f"Processing parameters for action {self.action}")
|
227
|
+
for param, param_info in properties.items():
|
228
|
+
is_required = param in required_params
|
229
|
+
param_type = param_info.get("type", "any")
|
230
|
+
param_desc = param_info.get("description", "").split(".")[0]
|
231
|
+
default_value = param_info.get("default", "Not specified")
|
232
|
+
examples = param_info.get("examples", [])
|
233
|
+
|
234
|
+
# Track parameter counts
|
235
|
+
if is_required:
|
236
|
+
total_required += 1
|
237
|
+
# Create detailed parameter description
|
238
|
+
param_detail = (
|
239
|
+
f"- `{param}`: ({param_type}*) {param_desc}\n"
|
240
|
+
f" - Default: {default_value}\n"
|
241
|
+
)
|
242
|
+
if examples:
|
243
|
+
param_detail += f" - Examples: {examples}\n"
|
244
|
+
param_details.append(param_detail)
|
245
|
+
else:
|
246
|
+
total_optional += 1
|
247
|
+
|
248
|
+
# Log detailed parameter information
|
249
|
+
logger.debug(
|
250
|
+
f"Parameter '{param}':\n"
|
251
|
+
f" - Type: {param_type}\n"
|
252
|
+
f" - Required: {is_required}\n"
|
253
|
+
f" - Description: {param_desc}\n"
|
254
|
+
f" - Default: {default_value}\n"
|
255
|
+
f" - Examples: {examples}"
|
256
|
+
)
|
257
|
+
|
258
|
+
logger.info(f"Parameter summary: {total_required} required, {total_optional} optional")
|
259
|
+
|
260
|
+
# Update description if not explicitly set
|
261
|
+
if not self.description:
|
262
|
+
# Create example parameters object with all required parameters
|
263
|
+
example_params = {}
|
264
|
+
for param, param_info in properties.items():
|
265
|
+
if param in required_params:
|
266
|
+
if param_info.get("examples"):
|
267
|
+
example_params[param] = param_info["examples"][0]
|
268
|
+
else:
|
269
|
+
# Generate a sensible example based on type
|
270
|
+
param_type = param_info.get("type", "string")
|
271
|
+
example_params[param] = self._get_example_value(param_type)
|
272
|
+
|
273
|
+
new_description = (
|
274
|
+
f"Execute Composio action {self.action}:\n"
|
275
|
+
f"Description: {self.action_schema.description}\n\n"
|
276
|
+
f"Required Parameters:\n" +
|
277
|
+
"".join(param_details) + "\n"
|
278
|
+
f"Example usage:\n"
|
279
|
+
f"```json\n"
|
280
|
+
f"{json.dumps(example_params, indent=2)}\n"
|
281
|
+
f"```"
|
282
|
+
)
|
283
|
+
self.description = new_description
|
284
|
+
logger.debug(f"Updated tool description:\n{new_description}")
|
285
|
+
else:
|
286
|
+
logger.debug("Tool description already set, skipping update")
|
287
|
+
|
288
|
+
# Update arguments with better examples
|
289
|
+
example_params = {}
|
290
|
+
for param, param_info in properties.items():
|
291
|
+
if param in required_params:
|
292
|
+
if param_info.get("examples"):
|
293
|
+
example_params[param] = param_info["examples"][0]
|
294
|
+
else:
|
295
|
+
param_type = param_info.get("type", "string")
|
296
|
+
example_params[param] = self._get_example_value(param_type)
|
297
|
+
|
298
|
+
self.arguments = [
|
299
|
+
ToolArgument(
|
300
|
+
name="action_name",
|
301
|
+
arg_type="string",
|
302
|
+
description=f"Name of the action to execute (must be {self.action})",
|
303
|
+
required=True,
|
304
|
+
example=self.action,
|
305
|
+
),
|
306
|
+
ToolArgument(
|
307
|
+
name="parameters",
|
308
|
+
arg_type="string",
|
309
|
+
description="JSON string of parameters for the action. Required parameters:\n" +
|
310
|
+
"\n".join([f"- {p}: {properties[p].get('description', '')}" for p in required_params]),
|
311
|
+
required=True,
|
312
|
+
example=json.dumps(example_params),
|
313
|
+
),
|
314
|
+
]
|
315
|
+
|
316
|
+
logger.debug(f"Updated tool description and {len(self.arguments)} arguments")
|
317
|
+
|
318
|
+
# Validate parameters if needed
|
319
|
+
if self.need_validation and self.action_schema:
|
320
|
+
logger.debug("Validating parameters against schema")
|
321
|
+
schema_dict = self.action_schema.model_dump()
|
322
|
+
parameters_data = schema_dict.get("parameters", {})
|
323
|
+
required_params = parameters_data.get("required", [])
|
324
|
+
missing_params = [p for p in required_params if p not in example_params]
|
325
|
+
if missing_params:
|
326
|
+
logger.error(f"Missing required parameters: {missing_params}")
|
327
|
+
raise ValueError(f"Missing required parameters: {', '.join(missing_params)}")
|
328
|
+
|
329
|
+
except Exception as e:
|
330
|
+
logger.error(f"Error updating tool info: {str(e)}")
|
331
|
+
logger.debug(f"Stack trace:\n{traceback.format_exc()}")
|
332
|
+
raise
|
333
|
+
|
334
|
+
def _get_example_value(self, param_type: str) -> Any:
|
335
|
+
"""Generate a sensible example value based on parameter type."""
|
336
|
+
type_examples = {
|
337
|
+
"string": "example_value",
|
338
|
+
"integer": 42,
|
339
|
+
"number": 3.14,
|
340
|
+
"boolean": True,
|
341
|
+
"array": [],
|
342
|
+
"object": {},
|
343
|
+
}
|
344
|
+
return type_examples.get(param_type, "example_value")
|
345
|
+
|
346
|
+
def execute(self, **kwargs: Any) -> str:
|
347
|
+
"""Execute the Composio action with the given parameters."""
|
348
|
+
start_time = datetime.now()
|
349
|
+
self._execution_count += 1
|
350
|
+
self._last_execution_time = start_time
|
351
|
+
|
352
|
+
logger.info(f"Executing Composio action {self.action}")
|
353
|
+
logger.debug(f"Execution parameters: {json.dumps(kwargs, indent=2)}")
|
354
|
+
|
355
|
+
try:
|
356
|
+
action_name = kwargs.get("action_name", "").upper()
|
357
|
+
parameters = kwargs.get("parameters")
|
358
|
+
|
359
|
+
if not action_name or not parameters:
|
360
|
+
raise ValueError("Both action_name and parameters are required")
|
361
|
+
|
362
|
+
# Validate action name
|
363
|
+
if action_name != self.action:
|
364
|
+
raise ValueError(f"This tool only handles the {self.action} action")
|
365
|
+
|
366
|
+
# Convert parameters to dict if string
|
367
|
+
try:
|
368
|
+
parameters_dict = json.loads(parameters) if isinstance(parameters, str) else parameters
|
369
|
+
logger.debug(f"Parsed parameters: {json.dumps(parameters_dict, indent=2)}")
|
370
|
+
except json.JSONDecodeError as e:
|
371
|
+
logger.error(f"Invalid JSON parameters: {str(e)}")
|
372
|
+
raise ValueError(f"Invalid JSON parameters: {str(e)}")
|
373
|
+
|
374
|
+
# Validate parameters if needed
|
375
|
+
if self.need_validation and self.action_schema:
|
376
|
+
logger.debug("Validating parameters against schema")
|
377
|
+
schema_dict = self.action_schema.model_dump()
|
378
|
+
parameters_data = schema_dict.get("parameters", {})
|
379
|
+
required_params = parameters_data.get("required", [])
|
380
|
+
missing_params = [p for p in required_params if p not in parameters_dict]
|
381
|
+
if missing_params:
|
382
|
+
logger.error(f"Missing required parameters: {missing_params}")
|
383
|
+
raise ValueError(f"Missing required parameters: {', '.join(missing_params)}")
|
384
|
+
|
385
|
+
# Execute action
|
386
|
+
logger.info(f"Executing {self.action} with validated parameters")
|
387
|
+
result = self.toolset.execute_action(
|
388
|
+
action=Action(self.action),
|
389
|
+
params=parameters_dict
|
390
|
+
)
|
391
|
+
|
392
|
+
execution_time = datetime.now() - start_time
|
393
|
+
logger.info(f"Action executed successfully in {execution_time.total_seconds():.2f}s")
|
394
|
+
logger.debug(f"Action result: {json.dumps(result, indent=2)}")
|
395
|
+
|
396
|
+
return json.dumps(result, indent=2)
|
397
|
+
|
398
|
+
except Exception as e:
|
399
|
+
self._error_count += 1
|
400
|
+
logger.error(f"Error executing action: {str(e)}")
|
401
|
+
logger.debug(f"Stack trace:\n{traceback.format_exc()}")
|
402
|
+
logger.debug(f"Tool state at error: {self._get_tool_info()}")
|
403
|
+
raise RuntimeError(f"Failed to execute action: {str(e)}")
|
404
|
+
|
405
|
+
|
406
|
+
if __name__ == "__main__":
|
407
|
+
# Example usage
|
408
|
+
try:
|
409
|
+
tool = ComposioTool(action="EXAMPLE_ACTION")
|
410
|
+
result = tool.execute(
|
411
|
+
action_name="EXAMPLE_ACTION",
|
412
|
+
parameters=json.dumps({"param1": "value1"})
|
413
|
+
)
|
414
|
+
print(f"Result: {result}")
|
415
|
+
except Exception as e:
|
416
|
+
logger.error(f"Example failed: {str(e)}")
|
quantalogic/tools/{generate_database_report_tool.py → database/generate_database_report_tool.py}
RENAMED
@@ -10,14 +10,12 @@ class GenerateDatabaseReportTool(Tool):
|
|
10
10
|
"""Tool for generating database documentation reports from a connection string."""
|
11
11
|
|
12
12
|
name: str = "generate_database_report_tool"
|
13
|
-
description: str =
|
14
|
-
"Generates a comprehensive Markdown database documentation report with ER diagram. "
|
15
|
-
)
|
13
|
+
description: str = "Generates a comprehensive Markdown database documentation report with ER diagram. "
|
16
14
|
arguments: list = [] # No execution arguments - connection string is configured during tool setup
|
17
15
|
connection_string: str = Field(
|
18
16
|
...,
|
19
17
|
description="SQLAlchemy-compatible database connection string (e.g., 'sqlite:///database.db')",
|
20
|
-
example="postgresql://user:password@localhost/mydatabase"
|
18
|
+
example="postgresql://user:password@localhost/mydatabase",
|
21
19
|
)
|
22
20
|
|
23
21
|
def execute(self) -> str:
|
@@ -39,14 +37,11 @@ class GenerateDatabaseReportTool(Tool):
|
|
39
37
|
|
40
38
|
|
41
39
|
if __name__ == "__main__":
|
42
|
-
|
43
40
|
from quantalogic.tools.utils.create_sample_database import create_sample_database
|
44
41
|
|
45
42
|
# Create and document sample database
|
46
43
|
create_sample_database("sample.db")
|
47
44
|
|
48
45
|
# Example usage
|
49
|
-
tool = GenerateDatabaseReportTool(
|
50
|
-
|
51
|
-
)
|
52
|
-
print(tool.execute())
|
46
|
+
tool = GenerateDatabaseReportTool(connection_string="sqlite:///sample.db")
|
47
|
+
print(tool.execute())
|