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,77 @@
|
|
|
1
|
+
"""Default configuration values for devsper."""
|
|
2
|
+
|
|
3
|
+
from devsper.config.schema import (
|
|
4
|
+
MemoryConfig,
|
|
5
|
+
ModelsConfig,
|
|
6
|
+
ProviderAzureConfig,
|
|
7
|
+
SwarmConfig,
|
|
8
|
+
TelemetryConfig,
|
|
9
|
+
ToolsConfig,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_swarm_defaults() -> SwarmConfig:
|
|
14
|
+
return SwarmConfig(
|
|
15
|
+
workers=4,
|
|
16
|
+
adaptive_planning=False,
|
|
17
|
+
max_iterations=10,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_models_defaults(worker_model: str = "mock", planner_model: str = "mock") -> ModelsConfig:
|
|
22
|
+
return ModelsConfig(
|
|
23
|
+
planner=planner_model,
|
|
24
|
+
worker=worker_model,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_memory_defaults() -> MemoryConfig:
|
|
29
|
+
return MemoryConfig(
|
|
30
|
+
enabled=True,
|
|
31
|
+
store_results=True,
|
|
32
|
+
top_k=5,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_tools_defaults() -> ToolsConfig:
|
|
37
|
+
return ToolsConfig(
|
|
38
|
+
enabled=None, # None = all categories
|
|
39
|
+
top_k=0, # 0 = no limit, use all tools
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_telemetry_defaults() -> TelemetryConfig:
|
|
44
|
+
return TelemetryConfig(
|
|
45
|
+
enabled=True,
|
|
46
|
+
save_events=True,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_provider_azure_defaults() -> ProviderAzureConfig:
|
|
51
|
+
return ProviderAzureConfig(
|
|
52
|
+
endpoint="",
|
|
53
|
+
deployment="",
|
|
54
|
+
api_key="",
|
|
55
|
+
api_version="",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def get_full_defaults(
|
|
60
|
+
worker_model: str = "mock",
|
|
61
|
+
planner_model: str = "mock",
|
|
62
|
+
events_dir: str = ".devsper/events",
|
|
63
|
+
data_dir: str = ".devsper",
|
|
64
|
+
) -> dict:
|
|
65
|
+
"""Raw defaults for merging. Used by resolver."""
|
|
66
|
+
return {
|
|
67
|
+
"swarm": get_swarm_defaults().model_dump(),
|
|
68
|
+
"models": get_models_defaults(worker_model, planner_model).model_dump(),
|
|
69
|
+
"memory": get_memory_defaults().model_dump(),
|
|
70
|
+
"tools": get_tools_defaults().model_dump(),
|
|
71
|
+
"telemetry": get_telemetry_defaults().model_dump(),
|
|
72
|
+
"events_dir": events_dir,
|
|
73
|
+
"data_dir": data_dir,
|
|
74
|
+
"providers": {
|
|
75
|
+
"azure": get_provider_azure_defaults().model_dump(),
|
|
76
|
+
},
|
|
77
|
+
}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
"""Resolve config: defaults -> user TOML -> project TOML -> env. Apply provider TOML to os.environ."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from copy import deepcopy
|
|
5
|
+
|
|
6
|
+
from devsper.credentials import inject_into_env
|
|
7
|
+
from devsper.config.config_loader import (
|
|
8
|
+
load_project_config,
|
|
9
|
+
load_user_config,
|
|
10
|
+
normalize_toml_to_flat,
|
|
11
|
+
)
|
|
12
|
+
from devsper.config.schema import (
|
|
13
|
+
AgentsConfig,
|
|
14
|
+
A2AConfig,
|
|
15
|
+
A2AAgentConfig,
|
|
16
|
+
BusConfig,
|
|
17
|
+
CacheConfig,
|
|
18
|
+
HitlConfig,
|
|
19
|
+
HitlPolicyConfig,
|
|
20
|
+
HitlTriggerConfig,
|
|
21
|
+
devsperConfigModel,
|
|
22
|
+
KnowledgeConfig,
|
|
23
|
+
MCPConfig,
|
|
24
|
+
MCPServerConfig,
|
|
25
|
+
MemoryConfig,
|
|
26
|
+
ModelsConfig,
|
|
27
|
+
NodesConfig,
|
|
28
|
+
ProviderAzureConfig,
|
|
29
|
+
ProviderOllamaConfig,
|
|
30
|
+
ProviderVLLMConfig,
|
|
31
|
+
ProviderCustomConfig,
|
|
32
|
+
ProvidersConfig,
|
|
33
|
+
SandboxConfig,
|
|
34
|
+
SandboxRoleConfig,
|
|
35
|
+
ComplianceConfig,
|
|
36
|
+
SwarmConfig,
|
|
37
|
+
TelemetryConfig,
|
|
38
|
+
ToolsConfig,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
_PROVIDER_ENV = {
|
|
42
|
+
"azure_openai": [
|
|
43
|
+
("endpoint", "AZURE_OPENAI_ENDPOINT"),
|
|
44
|
+
("api_key", "AZURE_OPENAI_API_KEY"),
|
|
45
|
+
("deployment_name", "AZURE_OPENAI_DEPLOYMENT_NAME"),
|
|
46
|
+
("api_version", "AZURE_OPENAI_API_VERSION"),
|
|
47
|
+
],
|
|
48
|
+
"azure_anthropic": [
|
|
49
|
+
("endpoint", "AZURE_ANTHROPIC_ENDPOINT"),
|
|
50
|
+
("api_key", "AZURE_ANTHROPIC_API_KEY"),
|
|
51
|
+
("deployment_name", "AZURE_ANTHROPIC_DEPLOYMENT_NAME"),
|
|
52
|
+
],
|
|
53
|
+
"openai": [("api_key", "OPENAI_API_KEY")],
|
|
54
|
+
"anthropic": [("api_key", "ANTHROPIC_API_KEY")],
|
|
55
|
+
"google": [("api_key", "GOOGLE_API_KEY")],
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _infer_worker_model_from_env() -> str:
|
|
60
|
+
if os.environ.get("AZURE_OPENAI_ENDPOINT") and os.environ.get(
|
|
61
|
+
"AZURE_OPENAI_API_KEY"
|
|
62
|
+
):
|
|
63
|
+
return "gpt-5-mini"
|
|
64
|
+
if os.environ.get("OPENAI_API_KEY"):
|
|
65
|
+
return "gpt-4o-mini"
|
|
66
|
+
if os.environ.get("AZURE_ANTHROPIC_ENDPOINT") or os.environ.get(
|
|
67
|
+
"AZURE_ANTHROPIC_API_KEY"
|
|
68
|
+
):
|
|
69
|
+
return "claude-opus-4-6-2"
|
|
70
|
+
if os.environ.get("ANTHROPIC_API_KEY"):
|
|
71
|
+
return "claude-3-haiku-20240307"
|
|
72
|
+
if os.environ.get("GOOGLE_API_KEY"):
|
|
73
|
+
return "gemini-1.5-flash"
|
|
74
|
+
return "mock"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _infer_planner_model_from_env() -> str:
|
|
78
|
+
if os.environ.get("AZURE_OPENAI_ENDPOINT") and os.environ.get(
|
|
79
|
+
"AZURE_OPENAI_API_KEY"
|
|
80
|
+
):
|
|
81
|
+
return "gpt-4o"
|
|
82
|
+
if os.environ.get("OPENAI_API_KEY"):
|
|
83
|
+
return "gpt-4o-mini"
|
|
84
|
+
if os.environ.get("AZURE_ANTHROPIC_ENDPOINT") or os.environ.get(
|
|
85
|
+
"AZURE_ANTHROPIC_API_KEY"
|
|
86
|
+
):
|
|
87
|
+
return "claude-opus-4-6-2"
|
|
88
|
+
if os.environ.get("ANTHROPIC_API_KEY"):
|
|
89
|
+
return "claude-3-haiku-20240307"
|
|
90
|
+
if os.environ.get("GOOGLE_API_KEY"):
|
|
91
|
+
return "gemini-1.5-flash"
|
|
92
|
+
return "mock"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _apply_provider_toml_to_env(toml_data: dict) -> None:
|
|
96
|
+
"""Apply [providers.azure], [azure_openai], etc. to os.environ when not already set."""
|
|
97
|
+
# New format: [providers.azure]
|
|
98
|
+
providers = toml_data.get("providers")
|
|
99
|
+
if isinstance(providers, dict) and "azure" in providers:
|
|
100
|
+
az = providers["azure"]
|
|
101
|
+
if isinstance(az, dict):
|
|
102
|
+
for toml_key, env_key in [
|
|
103
|
+
("endpoint", "AZURE_OPENAI_ENDPOINT"),
|
|
104
|
+
("api_key", "AZURE_OPENAI_API_KEY"),
|
|
105
|
+
("deployment", "AZURE_OPENAI_DEPLOYMENT_NAME"),
|
|
106
|
+
("api_version", "AZURE_OPENAI_API_VERSION"),
|
|
107
|
+
]:
|
|
108
|
+
val = az.get(toml_key)
|
|
109
|
+
if val is not None and str(val).strip() and env_key not in os.environ:
|
|
110
|
+
os.environ[env_key] = str(val).strip()
|
|
111
|
+
# Legacy sections
|
|
112
|
+
for section, mappings in _PROVIDER_ENV.items():
|
|
113
|
+
block = toml_data.get(section)
|
|
114
|
+
if not isinstance(block, dict):
|
|
115
|
+
continue
|
|
116
|
+
for toml_key, env_key in mappings:
|
|
117
|
+
val = block.get(toml_key)
|
|
118
|
+
if val is not None and str(val).strip() and env_key not in os.environ:
|
|
119
|
+
os.environ[env_key] = str(val).strip()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _deep_merge(base: dict, override: dict) -> dict:
|
|
123
|
+
"""Recursively merge override into base. Override wins."""
|
|
124
|
+
out = deepcopy(base)
|
|
125
|
+
for k, v in override.items():
|
|
126
|
+
if k in out and isinstance(out[k], dict) and isinstance(v, dict):
|
|
127
|
+
out[k] = _deep_merge(out[k], v)
|
|
128
|
+
else:
|
|
129
|
+
out[k] = v
|
|
130
|
+
return out
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _build_merged_raw(
|
|
134
|
+
user_raw: dict,
|
|
135
|
+
project_raw: dict,
|
|
136
|
+
) -> dict:
|
|
137
|
+
"""Merge user then project (project overrides user). Start from defaults."""
|
|
138
|
+
worker_default = _infer_worker_model_from_env()
|
|
139
|
+
planner_default = _infer_planner_model_from_env()
|
|
140
|
+
defaults: dict = {
|
|
141
|
+
"swarm": {
|
|
142
|
+
"workers": 4,
|
|
143
|
+
"adaptive_planning": False,
|
|
144
|
+
"adaptive_execution": False,
|
|
145
|
+
"max_iterations": 10,
|
|
146
|
+
"speculative_execution": False,
|
|
147
|
+
"cache_enabled": False,
|
|
148
|
+
},
|
|
149
|
+
"agents": {"roles": ["research_agent", "code_agent", "analysis_agent", "critic_agent"]},
|
|
150
|
+
"models": {"planner": planner_default, "worker": worker_default},
|
|
151
|
+
"memory": {"enabled": True, "store_results": True, "top_k": 5},
|
|
152
|
+
"knowledge": {"guide_planning": True, "min_confidence": 0.30, "auto_extract": True},
|
|
153
|
+
"tools": {"enabled": None, "top_k": 0},
|
|
154
|
+
"telemetry": {"enabled": True, "save_events": True},
|
|
155
|
+
"cache": {
|
|
156
|
+
"enabled": True,
|
|
157
|
+
"semantic": False,
|
|
158
|
+
"similarity_threshold": 0.92,
|
|
159
|
+
"max_age_hours": 168.0,
|
|
160
|
+
},
|
|
161
|
+
"bus": {"backend": "memory", "redis_url": "redis://localhost:6379"},
|
|
162
|
+
"nodes": {
|
|
163
|
+
"mode": "single",
|
|
164
|
+
"role": "hybrid",
|
|
165
|
+
"run_id": None,
|
|
166
|
+
"rpc_port": 7700,
|
|
167
|
+
"rpc_token": None,
|
|
168
|
+
"max_workers_per_node": 8,
|
|
169
|
+
"node_tags": [],
|
|
170
|
+
"controller_url": "http://localhost:7700",
|
|
171
|
+
"heartbeat_interval_seconds": 10.0,
|
|
172
|
+
"task_claim_timeout_seconds": 120,
|
|
173
|
+
},
|
|
174
|
+
"events_dir": ".devsper/events",
|
|
175
|
+
"data_dir": ".devsper",
|
|
176
|
+
"mcp": {"servers": []},
|
|
177
|
+
"a2a": {"agents": [], "serve": False, "serve_port": 8080},
|
|
178
|
+
"hitl": {"enabled": False, "policies": []},
|
|
179
|
+
"providers": {
|
|
180
|
+
"azure": {
|
|
181
|
+
"endpoint": "",
|
|
182
|
+
"deployment": "",
|
|
183
|
+
"api_key": "",
|
|
184
|
+
"api_version": "",
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
}
|
|
188
|
+
user_norm = normalize_toml_to_flat(user_raw)
|
|
189
|
+
project_norm = normalize_toml_to_flat(project_raw)
|
|
190
|
+
merged = _deep_merge(defaults, user_norm)
|
|
191
|
+
merged = _deep_merge(merged, project_norm)
|
|
192
|
+
return merged
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _apply_env_overrides(merged: dict) -> dict:
|
|
196
|
+
"""Apply env vars on top. Priority: env > project > user > defaults."""
|
|
197
|
+
if os.environ.get("DEVSPER_WORKER_MODEL"):
|
|
198
|
+
merged.setdefault("models", {})["worker"] = os.environ["DEVSPER_WORKER_MODEL"]
|
|
199
|
+
if os.environ.get("DEVSPER_PLANNER_MODEL"):
|
|
200
|
+
merged.setdefault("models", {})["planner"] = os.environ[
|
|
201
|
+
"DEVSPER_PLANNER_MODEL"
|
|
202
|
+
]
|
|
203
|
+
if os.environ.get("DEVSPER_EVENTS_DIR"):
|
|
204
|
+
merged["events_dir"] = os.environ["DEVSPER_EVENTS_DIR"]
|
|
205
|
+
if os.environ.get("DEVSPER_DATA_DIR"):
|
|
206
|
+
merged["data_dir"] = os.environ["DEVSPER_DATA_DIR"]
|
|
207
|
+
return merged
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def resolve_config(config_path: str | None = None) -> devsperConfigModel:
|
|
211
|
+
"""
|
|
212
|
+
Load user and project config, merge with defaults, apply env.
|
|
213
|
+
If config_path is given, load that file as the only project config (for Swarm(config="path")).
|
|
214
|
+
"""
|
|
215
|
+
user_raw = load_user_config()
|
|
216
|
+
if config_path:
|
|
217
|
+
from pathlib import Path
|
|
218
|
+
from devsper.config.config_loader import _load_toml
|
|
219
|
+
|
|
220
|
+
project_raw = _load_toml(Path(config_path))
|
|
221
|
+
else:
|
|
222
|
+
project_raw = load_project_config()
|
|
223
|
+
|
|
224
|
+
_apply_provider_toml_to_env(user_raw)
|
|
225
|
+
_apply_provider_toml_to_env(project_raw)
|
|
226
|
+
|
|
227
|
+
# Inject credentials from store if not already set in env
|
|
228
|
+
inject_into_env()
|
|
229
|
+
|
|
230
|
+
merged = _build_merged_raw(user_raw, project_raw)
|
|
231
|
+
merged = _apply_env_overrides(merged)
|
|
232
|
+
|
|
233
|
+
# Build Pydantic model
|
|
234
|
+
swarm = SwarmConfig(**(merged.get("swarm") or {}))
|
|
235
|
+
agents = AgentsConfig(**(merged.get("agents") or {}))
|
|
236
|
+
models = ModelsConfig(**(merged.get("models") or {}))
|
|
237
|
+
memory = MemoryConfig(**(merged.get("memory") or {}))
|
|
238
|
+
knowledge = KnowledgeConfig(**(merged.get("knowledge") or {}))
|
|
239
|
+
tools = ToolsConfig(**(merged.get("tools") or {}))
|
|
240
|
+
telemetry = TelemetryConfig(**(merged.get("telemetry") or {}))
|
|
241
|
+
cache = CacheConfig(**(merged.get("cache") or {}))
|
|
242
|
+
bus = BusConfig(**(merged.get("bus") or {}))
|
|
243
|
+
nodes = NodesConfig(**(merged.get("nodes") or {}))
|
|
244
|
+
# MCP: [[mcp.servers]] -> list of MCPServerConfig
|
|
245
|
+
mcp_data = merged.get("mcp") or {}
|
|
246
|
+
mcp_servers = mcp_data.get("servers") if isinstance(mcp_data, dict) else []
|
|
247
|
+
if not isinstance(mcp_servers, list):
|
|
248
|
+
mcp_servers = []
|
|
249
|
+
mcp = MCPConfig(servers=[MCPServerConfig(**s) for s in mcp_servers if isinstance(s, dict)])
|
|
250
|
+
# A2A: [[a2a.agents]] and [a2a] serve/serve_port
|
|
251
|
+
a2a_data = merged.get("a2a") or {}
|
|
252
|
+
a2a_agents = a2a_data.get("agents") if isinstance(a2a_data, dict) else []
|
|
253
|
+
if not isinstance(a2a_agents, list):
|
|
254
|
+
a2a_agents = []
|
|
255
|
+
a2a = A2AConfig(
|
|
256
|
+
agents=[A2AAgentConfig(**a) for a in a2a_agents if isinstance(a, dict)],
|
|
257
|
+
serve=bool(a2a_data.get("serve", False)) if isinstance(a2a_data, dict) else False,
|
|
258
|
+
serve_port=int(a2a_data.get("serve_port", 8080)) if isinstance(a2a_data, dict) else 8080,
|
|
259
|
+
)
|
|
260
|
+
providers_data = merged.get("providers") or {}
|
|
261
|
+
azure_data = providers_data.get("azure") or {}
|
|
262
|
+
ollama_data = providers_data.get("ollama") or {}
|
|
263
|
+
vllm_data = providers_data.get("vllm") or {}
|
|
264
|
+
custom_data = providers_data.get("custom") or {}
|
|
265
|
+
fallback_block = providers_data.get("fallback_order") or {}
|
|
266
|
+
fallback_order = (
|
|
267
|
+
fallback_block.get("order")
|
|
268
|
+
if isinstance(fallback_block, dict)
|
|
269
|
+
else fallback_block
|
|
270
|
+
)
|
|
271
|
+
if not isinstance(fallback_order, list):
|
|
272
|
+
fallback_order = []
|
|
273
|
+
providers = ProvidersConfig(
|
|
274
|
+
azure=ProviderAzureConfig(**azure_data),
|
|
275
|
+
ollama=ProviderOllamaConfig(**(ollama_data if isinstance(ollama_data, dict) else {})),
|
|
276
|
+
vllm=ProviderVLLMConfig(**(vllm_data if isinstance(vllm_data, dict) else {})),
|
|
277
|
+
custom=ProviderCustomConfig(**(custom_data if isinstance(custom_data, dict) else {})),
|
|
278
|
+
fallback_order=fallback_order,
|
|
279
|
+
)
|
|
280
|
+
sandbox_data = merged.get("sandbox") or {}
|
|
281
|
+
sandbox_roles = sandbox_data.get("roles") if isinstance(sandbox_data, dict) else []
|
|
282
|
+
if not isinstance(sandbox_roles, list):
|
|
283
|
+
sandbox_roles = []
|
|
284
|
+
sandbox = SandboxConfig(
|
|
285
|
+
enabled=bool(sandbox_data.get("enabled", True)) if isinstance(sandbox_data, dict) else True,
|
|
286
|
+
default_max_memory_mb=int(sandbox_data.get("default_max_memory_mb", 512)) if isinstance(sandbox_data, dict) else 512,
|
|
287
|
+
default_max_cpu_seconds=int(sandbox_data.get("default_max_cpu_seconds", 60)) if isinstance(sandbox_data, dict) else 60,
|
|
288
|
+
default_max_tool_calls=int(sandbox_data.get("default_max_tool_calls", 20)) if isinstance(sandbox_data, dict) else 20,
|
|
289
|
+
roles=[SandboxRoleConfig(**(r if isinstance(r, dict) else {})) for r in sandbox_roles],
|
|
290
|
+
)
|
|
291
|
+
compliance_data = merged.get("compliance") or {}
|
|
292
|
+
compliance = ComplianceConfig(
|
|
293
|
+
pii_redaction=bool(compliance_data.get("pii_redaction", True)) if isinstance(compliance_data, dict) else True,
|
|
294
|
+
pii_types=compliance_data.get("pii_types", ["EMAIL", "PHONE", "SSN", "CREDIT_CARD", "API_KEY"]) if isinstance(compliance_data, dict) else ["EMAIL", "PHONE", "SSN", "CREDIT_CARD", "API_KEY"],
|
|
295
|
+
gdpr_mode=bool(compliance_data.get("gdpr_mode", False)) if isinstance(compliance_data, dict) else False,
|
|
296
|
+
audit_logging=bool(compliance_data.get("audit_logging", True)) if isinstance(compliance_data, dict) else True,
|
|
297
|
+
data_residency=str(compliance_data.get("data_residency", "us")) if isinstance(compliance_data, dict) else "us",
|
|
298
|
+
)
|
|
299
|
+
hitl_data = merged.get("hitl") or {}
|
|
300
|
+
hitl_policies = hitl_data.get("policies") if isinstance(hitl_data, dict) else []
|
|
301
|
+
if not isinstance(hitl_policies, list):
|
|
302
|
+
hitl_policies = []
|
|
303
|
+
hitl_policy_configs = []
|
|
304
|
+
for p in hitl_policies:
|
|
305
|
+
if not isinstance(p, dict):
|
|
306
|
+
continue
|
|
307
|
+
triggers_data = p.get("triggers") or []
|
|
308
|
+
triggers = [HitlTriggerConfig(**(t if isinstance(t, dict) else {})) for t in triggers_data if isinstance(t, dict)]
|
|
309
|
+
hitl_policy_configs.append(
|
|
310
|
+
HitlPolicyConfig(
|
|
311
|
+
name=str(p.get("name", "")),
|
|
312
|
+
on_timeout=str(p.get("on_timeout", "auto_approve")),
|
|
313
|
+
timeout_seconds=int(p.get("timeout_seconds", 3600)),
|
|
314
|
+
approvers=list(p.get("approvers") or []),
|
|
315
|
+
triggers=triggers,
|
|
316
|
+
)
|
|
317
|
+
)
|
|
318
|
+
hitl = HitlConfig(
|
|
319
|
+
enabled=bool(hitl_data.get("enabled", False)) if isinstance(hitl_data, dict) else False,
|
|
320
|
+
policies=hitl_policy_configs,
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
return devsperConfigModel(
|
|
324
|
+
swarm=swarm,
|
|
325
|
+
agents=agents,
|
|
326
|
+
models=models,
|
|
327
|
+
memory=memory,
|
|
328
|
+
knowledge=knowledge,
|
|
329
|
+
tools=tools,
|
|
330
|
+
telemetry=telemetry,
|
|
331
|
+
cache=cache,
|
|
332
|
+
bus=bus,
|
|
333
|
+
nodes=nodes,
|
|
334
|
+
mcp=mcp,
|
|
335
|
+
a2a=a2a,
|
|
336
|
+
events_dir=merged.get("events_dir", ".devsper/events"),
|
|
337
|
+
data_dir=merged.get("data_dir", ".devsper"),
|
|
338
|
+
providers=providers,
|
|
339
|
+
sandbox=sandbox,
|
|
340
|
+
compliance=compliance,
|
|
341
|
+
hitl=hitl,
|
|
342
|
+
)
|
devsper/config/schema.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""Pydantic schema for devsper configuration."""
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BusConfig(BaseModel):
|
|
9
|
+
"""v1.9: message bus backend (memory or redis)."""
|
|
10
|
+
backend: Literal["memory", "redis"] = "memory"
|
|
11
|
+
redis_url: str = "redis://localhost:6379"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SwarmConfig(BaseModel):
|
|
15
|
+
workers: int = 4
|
|
16
|
+
adaptive_planning: bool = False
|
|
17
|
+
adaptive_execution: bool = False # v1.2: real-time adaptation (slow/failed task handling)
|
|
18
|
+
max_iterations: int = 10
|
|
19
|
+
speculative_execution: bool = False
|
|
20
|
+
cache_enabled: bool = False
|
|
21
|
+
parallel_tools: bool = True # v1.6: run independent tool calls in parallel within agents
|
|
22
|
+
# v1.7
|
|
23
|
+
critic_enabled: bool = True
|
|
24
|
+
critic_threshold: float = 0.70
|
|
25
|
+
critic_roles: list[str] = ["research", "analysis", "code"]
|
|
26
|
+
message_bus_enabled: bool = True
|
|
27
|
+
prefetch_enabled: bool = True
|
|
28
|
+
prefetch_max_age_seconds: float = 30.0
|
|
29
|
+
# v1.9
|
|
30
|
+
checkpoint_interval: int = 10
|
|
31
|
+
checkpoint_enabled: bool = True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CacheConfig(BaseModel):
|
|
35
|
+
"""v1.6: cache section for semantic task cache."""
|
|
36
|
+
enabled: bool = True
|
|
37
|
+
semantic: bool = False
|
|
38
|
+
similarity_threshold: float = 0.92
|
|
39
|
+
max_age_hours: float = 168.0 # 1 week
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class AgentsConfig(BaseModel):
|
|
43
|
+
"""Agent roles enabled for the swarm (research, analysis, critic, code)."""
|
|
44
|
+
roles: list[str] = ["research_agent", "code_agent", "analysis_agent", "critic_agent"]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ModelsConfig(BaseModel):
|
|
48
|
+
planner: str = "mock"
|
|
49
|
+
worker: str = "mock"
|
|
50
|
+
fast: str | None = None # v1.6: simple tier (e.g. haiku/flash)
|
|
51
|
+
quality: str | None = None # v1.6: complex tier (defaults to planner)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class MemoryConfig(BaseModel):
|
|
55
|
+
enabled: bool = True
|
|
56
|
+
store_results: bool = True
|
|
57
|
+
top_k: int = 5
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class KnowledgeConfig(BaseModel):
|
|
61
|
+
"""v1.8: knowledge-guided planning and auto-extraction."""
|
|
62
|
+
guide_planning: bool = True
|
|
63
|
+
min_confidence: float = 0.30
|
|
64
|
+
auto_extract: bool = True
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ToolsConfig(BaseModel):
|
|
68
|
+
enabled: list[str] | None = None # None = all categories
|
|
69
|
+
top_k: int = 0 # 0 = no limit
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class TelemetryConfig(BaseModel):
|
|
73
|
+
enabled: bool = True
|
|
74
|
+
save_events: bool = True
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ProviderAzureConfig(BaseModel):
|
|
78
|
+
endpoint: str = ""
|
|
79
|
+
deployment: str = ""
|
|
80
|
+
api_key: str = ""
|
|
81
|
+
api_version: str = ""
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ProviderOllamaConfig(BaseModel):
|
|
85
|
+
"""v2.0: Ollama local backend."""
|
|
86
|
+
enabled: bool = False
|
|
87
|
+
base_url: str = "http://localhost:11434"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class ProviderVLLMConfig(BaseModel):
|
|
91
|
+
"""v2.0: vLLM OpenAI-compatible endpoint."""
|
|
92
|
+
enabled: bool = False
|
|
93
|
+
base_url: str = "http://localhost:8000"
|
|
94
|
+
api_key: str = ""
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class ProviderCustomConfig(BaseModel):
|
|
98
|
+
"""v2.0: Custom OpenAI-compatible endpoint."""
|
|
99
|
+
enabled: bool = False
|
|
100
|
+
base_url: str = ""
|
|
101
|
+
api_key: str = ""
|
|
102
|
+
model_prefix_strip: str = ""
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class ProvidersConfig(BaseModel):
|
|
106
|
+
azure: ProviderAzureConfig = Field(default_factory=ProviderAzureConfig)
|
|
107
|
+
ollama: ProviderOllamaConfig = Field(default_factory=ProviderOllamaConfig)
|
|
108
|
+
vllm: ProviderVLLMConfig = Field(default_factory=ProviderVLLMConfig)
|
|
109
|
+
custom: ProviderCustomConfig = Field(default_factory=ProviderCustomConfig)
|
|
110
|
+
fallback_order: list[str] = Field(default_factory=lambda: [])
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class SandboxRoleConfig(BaseModel):
|
|
114
|
+
"""v2.0: per-role sandbox overrides."""
|
|
115
|
+
role: str = ""
|
|
116
|
+
max_tool_calls: int | None = None
|
|
117
|
+
allowed_tool_categories: list[str] | None = None
|
|
118
|
+
blocked_tool_categories: list[str] = Field(default_factory=list)
|
|
119
|
+
filesystem_write: bool = False
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class SandboxConfig(BaseModel):
|
|
123
|
+
"""v2.0: agent sandbox resource quotas."""
|
|
124
|
+
enabled: bool = True
|
|
125
|
+
default_max_memory_mb: int = 512
|
|
126
|
+
default_max_cpu_seconds: int = 60
|
|
127
|
+
default_max_tool_calls: int = 20
|
|
128
|
+
roles: list[SandboxRoleConfig] = Field(default_factory=list)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class ComplianceConfig(BaseModel):
|
|
132
|
+
"""v2.0: PII redaction and audit."""
|
|
133
|
+
pii_redaction: bool = True
|
|
134
|
+
pii_types: list[str] = Field(default_factory=lambda: ["EMAIL", "PHONE", "SSN", "CREDIT_CARD", "API_KEY"])
|
|
135
|
+
gdpr_mode: bool = False
|
|
136
|
+
audit_logging: bool = True
|
|
137
|
+
data_residency: str = "us"
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class NodesConfig(BaseModel):
|
|
141
|
+
"""v1.10: distributed node mode and RPC."""
|
|
142
|
+
mode: Literal["single", "distributed"] = "single"
|
|
143
|
+
role: Literal["controller", "worker", "hybrid"] = "hybrid"
|
|
144
|
+
run_id: str | None = None # shared run_id for distributed demo; None = generate (controller) or env (worker)
|
|
145
|
+
rpc_port: int = 7700
|
|
146
|
+
rpc_token: str | None = None
|
|
147
|
+
max_workers_per_node: int = 8
|
|
148
|
+
node_tags: list[str] = Field(default_factory=list)
|
|
149
|
+
controller_url: str = "http://localhost:7700"
|
|
150
|
+
heartbeat_interval_seconds: float = 10.0
|
|
151
|
+
task_claim_timeout_seconds: int = 120
|
|
152
|
+
deregister_stale_workers: bool = False # if False, workers are never removed from registry (only in-memory stats cleared)
|
|
153
|
+
claim_grant_wait_seconds: float = 15.0 # worker: max wait for TASK_CLAIM_GRANTED after claiming
|
|
154
|
+
task_execution_timeout_seconds: int = 90 # worker: fail task if agent.run exceeds this (0 = no limit)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class MCPServerConfig(BaseModel):
|
|
158
|
+
"""v1.10.5: MCP server connection config."""
|
|
159
|
+
name: str = ""
|
|
160
|
+
transport: Literal["stdio", "http", "sse"] = "stdio"
|
|
161
|
+
command: list[str] | None = None # stdio: e.g. ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
|
|
162
|
+
url: str | None = None # http/sse: e.g. "http://localhost:3000"
|
|
163
|
+
env: dict[str, str] = Field(default_factory=dict)
|
|
164
|
+
timeout_seconds: int = 30
|
|
165
|
+
auto_reconnect: bool = True
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class MCPConfig(BaseModel):
|
|
169
|
+
"""v1.10.5: MCP servers from [[mcp.servers]]."""
|
|
170
|
+
servers: list[MCPServerConfig] = Field(default_factory=list)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class A2AAgentConfig(BaseModel):
|
|
174
|
+
"""v1.10.5: External A2A agent config."""
|
|
175
|
+
name: str = ""
|
|
176
|
+
url: str = ""
|
|
177
|
+
auto_discover: bool = True # fetch AgentCard on startup, register skills as tools
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class A2AConfig(BaseModel):
|
|
181
|
+
"""v1.10.5: A2A agents and optional server exposure."""
|
|
182
|
+
agents: list[A2AAgentConfig] = Field(default_factory=list)
|
|
183
|
+
serve: bool = False # expose this devsper instance as A2A server
|
|
184
|
+
serve_port: int = 8080
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class HitlTriggerConfig(BaseModel):
|
|
188
|
+
"""v2.1: Single escalation trigger (e.g. cost_above, critic_score_below)."""
|
|
189
|
+
type: str = "confidence_below"
|
|
190
|
+
threshold: float | str = 0.5
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class HitlPolicyConfig(BaseModel):
|
|
194
|
+
"""v2.1: HITL policy with triggers and approvers."""
|
|
195
|
+
name: str = ""
|
|
196
|
+
on_timeout: Literal["auto_approve", "auto_reject", "escalate_further"] = "auto_approve"
|
|
197
|
+
timeout_seconds: int = 3600
|
|
198
|
+
approvers: list[str] = Field(default_factory=list)
|
|
199
|
+
triggers: list[HitlTriggerConfig] = Field(default_factory=list)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class HitlConfig(BaseModel):
|
|
203
|
+
"""v2.1: Human-in-the-loop escalation and approval."""
|
|
204
|
+
enabled: bool = False
|
|
205
|
+
policies: list[HitlPolicyConfig] = Field(default_factory=list)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class devsperConfigModel(BaseModel):
|
|
209
|
+
"""Full resolved configuration with Pydantic validation."""
|
|
210
|
+
|
|
211
|
+
swarm: SwarmConfig = Field(default_factory=SwarmConfig)
|
|
212
|
+
agents: AgentsConfig = Field(default_factory=AgentsConfig)
|
|
213
|
+
models: ModelsConfig = Field(default_factory=ModelsConfig)
|
|
214
|
+
memory: MemoryConfig = Field(default_factory=MemoryConfig)
|
|
215
|
+
knowledge: KnowledgeConfig = Field(default_factory=KnowledgeConfig)
|
|
216
|
+
tools: ToolsConfig = Field(default_factory=ToolsConfig)
|
|
217
|
+
telemetry: TelemetryConfig = Field(default_factory=TelemetryConfig)
|
|
218
|
+
cache: CacheConfig = Field(default_factory=CacheConfig)
|
|
219
|
+
bus: BusConfig = Field(default_factory=BusConfig)
|
|
220
|
+
nodes: NodesConfig = Field(default_factory=NodesConfig)
|
|
221
|
+
mcp: MCPConfig = Field(default_factory=MCPConfig)
|
|
222
|
+
a2a: A2AConfig = Field(default_factory=A2AConfig)
|
|
223
|
+
events_dir: str = ".devsper/events"
|
|
224
|
+
data_dir: str = ".devsper"
|
|
225
|
+
providers: ProvidersConfig = Field(default_factory=ProvidersConfig)
|
|
226
|
+
sandbox: SandboxConfig = Field(default_factory=SandboxConfig)
|
|
227
|
+
compliance: ComplianceConfig = Field(default_factory=ComplianceConfig)
|
|
228
|
+
hitl: HitlConfig = Field(default_factory=HitlConfig)
|
|
229
|
+
|
|
230
|
+
# Backward-compat aliases (property-style access from old devsperConfig)
|
|
231
|
+
@property
|
|
232
|
+
def worker_model(self) -> str:
|
|
233
|
+
return self.models.worker
|
|
234
|
+
|
|
235
|
+
@property
|
|
236
|
+
def planner_model(self) -> str:
|
|
237
|
+
return self.models.planner
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Secure credential store: OS keychain (keyring) only."""
|
|
2
|
+
|
|
3
|
+
from devsper.credentials.store import (
|
|
4
|
+
CredentialStore,
|
|
5
|
+
delete_credential,
|
|
6
|
+
get_credential,
|
|
7
|
+
inject_into_env,
|
|
8
|
+
list_credentials,
|
|
9
|
+
set_credential,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"get_credential",
|
|
14
|
+
"set_credential",
|
|
15
|
+
"delete_credential",
|
|
16
|
+
"list_credentials",
|
|
17
|
+
"inject_into_env",
|
|
18
|
+
"CredentialStore",
|
|
19
|
+
]
|