devsper 2.1.6__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 (375) hide show
  1. devsper/__init__.py +14 -0
  2. devsper/agents/a2a/__init__.py +27 -0
  3. devsper/agents/a2a/client.py +126 -0
  4. devsper/agents/a2a/discovery.py +24 -0
  5. devsper/agents/a2a/server.py +128 -0
  6. devsper/agents/a2a/tool_adapter.py +68 -0
  7. devsper/agents/a2a/types.py +49 -0
  8. devsper/agents/agent.py +602 -0
  9. devsper/agents/critic.py +80 -0
  10. devsper/agents/message_bus.py +124 -0
  11. devsper/agents/roles.py +181 -0
  12. devsper/agents/run_agent.py +78 -0
  13. devsper/analytics/__init__.py +5 -0
  14. devsper/analytics/tool_analytics.py +78 -0
  15. devsper/audit/__init__.py +5 -0
  16. devsper/audit/logger.py +214 -0
  17. devsper/bus/__init__.py +29 -0
  18. devsper/bus/backends/__init__.py +5 -0
  19. devsper/bus/backends/base.py +38 -0
  20. devsper/bus/backends/memory.py +55 -0
  21. devsper/bus/backends/redis.py +146 -0
  22. devsper/bus/message.py +56 -0
  23. devsper/bus/schema_version.py +3 -0
  24. devsper/bus/topics.py +19 -0
  25. devsper/cache/__init__.py +6 -0
  26. devsper/cache/embedding_index.py +98 -0
  27. devsper/cache/hashing.py +24 -0
  28. devsper/cache/store.py +153 -0
  29. devsper/cache/task_cache.py +191 -0
  30. devsper/cli/__init__.py +6 -0
  31. devsper/cli/commands/reg.py +733 -0
  32. devsper/cli/github_oauth.py +157 -0
  33. devsper/cli/init.py +637 -0
  34. devsper/cli/main.py +2956 -0
  35. devsper/cli/run_progress.py +103 -0
  36. devsper/cli/ui/__init__.py +65 -0
  37. devsper/cli/ui/components.py +94 -0
  38. devsper/cli/ui/errors.py +104 -0
  39. devsper/cli/ui/logging.py +120 -0
  40. devsper/cli/ui/onboarding.py +102 -0
  41. devsper/cli/ui/progress.py +43 -0
  42. devsper/cli/ui/run_view.py +308 -0
  43. devsper/cli/ui/theme.py +40 -0
  44. devsper/cluster/__init__.py +29 -0
  45. devsper/cluster/election.py +84 -0
  46. devsper/cluster/local.py +97 -0
  47. devsper/cluster/node_info.py +77 -0
  48. devsper/cluster/registry.py +71 -0
  49. devsper/cluster/router.py +117 -0
  50. devsper/cluster/state_backend.py +105 -0
  51. devsper/compliance/__init__.py +5 -0
  52. devsper/compliance/pii.py +147 -0
  53. devsper/config/__init__.py +52 -0
  54. devsper/config/config_loader.py +121 -0
  55. devsper/config/defaults.py +77 -0
  56. devsper/config/resolver.py +342 -0
  57. devsper/config/schema.py +237 -0
  58. devsper/credentials/__init__.py +19 -0
  59. devsper/credentials/cli.py +197 -0
  60. devsper/credentials/migration.py +124 -0
  61. devsper/credentials/store.py +142 -0
  62. devsper/dashboard/__init__.py +9 -0
  63. devsper/dashboard/dashboard.py +87 -0
  64. devsper/dev/__init__.py +25 -0
  65. devsper/dev/builder.py +195 -0
  66. devsper/dev/debugger.py +95 -0
  67. devsper/dev/repo_index.py +138 -0
  68. devsper/dev/sandbox.py +203 -0
  69. devsper/dev/scaffold.py +122 -0
  70. devsper/embeddings/__init__.py +5 -0
  71. devsper/embeddings/service.py +36 -0
  72. devsper/explainability/__init__.py +14 -0
  73. devsper/explainability/decision_tree.py +104 -0
  74. devsper/explainability/rationale.py +38 -0
  75. devsper/explainability/simulation.py +56 -0
  76. devsper/hitl/__init__.py +13 -0
  77. devsper/hitl/approval.py +160 -0
  78. devsper/hitl/escalation.py +95 -0
  79. devsper/intelligence/__init__.py +9 -0
  80. devsper/intelligence/adaptation.py +88 -0
  81. devsper/intelligence/analysis/__init__.py +19 -0
  82. devsper/intelligence/analysis/analyzer.py +71 -0
  83. devsper/intelligence/analysis/cost_estimator.py +66 -0
  84. devsper/intelligence/analysis/formatter.py +103 -0
  85. devsper/intelligence/analysis/run_report.py +402 -0
  86. devsper/intelligence/learning_engine.py +92 -0
  87. devsper/intelligence/strategies/__init__.py +23 -0
  88. devsper/intelligence/strategies/base.py +14 -0
  89. devsper/intelligence/strategies/code_analysis_strategy.py +33 -0
  90. devsper/intelligence/strategies/data_science_strategy.py +33 -0
  91. devsper/intelligence/strategies/document_pipeline_strategy.py +33 -0
  92. devsper/intelligence/strategies/experiment_strategy.py +33 -0
  93. devsper/intelligence/strategies/research_strategy.py +34 -0
  94. devsper/intelligence/strategy_selector.py +84 -0
  95. devsper/intelligence/synthesis.py +132 -0
  96. devsper/intelligence/task_optimizer.py +92 -0
  97. devsper/knowledge/__init__.py +5 -0
  98. devsper/knowledge/extractor.py +204 -0
  99. devsper/knowledge/knowledge_graph.py +184 -0
  100. devsper/knowledge/query.py +285 -0
  101. devsper/memory/__init__.py +35 -0
  102. devsper/memory/consolidation.py +138 -0
  103. devsper/memory/embeddings.py +60 -0
  104. devsper/memory/memory_index.py +97 -0
  105. devsper/memory/memory_router.py +62 -0
  106. devsper/memory/memory_store.py +221 -0
  107. devsper/memory/memory_types.py +54 -0
  108. devsper/memory/namespaces.py +45 -0
  109. devsper/memory/scoring.py +77 -0
  110. devsper/memory/summarizer.py +52 -0
  111. devsper/nodes/__init__.py +5 -0
  112. devsper/nodes/controller.py +449 -0
  113. devsper/nodes/rpc.py +127 -0
  114. devsper/nodes/single.py +161 -0
  115. devsper/nodes/worker.py +506 -0
  116. devsper/orchestration/__init__.py +19 -0
  117. devsper/orchestration/meta_planner.py +239 -0
  118. devsper/orchestration/priority_queue.py +61 -0
  119. devsper/plugins/__init__.py +19 -0
  120. devsper/plugins/marketplace/__init__.py +0 -0
  121. devsper/plugins/plugin_loader.py +70 -0
  122. devsper/plugins/plugin_registry.py +34 -0
  123. devsper/plugins/registry.py +83 -0
  124. devsper/protocols/__init__.py +6 -0
  125. devsper/providers/__init__.py +17 -0
  126. devsper/providers/anthropic.py +84 -0
  127. devsper/providers/base.py +75 -0
  128. devsper/providers/complexity_router.py +94 -0
  129. devsper/providers/gemini.py +36 -0
  130. devsper/providers/github.py +180 -0
  131. devsper/providers/model_router.py +40 -0
  132. devsper/providers/openai.py +105 -0
  133. devsper/providers/router/__init__.py +21 -0
  134. devsper/providers/router/backends/__init__.py +19 -0
  135. devsper/providers/router/backends/anthropic_backend.py +111 -0
  136. devsper/providers/router/backends/custom_backend.py +138 -0
  137. devsper/providers/router/backends/gemini_backend.py +89 -0
  138. devsper/providers/router/backends/github_backend.py +165 -0
  139. devsper/providers/router/backends/ollama_backend.py +104 -0
  140. devsper/providers/router/backends/openai_backend.py +142 -0
  141. devsper/providers/router/backends/vllm_backend.py +35 -0
  142. devsper/providers/router/base.py +60 -0
  143. devsper/providers/router/factory.py +92 -0
  144. devsper/providers/router/legacy.py +101 -0
  145. devsper/providers/router/router.py +135 -0
  146. devsper/reasoning/__init__.py +12 -0
  147. devsper/reasoning/graph.py +59 -0
  148. devsper/reasoning/nodes.py +20 -0
  149. devsper/reasoning/store.py +67 -0
  150. devsper/runtime/__init__.py +12 -0
  151. devsper/runtime/health.py +88 -0
  152. devsper/runtime/replay.py +53 -0
  153. devsper/runtime/replay_engine.py +142 -0
  154. devsper/runtime/run_history.py +204 -0
  155. devsper/runtime/telemetry.py +116 -0
  156. devsper/runtime/visualize.py +58 -0
  157. devsper/sandbox/__init__.py +13 -0
  158. devsper/sandbox/sandbox.py +161 -0
  159. devsper/swarm/checkpointer.py +65 -0
  160. devsper/swarm/executor.py +558 -0
  161. devsper/swarm/map_reduce.py +44 -0
  162. devsper/swarm/planner.py +197 -0
  163. devsper/swarm/prefetcher.py +91 -0
  164. devsper/swarm/scheduler.py +153 -0
  165. devsper/swarm/speculation.py +47 -0
  166. devsper/swarm/swarm.py +562 -0
  167. devsper/tools/__init__.py +33 -0
  168. devsper/tools/base.py +29 -0
  169. devsper/tools/code_intelligence/__init__.py +13 -0
  170. devsper/tools/code_intelligence/api_surface_extractor.py +73 -0
  171. devsper/tools/code_intelligence/architecture_analyzer.py +65 -0
  172. devsper/tools/code_intelligence/codebase_indexer.py +71 -0
  173. devsper/tools/code_intelligence/dependency_graph_builder.py +67 -0
  174. devsper/tools/code_intelligence/design_pattern_detector.py +62 -0
  175. devsper/tools/code_intelligence/large_function_detector.py +68 -0
  176. devsper/tools/code_intelligence/module_responsibility_mapper.py +56 -0
  177. devsper/tools/code_intelligence/parallel_codebase_analysis.py +44 -0
  178. devsper/tools/code_intelligence/refactor_candidate_detector.py +81 -0
  179. devsper/tools/code_intelligence/repository_semantic_index.py +61 -0
  180. devsper/tools/code_intelligence/test_coverage_estimator.py +62 -0
  181. devsper/tools/coding/__init__.py +12 -0
  182. devsper/tools/coding/analyze_code_complexity.py +48 -0
  183. devsper/tools/coding/dependency_analyzer.py +42 -0
  184. devsper/tools/coding/extract_functions.py +38 -0
  185. devsper/tools/coding/format_python.py +50 -0
  186. devsper/tools/coding/generate_docstrings.py +40 -0
  187. devsper/tools/coding/generate_unit_tests.py +42 -0
  188. devsper/tools/coding/lint_python.py +51 -0
  189. devsper/tools/coding/refactor_function.py +41 -0
  190. devsper/tools/coding/repo_structure_map.py +54 -0
  191. devsper/tools/coding/run_python.py +53 -0
  192. devsper/tools/data/__init__.py +12 -0
  193. devsper/tools/data/column_type_detection.py +64 -0
  194. devsper/tools/data/csv_summary.py +52 -0
  195. devsper/tools/data/dataframe_filter.py +51 -0
  196. devsper/tools/data/dataframe_groupby.py +47 -0
  197. devsper/tools/data/dataframe_stats.py +38 -0
  198. devsper/tools/data/dataset_sampling.py +55 -0
  199. devsper/tools/data/dataset_schema.py +45 -0
  200. devsper/tools/data/json_pretty_print.py +37 -0
  201. devsper/tools/data/json_query.py +46 -0
  202. devsper/tools/data/missing_value_report.py +47 -0
  203. devsper/tools/data_science/__init__.py +13 -0
  204. devsper/tools/data_science/correlation_heatmap.py +72 -0
  205. devsper/tools/data_science/dataset_bias_detector.py +49 -0
  206. devsper/tools/data_science/dataset_distribution_report.py +64 -0
  207. devsper/tools/data_science/dataset_drift_detector.py +64 -0
  208. devsper/tools/data_science/dataset_outlier_detector.py +65 -0
  209. devsper/tools/data_science/dataset_profile.py +76 -0
  210. devsper/tools/data_science/distributed_dataset_processor.py +54 -0
  211. devsper/tools/data_science/feature_engineering_suggestions.py +69 -0
  212. devsper/tools/data_science/feature_importance_estimator.py +82 -0
  213. devsper/tools/data_science/model_input_validator.py +59 -0
  214. devsper/tools/data_science/time_series_analyzer.py +57 -0
  215. devsper/tools/documents/__init__.py +11 -0
  216. devsper/tools/documents/_docproc.py +56 -0
  217. devsper/tools/documents/document_to_markdown.py +29 -0
  218. devsper/tools/documents/extract_document_images.py +39 -0
  219. devsper/tools/documents/extract_document_text.py +29 -0
  220. devsper/tools/documents/extract_equations.py +36 -0
  221. devsper/tools/documents/extract_tables.py +47 -0
  222. devsper/tools/documents/summarize_document.py +42 -0
  223. devsper/tools/documents/write_latex_document.py +133 -0
  224. devsper/tools/documents/write_markdown_document.py +89 -0
  225. devsper/tools/documents/write_word_document.py +149 -0
  226. devsper/tools/experiments/__init__.py +13 -0
  227. devsper/tools/experiments/bootstrap_estimator.py +54 -0
  228. devsper/tools/experiments/experiment_report_generator.py +50 -0
  229. devsper/tools/experiments/experiment_tracker.py +36 -0
  230. devsper/tools/experiments/grid_search_runner.py +50 -0
  231. devsper/tools/experiments/model_benchmark_runner.py +45 -0
  232. devsper/tools/experiments/monte_carlo_experiment.py +38 -0
  233. devsper/tools/experiments/parameter_sweep_runner.py +51 -0
  234. devsper/tools/experiments/result_comparator.py +58 -0
  235. devsper/tools/experiments/simulation_runner.py +43 -0
  236. devsper/tools/experiments/statistical_significance_test.py +56 -0
  237. devsper/tools/experiments/swarm_map_reduce.py +42 -0
  238. devsper/tools/filesystem/__init__.py +12 -0
  239. devsper/tools/filesystem/append_file.py +42 -0
  240. devsper/tools/filesystem/file_hash.py +40 -0
  241. devsper/tools/filesystem/file_line_count.py +36 -0
  242. devsper/tools/filesystem/file_metadata.py +38 -0
  243. devsper/tools/filesystem/file_preview.py +55 -0
  244. devsper/tools/filesystem/find_large_files.py +50 -0
  245. devsper/tools/filesystem/list_directory.py +39 -0
  246. devsper/tools/filesystem/read_file.py +35 -0
  247. devsper/tools/filesystem/search_files.py +60 -0
  248. devsper/tools/filesystem/write_file.py +41 -0
  249. devsper/tools/flagship/__init__.py +15 -0
  250. devsper/tools/flagship/distributed_document_analysis.py +77 -0
  251. devsper/tools/flagship/docproc_corpus_pipeline.py +91 -0
  252. devsper/tools/flagship/repository_semantic_map.py +99 -0
  253. devsper/tools/flagship/research_graph_builder.py +111 -0
  254. devsper/tools/flagship/swarm_experiment_runner.py +86 -0
  255. devsper/tools/knowledge/__init__.py +10 -0
  256. devsper/tools/knowledge/citation_graph_builder.py +69 -0
  257. devsper/tools/knowledge/concept_frequency_analyzer.py +74 -0
  258. devsper/tools/knowledge/corpus_builder.py +66 -0
  259. devsper/tools/knowledge/cross_document_entity_linker.py +71 -0
  260. devsper/tools/knowledge/document_corpus_summary.py +68 -0
  261. devsper/tools/knowledge/document_topic_extractor.py +58 -0
  262. devsper/tools/knowledge/knowledge_graph_extractor.py +58 -0
  263. devsper/tools/knowledge/timeline_extractor.py +59 -0
  264. devsper/tools/math/__init__.py +12 -0
  265. devsper/tools/math/calculate_expression.py +52 -0
  266. devsper/tools/math/correlation.py +44 -0
  267. devsper/tools/math/distribution_summary.py +39 -0
  268. devsper/tools/math/histogram.py +53 -0
  269. devsper/tools/math/linear_regression.py +47 -0
  270. devsper/tools/math/matrix_multiply.py +38 -0
  271. devsper/tools/math/mean_std.py +35 -0
  272. devsper/tools/math/monte_carlo_simulation.py +43 -0
  273. devsper/tools/math/polynomial_fit.py +40 -0
  274. devsper/tools/math/random_sample.py +36 -0
  275. devsper/tools/mcp/__init__.py +23 -0
  276. devsper/tools/mcp/adapter.py +53 -0
  277. devsper/tools/mcp/client.py +235 -0
  278. devsper/tools/mcp/discovery.py +53 -0
  279. devsper/tools/memory/__init__.py +16 -0
  280. devsper/tools/memory/delete_memory.py +25 -0
  281. devsper/tools/memory/list_memory.py +34 -0
  282. devsper/tools/memory/search_memory.py +36 -0
  283. devsper/tools/memory/store_memory.py +47 -0
  284. devsper/tools/memory/summarize_memory.py +41 -0
  285. devsper/tools/memory/tag_memory.py +47 -0
  286. devsper/tools/pipelines.py +92 -0
  287. devsper/tools/registry.py +39 -0
  288. devsper/tools/research/__init__.py +12 -0
  289. devsper/tools/research/arxiv_download.py +55 -0
  290. devsper/tools/research/arxiv_search.py +58 -0
  291. devsper/tools/research/citation_extractor.py +35 -0
  292. devsper/tools/research/duckduckgo_search.py +42 -0
  293. devsper/tools/research/paper_metadata_extractor.py +45 -0
  294. devsper/tools/research/paper_summarizer.py +41 -0
  295. devsper/tools/research/research_question_generator.py +39 -0
  296. devsper/tools/research/topic_cluster.py +46 -0
  297. devsper/tools/research/web_search.py +47 -0
  298. devsper/tools/research/wikipedia_lookup.py +50 -0
  299. devsper/tools/research_advanced/__init__.py +14 -0
  300. devsper/tools/research_advanced/citation_context_extractor.py +60 -0
  301. devsper/tools/research_advanced/literature_review_generator.py +79 -0
  302. devsper/tools/research_advanced/methodology_extractor.py +58 -0
  303. devsper/tools/research_advanced/paper_contribution_extractor.py +50 -0
  304. devsper/tools/research_advanced/paper_dataset_identifier.py +49 -0
  305. devsper/tools/research_advanced/paper_method_comparator.py +62 -0
  306. devsper/tools/research_advanced/paper_similarity_search.py +69 -0
  307. devsper/tools/research_advanced/paper_trend_analyzer.py +69 -0
  308. devsper/tools/research_advanced/parallel_document_analyzer.py +56 -0
  309. devsper/tools/research_advanced/research_gap_finder.py +71 -0
  310. devsper/tools/research_advanced/research_topic_mapper.py +69 -0
  311. devsper/tools/research_advanced/swarm_literature_review.py +58 -0
  312. devsper/tools/scoring/__init__.py +52 -0
  313. devsper/tools/scoring/report.py +44 -0
  314. devsper/tools/scoring/scorer.py +39 -0
  315. devsper/tools/scoring/selector.py +61 -0
  316. devsper/tools/scoring/store.py +267 -0
  317. devsper/tools/selector.py +130 -0
  318. devsper/tools/system/__init__.py +12 -0
  319. devsper/tools/system/cpu_usage.py +22 -0
  320. devsper/tools/system/disk_usage.py +35 -0
  321. devsper/tools/system/environment_variables.py +29 -0
  322. devsper/tools/system/memory_usage.py +23 -0
  323. devsper/tools/system/pip_install.py +44 -0
  324. devsper/tools/system/pip_search.py +29 -0
  325. devsper/tools/system/process_list.py +34 -0
  326. devsper/tools/system/python_package_list.py +40 -0
  327. devsper/tools/system/run_shell_command.py +51 -0
  328. devsper/tools/system/system_info.py +26 -0
  329. devsper/tools/tool_runner.py +122 -0
  330. devsper/tui/__init__.py +5 -0
  331. devsper/tui/activity_feed_view.py +73 -0
  332. devsper/tui/adaptive_tasks_view.py +75 -0
  333. devsper/tui/agent_role_view.py +35 -0
  334. devsper/tui/app.py +395 -0
  335. devsper/tui/dashboard_screen.py +290 -0
  336. devsper/tui/dev_view.py +99 -0
  337. devsper/tui/inject_screen.py +73 -0
  338. devsper/tui/knowledge_graph_view.py +46 -0
  339. devsper/tui/layout.py +43 -0
  340. devsper/tui/logs_view.py +83 -0
  341. devsper/tui/memory_view.py +58 -0
  342. devsper/tui/performance_view.py +33 -0
  343. devsper/tui/reasoning_graph_view.py +39 -0
  344. devsper/tui/results_view.py +139 -0
  345. devsper/tui/swarm_view.py +37 -0
  346. devsper/tui/task_detail_screen.py +55 -0
  347. devsper/tui/task_view.py +103 -0
  348. devsper/types/event.py +97 -0
  349. devsper/types/exceptions.py +21 -0
  350. devsper/types/swarm.py +41 -0
  351. devsper/types/task.py +80 -0
  352. devsper/upgrade/__init__.py +21 -0
  353. devsper/upgrade/changelog.py +124 -0
  354. devsper/upgrade/cli.py +145 -0
  355. devsper/upgrade/installer.py +103 -0
  356. devsper/upgrade/notifier.py +52 -0
  357. devsper/upgrade/version_check.py +121 -0
  358. devsper/utils/event_logger.py +88 -0
  359. devsper/utils/http.py +43 -0
  360. devsper/utils/models.py +54 -0
  361. devsper/visualization/__init__.py +5 -0
  362. devsper/visualization/dag_export.py +67 -0
  363. devsper/workflow/__init__.py +18 -0
  364. devsper/workflow/conditions.py +157 -0
  365. devsper/workflow/context.py +108 -0
  366. devsper/workflow/loader.py +156 -0
  367. devsper/workflow/resolver.py +109 -0
  368. devsper/workflow/runner.py +562 -0
  369. devsper/workflow/schema.py +63 -0
  370. devsper/workflow/validator.py +128 -0
  371. devsper-2.1.6.dist-info/METADATA +346 -0
  372. devsper-2.1.6.dist-info/RECORD +375 -0
  373. devsper-2.1.6.dist-info/WHEEL +4 -0
  374. devsper-2.1.6.dist-info/entry_points.txt +3 -0
  375. devsper-2.1.6.dist-info/licenses/LICENSE +639 -0
@@ -0,0 +1,39 @@
1
+ """Generate simple research questions from a topic (template-based, no LLM)."""
2
+
3
+ from devsper.tools.base import Tool
4
+ from devsper.tools.registry import register
5
+
6
+
7
+ class ResearchQuestionGeneratorTool(Tool):
8
+ """Generate example research questions for a topic using fixed templates."""
9
+
10
+ name = "research_question_generator"
11
+ description = "Generate sample research questions for a topic (template-based)."
12
+ input_schema = {
13
+ "type": "object",
14
+ "properties": {
15
+ "topic": {"type": "string", "description": "Research topic or domain"},
16
+ "count": {"type": "integer", "description": "Number of questions (default 3)"},
17
+ },
18
+ "required": ["topic"],
19
+ }
20
+
21
+ def run(self, **kwargs) -> str:
22
+ topic = kwargs.get("topic")
23
+ count = kwargs.get("count", 3)
24
+ if not topic or not isinstance(topic, str):
25
+ return "Error: topic must be a non-empty string"
26
+ if not isinstance(count, int) or count < 1:
27
+ count = 3
28
+ templates = [
29
+ f"What are the main challenges in {topic}?",
30
+ f"How has {topic} evolved in recent years?",
31
+ f"What are the best practices for applying {topic}?",
32
+ f"What is the relationship between {topic} and related fields?",
33
+ f"What open problems remain in {topic}?",
34
+ ]
35
+ chosen = templates[: min(count, len(templates))]
36
+ return "Suggested research questions:\n" + "\n".join(f"- {q}" for q in chosen)
37
+
38
+
39
+ register(ResearchQuestionGeneratorTool())
@@ -0,0 +1,46 @@
1
+ """Simple topic clustering by common words across titles/texts."""
2
+
3
+ import re
4
+ from collections import Counter
5
+
6
+ from devsper.tools.base import Tool
7
+ from devsper.tools.registry import register
8
+
9
+
10
+ class TopicClusterTool(Tool):
11
+ """Cluster a list of titles or short texts by common keywords (simple word overlap)."""
12
+
13
+ name = "topic_cluster"
14
+ description = "Find common topics across a list of text snippets. Returns top shared words."
15
+ input_schema = {
16
+ "type": "object",
17
+ "properties": {
18
+ "texts": {"type": "array", "description": "List of strings (e.g. paper titles or abstracts)"},
19
+ "top_n": {"type": "integer", "description": "Number of top words to return (default 10)"},
20
+ },
21
+ "required": ["texts"],
22
+ }
23
+
24
+ def run(self, **kwargs) -> str:
25
+ texts = kwargs.get("texts")
26
+ top_n = kwargs.get("top_n", 10)
27
+ if not isinstance(texts, list):
28
+ return "Error: texts must be an array of strings"
29
+ if not isinstance(top_n, int) or top_n < 1:
30
+ top_n = 10
31
+ stop = {"the", "a", "an", "and", "or", "of", "in", "on", "to", "for", "with", "by", "is", "are", "be", "as", "at"}
32
+ word_counts = Counter()
33
+ for t in texts:
34
+ if not isinstance(t, str):
35
+ continue
36
+ words = re.findall(r"\b[a-zA-Z]{3,}\b", t.lower())
37
+ for w in words:
38
+ if w not in stop:
39
+ word_counts[w] += 1
40
+ common = word_counts.most_common(top_n)
41
+ if not common:
42
+ return "No significant keywords found."
43
+ return "Top shared terms:\n" + "\n".join(f"{w}: {c}" for w, c in common)
44
+
45
+
46
+ register(TopicClusterTool())
@@ -0,0 +1,47 @@
1
+ """Web search using DuckDuckGo when duckduckgo-search is available."""
2
+
3
+ from devsper.tools.base import Tool
4
+ from devsper.tools.registry import register
5
+
6
+
7
+ class WebSearchTool(Tool):
8
+ """Search the web. Uses DuckDuckGo when the duckduckgo-search package is installed."""
9
+
10
+ name = "web_search"
11
+ description = "Search the web for a query. Returns titles and snippets. Requires duckduckgo-search."
12
+ input_schema = {
13
+ "type": "object",
14
+ "properties": {
15
+ "query": {"type": "string", "description": "Search query"},
16
+ "max_results": {"type": "integer", "description": "Max results to return (default 5)"},
17
+ },
18
+ "required": ["query"],
19
+ }
20
+
21
+ def run(self, **kwargs) -> str:
22
+ query = kwargs.get("query")
23
+ max_results = kwargs.get("max_results", 5)
24
+ if not query or not isinstance(query, str):
25
+ return "Error: query must be a non-empty string"
26
+ if not isinstance(max_results, int) or max_results < 1:
27
+ max_results = 5
28
+ try:
29
+ from duckduckgo_search import DDGS
30
+ with DDGS() as ddgs:
31
+ results = list(ddgs.text(query, max_results=max_results))
32
+ if not results:
33
+ return "No results found."
34
+ lines = []
35
+ for i, r in enumerate(results, 1):
36
+ title = r.get("title", "")
37
+ body = r.get("body", "")
38
+ href = r.get("href", "")
39
+ lines.append(f"{i}. {title}\n {body}\n {href}")
40
+ return "\n\n".join(lines)
41
+ except ImportError:
42
+ return "Error: Install duckduckgo-search (pip install duckduckgo-search) for web search."
43
+ except Exception as e:
44
+ return f"Error: {e}"
45
+
46
+
47
+ register(WebSearchTool())
@@ -0,0 +1,50 @@
1
+ """Look up a topic on Wikipedia using the JSON API."""
2
+
3
+ import json
4
+ import urllib.parse
5
+ import urllib.request
6
+
7
+ from devsper.tools.base import Tool
8
+ from devsper.tools.registry import register
9
+
10
+
11
+ class WikipediaLookupTool(Tool):
12
+ """Fetch a Wikipedia article summary for a topic."""
13
+
14
+ name = "wikipedia_lookup"
15
+ description = "Get a short Wikipedia summary for a topic. Uses the Wikipedia API."
16
+ input_schema = {
17
+ "type": "object",
18
+ "properties": {
19
+ "topic": {"type": "string", "description": "Topic or article title to look up"},
20
+ },
21
+ "required": ["topic"],
22
+ }
23
+
24
+ def run(self, **kwargs) -> str:
25
+ topic = kwargs.get("topic")
26
+ if not topic or not isinstance(topic, str):
27
+ return "Error: topic must be a non-empty string"
28
+ try:
29
+ url = "https://en.wikipedia.org/w/api.php?" + urllib.parse.urlencode({
30
+ "action": "query",
31
+ "titles": topic.strip(),
32
+ "prop": "extracts",
33
+ "exintro": True,
34
+ "explaintext": True,
35
+ "format": "json",
36
+ })
37
+ req = urllib.request.Request(url, headers={"User-Agent": "devsper/1.0"})
38
+ with urllib.request.urlopen(req, timeout=10) as resp:
39
+ data = json.loads(resp.read().decode())
40
+ pages = data.get("query", {}).get("pages", {})
41
+ page = next(iter(pages.values()), None)
42
+ if not page or page.get("missing"):
43
+ return f"No Wikipedia article found for: {topic}"
44
+ extract = page.get("extract", "").strip()
45
+ return extract or "No extract available."
46
+ except Exception as e:
47
+ return f"Error: {e}"
48
+
49
+
50
+ register(WikipediaLookupTool())
@@ -0,0 +1,14 @@
1
+ """Advanced research tools: literature review, similarity, gaps, methodology, citations."""
2
+
3
+ from devsper.tools.research_advanced.literature_review_generator import LiteratureReviewGeneratorTool
4
+ from devsper.tools.research_advanced.paper_similarity_search import PaperSimilaritySearchTool
5
+ from devsper.tools.research_advanced.research_gap_finder import ResearchGapFinderTool
6
+ from devsper.tools.research_advanced.methodology_extractor import MethodologyExtractorTool
7
+ from devsper.tools.research_advanced.paper_contribution_extractor import PaperContributionExtractorTool
8
+ from devsper.tools.research_advanced.paper_dataset_identifier import PaperDatasetIdentifierTool
9
+ from devsper.tools.research_advanced.citation_context_extractor import CitationContextExtractorTool
10
+ from devsper.tools.research_advanced.research_topic_mapper import ResearchTopicMapperTool
11
+ from devsper.tools.research_advanced.paper_trend_analyzer import PaperTrendAnalyzerTool
12
+ from devsper.tools.research_advanced.paper_method_comparator import PaperMethodComparatorTool
13
+ from devsper.tools.research_advanced.parallel_document_analyzer import ParallelDocumentAnalyzerTool
14
+ from devsper.tools.research_advanced.swarm_literature_review import SwarmLiteratureReviewTool
@@ -0,0 +1,60 @@
1
+ """Extract the surrounding context (sentence) for each citation in the text."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+ from devsper.tools.base import Tool
7
+ from devsper.tools.registry import register
8
+ from devsper.tools.documents._docproc import run_docproc_to_markdown
9
+
10
+ CITE_PATTERNS = [
11
+ re.compile(r"\([^)]*?\b(?:et\s+al\.?|&\s*[^)]+)[^)]*?\d{4}[^)]*\)", re.I),
12
+ re.compile(r"\[\d+(?:\s*[-–,]\s*\d+)*\]"),
13
+ re.compile(r"\([A-Z][a-z]+(?:\s+et\s+al\.?)?,?\s*\d{4}\)"),
14
+ ]
15
+
16
+
17
+ class CitationContextExtractorTool(Tool):
18
+ """
19
+ For each citation pattern found, extract the containing sentence as context.
20
+ """
21
+
22
+ name = "citation_context_extractor"
23
+ description = "Extract the sentence context around each citation in a document."
24
+ input_schema = {
25
+ "type": "object",
26
+ "properties": {
27
+ "file_path": {"type": "string", "description": "Path to the document"},
28
+ "max_contexts": {"type": "integer", "description": "Max citation contexts (default 25)"},
29
+ },
30
+ "required": ["file_path"],
31
+ }
32
+
33
+ def run(self, **kwargs) -> str:
34
+ file_path = kwargs.get("file_path")
35
+ max_contexts = kwargs.get("max_contexts", 25)
36
+ if not file_path or not isinstance(file_path, str):
37
+ return "Error: file_path must be a non-empty string"
38
+ if not isinstance(max_contexts, int) or max_contexts < 1:
39
+ max_contexts = 25
40
+ content, err = run_docproc_to_markdown(file_path)
41
+ if err:
42
+ return err
43
+ text = content or ""
44
+ sentences = re.split(r"(?<=[.!?])\s+", text)
45
+ results = []
46
+ seen = set()
47
+ for sent in sentences:
48
+ for pat in CITE_PATTERNS:
49
+ if pat.search(sent) and sent not in seen:
50
+ seen.add(sent)
51
+ results.append(sent.strip()[:400])
52
+ break
53
+ if len(results) >= max_contexts:
54
+ break
55
+ if not results:
56
+ return "No citation contexts found."
57
+ return "Citation contexts:\n\n" + "\n\n".join(results)
58
+
59
+
60
+ register(CitationContextExtractorTool())
@@ -0,0 +1,79 @@
1
+ """Generate a structured literature review outline from multiple paper abstracts or texts."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+ from devsper.tools.base import Tool
7
+ from devsper.tools.registry import register
8
+ from devsper.tools.documents._docproc import run_docproc_to_markdown
9
+
10
+ STOP = frozenset("a an the and or but in on at to for of with by from as is was are were been be have has had do does did will would could should may might must can this that it its".split())
11
+
12
+
13
+ class LiteratureReviewGeneratorTool(Tool):
14
+ """
15
+ Produce a literature review structure: common themes, key terms, and doc summaries from multiple papers.
16
+ """
17
+
18
+ name = "literature_review_generator"
19
+ description = "Generate a structured literature review from multiple paper texts or document paths."
20
+ input_schema = {
21
+ "type": "object",
22
+ "properties": {
23
+ "file_paths": {
24
+ "type": "array",
25
+ "items": {"type": "string"},
26
+ "description": "Paths to papers (PDF, DOCX, etc.)",
27
+ },
28
+ "texts": {
29
+ "type": "array",
30
+ "items": {"type": "string"},
31
+ "description": "Alternatively, raw text/abstracts",
32
+ },
33
+ "top_themes": {"type": "integer", "description": "Number of theme keywords (default 15)"},
34
+ },
35
+ "required": [],
36
+ }
37
+
38
+ def _get_texts(self, file_paths: list | None, texts: list | None) -> list[str]:
39
+ out = []
40
+ if texts and isinstance(texts, list):
41
+ for t in texts:
42
+ if isinstance(t, str) and t.strip():
43
+ out.append(t.strip())
44
+ if file_paths and isinstance(file_paths, list):
45
+ for path in file_paths:
46
+ if not isinstance(path, str) or not path.strip():
47
+ continue
48
+ content, err = run_docproc_to_markdown(path.strip())
49
+ if not err and content:
50
+ out.append(content.strip())
51
+ return out
52
+
53
+ def run(self, **kwargs) -> str:
54
+ file_paths = kwargs.get("file_paths")
55
+ texts = kwargs.get("texts")
56
+ top_themes = kwargs.get("top_themes", 15)
57
+ if not isinstance(top_themes, int) or top_themes < 1:
58
+ top_themes = 15
59
+ all_texts = self._get_texts(file_paths, texts)
60
+ if not all_texts:
61
+ return "Error: provide file_paths or texts (non-empty)"
62
+ combined = " ".join(all_texts).lower()
63
+ words = [w for w in re.findall(r"[a-z]+", combined) if len(w) >= 4 and w not in STOP]
64
+ from collections import Counter
65
+
66
+ counts = Counter(words)
67
+ themes = [w for w, _ in counts.most_common(top_themes)]
68
+ lines = [
69
+ "Literature review outline",
70
+ "=" * 40,
71
+ "Common themes (keywords): " + ", ".join(themes),
72
+ "",
73
+ f"Documents/sources: {len(all_texts)}",
74
+ "Per-source length (chars): " + ", ".join(str(len(t)) for t in all_texts),
75
+ ]
76
+ return "\n".join(lines)
77
+
78
+
79
+ register(LiteratureReviewGeneratorTool())
@@ -0,0 +1,58 @@
1
+ """Extract methodology-related sentences from paper text using keyword heuristics."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+ from devsper.tools.base import Tool
7
+ from devsper.tools.registry import register
8
+ from devsper.tools.documents._docproc import run_docproc_to_markdown
9
+
10
+ METHOD_KEYWORDS = re.compile(
11
+ r"\b(method|methods|methodology|experiment|dataset|evaluation|approach|algorithm|framework|procedure|protocol|design|implementation|training|model)\b",
12
+ re.I,
13
+ )
14
+
15
+
16
+ class MethodologyExtractorTool(Tool):
17
+ """
18
+ Extract sentences that likely describe methodology (method, experiment, dataset, etc.).
19
+ """
20
+
21
+ name = "methodology_extractor"
22
+ description = "Extract methodology-related sentences from a paper (PDF, DOCX, etc.)."
23
+ input_schema = {
24
+ "type": "object",
25
+ "properties": {
26
+ "file_path": {"type": "string", "description": "Path to the document"},
27
+ "max_sentences": {"type": "integer", "description": "Max sentences (default 20)"},
28
+ },
29
+ "required": ["file_path"],
30
+ }
31
+
32
+ def run(self, **kwargs) -> str:
33
+ file_path = kwargs.get("file_path")
34
+ max_sentences = kwargs.get("max_sentences", 20)
35
+ if not file_path or not isinstance(file_path, str):
36
+ return "Error: file_path must be a non-empty string"
37
+ if not isinstance(max_sentences, int) or max_sentences < 1:
38
+ max_sentences = 20
39
+ content, err = run_docproc_to_markdown(file_path)
40
+ if err:
41
+ return err
42
+ text = content or ""
43
+ sentences = re.split(r"(?<=[.!?])\s+", text)
44
+ selected = []
45
+ for s in sentences:
46
+ s = s.strip()
47
+ if len(s) < 20:
48
+ continue
49
+ if METHOD_KEYWORDS.search(s):
50
+ selected.append(s[:500])
51
+ if len(selected) >= max_sentences:
52
+ break
53
+ if not selected:
54
+ return "No methodology sentences found (look for method/experiment/dataset/evaluation)."
55
+ return "Methodology sentences:\n\n" + "\n\n".join(selected)
56
+
57
+
58
+ register(MethodologyExtractorTool())
@@ -0,0 +1,50 @@
1
+ """Extract contribution-like statements from paper text (we propose, our contribution, etc.)."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+ from devsper.tools.base import Tool
7
+ from devsper.tools.registry import register
8
+ from devsper.tools.documents._docproc import run_docproc_to_markdown
9
+
10
+ CONTRIBUTION_PAT = re.compile(
11
+ r"[^.!?]*(?:we\s+propose|our\s+contribution|this\s+paper\s+(?:presents|introduces|shows)|we\s+introduce|we\s+present|we\s+show|main\s+contribution)[^.!?]*[.!?]",
12
+ re.I,
13
+ )
14
+
15
+
16
+ class PaperContributionExtractorTool(Tool):
17
+ """
18
+ Extract sentences that state contributions (we propose, our contribution, this paper presents, etc.).
19
+ """
20
+
21
+ name = "paper_contribution_extractor"
22
+ description = "Extract contribution statements from a paper."
23
+ input_schema = {
24
+ "type": "object",
25
+ "properties": {
26
+ "file_path": {"type": "string", "description": "Path to the document"},
27
+ "max_sentences": {"type": "integer", "description": "Max sentences (default 15)"},
28
+ },
29
+ "required": ["file_path"],
30
+ }
31
+
32
+ def run(self, **kwargs) -> str:
33
+ file_path = kwargs.get("file_path")
34
+ max_sentences = kwargs.get("max_sentences", 15)
35
+ if not file_path or not isinstance(file_path, str):
36
+ return "Error: file_path must be a non-empty string"
37
+ if not isinstance(max_sentences, int) or max_sentences < 1:
38
+ max_sentences = 15
39
+ content, err = run_docproc_to_markdown(file_path)
40
+ if err:
41
+ return err
42
+ text = content or ""
43
+ matches = CONTRIBUTION_PAT.findall(text)
44
+ selected = [m.strip()[:400] for m in matches[:max_sentences]]
45
+ if not selected:
46
+ return "No contribution sentences found (look for 'we propose', 'our contribution', etc.)."
47
+ return "Contribution statements:\n\n" + "\n\n".join(selected)
48
+
49
+
50
+ register(PaperContributionExtractorTool())
@@ -0,0 +1,49 @@
1
+ """Identify dataset names mentioned in paper text using common patterns."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+ from devsper.tools.base import Tool
7
+ from devsper.tools.registry import register
8
+ from devsper.tools.documents._docproc import run_docproc_to_markdown
9
+
10
+ DATASET_PAT = re.compile(
11
+ r"\b([A-Z][A-Za-z0-9\-]+(?:\s+[A-Z][A-Za-z0-9\-]+)*)\s+(?:dataset|benchmark|corpus)\b|\b(?:on|using|with)\s+([A-Z][A-Za-z0-9\-]+(?:\s+[A-Z][A-Za-z0-9\-]+)*)\s+(?:dataset|benchmark)?",
12
+ re.I,
13
+ )
14
+
15
+
16
+ class PaperDatasetIdentifierTool(Tool):
17
+ """
18
+ Find dataset and benchmark names mentioned in a paper.
19
+ """
20
+
21
+ name = "paper_dataset_identifier"
22
+ description = "Identify dataset and benchmark names mentioned in a paper."
23
+ input_schema = {
24
+ "type": "object",
25
+ "properties": {
26
+ "file_path": {"type": "string", "description": "Path to the document"},
27
+ },
28
+ "required": ["file_path"],
29
+ }
30
+
31
+ def run(self, **kwargs) -> str:
32
+ file_path = kwargs.get("file_path")
33
+ if not file_path or not isinstance(file_path, str):
34
+ return "Error: file_path must be a non-empty string"
35
+ content, err = run_docproc_to_markdown(file_path)
36
+ if err:
37
+ return err
38
+ text = content or ""
39
+ found = set()
40
+ for m in DATASET_PAT.finditer(text):
41
+ for g in m.groups():
42
+ if g and len(g) > 1:
43
+ found.add(g.strip())
44
+ if not found:
45
+ return "No dataset/benchmark names identified (look for 'X dataset', 'on X', 'using X')."
46
+ return "Datasets/benchmarks: " + ", ".join(sorted(found))
47
+
48
+
49
+ register(PaperDatasetIdentifierTool())
@@ -0,0 +1,62 @@
1
+ """Compare methodology-related terms and sentences across multiple papers."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+ from devsper.tools.base import Tool
7
+ from devsper.tools.registry import register
8
+ from devsper.tools.documents._docproc import run_docproc_to_markdown
9
+
10
+ METHOD_WORDS = re.compile(
11
+ r"\b(method|algorithm|model|framework|dataset|evaluation|training|accuracy|baseline|neural|transformer|embedding)\b",
12
+ re.I,
13
+ )
14
+
15
+
16
+ class PaperMethodComparatorTool(Tool):
17
+ """
18
+ Compare methods across papers: shared methodology terms and per-paper method term counts.
19
+ """
20
+
21
+ name = "paper_method_comparator"
22
+ description = "Compare methodology terms and sentences across multiple papers."
23
+ input_schema = {
24
+ "type": "object",
25
+ "properties": {
26
+ "file_paths": {
27
+ "type": "array",
28
+ "items": {"type": "string"},
29
+ "description": "Paths to papers",
30
+ },
31
+ },
32
+ "required": ["file_paths"],
33
+ }
34
+
35
+ def run(self, **kwargs) -> str:
36
+ file_paths = kwargs.get("file_paths")
37
+ if not file_paths or not isinstance(file_paths, list):
38
+ return "Error: file_paths must be a non-empty list"
39
+ doc_terms = {}
40
+ all_terms = set()
41
+ for path in file_paths:
42
+ if not isinstance(path, str) or not path.strip():
43
+ continue
44
+ p = Path(path.strip()).resolve()
45
+ if not p.exists() or not p.is_file():
46
+ continue
47
+ content, err = run_docproc_to_markdown(str(p))
48
+ if err:
49
+ continue
50
+ text = content or ""
51
+ terms = list(dict.fromkeys(METHOD_WORDS.findall(text)))
52
+ doc_terms[p.name] = [t.lower() for t in terms]
53
+ all_terms.update(t.lower() for t in terms)
54
+ shared = [t for t in all_terms if sum(1 for v in doc_terms.values() if t in v) > 1]
55
+ lines = ["Method comparison", "=" * 40]
56
+ for name, terms in doc_terms.items():
57
+ lines.append(f"{name}: " + ", ".join(terms[:15]))
58
+ lines.append("\nShared method terms: " + ", ".join(sorted(shared)))
59
+ return "\n".join(lines)
60
+
61
+
62
+ register(PaperMethodComparatorTool())
@@ -0,0 +1,69 @@
1
+ """Search for papers similar to a query text using simple term overlap (no embeddings)."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+ from devsper.tools.base import Tool
7
+ from devsper.tools.registry import register
8
+ from devsper.tools.documents._docproc import run_docproc_to_markdown
9
+
10
+ STOP = frozenset("a an the and or but in on at to for of with by from as is was are were been be have has had do does did will would could should may might must can this that it its".split())
11
+
12
+
13
+ class PaperSimilaritySearchTool(Tool):
14
+ """
15
+ Rank documents by term-overlap similarity to a query (bag-of-words, no embeddings).
16
+ """
17
+
18
+ name = "paper_similarity_search"
19
+ description = "Find documents most similar to a query text using term overlap."
20
+ input_schema = {
21
+ "type": "object",
22
+ "properties": {
23
+ "query": {"type": "string", "description": "Query text or abstract"},
24
+ "file_paths": {
25
+ "type": "array",
26
+ "items": {"type": "string"},
27
+ "description": "Paths to candidate documents",
28
+ },
29
+ "top_k": {"type": "integer", "description": "Number of results (default 5)"},
30
+ },
31
+ "required": ["query", "file_paths"],
32
+ }
33
+
34
+ def _tokens(self, text: str, min_len: int = 3) -> set[str]:
35
+ words = re.findall(r"[a-z]+", text.lower())
36
+ return {w for w in words if len(w) >= min_len and w not in STOP}
37
+
38
+ def run(self, **kwargs) -> str:
39
+ query = kwargs.get("query")
40
+ file_paths = kwargs.get("file_paths")
41
+ top_k = kwargs.get("top_k", 5)
42
+ if not query or not isinstance(query, str):
43
+ return "Error: query must be a non-empty string"
44
+ if not file_paths or not isinstance(file_paths, list):
45
+ return "Error: file_paths must be a non-empty list"
46
+ if not isinstance(top_k, int) or top_k < 1:
47
+ top_k = 5
48
+ q_set = self._tokens(query)
49
+ if not q_set:
50
+ return "Error: query produced no tokens"
51
+ scores = []
52
+ for path in file_paths:
53
+ if not isinstance(path, str) or not path.strip():
54
+ continue
55
+ p = Path(path.strip()).resolve()
56
+ if not p.exists() or not p.is_file():
57
+ continue
58
+ content, err = run_docproc_to_markdown(str(p))
59
+ if err:
60
+ continue
61
+ doc_set = self._tokens(content or "")
62
+ overlap = len(q_set & doc_set) / len(q_set) if q_set else 0
63
+ scores.append((p.name, overlap))
64
+ scores.sort(key=lambda x: -x[1])
65
+ result = [f"{name}: {score:.3f}" for name, score in scores[:top_k]]
66
+ return "Similarity (term overlap):\n" + "\n".join(result) if result else "No documents processed."
67
+
68
+
69
+ register(PaperSimilaritySearchTool())