quantalogic 0.2.14__tar.gz → 0.2.15__tar.gz
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-0.2.14 → quantalogic-0.2.15}/PKG-INFO +2 -1
- {quantalogic-0.2.14 → quantalogic-0.2.15}/pyproject.toml +2 -1
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/agent_config.py +4 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/generative_model.py +43 -15
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/search_agent.py +14 -3
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/__init__.py +2 -0
- quantalogic-0.2.15/quantalogic/tools/duckduckgo_search_tool.py +214 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/markitdown_tool.py +36 -33
- {quantalogic-0.2.14 → quantalogic-0.2.15}/LICENSE +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/README.md +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/__init__.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/agent.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/coding_agent.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/event_emitter.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/interactive_text_editor.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/main.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/memory.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/model_names.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/print_event.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/prompts.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/server/__init__.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/server/agent_server.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/server/models.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/server/routes.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/server/state.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/server/static/js/event_visualizer.js +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/server/static/js/quantalogic.js +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/server/templates/index.html +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tool_manager.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/agent_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/download_http_file_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/edit_whole_content_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/elixir_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/execute_bash_command_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/input_question_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/__init__.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/c_handler.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/cpp_handler.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/go_handler.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/java_handler.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/javascript_handler.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/python_handler.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/rust_handler.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/scala_handler.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/typescript_handler.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/list_directory_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/llm_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/llm_vision_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/nodejs_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/python_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/read_file_block_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/read_file_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/replace_in_file_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/ripgrep_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/search_definition_names.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/serpapi_search_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/task_complete_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/unified_diff_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/wikipedia_search_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/write_file_tool.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/__init__.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/ask_user_validation.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/check_version.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/download_http_file.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/get_coding_environment.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/get_environment.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/get_quantalogic_rules_content.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/git_ls.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/read_file.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/read_http_text_content.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/version.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/xml_parser.py +0 -0
- {quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/xml_tool_parser.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: quantalogic
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.15
|
4
4
|
Summary: QuantaLogic ReAct Agents
|
5
5
|
Author: Raphaël MANSUY
|
6
6
|
Author-email: raphael.mansuy@gmail.com
|
@@ -10,6 +10,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.13
|
11
11
|
Requires-Dist: boto3 (>=1.35.86,<2.0.0)
|
12
12
|
Requires-Dist: click (>=8.1.8,<9.0.0)
|
13
|
+
Requires-Dist: duckduckgo-search (>=7.2.1,<8.0.0)
|
13
14
|
Requires-Dist: fastapi (>=0.115.6,<0.116.0)
|
14
15
|
Requires-Dist: google-auth (>=2.20.0,<3.0.0)
|
15
16
|
Requires-Dist: google-search-results (>=2.4.2,<3.0.0)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "quantalogic"
|
3
|
-
version = "0.2.
|
3
|
+
version = "0.2.15"
|
4
4
|
description = "QuantaLogic ReAct Agents"
|
5
5
|
authors = ["Raphaël MANSUY <raphael.mansuy@gmail.com>"]
|
6
6
|
readme = "README.md"
|
@@ -36,6 +36,7 @@ toml = "^0.10.2"
|
|
36
36
|
types-requests = "^2.32.0.20241016"
|
37
37
|
google-search-results = "^2.4.2"
|
38
38
|
serpapi = "^0.1.5"
|
39
|
+
duckduckgo-search = "^7.2.1"
|
39
40
|
|
40
41
|
[tool.poetry.scripts]
|
41
42
|
quantalogic = "quantalogic.main:cli"
|
@@ -24,6 +24,8 @@ from quantalogic.tools import (
|
|
24
24
|
SearchDefinitionNames,
|
25
25
|
TaskCompleteTool,
|
26
26
|
WriteFileTool,
|
27
|
+
DuckDuckGoSearchTool,
|
28
|
+
WikipediaSearchTool,
|
27
29
|
)
|
28
30
|
|
29
31
|
MODEL_NAME = "deepseek/deepseek-chat"
|
@@ -124,6 +126,8 @@ def create_full_agent(model_name: str, vision_model_name: str | None) -> Agent:
|
|
124
126
|
MarkitdownTool(),
|
125
127
|
LLMTool(model_name=model_name),
|
126
128
|
DownloadHttpFileTool(),
|
129
|
+
WikipediaSearchTool(),
|
130
|
+
DuckDuckGoSearchTool(),
|
127
131
|
]
|
128
132
|
|
129
133
|
if vision_model_name:
|
@@ -1,5 +1,7 @@
|
|
1
1
|
"""Generative model module for AI-powered text generation."""
|
2
2
|
|
3
|
+
import functools
|
4
|
+
|
3
5
|
import openai
|
4
6
|
from litellm import completion, exceptions, get_max_tokens, get_model_info, token_counter
|
5
7
|
from loguru import logger
|
@@ -83,6 +85,7 @@ class GenerativeModel:
|
|
83
85
|
logger.debug(f"Initializing GenerativeModel with model={model}, temperature={temperature}")
|
84
86
|
self.model = model
|
85
87
|
self.temperature = temperature
|
88
|
+
self._get_model_info_cached = functools.lru_cache(maxsize=32)(self._get_model_info_impl)
|
86
89
|
|
87
90
|
# Define retriable exceptions based on LiteLLM's exception mapping
|
88
91
|
RETRIABLE_EXCEPTIONS = (
|
@@ -235,21 +238,46 @@ class GenerativeModel:
|
|
235
238
|
litellm_messages.append({"role": "user", "content": str(prompt)})
|
236
239
|
return token_counter(model=self.model, messages=litellm_messages)
|
237
240
|
|
238
|
-
def
|
239
|
-
"""Get information about the model.
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
241
|
+
def _get_model_info_impl(self, model_name: str) -> dict:
|
242
|
+
"""Get information about the model with prefix fallback logic.
|
243
|
+
|
244
|
+
Attempts to find model info by progressively removing provider prefixes.
|
245
|
+
Raises ValueError if no valid model configuration is found.
|
246
|
+
Results are cached to improve performance.
|
247
|
+
|
248
|
+
Example:
|
249
|
+
openrouter/openai/gpt-4o-mini → openai/gpt-4o-mini → gpt-4o-mini
|
250
|
+
"""
|
251
|
+
original_model = model_name
|
252
|
+
|
253
|
+
while True:
|
254
|
+
try:
|
255
|
+
logger.debug(f"Attempting to retrieve model info for: {model_name}")
|
256
|
+
model_info = get_model_info(model_name)
|
257
|
+
if model_info:
|
258
|
+
logger.debug(f"Found model info for {model_name}: {model_info}")
|
259
|
+
return model_info
|
260
|
+
except Exception:
|
261
|
+
pass
|
262
|
+
|
263
|
+
# Try removing one prefix level
|
264
|
+
parts = model_name.split('/')
|
265
|
+
if len(parts) <= 1:
|
266
|
+
break
|
267
|
+
model_name = '/'.join(parts[1:])
|
268
|
+
|
269
|
+
error_msg = f"Could not find model info for {original_model} after trying: {self.model} → {model_name}"
|
270
|
+
logger.error(error_msg)
|
271
|
+
raise ValueError(error_msg)
|
272
|
+
|
273
|
+
def get_model_info(self, model_name: str = None) -> dict:
|
274
|
+
"""Get cached information about the model.
|
275
|
+
|
276
|
+
If no model name is provided, uses the current model.
|
277
|
+
"""
|
278
|
+
if model_name is None:
|
279
|
+
model_name = self.model
|
280
|
+
return self._get_model_info_cached(model_name)
|
253
281
|
|
254
282
|
def get_model_max_input_tokens(self) -> int:
|
255
283
|
"""Get the maximum number of input tokens for the model."""
|
@@ -1,16 +1,26 @@
|
|
1
1
|
from quantalogic.agent import Agent
|
2
|
-
from quantalogic.tools import
|
2
|
+
from quantalogic.tools import (
|
3
|
+
InputQuestionTool,
|
4
|
+
SerpApiSearchTool,
|
5
|
+
DuckDuckGoSearchTool,
|
6
|
+
TaskCompleteTool,
|
7
|
+
WikipediaSearchTool,
|
8
|
+
ReadFileBlockTool,
|
9
|
+
ReadFileTool,
|
10
|
+
MarkitdownTool,
|
11
|
+
RipgrepTool
|
12
|
+
)
|
3
13
|
|
4
14
|
|
5
15
|
def create_search_agent(model_name: str) -> Agent:
|
6
|
-
"""Creates and configures a search agent with web and
|
16
|
+
"""Creates and configures a search agent with web, knowledge, and privacy-focused search tools.
|
7
17
|
|
8
18
|
Args:
|
9
19
|
model_name (str): Name of the language model to use for the agent's core capabilities
|
10
20
|
|
11
21
|
Returns:
|
12
22
|
Agent: A fully configured search agent instance with:
|
13
|
-
- Web search capabilities (SerpAPI)
|
23
|
+
- Web search capabilities (SerpAPI, DuckDuckGo)
|
14
24
|
- Knowledge search capabilities (Wikipedia)
|
15
25
|
- Basic interaction tools
|
16
26
|
"""
|
@@ -22,6 +32,7 @@ def create_search_agent(model_name: str) -> Agent:
|
|
22
32
|
tools = [
|
23
33
|
# Search tools
|
24
34
|
SerpApiSearchTool(), # Web search capabilities
|
35
|
+
DuckDuckGoSearchTool(), # Privacy-focused web search
|
25
36
|
WikipediaSearchTool(), # Knowledge search capabilities
|
26
37
|
# Basic interaction tools
|
27
38
|
TaskCompleteTool(), # Marks task completion
|
@@ -18,6 +18,7 @@ from .replace_in_file_tool import ReplaceInFileTool
|
|
18
18
|
from .ripgrep_tool import RipgrepTool
|
19
19
|
from .search_definition_names import SearchDefinitionNames
|
20
20
|
from .serpapi_search_tool import SerpApiSearchTool
|
21
|
+
from .duckduckgo_search_tool import DuckDuckGoSearchTool
|
21
22
|
from .task_complete_tool import TaskCompleteTool
|
22
23
|
from .tool import Tool, ToolArgument
|
23
24
|
from .unified_diff_tool import UnifiedDiffTool
|
@@ -27,6 +28,7 @@ from .write_file_tool import WriteFileTool
|
|
27
28
|
__all__ = [
|
28
29
|
"WikipediaSearchTool",
|
29
30
|
"SerpApiSearchTool",
|
31
|
+
"DuckDuckGoSearchTool",
|
30
32
|
"Tool",
|
31
33
|
"ToolArgument",
|
32
34
|
"TaskCompleteTool",
|
@@ -0,0 +1,214 @@
|
|
1
|
+
"""Tool for interacting with DuckDuckGo for search results."""
|
2
|
+
|
3
|
+
from duckduckgo_search import DDGS
|
4
|
+
|
5
|
+
from quantalogic.tools.tool import Tool, ToolArgument
|
6
|
+
|
7
|
+
|
8
|
+
class DuckDuckGoSearchTool(Tool):
|
9
|
+
"""Tool for retrieving search results from DuckDuckGo.
|
10
|
+
|
11
|
+
This tool provides a convenient interface to DuckDuckGo's search capabilities,
|
12
|
+
supporting multiple search types and structured JSON output.
|
13
|
+
|
14
|
+
Example usage:
|
15
|
+
```python
|
16
|
+
tool = DuckDuckGoSearchTool()
|
17
|
+
results = tool.execute(
|
18
|
+
query="machine learning",
|
19
|
+
search_type="text",
|
20
|
+
max_results=10,
|
21
|
+
region="us-en",
|
22
|
+
safesearch="moderate"
|
23
|
+
)
|
24
|
+
print(results)
|
25
|
+
```
|
26
|
+
|
27
|
+
The tool handles:
|
28
|
+
- Query validation
|
29
|
+
- API error handling
|
30
|
+
- Multiple search types (text, images, videos, news)
|
31
|
+
- Scope filtering (region, safesearch, timelimit)
|
32
|
+
- JSON result formatting
|
33
|
+
"""
|
34
|
+
|
35
|
+
name: str = "duckduckgo_tool"
|
36
|
+
description: str = (
|
37
|
+
"Retrieves search results from DuckDuckGo. "
|
38
|
+
"Provides structured output of search results."
|
39
|
+
)
|
40
|
+
arguments: list = [
|
41
|
+
ToolArgument(
|
42
|
+
name="query",
|
43
|
+
arg_type="string",
|
44
|
+
description="The search query to execute",
|
45
|
+
required=True,
|
46
|
+
example="machine learning",
|
47
|
+
),
|
48
|
+
ToolArgument(
|
49
|
+
name="max_results",
|
50
|
+
arg_type="int",
|
51
|
+
description="Maximum number of results to retrieve (1-50)",
|
52
|
+
required=True,
|
53
|
+
default="10",
|
54
|
+
example="20",
|
55
|
+
),
|
56
|
+
ToolArgument(
|
57
|
+
name="search_type",
|
58
|
+
arg_type="string",
|
59
|
+
description="Type of search to perform (text, images, videos, news)",
|
60
|
+
required=False,
|
61
|
+
default="text",
|
62
|
+
example="images",
|
63
|
+
),
|
64
|
+
ToolArgument(
|
65
|
+
name="region",
|
66
|
+
arg_type="string",
|
67
|
+
description="Region for search results (e.g., 'wt-wt', 'us-en')",
|
68
|
+
required=False,
|
69
|
+
default="wt-wt",
|
70
|
+
example="us-en",
|
71
|
+
),
|
72
|
+
ToolArgument(
|
73
|
+
name="safesearch",
|
74
|
+
arg_type="string",
|
75
|
+
description="Safesearch level ('on', 'moderate', 'off')",
|
76
|
+
required=False,
|
77
|
+
default="moderate",
|
78
|
+
example="moderate",
|
79
|
+
),
|
80
|
+
ToolArgument(
|
81
|
+
name="timelimit",
|
82
|
+
arg_type="string",
|
83
|
+
description="Time limit for results (e.g., 'd' for day, 'w' for week)",
|
84
|
+
required=False,
|
85
|
+
default=None,
|
86
|
+
example="d",
|
87
|
+
),
|
88
|
+
]
|
89
|
+
|
90
|
+
def execute(
|
91
|
+
self,
|
92
|
+
query: str,
|
93
|
+
max_results: int = 10,
|
94
|
+
search_type: str = "text",
|
95
|
+
region: str = "wt-wt",
|
96
|
+
safesearch: str = "moderate",
|
97
|
+
timelimit: str = None,
|
98
|
+
) -> str:
|
99
|
+
"""Execute a search query using DuckDuckGo and return results.
|
100
|
+
|
101
|
+
Args:
|
102
|
+
query: The search query to execute
|
103
|
+
max_results: Maximum number of results to retrieve (1-50)
|
104
|
+
search_type: Type of search to perform (text, images, videos, news)
|
105
|
+
region: Region for search results (e.g., "wt-wt", "us-en")
|
106
|
+
safesearch: Safesearch level ("on", "moderate", "off")
|
107
|
+
timelimit: Time limit for results (e.g., "d" for day, "w" for week)
|
108
|
+
|
109
|
+
Returns:
|
110
|
+
Pretty-printed JSON string of search results.
|
111
|
+
|
112
|
+
Raises:
|
113
|
+
ValueError: If any parameter is invalid
|
114
|
+
RuntimeError: If search fails
|
115
|
+
"""
|
116
|
+
# Handle empty string parameters by setting to defaults
|
117
|
+
query = str(query) if query else query
|
118
|
+
search_type = search_type if search_type else "text"
|
119
|
+
region = region if region else "wt-wt"
|
120
|
+
safesearch = safesearch if safesearch else "moderate"
|
121
|
+
timelimit = timelimit if timelimit else None
|
122
|
+
|
123
|
+
# Validate and convert query
|
124
|
+
if not query:
|
125
|
+
raise ValueError("Query must be a non-empty string")
|
126
|
+
try:
|
127
|
+
query = str(query)
|
128
|
+
except (TypeError, ValueError) as e:
|
129
|
+
raise ValueError(f"Query must be convertible to string: {str(e)}")
|
130
|
+
|
131
|
+
# Validate and convert max_results
|
132
|
+
try:
|
133
|
+
max_results = int(max_results)
|
134
|
+
if max_results < 1 or max_results > 50:
|
135
|
+
raise ValueError("Number of results must be between 1 and 50")
|
136
|
+
except (TypeError, ValueError) as e:
|
137
|
+
raise ValueError(f"Invalid number of results: {str(e)}")
|
138
|
+
|
139
|
+
# Validate search_type
|
140
|
+
if search_type not in ["text", "images", "videos", "news"]:
|
141
|
+
raise ValueError("search_type must be one of: text, images, videos, news")
|
142
|
+
|
143
|
+
# Validate safesearch
|
144
|
+
if safesearch not in ["on", "moderate", "off"]:
|
145
|
+
raise ValueError("safesearch must be one of: on, moderate, off")
|
146
|
+
|
147
|
+
try:
|
148
|
+
ddgs = DDGS()
|
149
|
+
|
150
|
+
# Perform the appropriate search based on search_type
|
151
|
+
if search_type == "text":
|
152
|
+
results = ddgs.text(
|
153
|
+
keywords=query,
|
154
|
+
region=region,
|
155
|
+
safesearch=safesearch,
|
156
|
+
timelimit=timelimit,
|
157
|
+
max_results=max_results,
|
158
|
+
)
|
159
|
+
elif search_type == "images":
|
160
|
+
results = ddgs.images(
|
161
|
+
keywords=query,
|
162
|
+
region=region,
|
163
|
+
safesearch=safesearch,
|
164
|
+
timelimit=timelimit,
|
165
|
+
max_results=max_results,
|
166
|
+
)
|
167
|
+
elif search_type == "videos":
|
168
|
+
results = ddgs.videos(
|
169
|
+
keywords=query,
|
170
|
+
region=region,
|
171
|
+
safesearch=safesearch,
|
172
|
+
timelimit=timelimit,
|
173
|
+
max_results=max_results,
|
174
|
+
)
|
175
|
+
elif search_type == "news":
|
176
|
+
results = ddgs.news(
|
177
|
+
keywords=query,
|
178
|
+
region=region,
|
179
|
+
safesearch=safesearch,
|
180
|
+
timelimit=timelimit,
|
181
|
+
max_results=max_results,
|
182
|
+
)
|
183
|
+
|
184
|
+
# Return pretty-printed JSON
|
185
|
+
import json
|
186
|
+
return json.dumps(results, indent=4, ensure_ascii=False)
|
187
|
+
|
188
|
+
except Exception as e:
|
189
|
+
raise RuntimeError(f"Search failed: {str(e)}")
|
190
|
+
|
191
|
+
|
192
|
+
def main():
|
193
|
+
"""Demonstrate DuckDuckGoSearchTool functionality."""
|
194
|
+
try:
|
195
|
+
tool = DuckDuckGoSearchTool()
|
196
|
+
|
197
|
+
# Test basic search functionality
|
198
|
+
print("Testing DuckDuckGoSearchTool with sample query...")
|
199
|
+
results = tool.execute(query="Python programming", max_results=3)
|
200
|
+
print(results)
|
201
|
+
|
202
|
+
# Test error handling
|
203
|
+
print("\nTesting error handling with invalid query...")
|
204
|
+
try:
|
205
|
+
tool.execute(query="")
|
206
|
+
except ValueError as e:
|
207
|
+
print(f"Caught expected ValueError: {e}")
|
208
|
+
|
209
|
+
except Exception as e:
|
210
|
+
print(f"Error in main: {e}")
|
211
|
+
|
212
|
+
|
213
|
+
if __name__ == "__main__":
|
214
|
+
main()
|
@@ -47,50 +47,53 @@ class MarkitdownTool(Tool):
|
|
47
47
|
Returns:
|
48
48
|
str: The Markdown content or a success message.
|
49
49
|
"""
|
50
|
-
# Handle tilde expansion for local paths
|
51
|
-
if file_path.startswith("~"):
|
52
|
-
file_path = os.path.expanduser(file_path)
|
53
|
-
|
54
|
-
# Handle URL paths
|
55
|
-
if file_path.startswith(("http://", "https://")):
|
56
|
-
try:
|
57
|
-
# Create a temporary file
|
58
|
-
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
59
|
-
temp_path = temp_file.name
|
60
|
-
# Download the file from URL
|
61
|
-
download_http_file(file_path, temp_path)
|
62
|
-
# Use the temporary file path for conversion
|
63
|
-
file_path = temp_path
|
64
|
-
is_temp_file = True
|
65
|
-
except Exception as e:
|
66
|
-
return f"Error downloading file from URL: {str(e)}"
|
67
|
-
else:
|
68
|
-
is_temp_file = False
|
69
|
-
|
70
50
|
try:
|
71
|
-
|
51
|
+
# Handle URL paths first
|
52
|
+
if file_path.startswith(("http://", "https://")):
|
53
|
+
try:
|
54
|
+
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
55
|
+
temp_path = temp_file.name
|
56
|
+
download_http_file(file_path, temp_path)
|
57
|
+
file_path = temp_path
|
58
|
+
is_temp_file = True
|
59
|
+
except Exception as e:
|
60
|
+
return f"Error downloading file from URL: {str(e)}"
|
61
|
+
else:
|
62
|
+
is_temp_file = False
|
63
|
+
# Handle local paths
|
64
|
+
if file_path.startswith("~"):
|
65
|
+
file_path = os.path.expanduser(file_path)
|
66
|
+
if not os.path.isabs(file_path):
|
67
|
+
file_path = os.path.abspath(file_path)
|
68
|
+
|
69
|
+
# Verify file exists
|
70
|
+
if not os.path.exists(file_path):
|
71
|
+
return f"Error: File not found at path: {file_path}"
|
72
72
|
|
73
|
+
from markitdown import MarkItDown
|
73
74
|
md = MarkItDown()
|
74
75
|
result = md.convert(file_path)
|
75
76
|
|
76
77
|
if output_file_path:
|
78
|
+
# Ensure output directory exists
|
79
|
+
output_dir = os.path.dirname(output_file_path)
|
80
|
+
if output_dir and not os.path.exists(output_dir):
|
81
|
+
os.makedirs(output_dir)
|
82
|
+
|
77
83
|
with open(output_file_path, "w", encoding="utf-8") as f:
|
78
84
|
f.write(result.text_content)
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
return output_message
|
85
|
+
return f"Markdown content successfully written to {output_file_path}"
|
86
|
+
|
87
|
+
# Handle content truncation
|
88
|
+
lines = result.text_content.splitlines()
|
89
|
+
if len(lines) > MAX_LINES:
|
90
|
+
truncated_content = "\n".join(lines[:MAX_LINES])
|
91
|
+
return f"Markdown content truncated to {MAX_LINES} lines:\n{truncated_content}"
|
92
|
+
return result.text_content
|
93
|
+
|
90
94
|
except Exception as e:
|
91
95
|
return f"Error converting file to Markdown: {str(e)}"
|
92
96
|
finally:
|
93
|
-
# Clean up temporary file if it was created
|
94
97
|
if is_temp_file and os.path.exists(file_path):
|
95
98
|
os.remove(file_path)
|
96
99
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/cpp_handler.py
RENAMED
File without changes
|
File without changes
|
{quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/java_handler.py
RENAMED
File without changes
|
{quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/javascript_handler.py
RENAMED
File without changes
|
{quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/python_handler.py
RENAMED
File without changes
|
{quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/rust_handler.py
RENAMED
File without changes
|
{quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/scala_handler.py
RENAMED
File without changes
|
{quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/tools/language_handlers/typescript_handler.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{quantalogic-0.2.14 → quantalogic-0.2.15}/quantalogic/utils/get_quantalogic_rules_content.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|