local-deep-research 0.1.26__py3-none-any.whl → 0.2.2__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.
- local_deep_research/__init__.py +23 -22
- local_deep_research/__main__.py +16 -0
- local_deep_research/advanced_search_system/__init__.py +7 -0
- local_deep_research/advanced_search_system/filters/__init__.py +8 -0
- local_deep_research/advanced_search_system/filters/base_filter.py +38 -0
- local_deep_research/advanced_search_system/filters/cross_engine_filter.py +200 -0
- local_deep_research/advanced_search_system/findings/base_findings.py +81 -0
- local_deep_research/advanced_search_system/findings/repository.py +452 -0
- local_deep_research/advanced_search_system/knowledge/__init__.py +1 -0
- local_deep_research/advanced_search_system/knowledge/base_knowledge.py +151 -0
- local_deep_research/advanced_search_system/knowledge/standard_knowledge.py +159 -0
- local_deep_research/advanced_search_system/questions/__init__.py +1 -0
- local_deep_research/advanced_search_system/questions/base_question.py +64 -0
- local_deep_research/advanced_search_system/questions/decomposition_question.py +445 -0
- local_deep_research/advanced_search_system/questions/standard_question.py +119 -0
- local_deep_research/advanced_search_system/repositories/__init__.py +7 -0
- local_deep_research/advanced_search_system/strategies/__init__.py +1 -0
- local_deep_research/advanced_search_system/strategies/base_strategy.py +118 -0
- local_deep_research/advanced_search_system/strategies/iterdrag_strategy.py +450 -0
- local_deep_research/advanced_search_system/strategies/parallel_search_strategy.py +312 -0
- local_deep_research/advanced_search_system/strategies/rapid_search_strategy.py +270 -0
- local_deep_research/advanced_search_system/strategies/standard_strategy.py +300 -0
- local_deep_research/advanced_search_system/tools/__init__.py +1 -0
- local_deep_research/advanced_search_system/tools/base_tool.py +100 -0
- local_deep_research/advanced_search_system/tools/knowledge_tools/__init__.py +1 -0
- local_deep_research/advanced_search_system/tools/question_tools/__init__.py +1 -0
- local_deep_research/advanced_search_system/tools/search_tools/__init__.py +1 -0
- local_deep_research/api/__init__.py +5 -5
- local_deep_research/api/research_functions.py +154 -160
- local_deep_research/app.py +8 -0
- local_deep_research/citation_handler.py +25 -16
- local_deep_research/{config.py → config/config_files.py} +102 -110
- local_deep_research/config/llm_config.py +472 -0
- local_deep_research/config/search_config.py +77 -0
- local_deep_research/defaults/__init__.py +10 -5
- local_deep_research/defaults/main.toml +2 -2
- local_deep_research/defaults/search_engines.toml +60 -34
- local_deep_research/main.py +121 -19
- local_deep_research/migrate_db.py +147 -0
- local_deep_research/report_generator.py +87 -45
- local_deep_research/search_system.py +153 -283
- local_deep_research/setup_data_dir.py +35 -0
- local_deep_research/test_migration.py +178 -0
- local_deep_research/utilities/__init__.py +0 -0
- local_deep_research/utilities/db_utils.py +49 -0
- local_deep_research/{utilties → utilities}/enums.py +2 -2
- local_deep_research/{utilties → utilities}/llm_utils.py +63 -29
- local_deep_research/utilities/search_utilities.py +242 -0
- local_deep_research/{utilties → utilities}/setup_utils.py +4 -2
- local_deep_research/web/__init__.py +0 -1
- local_deep_research/web/app.py +86 -1709
- local_deep_research/web/app_factory.py +289 -0
- local_deep_research/web/database/README.md +70 -0
- local_deep_research/web/database/migrate_to_ldr_db.py +289 -0
- local_deep_research/web/database/migrations.py +447 -0
- local_deep_research/web/database/models.py +117 -0
- local_deep_research/web/database/schema_upgrade.py +107 -0
- local_deep_research/web/models/database.py +294 -0
- local_deep_research/web/models/settings.py +94 -0
- local_deep_research/web/routes/api_routes.py +559 -0
- local_deep_research/web/routes/history_routes.py +354 -0
- local_deep_research/web/routes/research_routes.py +715 -0
- local_deep_research/web/routes/settings_routes.py +1583 -0
- local_deep_research/web/services/research_service.py +947 -0
- local_deep_research/web/services/resource_service.py +149 -0
- local_deep_research/web/services/settings_manager.py +669 -0
- local_deep_research/web/services/settings_service.py +187 -0
- local_deep_research/web/services/socket_service.py +210 -0
- local_deep_research/web/static/css/custom_dropdown.css +277 -0
- local_deep_research/web/static/css/settings.css +1223 -0
- local_deep_research/web/static/css/styles.css +525 -48
- local_deep_research/web/static/js/components/custom_dropdown.js +428 -0
- local_deep_research/web/static/js/components/detail.js +348 -0
- local_deep_research/web/static/js/components/fallback/formatting.js +122 -0
- local_deep_research/web/static/js/components/fallback/ui.js +215 -0
- local_deep_research/web/static/js/components/history.js +487 -0
- local_deep_research/web/static/js/components/logpanel.js +949 -0
- local_deep_research/web/static/js/components/progress.js +1107 -0
- local_deep_research/web/static/js/components/research.js +1865 -0
- local_deep_research/web/static/js/components/results.js +766 -0
- local_deep_research/web/static/js/components/settings.js +3981 -0
- local_deep_research/web/static/js/components/settings_sync.js +106 -0
- local_deep_research/web/static/js/main.js +226 -0
- local_deep_research/web/static/js/services/api.js +253 -0
- local_deep_research/web/static/js/services/audio.js +31 -0
- local_deep_research/web/static/js/services/formatting.js +119 -0
- local_deep_research/web/static/js/services/pdf.js +622 -0
- local_deep_research/web/static/js/services/socket.js +882 -0
- local_deep_research/web/static/js/services/ui.js +546 -0
- local_deep_research/web/templates/base.html +72 -0
- local_deep_research/web/templates/components/custom_dropdown.html +47 -0
- local_deep_research/web/templates/components/log_panel.html +32 -0
- local_deep_research/web/templates/components/mobile_nav.html +22 -0
- local_deep_research/web/templates/components/settings_form.html +299 -0
- local_deep_research/web/templates/components/sidebar.html +21 -0
- local_deep_research/web/templates/pages/details.html +73 -0
- local_deep_research/web/templates/pages/history.html +51 -0
- local_deep_research/web/templates/pages/progress.html +57 -0
- local_deep_research/web/templates/pages/research.html +139 -0
- local_deep_research/web/templates/pages/results.html +59 -0
- local_deep_research/web/templates/settings_dashboard.html +78 -192
- local_deep_research/web/utils/__init__.py +0 -0
- local_deep_research/web/utils/formatters.py +76 -0
- local_deep_research/web_search_engines/engines/full_search.py +18 -16
- local_deep_research/web_search_engines/engines/meta_search_engine.py +182 -131
- local_deep_research/web_search_engines/engines/search_engine_arxiv.py +224 -139
- local_deep_research/web_search_engines/engines/search_engine_brave.py +88 -71
- local_deep_research/web_search_engines/engines/search_engine_ddg.py +48 -39
- local_deep_research/web_search_engines/engines/search_engine_github.py +415 -204
- local_deep_research/web_search_engines/engines/search_engine_google_pse.py +123 -90
- local_deep_research/web_search_engines/engines/search_engine_guardian.py +210 -157
- local_deep_research/web_search_engines/engines/search_engine_local.py +532 -369
- local_deep_research/web_search_engines/engines/search_engine_local_all.py +42 -36
- local_deep_research/web_search_engines/engines/search_engine_pubmed.py +358 -266
- local_deep_research/web_search_engines/engines/search_engine_searxng.py +212 -160
- local_deep_research/web_search_engines/engines/search_engine_semantic_scholar.py +213 -170
- local_deep_research/web_search_engines/engines/search_engine_serpapi.py +84 -68
- local_deep_research/web_search_engines/engines/search_engine_wayback.py +186 -154
- local_deep_research/web_search_engines/engines/search_engine_wikipedia.py +115 -77
- local_deep_research/web_search_engines/search_engine_base.py +174 -99
- local_deep_research/web_search_engines/search_engine_factory.py +192 -102
- local_deep_research/web_search_engines/search_engines_config.py +22 -15
- {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.2.dist-info}/METADATA +177 -97
- local_deep_research-0.2.2.dist-info/RECORD +135 -0
- {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.2.dist-info}/WHEEL +1 -2
- {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.2.dist-info}/entry_points.txt +3 -0
- local_deep_research/defaults/llm_config.py +0 -338
- local_deep_research/utilties/search_utilities.py +0 -114
- local_deep_research/web/static/js/app.js +0 -3763
- local_deep_research/web/templates/api_keys_config.html +0 -82
- local_deep_research/web/templates/collections_config.html +0 -90
- local_deep_research/web/templates/index.html +0 -348
- local_deep_research/web/templates/llm_config.html +0 -120
- local_deep_research/web/templates/main_config.html +0 -89
- local_deep_research/web/templates/search_engines_config.html +0 -154
- local_deep_research/web/templates/settings.html +0 -519
- local_deep_research-0.1.26.dist-info/RECORD +0 -61
- local_deep_research-0.1.26.dist-info/top_level.txt +0 -1
- /local_deep_research/{utilties → config}/__init__.py +0 -0
- {local_deep_research-0.1.26.dist-info → local_deep_research-0.2.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,300 @@
|
|
1
|
+
import json
|
2
|
+
import logging
|
3
|
+
from typing import Dict
|
4
|
+
|
5
|
+
from ...citation_handler import CitationHandler
|
6
|
+
from ...config.config_files import settings
|
7
|
+
from ...config.llm_config import get_llm
|
8
|
+
from ...config.search_config import get_search
|
9
|
+
from ...utilities.db_utils import get_db_setting
|
10
|
+
from ...utilities.enums import KnowledgeAccumulationApproach
|
11
|
+
from ...utilities.search_utilities import extract_links_from_search_results
|
12
|
+
from ..findings.repository import FindingsRepository
|
13
|
+
from ..knowledge.standard_knowledge import StandardKnowledge
|
14
|
+
from ..questions.standard_question import StandardQuestionGenerator
|
15
|
+
from .base_strategy import BaseSearchStrategy
|
16
|
+
|
17
|
+
logger = logging.getLogger(__name__)
|
18
|
+
|
19
|
+
|
20
|
+
class StandardSearchStrategy(BaseSearchStrategy):
|
21
|
+
"""Standard iterative search strategy that generates follow-up questions."""
|
22
|
+
|
23
|
+
def __init__(self, search=None, model=None, citation_handler=None):
|
24
|
+
"""Initialize with optional dependency injection for testing."""
|
25
|
+
self.search = search or get_search()
|
26
|
+
self.model = model or get_llm()
|
27
|
+
self.max_iterations = int(get_db_setting("search.iterations"))
|
28
|
+
self.questions_per_iteration = int(
|
29
|
+
get_db_setting("search.questions_per_iteration")
|
30
|
+
)
|
31
|
+
self.context_limit = int(
|
32
|
+
get_db_setting("general.knowledge_accumulation_context_limit")
|
33
|
+
)
|
34
|
+
self.questions_by_iteration = {}
|
35
|
+
|
36
|
+
# Use provided citation_handler or create one
|
37
|
+
self.citation_handler = citation_handler or CitationHandler(self.model)
|
38
|
+
|
39
|
+
# Initialize specialized components
|
40
|
+
self.question_generator = StandardQuestionGenerator(self.model)
|
41
|
+
self.knowledge_generator = StandardKnowledge(self.model)
|
42
|
+
self.findings_repository = FindingsRepository(self.model)
|
43
|
+
|
44
|
+
# Initialize other attributes
|
45
|
+
self.progress_callback = None
|
46
|
+
self.all_links_of_system = list()
|
47
|
+
|
48
|
+
def _update_progress(
|
49
|
+
self, message: str, progress_percent: int = None, metadata: dict = None
|
50
|
+
) -> None:
|
51
|
+
"""Send a progress update via the callback if available."""
|
52
|
+
if self.progress_callback:
|
53
|
+
self.progress_callback(message, progress_percent, metadata or {})
|
54
|
+
|
55
|
+
def analyze_topic(self, query: str) -> Dict:
|
56
|
+
"""Standard implementation of the topic analysis process."""
|
57
|
+
logger.info(f"Starting research on topic: {query}")
|
58
|
+
|
59
|
+
findings = []
|
60
|
+
current_knowledge = ""
|
61
|
+
iteration = 0
|
62
|
+
total_iterations = self.max_iterations
|
63
|
+
section_links = list()
|
64
|
+
|
65
|
+
self._update_progress(
|
66
|
+
"Initializing research system",
|
67
|
+
5,
|
68
|
+
{"phase": "init", "iterations_planned": total_iterations},
|
69
|
+
)
|
70
|
+
|
71
|
+
# Check if search engine is available
|
72
|
+
if self.search is None:
|
73
|
+
error_msg = (
|
74
|
+
"Error: No search engine available. Please check your configuration."
|
75
|
+
)
|
76
|
+
self._update_progress(
|
77
|
+
error_msg,
|
78
|
+
100,
|
79
|
+
{
|
80
|
+
"phase": "error",
|
81
|
+
"error": "No search engine available",
|
82
|
+
"status": "failed",
|
83
|
+
},
|
84
|
+
)
|
85
|
+
return {
|
86
|
+
"findings": [],
|
87
|
+
"iterations": 0,
|
88
|
+
"questions": {},
|
89
|
+
"formatted_findings": "Error: Unable to conduct research without a search engine.",
|
90
|
+
"current_knowledge": "",
|
91
|
+
"error": error_msg,
|
92
|
+
}
|
93
|
+
|
94
|
+
while iteration < self.max_iterations:
|
95
|
+
iteration_progress_base = (iteration / total_iterations) * 100
|
96
|
+
self._update_progress(
|
97
|
+
f"Starting iteration {iteration + 1} of {total_iterations}",
|
98
|
+
int(iteration_progress_base),
|
99
|
+
{"phase": "iteration_start", "iteration": iteration + 1},
|
100
|
+
)
|
101
|
+
|
102
|
+
# Generate questions for this iteration using the question generator
|
103
|
+
# Prepare context for question generation
|
104
|
+
context = f"""Current Query: {query}
|
105
|
+
Current Knowledge: {current_knowledge}
|
106
|
+
Previous Questions: {json.dumps(self.questions_by_iteration, indent=2)}
|
107
|
+
Iteration: {iteration + 1} of {total_iterations}"""
|
108
|
+
|
109
|
+
# Call question generator with updated interface
|
110
|
+
questions = self.question_generator.generate_questions(
|
111
|
+
query=query, context=context
|
112
|
+
)
|
113
|
+
|
114
|
+
self.questions_by_iteration[iteration] = questions
|
115
|
+
logger.info(f"Generated questions: {questions}")
|
116
|
+
|
117
|
+
question_count = len(questions)
|
118
|
+
knowledge_accumulation = get_db_setting(
|
119
|
+
"general.knowledge_accumulation",
|
120
|
+
settings.general.knowledge_accumulation,
|
121
|
+
)
|
122
|
+
for q_idx, question in enumerate(questions):
|
123
|
+
question_progress_base = iteration_progress_base + (
|
124
|
+
((q_idx + 1) / question_count) * (100 / total_iterations) * 0.5
|
125
|
+
)
|
126
|
+
|
127
|
+
self._update_progress(
|
128
|
+
f"Searching for: {question}",
|
129
|
+
int(question_progress_base),
|
130
|
+
{
|
131
|
+
"phase": "search",
|
132
|
+
"iteration": iteration + 1,
|
133
|
+
"question_index": q_idx + 1,
|
134
|
+
},
|
135
|
+
)
|
136
|
+
|
137
|
+
try:
|
138
|
+
if self.search is None:
|
139
|
+
self._update_progress(
|
140
|
+
f"Search engine unavailable, skipping search for: {question}",
|
141
|
+
int(question_progress_base + 2),
|
142
|
+
{
|
143
|
+
"phase": "search_error",
|
144
|
+
"error": "No search engine available",
|
145
|
+
},
|
146
|
+
)
|
147
|
+
search_results = []
|
148
|
+
else:
|
149
|
+
search_results = self.search.run(question)
|
150
|
+
except Exception as e:
|
151
|
+
error_msg = f"Error during search: {str(e)}"
|
152
|
+
logger.error(f"SEARCH ERROR: {error_msg}")
|
153
|
+
self._handle_search_error(error_msg, question_progress_base + 10)
|
154
|
+
search_results = []
|
155
|
+
|
156
|
+
if search_results is None:
|
157
|
+
self._update_progress(
|
158
|
+
f"No search results found for question: {question}",
|
159
|
+
int(question_progress_base + 2),
|
160
|
+
{"phase": "search_complete", "result_count": 0},
|
161
|
+
)
|
162
|
+
search_results = [] # Initialize to empty list instead of None
|
163
|
+
continue
|
164
|
+
|
165
|
+
self._update_progress(
|
166
|
+
f"Found {len(search_results)} results for question: {question}",
|
167
|
+
int(question_progress_base + 2),
|
168
|
+
{"phase": "search_complete", "result_count": len(search_results)},
|
169
|
+
)
|
170
|
+
|
171
|
+
logger.info(f"len search: {len(search_results)}")
|
172
|
+
|
173
|
+
if len(search_results) == 0:
|
174
|
+
continue
|
175
|
+
|
176
|
+
self._update_progress(
|
177
|
+
f"Analyzing results for: {question}",
|
178
|
+
int(question_progress_base + 5),
|
179
|
+
{"phase": "analysis"},
|
180
|
+
)
|
181
|
+
|
182
|
+
try:
|
183
|
+
result = self.citation_handler.analyze_followup(
|
184
|
+
question,
|
185
|
+
search_results,
|
186
|
+
current_knowledge,
|
187
|
+
nr_of_links=len(self.all_links_of_system),
|
188
|
+
)
|
189
|
+
links = extract_links_from_search_results(search_results)
|
190
|
+
self.all_links_of_system.extend(links)
|
191
|
+
section_links.extend(links)
|
192
|
+
|
193
|
+
if result is not None:
|
194
|
+
results_with_links = str(result["content"])
|
195
|
+
findings.append(
|
196
|
+
{
|
197
|
+
"phase": f"Follow-up {iteration}.{questions.index(question) + 1}",
|
198
|
+
"content": results_with_links,
|
199
|
+
"question": question,
|
200
|
+
"search_results": search_results,
|
201
|
+
"documents": result["documents"],
|
202
|
+
}
|
203
|
+
)
|
204
|
+
|
205
|
+
if knowledge_accumulation != str(
|
206
|
+
KnowledgeAccumulationApproach.NO_KNOWLEDGE.value
|
207
|
+
):
|
208
|
+
current_knowledge = (
|
209
|
+
current_knowledge
|
210
|
+
+ "\n\n\n New: \n"
|
211
|
+
+ results_with_links
|
212
|
+
)
|
213
|
+
|
214
|
+
if knowledge_accumulation == str(
|
215
|
+
KnowledgeAccumulationApproach.QUESTION.value
|
216
|
+
):
|
217
|
+
logger.info("Compressing knowledge")
|
218
|
+
self._update_progress(
|
219
|
+
f"Compress Knowledge for: {question}",
|
220
|
+
int(question_progress_base + 0),
|
221
|
+
{"phase": "analysis"},
|
222
|
+
)
|
223
|
+
current_knowledge = (
|
224
|
+
self.knowledge_generator.compress_knowledge(
|
225
|
+
current_knowledge, query, section_links
|
226
|
+
)
|
227
|
+
)
|
228
|
+
|
229
|
+
self._update_progress(
|
230
|
+
f"Analysis complete for question: {question}",
|
231
|
+
int(question_progress_base + 10),
|
232
|
+
{"phase": "analysis_complete"},
|
233
|
+
)
|
234
|
+
except Exception as e:
|
235
|
+
error_msg = f"Error analyzing results: {str(e)}"
|
236
|
+
logger.info(f"ANALYSIS ERROR: {error_msg}")
|
237
|
+
self._handle_search_error(error_msg, question_progress_base + 10)
|
238
|
+
|
239
|
+
iteration += 1
|
240
|
+
|
241
|
+
self._update_progress(
|
242
|
+
f"Compressing knowledge after iteration {iteration}",
|
243
|
+
int((iteration / total_iterations) * 100 - 5),
|
244
|
+
{"phase": "knowledge_compression"},
|
245
|
+
)
|
246
|
+
|
247
|
+
if knowledge_accumulation == KnowledgeAccumulationApproach.ITERATION.value:
|
248
|
+
try:
|
249
|
+
logger.info("ITERATION - Compressing Knowledge")
|
250
|
+
current_knowledge = self.knowledge_generator.compress_knowledge(
|
251
|
+
current_knowledge, query, section_links
|
252
|
+
)
|
253
|
+
logger.info("FINISHED ITERATION - Compressing Knowledge")
|
254
|
+
except Exception as e:
|
255
|
+
error_msg = f"Error compressing knowledge: {str(e)}"
|
256
|
+
logger.info(f"COMPRESSION ERROR: {error_msg}")
|
257
|
+
self._handle_search_error(
|
258
|
+
error_msg, int((iteration / total_iterations) * 100 - 3)
|
259
|
+
)
|
260
|
+
|
261
|
+
self._update_progress(
|
262
|
+
f"Iteration {iteration} complete",
|
263
|
+
int((iteration / total_iterations) * 100),
|
264
|
+
{"phase": "iteration_complete", "iteration": iteration},
|
265
|
+
)
|
266
|
+
|
267
|
+
# Extract content from findings for synthesis
|
268
|
+
finding_contents = [f["content"] for f in findings if "content" in f]
|
269
|
+
|
270
|
+
# First synthesize findings to get coherent content
|
271
|
+
synthesized_content = self.findings_repository.synthesize_findings(
|
272
|
+
query,
|
273
|
+
finding_contents,
|
274
|
+
findings, # Pass the full findings list with search results
|
275
|
+
accumulated_knowledge=current_knowledge,
|
276
|
+
old_formatting=False, # Don't format here, just synthesize content
|
277
|
+
)
|
278
|
+
|
279
|
+
# Transfer questions to the repository
|
280
|
+
self.findings_repository.set_questions_by_iteration(
|
281
|
+
self.questions_by_iteration
|
282
|
+
)
|
283
|
+
|
284
|
+
# Now format the findings with search questions and sources
|
285
|
+
formatted_findings = self.findings_repository.format_findings_to_text(
|
286
|
+
findings, synthesized_content
|
287
|
+
)
|
288
|
+
|
289
|
+
# Add the synthesized content to the repository
|
290
|
+
self.findings_repository.add_finding(query, synthesized_content)
|
291
|
+
|
292
|
+
self._update_progress("Research complete", 95, {"phase": "complete"})
|
293
|
+
|
294
|
+
return {
|
295
|
+
"findings": findings,
|
296
|
+
"iterations": iteration,
|
297
|
+
"questions": self.questions_by_iteration,
|
298
|
+
"formatted_findings": formatted_findings,
|
299
|
+
"current_knowledge": current_knowledge,
|
300
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
# Search System Tools Package
|
@@ -0,0 +1,100 @@
|
|
1
|
+
"""
|
2
|
+
Base class for all agent-compatible tools.
|
3
|
+
Defines the common interface and shared functionality for different tools.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import logging
|
7
|
+
from abc import ABC, abstractmethod
|
8
|
+
from typing import Any, Dict
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
|
13
|
+
class BaseTool(ABC):
|
14
|
+
"""Abstract base class for all agent-compatible tools."""
|
15
|
+
|
16
|
+
def __init__(self, name: str, description: str):
|
17
|
+
"""
|
18
|
+
Initialize the tool.
|
19
|
+
|
20
|
+
Args:
|
21
|
+
name: The name of the tool
|
22
|
+
description: A description of what the tool does
|
23
|
+
"""
|
24
|
+
self.name = name
|
25
|
+
self.description = description
|
26
|
+
self.parameters: Dict[str, Dict[str, Any]] = {}
|
27
|
+
|
28
|
+
@abstractmethod
|
29
|
+
def execute(self, **kwargs) -> Any:
|
30
|
+
"""
|
31
|
+
Execute the tool with the given parameters.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
**kwargs: Tool-specific parameters
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
Any: The result of the tool execution
|
38
|
+
"""
|
39
|
+
pass
|
40
|
+
|
41
|
+
def get_schema(self) -> Dict[str, Any]:
|
42
|
+
"""
|
43
|
+
Get the JSON schema for the tool's parameters.
|
44
|
+
|
45
|
+
Returns:
|
46
|
+
Dict[str, Any]: The JSON schema
|
47
|
+
"""
|
48
|
+
return {
|
49
|
+
"name": self.name,
|
50
|
+
"description": self.description,
|
51
|
+
"parameters": self.parameters,
|
52
|
+
}
|
53
|
+
|
54
|
+
def validate_parameters(self, **kwargs) -> bool:
|
55
|
+
"""
|
56
|
+
Validate the provided parameters against the tool's schema.
|
57
|
+
|
58
|
+
Args:
|
59
|
+
**kwargs: Parameters to validate
|
60
|
+
|
61
|
+
Returns:
|
62
|
+
bool: True if parameters are valid, False otherwise
|
63
|
+
"""
|
64
|
+
for param_name, param_schema in self.parameters.items():
|
65
|
+
if param_name not in kwargs:
|
66
|
+
if param_schema.get("required", False):
|
67
|
+
logger.error(f"Missing required parameter: {param_name}")
|
68
|
+
return False
|
69
|
+
continue
|
70
|
+
|
71
|
+
param_value = kwargs[param_name]
|
72
|
+
param_type = param_schema.get("type")
|
73
|
+
|
74
|
+
if param_type and not isinstance(param_value, eval(param_type)):
|
75
|
+
logger.error(f"Invalid type for parameter {param_name}")
|
76
|
+
return False
|
77
|
+
|
78
|
+
if "enum" in param_schema and param_value not in param_schema["enum"]:
|
79
|
+
logger.error(f"Invalid value for parameter {param_name}")
|
80
|
+
return False
|
81
|
+
|
82
|
+
return True
|
83
|
+
|
84
|
+
def _log_execution(self, **kwargs) -> None:
|
85
|
+
"""
|
86
|
+
Log tool execution details.
|
87
|
+
|
88
|
+
Args:
|
89
|
+
**kwargs: Parameters used in execution
|
90
|
+
"""
|
91
|
+
logger.info(f"Executing tool {self.name} with parameters: {kwargs}")
|
92
|
+
|
93
|
+
def _log_result(self, result: Any) -> None:
|
94
|
+
"""
|
95
|
+
Log tool execution result.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
result: The result of the tool execution
|
99
|
+
"""
|
100
|
+
logger.info(f"Tool {self.name} execution completed with result: {result}")
|
@@ -0,0 +1 @@
|
|
1
|
+
# Search System Tools Package
|
@@ -0,0 +1 @@
|
|
1
|
+
# Search System Tools Package
|
@@ -0,0 +1 @@
|
|
1
|
+
# Search System Tools Package
|
@@ -4,11 +4,11 @@ API module for programmatic access to Local Deep Research functionality.
|
|
4
4
|
"""
|
5
5
|
|
6
6
|
from .research_functions import (
|
7
|
-
quick_summary,
|
8
|
-
generate_report,
|
9
7
|
analyze_documents,
|
8
|
+
generate_report,
|
9
|
+
get_available_collections,
|
10
10
|
get_available_search_engines,
|
11
|
-
|
11
|
+
quick_summary,
|
12
12
|
)
|
13
13
|
|
14
14
|
__all__ = [
|
@@ -16,5 +16,5 @@ __all__ = [
|
|
16
16
|
"generate_report",
|
17
17
|
"analyze_documents",
|
18
18
|
"get_available_search_engines",
|
19
|
-
"get_available_collections"
|
20
|
-
]
|
19
|
+
"get_available_collections",
|
20
|
+
]
|