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,88 @@
1
+ """
2
+ Self-optimizing swarm: adapt execution strategy in real time.
3
+
4
+ Detects slow tasks, failed tasks, and spawns alternative subtasks.
5
+ The adaptive planner can inject new tasks into the scheduler DAG.
6
+ """
7
+
8
+ from datetime import datetime, timezone
9
+ from devsper.types.task import Task, TaskStatus
10
+ from devsper.swarm.scheduler import Scheduler
11
+
12
+
13
+ def detect_slow_tasks(
14
+ scheduler: Scheduler,
15
+ task_start_times: dict[str, datetime],
16
+ threshold_seconds: float = 60.0,
17
+ *,
18
+ now: datetime | None = None,
19
+ ) -> list[str]:
20
+ """
21
+ Return task ids that are still RUNNING and have been running longer than threshold_seconds.
22
+ task_start_times maps task_id -> start time (e.g. when task was set to RUNNING).
23
+ """
24
+ now = now or datetime.now(timezone.utc)
25
+ slow: list[str] = []
26
+ for task_id, task in scheduler._tasks.items():
27
+ if task.status != TaskStatus.RUNNING:
28
+ continue
29
+ start = task_start_times.get(task_id)
30
+ if start is None:
31
+ continue
32
+ elapsed = (now - start).total_seconds()
33
+ if elapsed >= threshold_seconds:
34
+ slow.append(task_id)
35
+ return slow
36
+
37
+
38
+ def detect_failed_tasks(scheduler: Scheduler) -> list[str]:
39
+ """Return task ids that have status FAILED."""
40
+ return [
41
+ task_id
42
+ for task_id, task in scheduler._tasks.items()
43
+ if task.status == TaskStatus.FAILED
44
+ ]
45
+
46
+
47
+ def suggest_alternative_tasks(
48
+ task: Task,
49
+ planner: object,
50
+ context: list[Task] | None = None,
51
+ ) -> list[Task]:
52
+ """
53
+ Ask the planner to suggest alternative follow-up tasks (e.g. after failure or timeout).
54
+ Returns new tasks that depend on the same dependencies as the given task, so they
55
+ can be injected as alternatives. The planner's expand_tasks is used with a synthetic
56
+ "failed" result to get alternatives.
57
+ """
58
+ if not hasattr(planner, "expand_tasks"):
59
+ return []
60
+ # Create a minimal completed task with a note that original failed/timed out
61
+ synthetic = Task(
62
+ id=task.id + "_alt",
63
+ description=f"(Alternative to failed/slow task) {task.description}",
64
+ dependencies=task.dependencies.copy(),
65
+ status=TaskStatus.COMPLETED,
66
+ result="[Previous attempt failed or timed out. Suggest alternative approach.]",
67
+ )
68
+ return planner.expand_tasks(synthetic, context=context)
69
+
70
+
71
+ def create_alternative_subtasks_for_failed(
72
+ failed_task: Task,
73
+ planner: object,
74
+ scheduler: Scheduler,
75
+ ) -> list[Task]:
76
+ """
77
+ Generate alternative tasks for a failed task and return them (caller should
78
+ add to scheduler via scheduler.add_tasks). New tasks depend on the same
79
+ dependencies as the failed task so they can run in place of it.
80
+ """
81
+ new_tasks = suggest_alternative_tasks(failed_task, planner)
82
+ if not new_tasks:
83
+ return []
84
+ # Ensure new tasks depend on same deps so they are runnable when failed_task's deps are done
85
+ for t in new_tasks:
86
+ if t.dependencies != failed_task.dependencies:
87
+ t.dependencies = failed_task.dependencies.copy()
88
+ return new_tasks
@@ -0,0 +1,19 @@
1
+ """
2
+ Run analysis: build RunReport from events, cost estimation, LLM analysis, Rich formatting.
3
+ """
4
+
5
+ from devsper.intelligence.analysis.run_report import (
6
+ RunReport,
7
+ TaskSummary,
8
+ build_report_from_events,
9
+ )
10
+ from devsper.intelligence.analysis.analyzer import analyze
11
+ from devsper.intelligence.analysis.formatter import print_run_report
12
+
13
+ __all__ = [
14
+ "RunReport",
15
+ "TaskSummary",
16
+ "build_report_from_events",
17
+ "analyze",
18
+ "print_run_report",
19
+ ]
@@ -0,0 +1,71 @@
1
+ """
2
+ LLM-powered plain-English analysis of a RunReport.
3
+ """
4
+
5
+ from typing import Callable
6
+
7
+ from devsper.types.task import TaskStatus
8
+ from devsper.intelligence.analysis.run_report import RunReport
9
+
10
+
11
+ def analyze(
12
+ report: RunReport,
13
+ worker_model: str,
14
+ stream_callback: Callable[[str], None] | None = None,
15
+ ) -> str:
16
+ """
17
+ Call the LLM with a structured prompt; stream the response for progressive CLI display
18
+ when stream_callback is provided. On error return "Analysis unavailable."
19
+ """
20
+ try:
21
+ from devsper.utils.models import generate
22
+ except ImportError:
23
+ return "Analysis unavailable."
24
+
25
+ bottleneck_desc = ""
26
+ if report.bottleneck_task_id:
27
+ for t in report.tasks:
28
+ if t.task_id == report.bottleneck_task_id:
29
+ bottleneck_desc = f"{t.description[:80]} ({t.duration_seconds:.1f}s)"
30
+ break
31
+ if not bottleneck_desc:
32
+ bottleneck_desc = report.bottleneck_task_id
33
+
34
+ failed_block = []
35
+ for t in report.tasks:
36
+ if t.status == TaskStatus.FAILED:
37
+ failed_block.append(
38
+ f"- {t.description[:100]}: error={t.error or 'unknown'}; tools_that_failed={t.tool_failures or 'none'}"
39
+ )
40
+ failed_text = "\n".join(failed_block) if failed_block else "(none)"
41
+
42
+ user_content = f"""Run ID: {report.run_id}
43
+ Root task: {report.root_task[:200]}
44
+ Duration: {report.total_duration_seconds:.1f}s
45
+ Tasks: {report.completed_tasks}/{report.total_tasks} completed, {report.failed_tasks} failed
46
+ Bottleneck: {bottleneck_desc}
47
+ Failed tasks:
48
+ {failed_text}
49
+ Tool success rate: {report.tool_success_rate:.1f}%
50
+ Peak parallelism: {report.peak_parallelism}"""
51
+
52
+ system_content = """You are analyzing a devsper swarm run. Be concise, specific, and actionable.
53
+ Focus on: what failed and why, what was slow, what could be improved.
54
+ Do not summarize what succeeded unless it's relevant to failures.
55
+ Max 200 words."""
56
+
57
+ prompt = f"{system_content}\n\n---\n\n{user_content}"
58
+
59
+ try:
60
+ out = generate(worker_model, prompt, stream=bool(stream_callback))
61
+ if isinstance(out, str):
62
+ return out.strip() or "Analysis unavailable."
63
+ chunks = []
64
+ for chunk in out:
65
+ if chunk:
66
+ chunks.append(chunk)
67
+ if stream_callback:
68
+ stream_callback(chunk)
69
+ return "".join(chunks).strip() or "Analysis unavailable."
70
+ except Exception:
71
+ return "Analysis unavailable."
@@ -0,0 +1,66 @@
1
+ """
2
+ Cost estimation from token counts and model pricing.
3
+ """
4
+
5
+ from devsper.intelligence.analysis.run_report import TaskSummary
6
+
7
+
8
+ MODEL_PRICING = {
9
+ # (input_per_1k_tokens, output_per_1k_tokens) in USD
10
+ "gpt-4o": (0.0025, 0.010),
11
+ "gpt-4o-mini": (0.000150, 0.000600),
12
+ "claude-opus-4": (0.015, 0.075),
13
+ "claude-sonnet-4": (0.003, 0.015),
14
+ "claude-haiku-4": (0.00025, 0.00125),
15
+ "gemini-1.5-pro": (0.00125, 0.005),
16
+ "gemini-1.5-flash": (0.000075, 0.000300),
17
+ }
18
+
19
+
20
+ class CostEstimator:
21
+ """Estimate run cost from task token usage and model pricing."""
22
+
23
+ @staticmethod
24
+ def estimate(
25
+ tasks: list[TaskSummary],
26
+ models_used: list[str],
27
+ ) -> float | None:
28
+ """
29
+ Compute total USD cost from token counts and model pricing.
30
+ Returns None if token counts are not available (don't guess).
31
+ """
32
+ if not tasks and not models_used:
33
+ return None
34
+ total = 0.0
35
+ any_tokens = False
36
+ for t in tasks:
37
+ if t.tokens_used is None:
38
+ continue
39
+ any_tokens = True
40
+ model = models_used[0] if models_used else None
41
+ if not model:
42
+ return None
43
+ pricing = MODEL_PRICING.get(model)
44
+ if not pricing:
45
+ # Try prefix match for model variants
46
+ for key in MODEL_PRICING:
47
+ if model.startswith(key) or key in model:
48
+ pricing = MODEL_PRICING[key]
49
+ break
50
+ if not pricing:
51
+ return None
52
+ input_per_1k, output_per_1k = pricing
53
+ # Assume 50/50 split if we only have total; task summary has tokens_used as single int
54
+ inp = t.tokens_used // 2
55
+ out = t.tokens_used - inp
56
+ total += (inp / 1000.0) * input_per_1k + (out / 1000.0) * output_per_1k
57
+ if not any_tokens:
58
+ return None
59
+ return round(total, 4)
60
+
61
+ @staticmethod
62
+ def format_cost(usd: float | None) -> str:
63
+ """Return '$0.0023' or 'unknown'."""
64
+ if usd is None:
65
+ return "unknown"
66
+ return f"${usd:.4f}"
@@ -0,0 +1,103 @@
1
+ """
2
+ Rich CLI output for RunReport.
3
+ """
4
+
5
+ from rich.console import Console
6
+ from rich.panel import Panel
7
+ from rich.table import Table
8
+
9
+ from devsper.types.task import TaskStatus
10
+ from devsper.intelligence.analysis.run_report import RunReport
11
+ from devsper.intelligence.analysis.cost_estimator import CostEstimator
12
+
13
+
14
+ def print_run_report(report: RunReport, console: Console) -> None:
15
+ """Print report sections: header, overview, timeline table, critical path, tool usage, analysis panel, footer."""
16
+ # 1. Header
17
+ console.print()
18
+ console.print(f"[bold cyan]Run[/] [bold]{report.run_id}[/]")
19
+ console.print(f" Root task: [dim]{report.root_task[:120]}{'…' if len(report.root_task) > 120 else ''}[/]")
20
+ console.print(f" Strategy: [dim]{report.strategy}[/] Started: [dim]{report.started_at}[/] Finished: [dim]{report.finished_at}[/]")
21
+ console.print()
22
+
23
+ # 2. Overview panel
24
+ cost_str = CostEstimator.format_cost(report.estimated_cost_usd)
25
+ overview = (
26
+ f"Duration: [bold]{report.total_duration_seconds:.1f}s[/] "
27
+ f"Tasks: [green]{report.completed_tasks}[/]/[bold]{report.total_tasks}[/] completed, "
28
+ f"[red]{report.failed_tasks}[/] failed "
29
+ f"Cost: [dim]{cost_str}[/] "
30
+ f"Models: [dim]{', '.join(report.models_used) or '—'}[/]"
31
+ )
32
+ console.print(Panel(overview, title="Overview", border_style="dim"))
33
+ console.print()
34
+
35
+ # 3. Timeline table
36
+ table = Table(title="Timeline")
37
+ table.add_column("Task", style="dim", max_width=50, overflow="fold")
38
+ table.add_column("Role", style="dim", width=10)
39
+ table.add_column("Status", width=12)
40
+ table.add_column("Duration", justify="right", width=10)
41
+ table.add_column("Tools", style="dim", max_width=30, overflow="fold")
42
+ bottleneck_id = report.bottleneck_task_id
43
+ for t in report.tasks:
44
+ desc = (t.description or t.task_id)[:48]
45
+ role = (t.role or "—")
46
+ if t.status == TaskStatus.COMPLETED:
47
+ status = "[green]completed[/]"
48
+ elif t.status == TaskStatus.FAILED:
49
+ status = "[red]failed[/]"
50
+ elif t.status == TaskStatus.PENDING:
51
+ status = "[dim]skipped[/]"
52
+ else:
53
+ status = "[yellow]running[/]"
54
+ dur = f"{t.duration_seconds:.1f}s"
55
+ tools = ", ".join(t.tools_used[:5]) if t.tools_used else "—"
56
+ if len(t.tools_used) > 5:
57
+ tools += "…"
58
+ row_style = ""
59
+ if t.task_id == bottleneck_id:
60
+ row_style = "bold"
61
+ status = "[bold]⚡ bottleneck[/]"
62
+ elif t.status == TaskStatus.FAILED:
63
+ row_style = "red"
64
+ elif t.status == TaskStatus.PENDING:
65
+ row_style = "dim"
66
+ table.add_row(desc, role, status, dur, tools, style=row_style)
67
+ console.print(table)
68
+ console.print()
69
+
70
+ # 4. Critical path
71
+ if report.critical_path:
72
+ path_parts = [
73
+ tid + (" [bold](bottleneck)[/]" if tid == report.bottleneck_task_id else "")
74
+ for tid in report.critical_path
75
+ ]
76
+ path_str = " → ".join(path_parts)
77
+ else:
78
+ path_str = "(none)"
79
+ console.print("[bold]Critical path:[/] [dim]" + path_str)
80
+ console.print()
81
+
82
+ # 5. Tool usage (aggregate)
83
+ tool_table = Table(title="Tool usage")
84
+ tool_table.add_column("Metric", style="dim")
85
+ tool_table.add_column("Value", justify="right")
86
+ tool_table.add_row("Tools called", str(report.tools_called))
87
+ tool_table.add_row("Success rate", f"{report.tool_success_rate:.1f}%")
88
+ console.print(tool_table)
89
+ console.print()
90
+
91
+ # 6. Plain-English Analysis (only if already set; CLI streams and prints after)
92
+ if report.plain_english_analysis:
93
+ console.print(
94
+ Panel(
95
+ report.plain_english_analysis,
96
+ title="Plain-English Analysis",
97
+ border_style="dim",
98
+ )
99
+ )
100
+ console.print()
101
+
102
+ # 7. Footer (caller may print again after streaming analysis)
103
+ console.print(f"[dim]Cost estimate: {CostEstimator.format_cost(report.estimated_cost_usd)}[/]")