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.
- devsper/__init__.py +14 -0
- devsper/agents/a2a/__init__.py +27 -0
- devsper/agents/a2a/client.py +126 -0
- devsper/agents/a2a/discovery.py +24 -0
- devsper/agents/a2a/server.py +128 -0
- devsper/agents/a2a/tool_adapter.py +68 -0
- devsper/agents/a2a/types.py +49 -0
- devsper/agents/agent.py +602 -0
- devsper/agents/critic.py +80 -0
- devsper/agents/message_bus.py +124 -0
- devsper/agents/roles.py +181 -0
- devsper/agents/run_agent.py +78 -0
- devsper/analytics/__init__.py +5 -0
- devsper/analytics/tool_analytics.py +78 -0
- devsper/audit/__init__.py +5 -0
- devsper/audit/logger.py +214 -0
- devsper/bus/__init__.py +29 -0
- devsper/bus/backends/__init__.py +5 -0
- devsper/bus/backends/base.py +38 -0
- devsper/bus/backends/memory.py +55 -0
- devsper/bus/backends/redis.py +146 -0
- devsper/bus/message.py +56 -0
- devsper/bus/schema_version.py +3 -0
- devsper/bus/topics.py +19 -0
- devsper/cache/__init__.py +6 -0
- devsper/cache/embedding_index.py +98 -0
- devsper/cache/hashing.py +24 -0
- devsper/cache/store.py +153 -0
- devsper/cache/task_cache.py +191 -0
- devsper/cli/__init__.py +6 -0
- devsper/cli/commands/reg.py +733 -0
- devsper/cli/github_oauth.py +157 -0
- devsper/cli/init.py +637 -0
- devsper/cli/main.py +2956 -0
- devsper/cli/run_progress.py +103 -0
- devsper/cli/ui/__init__.py +65 -0
- devsper/cli/ui/components.py +94 -0
- devsper/cli/ui/errors.py +104 -0
- devsper/cli/ui/logging.py +120 -0
- devsper/cli/ui/onboarding.py +102 -0
- devsper/cli/ui/progress.py +43 -0
- devsper/cli/ui/run_view.py +308 -0
- devsper/cli/ui/theme.py +40 -0
- devsper/cluster/__init__.py +29 -0
- devsper/cluster/election.py +84 -0
- devsper/cluster/local.py +97 -0
- devsper/cluster/node_info.py +77 -0
- devsper/cluster/registry.py +71 -0
- devsper/cluster/router.py +117 -0
- devsper/cluster/state_backend.py +105 -0
- devsper/compliance/__init__.py +5 -0
- devsper/compliance/pii.py +147 -0
- devsper/config/__init__.py +52 -0
- devsper/config/config_loader.py +121 -0
- devsper/config/defaults.py +77 -0
- devsper/config/resolver.py +342 -0
- devsper/config/schema.py +237 -0
- devsper/credentials/__init__.py +19 -0
- devsper/credentials/cli.py +197 -0
- devsper/credentials/migration.py +124 -0
- devsper/credentials/store.py +142 -0
- devsper/dashboard/__init__.py +9 -0
- devsper/dashboard/dashboard.py +87 -0
- devsper/dev/__init__.py +25 -0
- devsper/dev/builder.py +195 -0
- devsper/dev/debugger.py +95 -0
- devsper/dev/repo_index.py +138 -0
- devsper/dev/sandbox.py +203 -0
- devsper/dev/scaffold.py +122 -0
- devsper/embeddings/__init__.py +5 -0
- devsper/embeddings/service.py +36 -0
- devsper/explainability/__init__.py +14 -0
- devsper/explainability/decision_tree.py +104 -0
- devsper/explainability/rationale.py +38 -0
- devsper/explainability/simulation.py +56 -0
- devsper/hitl/__init__.py +13 -0
- devsper/hitl/approval.py +160 -0
- devsper/hitl/escalation.py +95 -0
- devsper/intelligence/__init__.py +9 -0
- devsper/intelligence/adaptation.py +88 -0
- devsper/intelligence/analysis/__init__.py +19 -0
- devsper/intelligence/analysis/analyzer.py +71 -0
- devsper/intelligence/analysis/cost_estimator.py +66 -0
- devsper/intelligence/analysis/formatter.py +103 -0
- devsper/intelligence/analysis/run_report.py +402 -0
- devsper/intelligence/learning_engine.py +92 -0
- devsper/intelligence/strategies/__init__.py +23 -0
- devsper/intelligence/strategies/base.py +14 -0
- devsper/intelligence/strategies/code_analysis_strategy.py +33 -0
- devsper/intelligence/strategies/data_science_strategy.py +33 -0
- devsper/intelligence/strategies/document_pipeline_strategy.py +33 -0
- devsper/intelligence/strategies/experiment_strategy.py +33 -0
- devsper/intelligence/strategies/research_strategy.py +34 -0
- devsper/intelligence/strategy_selector.py +84 -0
- devsper/intelligence/synthesis.py +132 -0
- devsper/intelligence/task_optimizer.py +92 -0
- devsper/knowledge/__init__.py +5 -0
- devsper/knowledge/extractor.py +204 -0
- devsper/knowledge/knowledge_graph.py +184 -0
- devsper/knowledge/query.py +285 -0
- devsper/memory/__init__.py +35 -0
- devsper/memory/consolidation.py +138 -0
- devsper/memory/embeddings.py +60 -0
- devsper/memory/memory_index.py +97 -0
- devsper/memory/memory_router.py +62 -0
- devsper/memory/memory_store.py +221 -0
- devsper/memory/memory_types.py +54 -0
- devsper/memory/namespaces.py +45 -0
- devsper/memory/scoring.py +77 -0
- devsper/memory/summarizer.py +52 -0
- devsper/nodes/__init__.py +5 -0
- devsper/nodes/controller.py +449 -0
- devsper/nodes/rpc.py +127 -0
- devsper/nodes/single.py +161 -0
- devsper/nodes/worker.py +506 -0
- devsper/orchestration/__init__.py +19 -0
- devsper/orchestration/meta_planner.py +239 -0
- devsper/orchestration/priority_queue.py +61 -0
- devsper/plugins/__init__.py +19 -0
- devsper/plugins/marketplace/__init__.py +0 -0
- devsper/plugins/plugin_loader.py +70 -0
- devsper/plugins/plugin_registry.py +34 -0
- devsper/plugins/registry.py +83 -0
- devsper/protocols/__init__.py +6 -0
- devsper/providers/__init__.py +17 -0
- devsper/providers/anthropic.py +84 -0
- devsper/providers/base.py +75 -0
- devsper/providers/complexity_router.py +94 -0
- devsper/providers/gemini.py +36 -0
- devsper/providers/github.py +180 -0
- devsper/providers/model_router.py +40 -0
- devsper/providers/openai.py +105 -0
- devsper/providers/router/__init__.py +21 -0
- devsper/providers/router/backends/__init__.py +19 -0
- devsper/providers/router/backends/anthropic_backend.py +111 -0
- devsper/providers/router/backends/custom_backend.py +138 -0
- devsper/providers/router/backends/gemini_backend.py +89 -0
- devsper/providers/router/backends/github_backend.py +165 -0
- devsper/providers/router/backends/ollama_backend.py +104 -0
- devsper/providers/router/backends/openai_backend.py +142 -0
- devsper/providers/router/backends/vllm_backend.py +35 -0
- devsper/providers/router/base.py +60 -0
- devsper/providers/router/factory.py +92 -0
- devsper/providers/router/legacy.py +101 -0
- devsper/providers/router/router.py +135 -0
- devsper/reasoning/__init__.py +12 -0
- devsper/reasoning/graph.py +59 -0
- devsper/reasoning/nodes.py +20 -0
- devsper/reasoning/store.py +67 -0
- devsper/runtime/__init__.py +12 -0
- devsper/runtime/health.py +88 -0
- devsper/runtime/replay.py +53 -0
- devsper/runtime/replay_engine.py +142 -0
- devsper/runtime/run_history.py +204 -0
- devsper/runtime/telemetry.py +116 -0
- devsper/runtime/visualize.py +58 -0
- devsper/sandbox/__init__.py +13 -0
- devsper/sandbox/sandbox.py +161 -0
- devsper/swarm/checkpointer.py +65 -0
- devsper/swarm/executor.py +558 -0
- devsper/swarm/map_reduce.py +44 -0
- devsper/swarm/planner.py +197 -0
- devsper/swarm/prefetcher.py +91 -0
- devsper/swarm/scheduler.py +153 -0
- devsper/swarm/speculation.py +47 -0
- devsper/swarm/swarm.py +562 -0
- devsper/tools/__init__.py +33 -0
- devsper/tools/base.py +29 -0
- devsper/tools/code_intelligence/__init__.py +13 -0
- devsper/tools/code_intelligence/api_surface_extractor.py +73 -0
- devsper/tools/code_intelligence/architecture_analyzer.py +65 -0
- devsper/tools/code_intelligence/codebase_indexer.py +71 -0
- devsper/tools/code_intelligence/dependency_graph_builder.py +67 -0
- devsper/tools/code_intelligence/design_pattern_detector.py +62 -0
- devsper/tools/code_intelligence/large_function_detector.py +68 -0
- devsper/tools/code_intelligence/module_responsibility_mapper.py +56 -0
- devsper/tools/code_intelligence/parallel_codebase_analysis.py +44 -0
- devsper/tools/code_intelligence/refactor_candidate_detector.py +81 -0
- devsper/tools/code_intelligence/repository_semantic_index.py +61 -0
- devsper/tools/code_intelligence/test_coverage_estimator.py +62 -0
- devsper/tools/coding/__init__.py +12 -0
- devsper/tools/coding/analyze_code_complexity.py +48 -0
- devsper/tools/coding/dependency_analyzer.py +42 -0
- devsper/tools/coding/extract_functions.py +38 -0
- devsper/tools/coding/format_python.py +50 -0
- devsper/tools/coding/generate_docstrings.py +40 -0
- devsper/tools/coding/generate_unit_tests.py +42 -0
- devsper/tools/coding/lint_python.py +51 -0
- devsper/tools/coding/refactor_function.py +41 -0
- devsper/tools/coding/repo_structure_map.py +54 -0
- devsper/tools/coding/run_python.py +53 -0
- devsper/tools/data/__init__.py +12 -0
- devsper/tools/data/column_type_detection.py +64 -0
- devsper/tools/data/csv_summary.py +52 -0
- devsper/tools/data/dataframe_filter.py +51 -0
- devsper/tools/data/dataframe_groupby.py +47 -0
- devsper/tools/data/dataframe_stats.py +38 -0
- devsper/tools/data/dataset_sampling.py +55 -0
- devsper/tools/data/dataset_schema.py +45 -0
- devsper/tools/data/json_pretty_print.py +37 -0
- devsper/tools/data/json_query.py +46 -0
- devsper/tools/data/missing_value_report.py +47 -0
- devsper/tools/data_science/__init__.py +13 -0
- devsper/tools/data_science/correlation_heatmap.py +72 -0
- devsper/tools/data_science/dataset_bias_detector.py +49 -0
- devsper/tools/data_science/dataset_distribution_report.py +64 -0
- devsper/tools/data_science/dataset_drift_detector.py +64 -0
- devsper/tools/data_science/dataset_outlier_detector.py +65 -0
- devsper/tools/data_science/dataset_profile.py +76 -0
- devsper/tools/data_science/distributed_dataset_processor.py +54 -0
- devsper/tools/data_science/feature_engineering_suggestions.py +69 -0
- devsper/tools/data_science/feature_importance_estimator.py +82 -0
- devsper/tools/data_science/model_input_validator.py +59 -0
- devsper/tools/data_science/time_series_analyzer.py +57 -0
- devsper/tools/documents/__init__.py +11 -0
- devsper/tools/documents/_docproc.py +56 -0
- devsper/tools/documents/document_to_markdown.py +29 -0
- devsper/tools/documents/extract_document_images.py +39 -0
- devsper/tools/documents/extract_document_text.py +29 -0
- devsper/tools/documents/extract_equations.py +36 -0
- devsper/tools/documents/extract_tables.py +47 -0
- devsper/tools/documents/summarize_document.py +42 -0
- devsper/tools/documents/write_latex_document.py +133 -0
- devsper/tools/documents/write_markdown_document.py +89 -0
- devsper/tools/documents/write_word_document.py +149 -0
- devsper/tools/experiments/__init__.py +13 -0
- devsper/tools/experiments/bootstrap_estimator.py +54 -0
- devsper/tools/experiments/experiment_report_generator.py +50 -0
- devsper/tools/experiments/experiment_tracker.py +36 -0
- devsper/tools/experiments/grid_search_runner.py +50 -0
- devsper/tools/experiments/model_benchmark_runner.py +45 -0
- devsper/tools/experiments/monte_carlo_experiment.py +38 -0
- devsper/tools/experiments/parameter_sweep_runner.py +51 -0
- devsper/tools/experiments/result_comparator.py +58 -0
- devsper/tools/experiments/simulation_runner.py +43 -0
- devsper/tools/experiments/statistical_significance_test.py +56 -0
- devsper/tools/experiments/swarm_map_reduce.py +42 -0
- devsper/tools/filesystem/__init__.py +12 -0
- devsper/tools/filesystem/append_file.py +42 -0
- devsper/tools/filesystem/file_hash.py +40 -0
- devsper/tools/filesystem/file_line_count.py +36 -0
- devsper/tools/filesystem/file_metadata.py +38 -0
- devsper/tools/filesystem/file_preview.py +55 -0
- devsper/tools/filesystem/find_large_files.py +50 -0
- devsper/tools/filesystem/list_directory.py +39 -0
- devsper/tools/filesystem/read_file.py +35 -0
- devsper/tools/filesystem/search_files.py +60 -0
- devsper/tools/filesystem/write_file.py +41 -0
- devsper/tools/flagship/__init__.py +15 -0
- devsper/tools/flagship/distributed_document_analysis.py +77 -0
- devsper/tools/flagship/docproc_corpus_pipeline.py +91 -0
- devsper/tools/flagship/repository_semantic_map.py +99 -0
- devsper/tools/flagship/research_graph_builder.py +111 -0
- devsper/tools/flagship/swarm_experiment_runner.py +86 -0
- devsper/tools/knowledge/__init__.py +10 -0
- devsper/tools/knowledge/citation_graph_builder.py +69 -0
- devsper/tools/knowledge/concept_frequency_analyzer.py +74 -0
- devsper/tools/knowledge/corpus_builder.py +66 -0
- devsper/tools/knowledge/cross_document_entity_linker.py +71 -0
- devsper/tools/knowledge/document_corpus_summary.py +68 -0
- devsper/tools/knowledge/document_topic_extractor.py +58 -0
- devsper/tools/knowledge/knowledge_graph_extractor.py +58 -0
- devsper/tools/knowledge/timeline_extractor.py +59 -0
- devsper/tools/math/__init__.py +12 -0
- devsper/tools/math/calculate_expression.py +52 -0
- devsper/tools/math/correlation.py +44 -0
- devsper/tools/math/distribution_summary.py +39 -0
- devsper/tools/math/histogram.py +53 -0
- devsper/tools/math/linear_regression.py +47 -0
- devsper/tools/math/matrix_multiply.py +38 -0
- devsper/tools/math/mean_std.py +35 -0
- devsper/tools/math/monte_carlo_simulation.py +43 -0
- devsper/tools/math/polynomial_fit.py +40 -0
- devsper/tools/math/random_sample.py +36 -0
- devsper/tools/mcp/__init__.py +23 -0
- devsper/tools/mcp/adapter.py +53 -0
- devsper/tools/mcp/client.py +235 -0
- devsper/tools/mcp/discovery.py +53 -0
- devsper/tools/memory/__init__.py +16 -0
- devsper/tools/memory/delete_memory.py +25 -0
- devsper/tools/memory/list_memory.py +34 -0
- devsper/tools/memory/search_memory.py +36 -0
- devsper/tools/memory/store_memory.py +47 -0
- devsper/tools/memory/summarize_memory.py +41 -0
- devsper/tools/memory/tag_memory.py +47 -0
- devsper/tools/pipelines.py +92 -0
- devsper/tools/registry.py +39 -0
- devsper/tools/research/__init__.py +12 -0
- devsper/tools/research/arxiv_download.py +55 -0
- devsper/tools/research/arxiv_search.py +58 -0
- devsper/tools/research/citation_extractor.py +35 -0
- devsper/tools/research/duckduckgo_search.py +42 -0
- devsper/tools/research/paper_metadata_extractor.py +45 -0
- devsper/tools/research/paper_summarizer.py +41 -0
- devsper/tools/research/research_question_generator.py +39 -0
- devsper/tools/research/topic_cluster.py +46 -0
- devsper/tools/research/web_search.py +47 -0
- devsper/tools/research/wikipedia_lookup.py +50 -0
- devsper/tools/research_advanced/__init__.py +14 -0
- devsper/tools/research_advanced/citation_context_extractor.py +60 -0
- devsper/tools/research_advanced/literature_review_generator.py +79 -0
- devsper/tools/research_advanced/methodology_extractor.py +58 -0
- devsper/tools/research_advanced/paper_contribution_extractor.py +50 -0
- devsper/tools/research_advanced/paper_dataset_identifier.py +49 -0
- devsper/tools/research_advanced/paper_method_comparator.py +62 -0
- devsper/tools/research_advanced/paper_similarity_search.py +69 -0
- devsper/tools/research_advanced/paper_trend_analyzer.py +69 -0
- devsper/tools/research_advanced/parallel_document_analyzer.py +56 -0
- devsper/tools/research_advanced/research_gap_finder.py +71 -0
- devsper/tools/research_advanced/research_topic_mapper.py +69 -0
- devsper/tools/research_advanced/swarm_literature_review.py +58 -0
- devsper/tools/scoring/__init__.py +52 -0
- devsper/tools/scoring/report.py +44 -0
- devsper/tools/scoring/scorer.py +39 -0
- devsper/tools/scoring/selector.py +61 -0
- devsper/tools/scoring/store.py +267 -0
- devsper/tools/selector.py +130 -0
- devsper/tools/system/__init__.py +12 -0
- devsper/tools/system/cpu_usage.py +22 -0
- devsper/tools/system/disk_usage.py +35 -0
- devsper/tools/system/environment_variables.py +29 -0
- devsper/tools/system/memory_usage.py +23 -0
- devsper/tools/system/pip_install.py +44 -0
- devsper/tools/system/pip_search.py +29 -0
- devsper/tools/system/process_list.py +34 -0
- devsper/tools/system/python_package_list.py +40 -0
- devsper/tools/system/run_shell_command.py +51 -0
- devsper/tools/system/system_info.py +26 -0
- devsper/tools/tool_runner.py +122 -0
- devsper/tui/__init__.py +5 -0
- devsper/tui/activity_feed_view.py +73 -0
- devsper/tui/adaptive_tasks_view.py +75 -0
- devsper/tui/agent_role_view.py +35 -0
- devsper/tui/app.py +395 -0
- devsper/tui/dashboard_screen.py +290 -0
- devsper/tui/dev_view.py +99 -0
- devsper/tui/inject_screen.py +73 -0
- devsper/tui/knowledge_graph_view.py +46 -0
- devsper/tui/layout.py +43 -0
- devsper/tui/logs_view.py +83 -0
- devsper/tui/memory_view.py +58 -0
- devsper/tui/performance_view.py +33 -0
- devsper/tui/reasoning_graph_view.py +39 -0
- devsper/tui/results_view.py +139 -0
- devsper/tui/swarm_view.py +37 -0
- devsper/tui/task_detail_screen.py +55 -0
- devsper/tui/task_view.py +103 -0
- devsper/types/event.py +97 -0
- devsper/types/exceptions.py +21 -0
- devsper/types/swarm.py +41 -0
- devsper/types/task.py +80 -0
- devsper/upgrade/__init__.py +21 -0
- devsper/upgrade/changelog.py +124 -0
- devsper/upgrade/cli.py +145 -0
- devsper/upgrade/installer.py +103 -0
- devsper/upgrade/notifier.py +52 -0
- devsper/upgrade/version_check.py +121 -0
- devsper/utils/event_logger.py +88 -0
- devsper/utils/http.py +43 -0
- devsper/utils/models.py +54 -0
- devsper/visualization/__init__.py +5 -0
- devsper/visualization/dag_export.py +67 -0
- devsper/workflow/__init__.py +18 -0
- devsper/workflow/conditions.py +157 -0
- devsper/workflow/context.py +108 -0
- devsper/workflow/loader.py +156 -0
- devsper/workflow/resolver.py +109 -0
- devsper/workflow/runner.py +562 -0
- devsper/workflow/schema.py +63 -0
- devsper/workflow/validator.py +128 -0
- devsper-2.1.6.dist-info/METADATA +346 -0
- devsper-2.1.6.dist-info/RECORD +375 -0
- devsper-2.1.6.dist-info/WHEEL +4 -0
- devsper-2.1.6.dist-info/entry_points.txt +3 -0
- 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())
|