quantalogic 0.35.0__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 -363
- quantalogic/agent_config.py +233 -46
- quantalogic/agent_factory.py +34 -22
- quantalogic/coding_agent.py +16 -14
- quantalogic/config.py +2 -1
- 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 +5 -5
- quantalogic/interactive_text_editor.py +100 -73
- quantalogic/main.py +17 -21
- quantalogic/model_info_list.py +3 -3
- 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 +20 -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.35.0.dist-info → quantalogic-0.40.0.dist-info}/METADATA +41 -1
- quantalogic-0.40.0.dist-info/RECORD +148 -0
- quantalogic-0.35.0.dist-info/RECORD +0 -102
- {quantalogic-0.35.0.dist-info → quantalogic-0.40.0.dist-info}/LICENSE +0 -0
- {quantalogic-0.35.0.dist-info → quantalogic-0.40.0.dist-info}/WHEEL +0 -0
- {quantalogic-0.35.0.dist-info → quantalogic-0.40.0.dist-info}/entry_points.txt +0 -0
@@ -1,21 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
__all__ = [
|
4
|
-
"generate_completion",
|
5
|
-
"generate_image",
|
6
|
-
"count_tokens",
|
7
|
-
"get_model_max_input_tokens",
|
8
|
-
"get_model_max_output_tokens",
|
9
|
-
]
|
10
|
-
|
1
|
+
# quantlitellm.py
|
11
2
|
import os
|
12
|
-
from typing import Any, Dict
|
3
|
+
from typing import Any, Dict
|
13
4
|
|
14
|
-
from litellm import
|
15
|
-
completion,
|
16
|
-
image_generation,
|
17
|
-
token_counter,
|
18
|
-
)
|
5
|
+
from litellm import aimage_generation, exceptions, token_counter
|
19
6
|
from loguru import logger
|
20
7
|
|
21
8
|
from quantalogic.get_model_info import (
|
@@ -25,11 +12,6 @@ from quantalogic.get_model_info import (
|
|
25
12
|
)
|
26
13
|
|
27
14
|
|
28
|
-
def get_model_info(model_name: str) -> dict | None:
|
29
|
-
"""Get model information for a given model name."""
|
30
|
-
return model_info.get(model_name, None)
|
31
|
-
|
32
|
-
|
33
15
|
class ModelProviderConfig:
|
34
16
|
def __init__(self, prefix: str, provider: str, base_url: str, env_var: str):
|
35
17
|
self.prefix = prefix
|
@@ -53,44 +35,47 @@ PROVIDERS = {
|
|
53
35
|
prefix="dashscope/",
|
54
36
|
provider="openai",
|
55
37
|
base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
|
56
|
-
env_var="DASHSCOPE_API_KEY"
|
38
|
+
env_var="DASHSCOPE_API_KEY",
|
57
39
|
),
|
58
40
|
"nvidia": ModelProviderConfig(
|
59
|
-
prefix="nvidia/",
|
60
|
-
provider="openai",
|
61
|
-
base_url="https://integrate.api.nvidia.com/v1",
|
62
|
-
env_var="NVIDIA_API_KEY"
|
41
|
+
prefix="nvidia/", provider="openai", base_url="https://integrate.api.nvidia.com/v1", env_var="NVIDIA_API_KEY"
|
63
42
|
),
|
64
43
|
"ovh": ModelProviderConfig(
|
65
44
|
prefix="ovh/",
|
66
45
|
provider="openai",
|
67
46
|
base_url="https://deepseek-r1-distill-llama-70b.endpoints.kepler.ai.cloud.ovh.net/api/openai_compat/v1",
|
68
|
-
env_var="OVH_API_KEY"
|
69
|
-
)
|
47
|
+
env_var="OVH_API_KEY",
|
48
|
+
),
|
70
49
|
}
|
71
50
|
|
72
51
|
|
73
|
-
def
|
52
|
+
async def acompletion(**kwargs: Dict[str, Any]) -> Any:
|
74
53
|
"""Wraps litellm completion with proper type hints."""
|
75
54
|
model = kwargs.get("model", "")
|
76
|
-
|
55
|
+
|
77
56
|
# Find matching provider
|
78
57
|
for provider_name, provider_config in PROVIDERS.items():
|
79
58
|
if model.startswith(provider_config.prefix):
|
80
59
|
provider_config.configure(model, kwargs)
|
81
60
|
break
|
82
|
-
|
83
|
-
return completion(**kwargs)
|
84
61
|
|
62
|
+
from litellm import acompletion
|
85
63
|
|
86
|
-
|
87
|
-
"""Wraps litellm image_generation with proper type hints."""
|
88
|
-
return image_generation(**kwargs)
|
64
|
+
return await acompletion(**kwargs)
|
89
65
|
|
90
66
|
|
91
|
-
|
92
|
-
|
93
|
-
|
67
|
+
# Expose the imported litellm components directly
|
68
|
+
__all__ = ["acompletion", "aimage_generation", "exceptions", "token_counter"]
|
69
|
+
|
70
|
+
|
71
|
+
def suppress_lite_llm_debug_logging():
|
72
|
+
"""Suppress debug logging from LiteLLM library."""
|
73
|
+
from litellm import litellm
|
74
|
+
|
75
|
+
litellm.suppress_debug_info = True # Very important to suppress prints don't remove
|
76
|
+
|
77
|
+
|
78
|
+
suppress_lite_llm_debug_logging()
|
94
79
|
|
95
80
|
|
96
81
|
def _get_model_info_impl(model_name: str) -> dict:
|
@@ -170,4 +155,9 @@ def get_model_max_output_tokens(model_name: str) -> int | None:
|
|
170
155
|
|
171
156
|
except Exception as e:
|
172
157
|
logger.error(f"Error getting max output tokens for {model_name}: {e}")
|
173
|
-
return None
|
158
|
+
return None
|
159
|
+
|
160
|
+
|
161
|
+
def get_model_info(model_name: str) -> dict | None:
|
162
|
+
"""Get model information for a given model name."""
|
163
|
+
return model_info.get(model_name, None)
|
quantalogic/search_agent.py
CHANGED
@@ -13,11 +13,11 @@ from quantalogic.tools import (
|
|
13
13
|
|
14
14
|
|
15
15
|
def create_search_agent(
|
16
|
-
model_name: str,
|
17
|
-
mode_full: bool = False,
|
18
|
-
no_stream: bool = False,
|
16
|
+
model_name: str,
|
17
|
+
mode_full: bool = False,
|
18
|
+
no_stream: bool = False,
|
19
19
|
compact_every_n_iteration: int | None = None,
|
20
|
-
max_tokens_working_memory: int | None = None
|
20
|
+
max_tokens_working_memory: int | None = None,
|
21
21
|
) -> Agent:
|
22
22
|
"""Creates and configures a search agent with web, knowledge, and privacy-focused search tools.
|
23
23
|
|
quantalogic/server/models.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"""Pydantic models for the QuantaLogic API."""
|
2
2
|
|
3
|
-
from typing import Any, Dict, Optional
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
4
|
|
5
5
|
from pydantic import BaseModel
|
6
6
|
|
@@ -42,6 +42,9 @@ class TaskSubmission(BaseModel):
|
|
42
42
|
task: str
|
43
43
|
model_name: Optional[str] = MODEL_NAME
|
44
44
|
max_iterations: Optional[int] = 30
|
45
|
+
mode: Optional[str] = "minimal"
|
46
|
+
expertise: Optional[str] = ""
|
47
|
+
tools: Optional[List[Dict[str, Any]]] = None
|
45
48
|
|
46
49
|
model_config = {"extra": "forbid"}
|
47
50
|
|
quantalogic/task_file_reader.py
CHANGED
@@ -5,13 +5,13 @@ import requests
|
|
5
5
|
|
6
6
|
def get_task_from_file(source: str) -> str:
|
7
7
|
"""Get task content from specified file path or URL.
|
8
|
-
|
8
|
+
|
9
9
|
Args:
|
10
10
|
source (str): File path or URL to read task content from
|
11
|
-
|
11
|
+
|
12
12
|
Returns:
|
13
13
|
str: Stripped task content from the file or URL
|
14
|
-
|
14
|
+
|
15
15
|
Raises:
|
16
16
|
FileNotFoundError: If the local file does not exist
|
17
17
|
PermissionError: If there are permission issues reading the file
|
@@ -20,11 +20,11 @@ def get_task_from_file(source: str) -> str:
|
|
20
20
|
"""
|
21
21
|
try:
|
22
22
|
# Check if source is a URL
|
23
|
-
if source.startswith((
|
23
|
+
if source.startswith(("http://", "https://")):
|
24
24
|
response = requests.get(source, timeout=10)
|
25
25
|
response.raise_for_status() # Raise an exception for bad status codes
|
26
26
|
return response.text.strip()
|
27
|
-
|
27
|
+
|
28
28
|
# If not a URL, treat as a local file path
|
29
29
|
with open(source, encoding="utf-8") as f:
|
30
30
|
return f.read().strip()
|
quantalogic/task_runner.py
CHANGED
@@ -84,16 +84,16 @@ def interactive_task_runner(
|
|
84
84
|
while True:
|
85
85
|
logger.debug("Waiting for user input...")
|
86
86
|
task_content = get_multiline_input(console).strip()
|
87
|
-
|
87
|
+
|
88
88
|
if not task_content:
|
89
89
|
logger.info("No task provided. Exiting...")
|
90
90
|
console.print("[yellow]No task provided. Exiting...[/yellow]")
|
91
91
|
break
|
92
92
|
|
93
93
|
# Handle commands with single return
|
94
|
-
if task_content.startswith(
|
94
|
+
if task_content.startswith("/"):
|
95
95
|
command = task_content.lower()
|
96
|
-
if command ==
|
96
|
+
if command == "/clear":
|
97
97
|
logger.info("Clearing agent memory...")
|
98
98
|
console.print("[yellow]Clearing agent memory...[/yellow]")
|
99
99
|
agent.clear_memory()
|
@@ -111,7 +111,7 @@ def interactive_task_runner(
|
|
111
111
|
border_style="blue",
|
112
112
|
)
|
113
113
|
)
|
114
|
-
|
114
|
+
|
115
115
|
if not Confirm.ask("[bold]Are you sure you want to submit this task?[/bold]"):
|
116
116
|
console.print("[yellow]Task submission cancelled.[/yellow]")
|
117
117
|
if not Confirm.ask("[bold]Would you like to ask another question?[/bold]"):
|
@@ -127,14 +127,14 @@ def interactive_task_runner(
|
|
127
127
|
)
|
128
128
|
|
129
129
|
logger.debug(f"Solving task with agent: {task_content}")
|
130
|
-
result = agent.solve_task(
|
130
|
+
result = agent.solve_task(
|
131
|
+
task=task_content, max_iterations=max_iterations, streaming=not no_stream, clear_memory=False
|
132
|
+
)
|
131
133
|
logger.debug(f"Task solved with result: {result} using {max_iterations} iterations")
|
132
134
|
|
133
135
|
console.print(
|
134
136
|
Panel.fit(
|
135
|
-
f"[bold]Task Result:[/bold]\n{result}",
|
136
|
-
title="[bold]Execution Output[/bold]",
|
137
|
-
border_style="green"
|
137
|
+
f"[bold]Task Result:[/bold]\n{result}", title="[bold]Execution Output[/bold]", border_style="green"
|
138
138
|
)
|
139
139
|
)
|
140
140
|
|
@@ -165,7 +165,7 @@ def task_runner(
|
|
165
165
|
vision_model_name=config.vision_model_name,
|
166
166
|
thinking_model_name=config.thinking_model_name,
|
167
167
|
compact_every_n_iteration=config.compact_every_n_iteration,
|
168
|
-
max_tokens_working_memory=config.max_tokens_working_memory
|
168
|
+
max_tokens_working_memory=config.max_tokens_working_memory,
|
169
169
|
)
|
170
170
|
|
171
171
|
AgentRegistry.register_agent("main_agent", agent)
|
@@ -176,14 +176,14 @@ def task_runner(
|
|
176
176
|
logger.debug(f"Solving task with agent: {task_content}")
|
177
177
|
if config.max_iterations < 1:
|
178
178
|
raise ValueError("max_iterations must be greater than 0")
|
179
|
-
result = agent.solve_task(
|
179
|
+
result = agent.solve_task(
|
180
|
+
task=task_content, max_iterations=config.max_iterations, streaming=not config.no_stream
|
181
|
+
)
|
180
182
|
logger.debug(f"Task solved with result: {result} using {config.max_iterations} iterations")
|
181
183
|
|
182
184
|
console.print(
|
183
185
|
Panel.fit(
|
184
|
-
f"[bold]Task Result:[/bold]\n{result}",
|
185
|
-
title="[bold]Execution Output[/bold]",
|
186
|
-
border_style="green"
|
186
|
+
f"[bold]Task Result:[/bold]\n{result}", title="[bold]Execution Output[/bold]", border_style="green"
|
187
187
|
)
|
188
188
|
)
|
189
189
|
else:
|
@@ -194,14 +194,14 @@ def task_runner(
|
|
194
194
|
logger.debug(f"Solving task with agent: {task_content}")
|
195
195
|
if config.max_iterations < 1:
|
196
196
|
raise ValueError("max_iterations must be greater than 0")
|
197
|
-
result = agent.solve_task(
|
197
|
+
result = agent.solve_task(
|
198
|
+
task=task_content, max_iterations=config.max_iterations, streaming=not config.no_stream
|
199
|
+
)
|
198
200
|
logger.debug(f"Task solved with result: {result} using {config.max_iterations} iterations")
|
199
201
|
|
200
202
|
console.print(
|
201
203
|
Panel.fit(
|
202
|
-
f"[bold]Task Result:[/bold]\n{result}",
|
203
|
-
title="[bold]Execution Output[/bold]",
|
204
|
-
border_style="green"
|
204
|
+
f"[bold]Task Result:[/bold]\n{result}", title="[bold]Execution Output[/bold]", border_style="green"
|
205
205
|
)
|
206
206
|
)
|
207
207
|
else:
|
@@ -234,7 +234,7 @@ def task_runner(
|
|
234
234
|
"memory_summary",
|
235
235
|
]
|
236
236
|
|
237
|
-
#def ask_continue(event: str, data: any) -> None:
|
237
|
+
# def ask_continue(event: str, data: any) -> None:
|
238
238
|
# ## Ask for ctrl+return
|
239
239
|
# if event == "task_think_end":
|
240
240
|
# ## Wait return on the keyboard
|
@@ -253,10 +253,10 @@ def task_runner(
|
|
253
253
|
if data is not None:
|
254
254
|
console.print(data, end="", markup=False)
|
255
255
|
|
256
|
-
#agent.event_emitter.on(
|
256
|
+
# agent.event_emitter.on(
|
257
257
|
# event="task_think_end",
|
258
258
|
# listener=ask_continue,
|
259
|
-
#)
|
259
|
+
# )
|
260
260
|
|
261
261
|
agent.event_emitter.on(
|
262
262
|
event=events,
|
quantalogic/tool_manager.py
CHANGED
@@ -67,18 +67,16 @@ class ToolManager(BaseModel):
|
|
67
67
|
index += 1
|
68
68
|
return markdown
|
69
69
|
|
70
|
-
|
71
|
-
|
72
70
|
def validate_and_convert_arguments(self, tool_name: str, provided_args: dict) -> dict:
|
73
71
|
"""Validates and converts arguments based on tool definition.
|
74
|
-
|
72
|
+
|
75
73
|
Args:
|
76
74
|
tool_name: Name of the tool to validate against
|
77
75
|
provided_args: Dictionary of arguments to validate
|
78
|
-
|
76
|
+
|
79
77
|
Returns:
|
80
78
|
Dictionary of converted arguments with proper types
|
81
|
-
|
79
|
+
|
82
80
|
Raises:
|
83
81
|
ValueError: For missing/invalid arguments or conversion errors
|
84
82
|
"""
|
@@ -88,7 +86,7 @@ class ToolManager(BaseModel):
|
|
88
86
|
"string": lambda x: str(x),
|
89
87
|
"int": lambda x: int(x),
|
90
88
|
"float": lambda x: float(x),
|
91
|
-
"bool": lambda x: str(x).lower() in [
|
89
|
+
"bool": lambda x: str(x).lower() in ["true", "1", "yes"],
|
92
90
|
}
|
93
91
|
|
94
92
|
for arg_def in tool.arguments:
|
@@ -108,12 +106,7 @@ class ToolManager(BaseModel):
|
|
108
106
|
value = provided_args[arg_name]
|
109
107
|
|
110
108
|
# Handle empty string for non-string types by replacing with default if available
|
111
|
-
if (
|
112
|
-
arg_type != "string"
|
113
|
-
and isinstance(value, str)
|
114
|
-
and value.strip() == ""
|
115
|
-
and default is not None
|
116
|
-
):
|
109
|
+
if arg_type != "string" and isinstance(value, str) and value.strip() == "" and default is not None:
|
117
110
|
logger.debug(f"Replaced empty string for argument {arg_name} with default value {default}")
|
118
111
|
value = default
|
119
112
|
provided_args[arg_name] = value # Update to ensure validation uses the default
|
@@ -123,9 +116,7 @@ class ToolManager(BaseModel):
|
|
123
116
|
try:
|
124
117
|
converted = type_conversion[arg_type](value)
|
125
118
|
except (ValueError, TypeError) as e:
|
126
|
-
raise ValueError(
|
127
|
-
f"Invalid value '{value}' for {arg_name} ({arg_type}): {str(e)}"
|
128
|
-
)
|
119
|
+
raise ValueError(f"Invalid value '{value}' for {arg_name} ({arg_type}): {str(e)}")
|
129
120
|
converted_args[arg_name] = converted
|
130
121
|
else:
|
131
122
|
converted_args[arg_name] = value # Unknown type, pass through
|
@@ -154,14 +145,14 @@ class ToolManager(BaseModel):
|
|
154
145
|
"string": lambda x: str(x),
|
155
146
|
"int": lambda x: int(x),
|
156
147
|
"float": lambda x: float(x),
|
157
|
-
"bool": lambda x: str(x).lower() in [
|
148
|
+
"bool": lambda x: str(x).lower() in ["true", "1", "yes"],
|
158
149
|
}
|
159
150
|
|
160
151
|
for arg_def in tool.arguments:
|
161
152
|
arg_name = arg_def.name
|
162
153
|
arg_type = arg_def.arg_type
|
163
154
|
required = arg_def.required
|
164
|
-
default = getattr(arg_def,
|
155
|
+
default = getattr(arg_def, "default", None)
|
165
156
|
|
166
157
|
# Handle missing arguments
|
167
158
|
if arg_name not in provided_args:
|
@@ -177,9 +168,7 @@ class ToolManager(BaseModel):
|
|
177
168
|
try:
|
178
169
|
converted = type_conversion[arg_type](value)
|
179
170
|
except (ValueError, TypeError) as e:
|
180
|
-
raise ValueError(
|
181
|
-
f"Invalid value '{value}' for {arg_name} ({arg_type}): {str(e)}"
|
182
|
-
)
|
171
|
+
raise ValueError(f"Invalid value '{value}' for {arg_name} ({arg_type}): {str(e)}")
|
183
172
|
converted_args[arg_name] = converted
|
184
173
|
else:
|
185
174
|
converted_args[arg_name] = value # Unknown type, pass through
|
@@ -189,4 +178,4 @@ class ToolManager(BaseModel):
|
|
189
178
|
if extra_args:
|
190
179
|
raise ValueError(f"Unexpected arguments: {', '.join(extra_args)}")
|
191
180
|
|
192
|
-
return converted_args
|
181
|
+
return converted_args
|
quantalogic/tools/__init__.py
CHANGED
@@ -1,71 +1,101 @@
|
|
1
1
|
"""Tools for the QuantaLogic agent."""
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
from
|
6
|
-
from .duckduckgo_search_tool import DuckDuckGoSearchTool
|
7
|
-
from .edit_whole_content_tool import EditWholeContentTool
|
8
|
-
from .elixir_tool import ElixirTool
|
9
|
-
from .execute_bash_command_tool import ExecuteBashCommandTool
|
10
|
-
from .generate_database_report_tool import GenerateDatabaseReportTool
|
11
|
-
from .grep_app_tool import GrepAppTool
|
12
|
-
from .input_question_tool import InputQuestionTool
|
13
|
-
from .jinja_tool import JinjaTool
|
14
|
-
from .list_directory_tool import ListDirectoryTool
|
15
|
-
from .llm_tool import LLMTool
|
16
|
-
from .llm_vision_tool import LLMVisionTool
|
17
|
-
from .markitdown_tool import MarkitdownTool
|
18
|
-
from .nodejs_tool import NodeJsTool
|
19
|
-
from .python_tool import PythonTool
|
20
|
-
from .read_file_block_tool import ReadFileBlockTool
|
21
|
-
from .read_file_tool import ReadFileTool
|
22
|
-
from .read_html_tool import ReadHTMLTool
|
23
|
-
from .replace_in_file_tool import ReplaceInFileTool
|
24
|
-
from .ripgrep_tool import RipgrepTool
|
25
|
-
from .safe_python_interpreter_tool import SafePythonInterpreterTool
|
26
|
-
from .search_definition_names import SearchDefinitionNames
|
27
|
-
from .sequence_tool import SequenceTool
|
28
|
-
from .serpapi_search_tool import SerpApiSearchTool
|
29
|
-
from .sql_query_tool import SQLQueryTool
|
30
|
-
from .task_complete_tool import TaskCompleteTool
|
31
|
-
from .tool import Tool, ToolArgument
|
32
|
-
from .unified_diff_tool import UnifiedDiffTool
|
33
|
-
from .wikipedia_search_tool import WikipediaSearchTool
|
34
|
-
from .write_file_tool import WriteFileTool
|
3
|
+
import importlib
|
4
|
+
import sys
|
5
|
+
from typing import Any, Dict
|
35
6
|
|
36
|
-
|
37
|
-
|
38
|
-
"
|
39
|
-
|
40
|
-
|
41
|
-
"
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
"
|
55
|
-
"
|
56
|
-
"
|
57
|
-
"
|
58
|
-
"
|
59
|
-
"
|
60
|
-
"
|
61
|
-
"
|
62
|
-
"
|
63
|
-
"
|
64
|
-
"
|
65
|
-
"
|
66
|
-
"
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
7
|
+
|
8
|
+
class LazyLoader:
|
9
|
+
"""
|
10
|
+
Lazily import a module only when its attributes are accessed.
|
11
|
+
This helps reduce startup time by deferring imports until needed.
|
12
|
+
"""
|
13
|
+
def __init__(self, module_path: str):
|
14
|
+
self.module_path = module_path
|
15
|
+
self._module = None
|
16
|
+
|
17
|
+
def __getattr__(self, name: str) -> Any:
|
18
|
+
if self._module is None:
|
19
|
+
self._module = importlib.import_module(self.module_path)
|
20
|
+
return getattr(self._module, name)
|
21
|
+
|
22
|
+
|
23
|
+
# Map of tool names to their import paths
|
24
|
+
_TOOL_IMPORTS = {
|
25
|
+
"AgentTool": ".agent_tool",
|
26
|
+
"ComposioTool": ".composio.composio",
|
27
|
+
"GenerateDatabaseReportTool": ".database.generate_database_report_tool",
|
28
|
+
"SQLQueryToolAdvanced": ".database.sql_query_tool_advanced",
|
29
|
+
"MarkdownToDocxTool": ".document_tools.markdown_to_docx_tool",
|
30
|
+
"MarkdownToEpubTool": ".document_tools.markdown_to_epub_tool",
|
31
|
+
"MarkdownToHtmlTool": ".document_tools.markdown_to_html_tool",
|
32
|
+
"MarkdownToIpynbTool": ".document_tools.markdown_to_ipynb_tool",
|
33
|
+
"MarkdownToLatexTool": ".document_tools.markdown_to_latex_tool",
|
34
|
+
"MarkdownToPdfTool": ".document_tools.markdown_to_pdf_tool",
|
35
|
+
"MarkdownToPptxTool": ".document_tools.markdown_to_pptx_tool",
|
36
|
+
"DownloadHttpFileTool": ".download_http_file_tool",
|
37
|
+
"DuckDuckGoSearchTool": ".duckduckgo_search_tool",
|
38
|
+
"EditWholeContentTool": ".edit_whole_content_tool",
|
39
|
+
"ElixirTool": ".elixir_tool",
|
40
|
+
"ExecuteBashCommandTool": ".execute_bash_command_tool",
|
41
|
+
"BitbucketCloneTool": ".git.bitbucket_clone_repo_tool",
|
42
|
+
"BitbucketOperationsTool": ".git.bitbucket_operations_tool",
|
43
|
+
"CloneRepoTool": ".git.clone_repo_tool",
|
44
|
+
"GitOperationsTool": ".git.git_operations_tool",
|
45
|
+
"GoogleNewsTool": ".google_packages.google_news_tool",
|
46
|
+
"GrepAppTool": ".grep_app_tool",
|
47
|
+
"LLMImageGenerationTool": ".image_generation.dalle_e",
|
48
|
+
"InputQuestionTool": ".input_question_tool",
|
49
|
+
"JinjaTool": ".jinja_tool",
|
50
|
+
"ListDirectoryTool": ".list_directory_tool",
|
51
|
+
"LLMTool": ".llm_tool",
|
52
|
+
"LLMVisionTool": ".llm_vision_tool",
|
53
|
+
"MarkitdownTool": ".markitdown_tool",
|
54
|
+
"NasaApodTool": ".nasa_packages.nasa_apod_tool",
|
55
|
+
"NasaNeoWsTool": ".nasa_packages.nasa_neows_tool",
|
56
|
+
"NodeJsTool": ".nodejs_tool",
|
57
|
+
"PresentationLLMTool": ".presentation_tools.presentation_llm_tool",
|
58
|
+
"ProductHuntTool": ".product_hunt.product_hunt_tool",
|
59
|
+
"PythonTool": ".python_tool",
|
60
|
+
"RagTool": ".rag_tool.rag_tool",
|
61
|
+
"ReadFileBlockTool": ".read_file_block_tool",
|
62
|
+
"ReadFileTool": ".read_file_tool",
|
63
|
+
"ReadHTMLTool": ".read_html_tool",
|
64
|
+
"ReplaceInFileTool": ".replace_in_file_tool",
|
65
|
+
"RipgrepTool": ".ripgrep_tool",
|
66
|
+
"SafePythonInterpreterTool": ".safe_python_interpreter_tool",
|
67
|
+
"SearchDefinitionNames": ".search_definition_names",
|
68
|
+
"SequenceTool": ".sequence_tool",
|
69
|
+
"SerpApiSearchTool": ".serpapi_search_tool",
|
70
|
+
"SQLQueryTool": ".sql_query_tool",
|
71
|
+
"TaskCompleteTool": ".task_complete_tool",
|
72
|
+
"Tool": ".tool",
|
73
|
+
"ToolArgument": ".tool",
|
74
|
+
"UnifiedDiffTool": ".unified_diff_tool",
|
75
|
+
"CSVProcessorTool": ".utilities.csv_processor_tool",
|
76
|
+
"PrepareDownloadTool": ".utilities.download_file_tool",
|
77
|
+
"MermaidValidatorTool": ".utilities.mermaid_validator_tool",
|
78
|
+
"WikipediaSearchTool": ".wikipedia_search_tool",
|
79
|
+
"WriteFileTool": ".write_file_tool",
|
80
|
+
}
|
81
|
+
|
82
|
+
# Create lazy loaders for each module path
|
83
|
+
_lazy_modules: Dict[str, LazyLoader] = {}
|
84
|
+
for tool, path in _TOOL_IMPORTS.items():
|
85
|
+
full_path = f"{__package__}{path}"
|
86
|
+
if full_path not in _lazy_modules:
|
87
|
+
_lazy_modules[full_path] = LazyLoader(full_path)
|
88
|
+
|
89
|
+
# Set up attributes for lazy loading
|
90
|
+
_tools_to_lazy_modules = {}
|
91
|
+
for tool, path in _TOOL_IMPORTS.items():
|
92
|
+
full_path = f"{__package__}{path}"
|
93
|
+
_tools_to_lazy_modules[tool] = _lazy_modules[full_path]
|
94
|
+
|
95
|
+
# Define __all__ so that import * works properly
|
96
|
+
__all__ = list(_TOOL_IMPORTS.keys())
|
97
|
+
|
98
|
+
# Set up lazy loading for each tool
|
99
|
+
for tool, lazy_module in _tools_to_lazy_modules.items():
|
100
|
+
# This will create properties that lazily load the requested tool
|
101
|
+
setattr(sys.modules[__name__], tool, getattr(lazy_module, tool))
|