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,47 @@
1
+ """Extract table-like content from docproc markdown (pipe tables)."""
2
+
3
+ import re
4
+ from devsper.tools.base import Tool
5
+ from devsper.tools.registry import register
6
+ from devsper.tools.documents._docproc import run_docproc_to_markdown
7
+
8
+
9
+ class ExtractTablesTool(Tool):
10
+ """Extract markdown tables from document (docproc output)."""
11
+
12
+ name = "extract_tables"
13
+ description = "Extract tables from document as markdown. Uses docproc output."
14
+ input_schema = {
15
+ "type": "object",
16
+ "properties": {"file_path": {"type": "string", "description": "Path to the document"}},
17
+ "required": ["file_path"],
18
+ }
19
+
20
+ def run(self, **kwargs) -> str:
21
+ file_path = kwargs.get("file_path")
22
+ if not file_path or not isinstance(file_path, str):
23
+ return "Error: file_path must be a non-empty string"
24
+ content, err = run_docproc_to_markdown(file_path)
25
+ if err:
26
+ return err
27
+ lines = content.splitlines()
28
+ tables = []
29
+ current = []
30
+ in_table = False
31
+ for line in lines:
32
+ if "|" in line and line.strip().startswith("|"):
33
+ current.append(line)
34
+ in_table = True
35
+ else:
36
+ if in_table and current:
37
+ tables.append("\n".join(current))
38
+ current = []
39
+ in_table = False
40
+ if current:
41
+ tables.append("\n".join(current))
42
+ if not tables:
43
+ return "No markdown tables found in extracted content."
44
+ return "\n\n---\n\n".join(tables[:10])
45
+
46
+
47
+ register(ExtractTablesTool())
@@ -0,0 +1,42 @@
1
+ """Summarize document by truncating docproc markdown (first N chars + key sentences)."""
2
+
3
+ import re
4
+ from devsper.tools.base import Tool
5
+ from devsper.tools.registry import register
6
+ from devsper.tools.documents._docproc import run_docproc_to_markdown
7
+
8
+
9
+ class SummarizeDocumentTool(Tool):
10
+ """Produce a short summary of a document: first 500 chars and first 3 sentences. No LLM."""
11
+
12
+ name = "summarize_document"
13
+ description = "Summarize document (heuristic: first N chars and first sentences). Uses docproc."
14
+ input_schema = {
15
+ "type": "object",
16
+ "properties": {
17
+ "file_path": {"type": "string", "description": "Path to the document"},
18
+ "max_chars": {"type": "integer", "description": "Max chars in summary (default 500)"},
19
+ },
20
+ "required": ["file_path"],
21
+ }
22
+
23
+ def run(self, **kwargs) -> str:
24
+ file_path = kwargs.get("file_path")
25
+ max_chars = kwargs.get("max_chars", 500)
26
+ if not file_path or not isinstance(file_path, str):
27
+ return "Error: file_path must be a non-empty string"
28
+ if not isinstance(max_chars, int) or max_chars < 1:
29
+ max_chars = 500
30
+ content, err = run_docproc_to_markdown(file_path)
31
+ if err:
32
+ return err
33
+ content = content.strip()
34
+ if not content:
35
+ return "(no content)"
36
+ head = content[:max_chars] + ("..." if len(content) > max_chars else "")
37
+ sentences = re.split(r"(?<=[.!?])\s+", content)
38
+ first = " ".join(sentences[:3]) if sentences else head
39
+ return f"Summary (first {max_chars} chars):\n{head}\n\nKey sentences:\n{first}"
40
+
41
+
42
+ register(SummarizeDocumentTool())
@@ -0,0 +1,133 @@
1
+ """Write a structured LaTeX document with optional BibTeX references."""
2
+
3
+ from pathlib import Path
4
+
5
+ from devsper.tools.base import Tool
6
+ from devsper.tools.registry import register
7
+
8
+
9
+ def _latex_escape(s: str) -> str:
10
+ """Escape braces for use inside BibTeX/LaTeX strings."""
11
+ if not s:
12
+ return ""
13
+ return s.replace("\\", "\\\\").replace("{", "\\{").replace("}", "\\}")
14
+
15
+
16
+ def _bib_entry(key: str, ref: dict) -> str:
17
+ """Build one BibTeX entry (article by default)."""
18
+ author = ref.get("authors") or ref.get("author") or "Unknown"
19
+ title = ref.get("title") or ""
20
+ year = ref.get("year") or ""
21
+ journal = ref.get("journal")
22
+ url = ref.get("url")
23
+ publisher = ref.get("publisher")
24
+ author = _latex_escape(str(author))
25
+ title = _latex_escape(str(title))
26
+ year = _latex_escape(str(year))
27
+ lines = [f"@article{{{key},"]
28
+ lines.append(f" author = {{{author}}},")
29
+ lines.append(f" title = {{{title}}},")
30
+ lines.append(f" year = {{{year}}},")
31
+ if journal:
32
+ lines.append(f" journal = {{{_latex_escape(str(journal))}}},")
33
+ if publisher:
34
+ lines.append(f" publisher = {{{_latex_escape(str(publisher))}}},")
35
+ if url:
36
+ lines.append(f" url = {{{_latex_escape(str(url))}}},")
37
+ lines.append("}")
38
+ return "\n".join(lines)
39
+
40
+
41
+ class WriteLaTeXDocumentTool(Tool):
42
+ """Write a structured LaTeX document with optional references. Use \\cite{key} in content."""
43
+
44
+ name = "write_latex_document"
45
+ description = (
46
+ r"Write a structured LaTeX document with optional references. "
47
+ r"Use \cite{key} (LaTeX) in content; pass references array (key, authors, title, year, journal, url, publisher) for bibliography. Produces .tex and .bib files."
48
+ )
49
+ input_schema = {
50
+ "type": "object",
51
+ "properties": {
52
+ "path": {"type": "string", "description": "Output path (e.g. report.tex)"},
53
+ "title": {"type": "string", "description": "Document title"},
54
+ "content": {"type": "string", "description": r"Body (LaTeX). Use \cite{key} for citations."},
55
+ "references": {
56
+ "type": "array",
57
+ "items": {"type": "object"},
58
+ "description": "Optional list of refs: key, authors, title, year, journal, url, publisher",
59
+ },
60
+ },
61
+ "required": ["path", "title", "content"],
62
+ }
63
+
64
+ def run(self, **kwargs) -> str:
65
+ path = kwargs.get("path")
66
+ title = kwargs.get("title")
67
+ content = kwargs.get("content")
68
+ references = kwargs.get("references")
69
+
70
+ if not path or not isinstance(path, str) or not path.strip():
71
+ return "Error: path must be a non-empty string"
72
+ if not title or not isinstance(title, str):
73
+ return "Error: title must be a non-empty string"
74
+ if content is None:
75
+ return "Error: content is required"
76
+ if not isinstance(content, str):
77
+ content = str(content)
78
+
79
+ path = path.strip()
80
+ if not path.endswith(".tex"):
81
+ path = path.rstrip("/") + ".tex"
82
+ p = Path(path).resolve()
83
+ try:
84
+ p.parent.mkdir(parents=True, exist_ok=True)
85
+ except Exception as e:
86
+ return f"Error creating directory: {e}"
87
+
88
+ basename = p.stem
89
+ title_esc = _latex_escape(title)
90
+
91
+ tex_parts = [
92
+ "\\documentclass{article}",
93
+ "\\begin{document}",
94
+ "\\title{" + title_esc + "}",
95
+ "\\maketitle",
96
+ "",
97
+ content.strip(),
98
+ "",
99
+ ]
100
+ if references and isinstance(references, list):
101
+ tex_parts.append("\\bibliographystyle{plain}")
102
+ tex_parts.append("\\bibliography{" + basename + "}")
103
+ tex_parts.append("")
104
+ tex_parts.append("\\end{document}")
105
+ tex_content = "\n".join(tex_parts)
106
+
107
+ try:
108
+ p.write_text(tex_content, encoding="utf-8")
109
+ except Exception as e:
110
+ return f"Error writing .tex file: {e}"
111
+
112
+ out_msg = f"Wrote {len(tex_content)} characters to {p}"
113
+
114
+ if references and isinstance(references, list):
115
+ bib_path = p.with_suffix(".bib")
116
+ bib_entries = []
117
+ for i, ref in enumerate(references):
118
+ if not isinstance(ref, dict):
119
+ continue
120
+ key = ref.get("key") or f"ref{i+1}"
121
+ bib_entries.append(_bib_entry(key, ref))
122
+ if bib_entries:
123
+ bib_content = "\n\n".join(bib_entries)
124
+ try:
125
+ bib_path.write_text(bib_content, encoding="utf-8")
126
+ except Exception as e:
127
+ return f"{out_msg}. Error writing .bib file: {e}"
128
+ out_msg = f"Wrote {p} and {bib_path}. Compile with: pdflatex {basename} && bibtex {basename} && pdflatex {basename} && pdflatex {basename}."
129
+
130
+ return out_msg
131
+
132
+
133
+ register(WriteLaTeXDocumentTool())
@@ -0,0 +1,89 @@
1
+ """Write a structured Markdown document with optional references section."""
2
+
3
+ from pathlib import Path
4
+
5
+ from devsper.tools.base import Tool
6
+ from devsper.tools.registry import register
7
+
8
+
9
+ def _format_ref_md(ref: dict, index: int) -> str:
10
+ """Format one reference as a Markdown list item."""
11
+ authors = ref.get("authors") or ref.get("author") or "Unknown"
12
+ title = ref.get("title") or ""
13
+ year = ref.get("year") or ""
14
+ journal = ref.get("journal")
15
+ url = ref.get("url")
16
+ parts = [f"**{authors} ({year})**. *{title}*."]
17
+ if journal:
18
+ parts.append(f" {journal}.")
19
+ if url:
20
+ parts.append(f" [{url}]({url})")
21
+ return "- " + " ".join(parts).strip()
22
+
23
+
24
+ class WriteMarkdownDocumentTool(Tool):
25
+ """Write a structured Markdown document with optional references. Use [^1] or [Author (Year)] in content."""
26
+
27
+ name = "write_markdown_document"
28
+ description = (
29
+ "Write a structured Markdown document with optional references. "
30
+ "Use [1] / Author (Year) in content; pass references array (key, authors, title, year, journal, url, publisher) for bibliography. Produces .md file."
31
+ )
32
+ input_schema = {
33
+ "type": "object",
34
+ "properties": {
35
+ "path": {"type": "string", "description": "Output path (e.g. report.md)"},
36
+ "title": {"type": "string", "description": "Document title"},
37
+ "content": {"type": "string", "description": "Body (markdown). Use [^1] or [Author (Year)] for citations."},
38
+ "references": {
39
+ "type": "array",
40
+ "items": {"type": "object"},
41
+ "description": "Optional list of refs: key, authors, title, year, journal, url, publisher",
42
+ },
43
+ },
44
+ "required": ["path", "title", "content"],
45
+ }
46
+
47
+ def run(self, **kwargs) -> str:
48
+ path = kwargs.get("path")
49
+ title = kwargs.get("title")
50
+ content = kwargs.get("content")
51
+ references = kwargs.get("references")
52
+
53
+ if not path or not isinstance(path, str) or not path.strip():
54
+ return "Error: path must be a non-empty string"
55
+ if not title or not isinstance(title, str):
56
+ return "Error: title must be a non-empty string"
57
+ if content is None:
58
+ return "Error: content is required"
59
+ if not isinstance(content, str):
60
+ content = str(content)
61
+
62
+ path = path.strip()
63
+ if not path.endswith(".md") and not path.endswith(".markdown"):
64
+ path = path.rstrip("/") + ".md"
65
+ p = Path(path).resolve()
66
+ try:
67
+ p.parent.mkdir(parents=True, exist_ok=True)
68
+ except Exception as e:
69
+ return f"Error creating directory: {e}"
70
+
71
+ parts = [f"# {title.strip()}", "", content.strip(), ""]
72
+ if references and isinstance(references, list):
73
+ parts.append("## References")
74
+ parts.append("")
75
+ for i, ref in enumerate(references):
76
+ if not isinstance(ref, dict):
77
+ continue
78
+ parts.append(_format_ref_md(ref, i))
79
+ parts.append("")
80
+
81
+ full = "\n".join(parts)
82
+ try:
83
+ p.write_text(full, encoding="utf-8")
84
+ except Exception as e:
85
+ return f"Error writing file: {e}"
86
+ return f"Wrote {len(full)} characters to {p}"
87
+
88
+
89
+ register(WriteMarkdownDocumentTool())
@@ -0,0 +1,149 @@
1
+ """Write a structured Word document with optional references section and proper citation formatting."""
2
+
3
+ from pathlib import Path
4
+
5
+ from devsper.tools.base import Tool
6
+ from devsper.tools.registry import register
7
+
8
+
9
+ def _add_hyperlink(paragraph, text: str, url: str):
10
+ """Add a hyperlink run to a paragraph (python-docx has no built-in add_hyperlink)."""
11
+ from docx.oxml import OxmlElement
12
+ from docx.oxml.ns import qn
13
+
14
+ part = paragraph.part
15
+ r_id = part.relate_to(
16
+ url,
17
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
18
+ is_external=True,
19
+ )
20
+ hyperlink = OxmlElement("w:hyperlink")
21
+ hyperlink.set(qn("r:id"), r_id)
22
+ new_run = OxmlElement("w:r")
23
+ r_pr = OxmlElement("w:rPr")
24
+ u = OxmlElement("w:u")
25
+ u.set(qn("w:val"), "single")
26
+ color = OxmlElement("w:color")
27
+ color.set(qn("w:val"), "0563C1")
28
+ r_pr.append(u)
29
+ r_pr.append(color)
30
+ new_run.append(r_pr)
31
+ t = OxmlElement("w:t")
32
+ t.set(qn("xml:space"), "preserve")
33
+ t.text = text
34
+ new_run.append(t)
35
+ hyperlink.append(new_run)
36
+ paragraph._p.append(hyperlink)
37
+
38
+
39
+ def _add_reference_paragraph(doc, number: int, ref: dict) -> None:
40
+ """Add one reference as a numbered paragraph with APA-like formatting and optional hyperlink."""
41
+ from docx.shared import Pt
42
+
43
+ authors = ref.get("authors") or ref.get("author") or "Unknown"
44
+ title = ref.get("title") or ""
45
+ year = ref.get("year") or ""
46
+ journal = ref.get("journal")
47
+ url = ref.get("url")
48
+ publisher = ref.get("publisher")
49
+
50
+ para = doc.add_paragraph()
51
+ para.paragraph_format.left_indent = Pt(18)
52
+ para.paragraph_format.first_line_indent = Pt(-18)
53
+ para.paragraph_format.space_after = Pt(6)
54
+
55
+ run = para.add_run(f"[{number}] ")
56
+ run.bold = True
57
+
58
+ para.add_run(f"{authors} ({year}). ")
59
+
60
+ r_title = para.add_run(f"{title}.")
61
+ r_title.italic = True
62
+ para.add_run(" ")
63
+
64
+ if journal:
65
+ r_journal = para.add_run(f" {journal}.")
66
+ r_journal.italic = True
67
+ if publisher:
68
+ para.add_run(f" {publisher}.")
69
+ if url:
70
+ para.add_run(" ")
71
+ _add_hyperlink(para, url if len(url) < 50 else "Link", url)
72
+
73
+
74
+ class WriteWordDocumentTool(Tool):
75
+ """Write a structured Word document with optional references. Use [1], [2] in content to match numbered refs."""
76
+
77
+ name = "write_word_document"
78
+ description = (
79
+ "Write a structured Word document with optional references. "
80
+ "Use [1] / Author (Year) (Word/MD) in content; pass references array (key, authors, title, year, journal, url, publisher) for bibliography. Produces .docx. Requires: pip install devsper[document]."
81
+ )
82
+ input_schema = {
83
+ "type": "object",
84
+ "properties": {
85
+ "path": {"type": "string", "description": "Output path (e.g. report.docx)"},
86
+ "title": {"type": "string", "description": "Document title"},
87
+ "content": {"type": "string", "description": "Body (plain or markdown-style newlines). Use [1], [2] for citations."},
88
+ "references": {
89
+ "type": "array",
90
+ "items": {"type": "object"},
91
+ "description": "Optional list of refs: key, authors, title, year, journal, url, publisher",
92
+ },
93
+ },
94
+ "required": ["path", "title", "content"],
95
+ }
96
+
97
+ def run(self, **kwargs) -> str:
98
+ try:
99
+ from docx import Document
100
+ except ImportError:
101
+ return "Word export requires the document extra: pip install devsper[document]"
102
+
103
+ path = kwargs.get("path")
104
+ title = kwargs.get("title")
105
+ content = kwargs.get("content")
106
+ references = kwargs.get("references")
107
+
108
+ if not path or not isinstance(path, str) or not path.strip():
109
+ return "Error: path must be a non-empty string"
110
+ if not title or not isinstance(title, str):
111
+ return "Error: title must be a non-empty string"
112
+ if content is None:
113
+ return "Error: content is required"
114
+ if not isinstance(content, str):
115
+ content = str(content)
116
+
117
+ path = path.strip()
118
+ if not path.endswith(".docx"):
119
+ path = path.rstrip("/") + ".docx"
120
+ p = Path(path).resolve()
121
+ try:
122
+ p.parent.mkdir(parents=True, exist_ok=True)
123
+ except Exception as e:
124
+ return f"Error creating directory: {e}"
125
+
126
+ doc = Document()
127
+ doc.add_heading(title.strip(), level=0)
128
+ for block in content.strip().split("\n\n"):
129
+ block = block.strip()
130
+ if block:
131
+ doc.add_paragraph(block)
132
+
133
+ if references and isinstance(references, list):
134
+ doc.add_heading("References", level=1)
135
+ num = 0
136
+ for ref in references:
137
+ if not isinstance(ref, dict):
138
+ continue
139
+ num += 1
140
+ _add_reference_paragraph(doc, num, ref)
141
+
142
+ try:
143
+ doc.save(str(p))
144
+ except Exception as e:
145
+ return f"Error writing file: {e}"
146
+ return f"Wrote {p}"
147
+
148
+
149
+ register(WriteWordDocumentTool())
@@ -0,0 +1,13 @@
1
+ """Experimentation tools: parameter sweep, grid search, tracking, benchmarks, Monte Carlo."""
2
+
3
+ from devsper.tools.experiments.parameter_sweep_runner import ParameterSweepRunnerTool
4
+ from devsper.tools.experiments.grid_search_runner import GridSearchRunnerTool
5
+ from devsper.tools.experiments.experiment_tracker import ExperimentTrackerTool
6
+ from devsper.tools.experiments.result_comparator import ResultComparatorTool
7
+ from devsper.tools.experiments.model_benchmark_runner import ModelBenchmarkRunnerTool
8
+ from devsper.tools.experiments.simulation_runner import SimulationRunnerTool
9
+ from devsper.tools.experiments.monte_carlo_experiment import MonteCarloExperimentTool
10
+ from devsper.tools.experiments.statistical_significance_test import StatisticalSignificanceTestTool
11
+ from devsper.tools.experiments.bootstrap_estimator import BootstrapEstimatorTool
12
+ from devsper.tools.experiments.experiment_report_generator import ExperimentReportGeneratorTool
13
+ from devsper.tools.experiments.swarm_map_reduce import SwarmMapReduceTool
@@ -0,0 +1,54 @@
1
+ """Bootstrap estimate: resample with replacement B times and report mean and CI (percentile)."""
2
+
3
+ from devsper.tools.base import Tool
4
+ from devsper.tools.registry import register
5
+ import random
6
+
7
+
8
+ class BootstrapEstimatorTool(Tool):
9
+ """
10
+ Bootstrap: resample with replacement B times, compute statistic (mean) each time; report mean and percentile CI.
11
+ """
12
+
13
+ name = "bootstrap_estimator"
14
+ description = "Bootstrap resampling: report mean and percentile confidence interval."
15
+ input_schema = {
16
+ "type": "object",
17
+ "properties": {
18
+ "values": {"type": "array", "items": {"type": "number"}, "description": "Sample data"},
19
+ "n_bootstrap": {"type": "integer", "description": "Number of bootstrap samples (default 200)"},
20
+ "confidence": {"type": "number", "description": "CI level (default 0.95)"},
21
+ },
22
+ "required": ["values"],
23
+ }
24
+
25
+ def run(self, **kwargs) -> str:
26
+ values = kwargs.get("values")
27
+ n_bootstrap = kwargs.get("n_bootstrap", 200)
28
+ confidence = kwargs.get("confidence", 0.95)
29
+ if not values or not isinstance(values, list):
30
+ return "Error: values must be a non-empty list of numbers"
31
+ if not isinstance(n_bootstrap, int) or n_bootstrap < 1:
32
+ n_bootstrap = 200
33
+ if not isinstance(confidence, (int, float)) or confidence <= 0 or confidence >= 1:
34
+ confidence = 0.95
35
+ try:
36
+ data = [float(x) for x in values]
37
+ except (ValueError, TypeError):
38
+ return "Error: all values must be numeric"
39
+ if len(data) < 2:
40
+ return "Error: need at least 2 values"
41
+ n = len(data)
42
+ means = []
43
+ for _ in range(n_bootstrap):
44
+ sample = random.choices(data, k=n)
45
+ means.append(sum(sample) / n)
46
+ means.sort()
47
+ alpha = 1 - confidence
48
+ lo = means[int(alpha / 2 * n_bootstrap)]
49
+ hi = means[int((1 - alpha / 2) * n_bootstrap)]
50
+ point = sum(data) / len(data)
51
+ return f"Bootstrap (n={len(data)}, B={n_bootstrap}): point estimate={point:.4f}, {int(confidence*100)}% CI = [{lo:.4f}, {hi:.4f}]"
52
+
53
+
54
+ register(BootstrapEstimatorTool())
@@ -0,0 +1,50 @@
1
+ """Generate a text report from experiment results (runs and metrics)."""
2
+
3
+ import json
4
+
5
+ from devsper.tools.base import Tool
6
+ from devsper.tools.registry import register
7
+
8
+
9
+ class ExperimentReportGeneratorTool(Tool):
10
+ """
11
+ Generate a human-readable experiment report from a list of runs with params and metrics.
12
+ """
13
+
14
+ name = "experiment_report_generator"
15
+ description = "Generate a text report from experiment results (runs, params, metrics)."
16
+ input_schema = {
17
+ "type": "object",
18
+ "properties": {
19
+ "runs": {
20
+ "type": "array",
21
+ "items": {"type": "object"},
22
+ "description": "List of {run_id, params, metrics}",
23
+ },
24
+ "title": {"type": "string", "description": "Report title"},
25
+ },
26
+ "required": ["runs"],
27
+ }
28
+
29
+ def run(self, **kwargs) -> str:
30
+ runs = kwargs.get("runs")
31
+ title = kwargs.get("title") or "Experiment Report"
32
+ if not runs or not isinstance(runs, list):
33
+ return "Error: runs must be a non-empty list of {run_id, params, metrics}"
34
+ lines = [title, "=" * 40, f"Total runs: {len(runs)}", ""]
35
+ for i, r in enumerate(runs):
36
+ if not isinstance(r, dict):
37
+ continue
38
+ run_id = r.get("run_id", f"run_{i}")
39
+ params = r.get("params", {})
40
+ metrics = r.get("metrics", r)
41
+ lines.append(f"Run: {run_id}")
42
+ if params:
43
+ lines.append(" Params: " + json.dumps(params))
44
+ if metrics and isinstance(metrics, dict):
45
+ lines.append(" Metrics: " + json.dumps(metrics))
46
+ lines.append("")
47
+ return "\n".join(lines)
48
+
49
+
50
+ register(ExperimentReportGeneratorTool())
@@ -0,0 +1,36 @@
1
+ """Track experiments: append or list experiment runs (in-memory or structured output for logging)."""
2
+
3
+ import json
4
+
5
+ from devsper.tools.base import Tool
6
+ from devsper.tools.registry import register
7
+
8
+
9
+ class ExperimentTrackerTool(Tool):
10
+ """
11
+ Track experiment runs: record run_id, params, metric and return a log entry. Stateless; returns structured log.
12
+ """
13
+
14
+ name = "experiment_tracker"
15
+ description = "Record an experiment run (run_id, params, metrics) and return log entry."
16
+ input_schema = {
17
+ "type": "object",
18
+ "properties": {
19
+ "run_id": {"type": "string", "description": "Run identifier"},
20
+ "params": {"type": "object", "description": "Parameters used"},
21
+ "metrics": {"type": "object", "description": "Metrics (e.g. accuracy, loss)"},
22
+ },
23
+ "required": ["run_id"],
24
+ }
25
+
26
+ def run(self, **kwargs) -> str:
27
+ run_id = kwargs.get("run_id")
28
+ params = kwargs.get("params") or {}
29
+ metrics = kwargs.get("metrics") or {}
30
+ if not run_id or not isinstance(run_id, str):
31
+ return "Error: run_id must be a non-empty string"
32
+ entry = {"run_id": run_id, "params": params, "metrics": metrics}
33
+ return json.dumps({"logged": entry}, indent=2)
34
+
35
+
36
+ register(ExperimentTrackerTool())
@@ -0,0 +1,50 @@
1
+ """Grid search: same as parameter sweep, return grid of (param, value) combinations."""
2
+
3
+ import json
4
+
5
+ from devsper.tools.base import Tool
6
+ from devsper.tools.registry import register
7
+
8
+
9
+ class GridSearchRunnerTool(Tool):
10
+ """
11
+ Generate grid search combinations (full Cartesian product of parameter values).
12
+ """
13
+
14
+ name = "grid_search_runner"
15
+ description = "Generate grid search parameter combinations (Cartesian product)."
16
+ input_schema = {
17
+ "type": "object",
18
+ "properties": {
19
+ "param_grid": {
20
+ "type": "object",
21
+ "description": "Map of param name -> list of values",
22
+ },
23
+ "max_combinations": {"type": "integer", "description": "Cap (default 50)"},
24
+ },
25
+ "required": ["param_grid"],
26
+ }
27
+
28
+ def run(self, **kwargs) -> str:
29
+ param_grid = kwargs.get("param_grid")
30
+ max_combinations = kwargs.get("max_combinations", 50)
31
+ if not param_grid or not isinstance(param_grid, dict):
32
+ return "Error: param_grid must be a dict of param name -> list of values"
33
+ if not isinstance(max_combinations, int) or max_combinations < 1:
34
+ max_combinations = 50
35
+ names = list(param_grid.keys())
36
+ values = []
37
+ for n in names:
38
+ v = param_grid[n]
39
+ if not isinstance(v, list):
40
+ v = [v]
41
+ values.append(v)
42
+ result = [{}]
43
+ for i, vlist in enumerate(values):
44
+ result = [r | {names[i]: x} for r in result for x in vlist]
45
+ if len(result) > max_combinations:
46
+ result = result[:max_combinations]
47
+ return json.dumps({"grid_size": len(result), "combinations": result}, indent=2)
48
+
49
+
50
+ register(GridSearchRunnerTool())