quantalogic 0.35.0__py3-none-any.whl → 0.50.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.
Files changed (107) hide show
  1. quantalogic/__init__.py +0 -4
  2. quantalogic/agent.py +603 -363
  3. quantalogic/agent_config.py +233 -46
  4. quantalogic/agent_factory.py +34 -22
  5. quantalogic/coding_agent.py +16 -14
  6. quantalogic/config.py +2 -1
  7. quantalogic/console_print_events.py +4 -8
  8. quantalogic/console_print_token.py +2 -2
  9. quantalogic/docs_cli.py +15 -10
  10. quantalogic/event_emitter.py +258 -83
  11. quantalogic/flow/__init__.py +23 -0
  12. quantalogic/flow/flow.py +595 -0
  13. quantalogic/flow/flow_extractor.py +672 -0
  14. quantalogic/flow/flow_generator.py +89 -0
  15. quantalogic/flow/flow_manager.py +407 -0
  16. quantalogic/flow/flow_manager_schema.py +169 -0
  17. quantalogic/flow/flow_yaml.md +419 -0
  18. quantalogic/generative_model.py +109 -77
  19. quantalogic/get_model_info.py +5 -5
  20. quantalogic/interactive_text_editor.py +100 -73
  21. quantalogic/main.py +17 -21
  22. quantalogic/model_info_list.py +3 -3
  23. quantalogic/model_info_litellm.py +14 -14
  24. quantalogic/prompts.py +2 -1
  25. quantalogic/{llm.py → quantlitellm.py} +29 -39
  26. quantalogic/search_agent.py +4 -4
  27. quantalogic/server/models.py +4 -1
  28. quantalogic/task_file_reader.py +5 -5
  29. quantalogic/task_runner.py +20 -20
  30. quantalogic/tool_manager.py +10 -21
  31. quantalogic/tools/__init__.py +98 -68
  32. quantalogic/tools/composio/composio.py +416 -0
  33. quantalogic/tools/{generate_database_report_tool.py → database/generate_database_report_tool.py} +4 -9
  34. quantalogic/tools/database/sql_query_tool_advanced.py +261 -0
  35. quantalogic/tools/document_tools/markdown_to_docx_tool.py +620 -0
  36. quantalogic/tools/document_tools/markdown_to_epub_tool.py +438 -0
  37. quantalogic/tools/document_tools/markdown_to_html_tool.py +362 -0
  38. quantalogic/tools/document_tools/markdown_to_ipynb_tool.py +319 -0
  39. quantalogic/tools/document_tools/markdown_to_latex_tool.py +420 -0
  40. quantalogic/tools/document_tools/markdown_to_pdf_tool.py +623 -0
  41. quantalogic/tools/document_tools/markdown_to_pptx_tool.py +319 -0
  42. quantalogic/tools/duckduckgo_search_tool.py +2 -4
  43. quantalogic/tools/finance/alpha_vantage_tool.py +440 -0
  44. quantalogic/tools/finance/ccxt_tool.py +373 -0
  45. quantalogic/tools/finance/finance_llm_tool.py +387 -0
  46. quantalogic/tools/finance/google_finance.py +192 -0
  47. quantalogic/tools/finance/market_intelligence_tool.py +520 -0
  48. quantalogic/tools/finance/technical_analysis_tool.py +491 -0
  49. quantalogic/tools/finance/tradingview_tool.py +336 -0
  50. quantalogic/tools/finance/yahoo_finance.py +236 -0
  51. quantalogic/tools/git/bitbucket_clone_repo_tool.py +181 -0
  52. quantalogic/tools/git/bitbucket_operations_tool.py +326 -0
  53. quantalogic/tools/git/clone_repo_tool.py +189 -0
  54. quantalogic/tools/git/git_operations_tool.py +532 -0
  55. quantalogic/tools/google_packages/google_news_tool.py +480 -0
  56. quantalogic/tools/grep_app_tool.py +123 -186
  57. quantalogic/tools/{dalle_e.py → image_generation/dalle_e.py} +37 -27
  58. quantalogic/tools/jinja_tool.py +6 -10
  59. quantalogic/tools/language_handlers/__init__.py +22 -9
  60. quantalogic/tools/list_directory_tool.py +131 -42
  61. quantalogic/tools/llm_tool.py +45 -15
  62. quantalogic/tools/llm_vision_tool.py +59 -7
  63. quantalogic/tools/markitdown_tool.py +17 -5
  64. quantalogic/tools/nasa_packages/models.py +47 -0
  65. quantalogic/tools/nasa_packages/nasa_apod_tool.py +232 -0
  66. quantalogic/tools/nasa_packages/nasa_neows_tool.py +147 -0
  67. quantalogic/tools/nasa_packages/services.py +82 -0
  68. quantalogic/tools/presentation_tools/presentation_llm_tool.py +396 -0
  69. quantalogic/tools/product_hunt/product_hunt_tool.py +258 -0
  70. quantalogic/tools/product_hunt/services.py +63 -0
  71. quantalogic/tools/rag_tool/__init__.py +48 -0
  72. quantalogic/tools/rag_tool/document_metadata.py +15 -0
  73. quantalogic/tools/rag_tool/query_response.py +20 -0
  74. quantalogic/tools/rag_tool/rag_tool.py +566 -0
  75. quantalogic/tools/rag_tool/rag_tool_beta.py +264 -0
  76. quantalogic/tools/read_html_tool.py +24 -38
  77. quantalogic/tools/replace_in_file_tool.py +10 -10
  78. quantalogic/tools/safe_python_interpreter_tool.py +10 -24
  79. quantalogic/tools/search_definition_names.py +2 -2
  80. quantalogic/tools/sequence_tool.py +14 -23
  81. quantalogic/tools/sql_query_tool.py +17 -19
  82. quantalogic/tools/tool.py +39 -15
  83. quantalogic/tools/unified_diff_tool.py +1 -1
  84. quantalogic/tools/utilities/csv_processor_tool.py +234 -0
  85. quantalogic/tools/utilities/download_file_tool.py +179 -0
  86. quantalogic/tools/utilities/mermaid_validator_tool.py +661 -0
  87. quantalogic/tools/utils/__init__.py +1 -4
  88. quantalogic/tools/utils/create_sample_database.py +24 -38
  89. quantalogic/tools/utils/generate_database_report.py +74 -82
  90. quantalogic/tools/wikipedia_search_tool.py +17 -21
  91. quantalogic/utils/ask_user_validation.py +1 -1
  92. quantalogic/utils/async_utils.py +35 -0
  93. quantalogic/utils/check_version.py +3 -5
  94. quantalogic/utils/get_all_models.py +2 -1
  95. quantalogic/utils/git_ls.py +21 -7
  96. quantalogic/utils/lm_studio_model_info.py +9 -7
  97. quantalogic/utils/python_interpreter.py +113 -43
  98. quantalogic/utils/xml_utility.py +178 -0
  99. quantalogic/version_check.py +1 -1
  100. quantalogic/welcome_message.py +7 -7
  101. quantalogic/xml_parser.py +0 -1
  102. {quantalogic-0.35.0.dist-info → quantalogic-0.50.0.dist-info}/METADATA +40 -1
  103. quantalogic-0.50.0.dist-info/RECORD +148 -0
  104. quantalogic-0.35.0.dist-info/RECORD +0 -102
  105. {quantalogic-0.35.0.dist-info → quantalogic-0.50.0.dist-info}/LICENSE +0 -0
  106. {quantalogic-0.35.0.dist-info → quantalogic-0.50.0.dist-info}/WHEEL +0 -0
  107. {quantalogic-0.35.0.dist-info → quantalogic-0.50.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,261 @@
1
+ """Tool for executing SQL queries and performing database operations with safety checks."""
2
+
3
+ import json
4
+ from enum import Enum
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ from loguru import logger
8
+ from pydantic import Field
9
+ from sqlalchemy import create_engine, inspect, text
10
+ from sqlalchemy.engine import Engine
11
+
12
+ from quantalogic.tools.tool import Tool, ToolArgument
13
+
14
+
15
+ class QueryType(Enum):
16
+ """Supported SQL query types"""
17
+ SELECT = "SELECT"
18
+ INSERT = "INSERT"
19
+ UPDATE = "UPDATE"
20
+ DELETE = "DELETE"
21
+ CREATE = "CREATE"
22
+ ALTER = "ALTER"
23
+ DROP = "DROP"
24
+
25
+
26
+ class SQLQueryToolAdvanced(Tool):
27
+ """Tool for executing SQL queries and performing database operations safely."""
28
+
29
+ name: str = "sql_query_tool"
30
+ description: str = (
31
+ "Executes SQL operations including queries, inserts, updates, and schema modifications "
32
+ "with built-in safety checks and pagination support for queries."
33
+ )
34
+ arguments: list = [
35
+ ToolArgument(
36
+ name="query",
37
+ arg_type="string",
38
+ description="The SQL query/statement to execute",
39
+ required=True,
40
+ example="SELECT * FROM customers WHERE country = :country"
41
+ ),
42
+ ToolArgument(
43
+ name="params",
44
+ arg_type="string",
45
+ description="JSON string containing named parameters for SQL query binding (e.g., '{\"country\": \"France\"}')",
46
+ required=False,
47
+ example='{"country": "France"}'
48
+ ),
49
+ ToolArgument(
50
+ name="start_row",
51
+ arg_type="int",
52
+ description="1-based starting row number for SELECT results",
53
+ required=False,
54
+ example="1",
55
+ default="1"
56
+ ),
57
+ ToolArgument(
58
+ name="end_row",
59
+ arg_type="int",
60
+ description="1-based ending row number for SELECT results",
61
+ required=False,
62
+ example="100",
63
+ default="100"
64
+ ),
65
+ ]
66
+ connection_string: str = Field(
67
+ ...,
68
+ description="SQLAlchemy-compatible database connection string",
69
+ example="postgresql://user:password@localhost/mydb"
70
+ )
71
+ _engine: Optional[Engine] = None
72
+
73
+ def __init__(self, **data):
74
+ super().__init__(**data)
75
+ self._engine = create_engine(self.connection_string)
76
+ logger.info(f"Initialized SQL tool with engine for {self.connection_string}")
77
+
78
+ def execute(
79
+ self,
80
+ query: str,
81
+ params: Optional[str] = None,
82
+ start_row: Optional[Any] = 1,
83
+ end_row: Optional[Any] = 100
84
+ ) -> str:
85
+ """
86
+ Executes a SQL operation with parameter binding and appropriate handling based on query type.
87
+
88
+ Args:
89
+ query: SQL query/statement to execute
90
+ params: JSON string containing named parameters for query binding
91
+ start_row: Starting row for SELECT pagination
92
+ end_row: Ending row for SELECT pagination
93
+
94
+ Returns:
95
+ str: Operation results in markdown format
96
+
97
+ Raises:
98
+ ValueError: For invalid parameters or query errors
99
+ RuntimeError: For database connection issues
100
+ """
101
+ try:
102
+ # Parse params JSON if provided
103
+ params_dict = json.loads(params) if params else {}
104
+
105
+ query_type = self._detect_query_type(query)
106
+ logger.debug(f"Executing {query_type} operation")
107
+
108
+ if query_type == QueryType.SELECT:
109
+ return self._execute_select(query, params_dict, start_row, end_row)
110
+ else:
111
+ return self._execute_modification(query, params_dict, query_type)
112
+
113
+ except json.JSONDecodeError as e:
114
+ logger.error(f"Invalid params JSON: {str(e)}")
115
+ raise ValueError(f"Invalid params JSON: {str(e)}")
116
+ except Exception as e:
117
+ logger.error(f"SQL operation failed: {str(e)}")
118
+ raise
119
+
120
+ def _detect_query_type(self, query: str) -> QueryType:
121
+ """Detect the type of SQL operation from the query string."""
122
+ first_word = query.strip().split()[0].upper()
123
+ try:
124
+ return QueryType(first_word)
125
+ except ValueError:
126
+ raise ValueError(f"Unsupported SQL operation: {first_word}")
127
+
128
+ def _execute_select(
129
+ self,
130
+ query: str,
131
+ params: Dict[str, Any],
132
+ start_row: Any,
133
+ end_row: Any
134
+ ) -> str:
135
+ """Execute a SELECT query with pagination."""
136
+ start = self._convert_row_number(start_row, "start_row")
137
+ end = self._convert_row_number(end_row, "end_row")
138
+
139
+ if start > end:
140
+ raise ValueError(f"start_row ({start}) must be <= end_row ({end})")
141
+
142
+ with self._engine.connect() as conn:
143
+ result = conn.execute(text(query), params)
144
+ columns: List[str] = result.keys()
145
+ all_rows: List[Dict] = [dict(row._mapping) for row in result]
146
+
147
+ total_rows = len(all_rows)
148
+ actual_start = max(1, start)
149
+ actual_end = min(end, total_rows)
150
+
151
+ if actual_start > total_rows:
152
+ return f"No results found (total rows: {total_rows})"
153
+
154
+ displayed_rows = all_rows[actual_start-1:actual_end]
155
+
156
+ markdown = [
157
+ f"**SELECT Results:** `{actual_start}-{actual_end}` of `{total_rows}` rows",
158
+ self._format_table(columns, displayed_rows)
159
+ ]
160
+
161
+ if actual_end < total_rows:
162
+ remaining = total_rows - actual_end
163
+ markdown.append(f"\n*Showing first {actual_end} rows - {remaining} more row{'s' if remaining > 1 else ''} available*")
164
+
165
+ return "\n".join(markdown)
166
+
167
+ def _execute_modification(
168
+ self,
169
+ query: str,
170
+ params: Dict[str, Any],
171
+ query_type: QueryType
172
+ ) -> str:
173
+ """Execute a database modification operation within a transaction."""
174
+ with self._engine.begin() as conn:
175
+ try:
176
+ if query_type in [QueryType.CREATE, QueryType.ALTER, QueryType.DROP]:
177
+ self._validate_schema_operation(query)
178
+
179
+ result = conn.execute(text(query), params)
180
+ row_count = result.rowcount
181
+
182
+ operation = query_type.value.capitalize()
183
+ message = f"**{operation} Operation Successful**\n"
184
+
185
+ if row_count >= 0: # Not all operations return a row count
186
+ message += f"Affected rows: `{row_count}`"
187
+
188
+ logger.info(f"{operation} operation completed successfully")
189
+ return message
190
+
191
+ except Exception as e:
192
+ logger.error(f"Modification operation failed: {str(e)}")
193
+ raise
194
+
195
+ def _validate_schema_operation(self, query: str):
196
+ """Validate schema modification operations for safety."""
197
+ # Basic validation - could be extended based on requirements
198
+ query_lower = query.lower()
199
+ if "drop database" in query_lower:
200
+ raise ValueError("DROP DATABASE operations are not allowed")
201
+
202
+ inspector = inspect(self._engine)
203
+ existing_tables = inspector.get_table_names()
204
+
205
+ # Additional safety checks could be added here
206
+ logger.debug(f"Schema validation passed for operation")
207
+
208
+ def _convert_row_number(self, value: Any, field_name: str) -> int:
209
+ """Convert and validate row number input."""
210
+ try:
211
+ # Handle numeric strings and floats
212
+ if isinstance(value, str):
213
+ if "." in value:
214
+ num = float(value)
215
+ else:
216
+ num = int(value)
217
+ else:
218
+ num = value
219
+
220
+ converted = int(num)
221
+ if converted != num: # Check if float had decimal part
222
+ raise ValueError("Decimal values are not allowed for row numbers")
223
+
224
+ if converted <= 0:
225
+ raise ValueError(f"{field_name} must be a positive integer")
226
+
227
+ return converted
228
+ except (ValueError, TypeError) as e:
229
+ raise ValueError(f"Invalid value for {field_name}: {repr(value)}") from e
230
+
231
+ def _format_table(self, columns: List[str], rows: List[Dict]) -> str:
232
+ """Format results as markdown table with truncation."""
233
+ if not rows:
234
+ return "No results found"
235
+
236
+ # Create header
237
+ header = "| " + " | ".join(columns) + " |"
238
+ separator = "| " + " | ".join(["---"] * len(columns)) + " |"
239
+
240
+ # Create rows with truncation
241
+ body = []
242
+ for row in rows:
243
+ values = []
244
+ for col in columns:
245
+ val = str(row.get(col, ""))
246
+ # Truncate long values
247
+ values.append(val[:50] + "..." if len(val) > 50 else val)
248
+ body.append("| " + " | ".join(values) + " |")
249
+
250
+ return "\n".join([header, separator] + body)
251
+
252
+
253
+
254
+ if __name__ == "__main__":
255
+ from quantalogic.tools.utils.create_sample_database import create_sample_database
256
+
257
+ # Create and document sample database
258
+ create_sample_database("sample.db")
259
+ tool = SQLQueryToolAdvanced(connection_string="sqlite:///sample.db")
260
+ print(tool.execute("select * from customers", 1, 10))
261
+ print(tool.execute("select * from customers", 11, 20))