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,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
+ )
@@ -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
+ ]