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,58 @@
1
+ """
2
+ Swarm visualization: produce a simple ASCII DAG of the scheduler graph.
3
+
4
+ Input: scheduler (or its graph). Output: ASCII DAG visualization.
5
+ """
6
+
7
+ from devsper.swarm.scheduler import Scheduler
8
+
9
+
10
+ def visualize_scheduler_dag(scheduler: Scheduler) -> str:
11
+ """
12
+ Create a simple ASCII DAG visualization of the scheduler's task graph.
13
+
14
+ Example:
15
+ task_1
16
+ |
17
+ task_2
18
+ |
19
+ task_3
20
+ / \\
21
+ task_4 task_5
22
+ """
23
+ graph = scheduler._graph
24
+ if graph.number_of_nodes() == 0:
25
+ return "(empty graph)"
26
+
27
+ try:
28
+ import networkx as nx
29
+ order = list(nx.topological_sort(graph))
30
+ except Exception:
31
+ order = list(graph.nodes())
32
+
33
+ roots = [n for n in order if graph.in_degree(n) == 0]
34
+ if not roots:
35
+ roots = [order[0]]
36
+
37
+ lines = []
38
+
39
+ def visit(node: str, print_name: bool) -> None:
40
+ if print_name:
41
+ lines.append(node)
42
+ succs = list(graph.successors(node))
43
+ if not succs:
44
+ return
45
+ if len(succs) == 1:
46
+ lines.append(" |")
47
+ lines.append(succs[0])
48
+ visit(succs[0], False)
49
+ else:
50
+ lines.append(" " + " / \\")
51
+ lines.append(" " + " ".join(succs))
52
+ for c in succs:
53
+ visit(c, False)
54
+
55
+ for r in roots:
56
+ visit(r, True)
57
+
58
+ return "\n".join(lines)
@@ -0,0 +1,13 @@
1
+ """Agent sandboxing: resource quotas and isolation (v2.0)."""
2
+
3
+ from devsper.sandbox.sandbox import (
4
+ AgentSandbox,
5
+ ResourceQuota,
6
+ SandboxQuotaExceeded,
7
+ )
8
+
9
+ __all__ = [
10
+ "AgentSandbox",
11
+ "ResourceQuota",
12
+ "SandboxQuotaExceeded",
13
+ ]
@@ -0,0 +1,161 @@
1
+ """
2
+ AgentSandbox: wraps agent execution with resource quotas and isolation.
3
+
4
+ Enforces: allowed_tool_categories, max_tool_calls, max_output_tokens;
5
+ tracks usage (wall time, tool calls, tokens).
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+ from typing import TYPE_CHECKING
10
+
11
+ from devsper.agents.agent import Agent, AgentRequest, AgentResponse
12
+
13
+ if TYPE_CHECKING:
14
+ from devsper.config.schema import SandboxConfig
15
+
16
+
17
+ @dataclass
18
+ class ResourceQuota:
19
+ """Limits and permissions for a sandboxed run."""
20
+ max_memory_mb: int = 512
21
+ max_cpu_seconds: int = 60
22
+ max_tool_calls: int = 20
23
+ max_output_tokens: int = 4096
24
+ allowed_tool_categories: list[str] | None = None # None = all
25
+ blocked_tool_categories: list[str] = field(default_factory=list)
26
+ network_access: bool = True
27
+ filesystem_write: bool = False
28
+
29
+
30
+ class SandboxQuotaExceeded(Exception):
31
+ """Raised when a quota limit is exceeded."""
32
+
33
+ def __init__(self, quota_type: str, limit: int | float, actual: int | float) -> None:
34
+ self.quota_type = quota_type
35
+ self.limit = limit
36
+ self.actual = actual
37
+ super().__init__(f"Sandbox quota exceeded: {quota_type} (limit={limit}, actual={actual})")
38
+
39
+
40
+ def _get_tool_categories(tool_name: str) -> list[str]:
41
+ """Return categories for a tool (from registry if available)."""
42
+ try:
43
+ from devsper.tools.registry import get
44
+ t = get(tool_name)
45
+ if t is not None and getattr(t, "category", None):
46
+ return [t.category]
47
+ except Exception:
48
+ pass
49
+ return []
50
+
51
+
52
+ def _filter_tools_by_quota(tool_names: list[str], quota: ResourceQuota) -> list[str]:
53
+ """Return tool names that are allowed by quota."""
54
+ if quota.allowed_tool_categories is None and not quota.blocked_tool_categories:
55
+ return list(tool_names)
56
+ out = []
57
+ for name in tool_names:
58
+ cats = _get_tool_categories(name)
59
+ if quota.blocked_tool_categories and any(c in quota.blocked_tool_categories for c in cats):
60
+ continue
61
+ if quota.allowed_tool_categories is not None and cats:
62
+ if not any(c in quota.allowed_tool_categories for c in cats):
63
+ continue
64
+ out.append(name)
65
+ return out
66
+
67
+
68
+ class AgentSandbox:
69
+ """Wraps agent execution with resource quotas. Use run(request, quota) -> AgentResponse."""
70
+
71
+ def __init__(self, agent: Agent) -> None:
72
+ self.agent = agent
73
+
74
+ def run(self, request: AgentRequest, quota: ResourceQuota) -> AgentResponse:
75
+ """
76
+ Run the agent with quota enforcement: filter tools, enforce max_tool_calls and max_output_tokens.
77
+ Tracks usage and includes it in AgentResponse (via agent's response; we add quota_usage if needed).
78
+ """
79
+ filtered_tools = _filter_tools_by_quota(request.tools, quota)
80
+ req = AgentRequest(
81
+ task=request.task,
82
+ memory_context=request.memory_context,
83
+ tools=filtered_tools,
84
+ model=request.model,
85
+ system_prompt=request.system_prompt,
86
+ prefetch_used=request.prefetch_used,
87
+ )
88
+ tool_call_count = [0]
89
+ max_tool_calls = quota.max_tool_calls
90
+ max_output_tokens = quota.max_output_tokens
91
+
92
+ from devsper.tools.tool_runner import run_tool as _run_tool_impl
93
+
94
+ def counting_run_tool(name: str, args: dict, task_type: str | None = None):
95
+ tool_call_count[0] += 1
96
+ if tool_call_count[0] > max_tool_calls:
97
+ raise SandboxQuotaExceeded("max_tool_calls", max_tool_calls, tool_call_count[0])
98
+ return _run_tool_impl(name, args, task_type=task_type)
99
+
100
+ try:
101
+ with _patch_tool_runner(counting_run_tool):
102
+ response = self.agent.run(req)
103
+ except SandboxQuotaExceeded:
104
+ raise
105
+
106
+ result = response.result or ""
107
+ if max_output_tokens and len(result) > max_output_tokens:
108
+ result = result[:max_output_tokens] + "\n\n[Output truncated: max_output_tokens exceeded.]"
109
+ return AgentResponse(
110
+ task_id=response.task_id,
111
+ result=result,
112
+ tools_called=response.tools_called,
113
+ broadcasts=response.broadcasts,
114
+ tokens_used=response.tokens_used,
115
+ duration_seconds=response.duration_seconds,
116
+ error=response.error,
117
+ success=response.success,
118
+ )
119
+
120
+
121
+ def get_quota_for_role(sandbox_config: "SandboxConfig", role: str | None) -> ResourceQuota:
122
+ """Build ResourceQuota for a role from sandbox config (defaults + role overrides)."""
123
+ role = (role or "").strip()
124
+ q = ResourceQuota(
125
+ max_memory_mb=sandbox_config.default_max_memory_mb,
126
+ max_cpu_seconds=sandbox_config.default_max_cpu_seconds,
127
+ max_tool_calls=sandbox_config.default_max_tool_calls,
128
+ max_output_tokens=4096,
129
+ )
130
+ for r in sandbox_config.roles or []:
131
+ if (r.role or "").strip() == role:
132
+ if r.max_tool_calls is not None:
133
+ q.max_tool_calls = r.max_tool_calls
134
+ if r.allowed_tool_categories is not None:
135
+ q.allowed_tool_categories = r.allowed_tool_categories
136
+ if r.blocked_tool_categories:
137
+ q.blocked_tool_categories = list(r.blocked_tool_categories)
138
+ if r.filesystem_write:
139
+ q.filesystem_write = True
140
+ break
141
+ return q
142
+
143
+
144
+ class _patch_tool_runner:
145
+ """Temporarily patch the tool runner so we can count calls."""
146
+
147
+ def __init__(self, replacement):
148
+ self.replacement = replacement
149
+ self.orig = None
150
+
151
+ def __enter__(self):
152
+ import devsper.tools.tool_runner as tr
153
+ self.orig = getattr(tr, "run_tool", None)
154
+ tr.run_tool = self.replacement
155
+ return self
156
+
157
+ def __exit__(self, *args):
158
+ import devsper.tools.tool_runner as tr
159
+ if self.orig is not None:
160
+ tr.run_tool = self.orig
161
+ return False
@@ -0,0 +1,65 @@
1
+ """
2
+ Scheduler checkpointer: write snapshot to disk periodically for resume and node sync.
3
+
4
+ v1.9: Writes to {events_dir}/{run_id}.checkpoint.json. Atomic write. Restore for resume.
5
+ """
6
+
7
+ import json
8
+ import os
9
+
10
+ from devsper.swarm.scheduler import Scheduler
11
+ from devsper.types.exceptions import CheckpointNotFoundError
12
+
13
+
14
+ class SchedulerCheckpointer:
15
+ """Writes scheduler.snapshot() to disk periodically. Atomic write. Restore by run_id."""
16
+
17
+ def __init__(
18
+ self,
19
+ events_dir: str = ".devsper/events",
20
+ interval_tasks: int = 10,
21
+ ) -> None:
22
+ self.events_dir = events_dir
23
+ self.interval_tasks = interval_tasks
24
+ self._completions_since_write = 0
25
+
26
+ def _path(self, run_id: str) -> str:
27
+ return os.path.join(self.events_dir, f"{run_id}.checkpoint.json")
28
+
29
+ def _write_atomic(self, path: str, data: dict) -> None:
30
+ tmp = path + ".tmp"
31
+ os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
32
+ with open(tmp, "w", encoding="utf-8") as f:
33
+ json.dump(data, f, indent=0)
34
+ os.replace(tmp, path)
35
+
36
+ def on_task_completed(self, scheduler: Scheduler) -> None:
37
+ """Call after each task completion; writes checkpoint every interval_tasks."""
38
+ self._completions_since_write += 1
39
+ if self._completions_since_write >= self.interval_tasks:
40
+ self._completions_since_write = 0
41
+ self.write_now(scheduler)
42
+
43
+ def write_now(self, scheduler: Scheduler) -> None:
44
+ """Write checkpoint once."""
45
+ run_id = getattr(scheduler, "run_id", "")
46
+ if not run_id:
47
+ return
48
+ path = self._path(run_id)
49
+ self._write_atomic(path, scheduler.snapshot())
50
+
51
+ def restore_latest(self, run_id: str) -> Scheduler | None:
52
+ """Load checkpoint file; return restored Scheduler or None if not found."""
53
+ path = self._path(run_id)
54
+ if not os.path.isfile(path):
55
+ return None
56
+ with open(path, "r", encoding="utf-8") as f:
57
+ data = json.load(f)
58
+ return Scheduler.restore(data)
59
+
60
+ def restore_or_raise(self, run_id: str) -> Scheduler:
61
+ """Restore scheduler or raise CheckpointNotFoundError."""
62
+ s = self.restore_latest(run_id)
63
+ if s is None:
64
+ raise CheckpointNotFoundError(f"No checkpoint found for run_id: {run_id!r}")
65
+ return s