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
devsper/tui/app.py ADDED
@@ -0,0 +1,395 @@
1
+ """
2
+ devsper TUI: prompt + output. Enter or r to run. Esc unfocuses input. q quit.
3
+ """
4
+
5
+ import os
6
+ import threading
7
+
8
+ from textual.app import App, ComposeResult
9
+ from textual.binding import Binding
10
+ from textual.widgets import Footer, Input
11
+
12
+ from devsper.tui.dashboard_screen import DashboardScreen
13
+ from devsper.tui.layout import devsperLayout
14
+
15
+
16
+ class devsperTUI(App[None]):
17
+ """Main screen: prompt + output. Run shows loading then result."""
18
+
19
+ TITLE = "devsper"
20
+ SUB_TITLE = "Distributed AI Swarm Runtime"
21
+
22
+ BINDINGS = [
23
+ Binding("r", "run_swarm", "Run", show=True),
24
+ Binding("d", "dashboard", "Dashboard", show=True),
25
+ Binding("p", "toggle_pause", "Pause", show=True),
26
+ Binding("i", "inject_note", "Inject", show=True),
27
+ Binding("escape", "unfocus_input", "Unfocus input", show=True),
28
+ Binding("o", "focus_output", "Output", show=True),
29
+ Binding("q", "quit", "Quit", show=True),
30
+ ]
31
+
32
+ CSS = """
33
+ /* Compact branding */
34
+ #branding {
35
+ height: auto;
36
+ padding: 0 2;
37
+ text-align: center;
38
+ }
39
+ #logo-line {
40
+ color: #6EE7B7;
41
+ text-style: bold;
42
+ }
43
+ /* Prompt box — full border so box is closed */
44
+ #prompt-box {
45
+ border: heavy #6EE7B7;
46
+ padding: 1 2;
47
+ margin: 0 2 0 2;
48
+ height: auto;
49
+ background: #0F172A;
50
+ }
51
+ #prompt-input {
52
+ border: none;
53
+ background: transparent;
54
+ padding: 0;
55
+ margin: 0;
56
+ width: 100%;
57
+ }
58
+ #action-hints {
59
+ color: #64748b;
60
+ padding: 0 2 1 2;
61
+ text-align: center;
62
+ }
63
+ /* Response area — full border, takes rest of screen */
64
+ #output-container {
65
+ height: 1fr;
66
+ min-height: 8;
67
+ border: heavy #6EE7B7;
68
+ padding: 1 2;
69
+ margin: 0 2 1 2;
70
+ }
71
+ .output-title {
72
+ text-style: bold;
73
+ color: #6EE7B7;
74
+ margin-bottom: 1;
75
+ }
76
+ #results-view {
77
+ scrollbar-size: 1 1;
78
+ overflow-y: auto;
79
+ height: 1fr;
80
+ }
81
+ """
82
+
83
+ def __init__(self, events_folder: str = ".devsper/events", *args, **kwargs) -> None:
84
+ super().__init__(*args, **kwargs)
85
+ self._events_folder = events_folder
86
+ self._event_log_path: str | None = None
87
+ self._last_scheduler = None
88
+ self._last_reasoning_store = None
89
+ self._run_thread: threading.Thread | None = None
90
+ self._last_prompt = ""
91
+ self._loading_timer = None
92
+ self._current_swarm = None
93
+ self._paused = False
94
+ self._default_subtitle = "Distributed AI Swarm Runtime"
95
+
96
+ def compose(self) -> ComposeResult:
97
+ yield devsperLayout()
98
+ yield Footer()
99
+
100
+ def on_mount(self) -> None:
101
+ try:
102
+ self.set_focus(self.query_one("#prompt-input"))
103
+ except Exception:
104
+ pass
105
+
106
+ def _get_results_view(self):
107
+ return self.query_one("#results-view")
108
+
109
+ def _run_swarm_worker(self, prompt: str) -> None:
110
+ """Run swarm in background thread."""
111
+ try:
112
+ from devsper.config import get_config
113
+ from devsper.utils.event_logger import EventLog
114
+ from devsper.swarm.swarm import Swarm
115
+ from devsper.memory.memory_router import MemoryRouter
116
+ from devsper.memory.memory_store import get_default_store
117
+ from devsper.memory.memory_index import MemoryIndex
118
+
119
+ cfg = get_config()
120
+ event_log = EventLog(events_folder_path=self._events_folder)
121
+ self._event_log_path = event_log.log_path
122
+ memory_router = MemoryRouter(
123
+ store=get_default_store(),
124
+ index=MemoryIndex(get_default_store()),
125
+ top_k=5,
126
+ )
127
+ swarm = Swarm(
128
+ worker_count=2,
129
+ worker_model=cfg.worker_model,
130
+ planner_model=cfg.planner_model,
131
+ event_log=event_log,
132
+ memory_router=memory_router,
133
+ use_tools=True,
134
+ )
135
+ self._current_swarm = swarm
136
+ swarm.run(prompt)
137
+ self._current_swarm = None
138
+ self._last_scheduler = swarm._last_scheduler
139
+ self._last_reasoning_store = getattr(swarm, "_last_reasoning_store", None)
140
+ self.call_from_thread(self._on_swarm_finished)
141
+ except Exception as err:
142
+ msg = str(err)
143
+ self.call_from_thread(lambda: self._on_swarm_error(msg))
144
+
145
+ def _on_swarm_finished(self) -> None:
146
+ self._update_ui_after_run()
147
+
148
+ def _on_swarm_error(self, msg: str) -> None:
149
+ self._run_thread = None
150
+ self._stop_loading_timer()
151
+ try:
152
+ rv = self._get_results_view()
153
+ if rv is not None and hasattr(rv, "set_loading"):
154
+ rv.set_loading(False)
155
+ except Exception:
156
+ pass
157
+ self.notify(f"Swarm error: {msg}", severity="error")
158
+
159
+ def _update_ui_after_run(self) -> None:
160
+ self._run_thread = None
161
+ self._stop_loading_timer()
162
+ try:
163
+ rv = self._get_results_view()
164
+ if rv is not None and hasattr(rv, "set_loading"):
165
+ rv.set_loading(False)
166
+ if rv is None or not hasattr(rv, "set_exchange"):
167
+ return
168
+ response = ""
169
+ if self._last_scheduler is not None:
170
+ completed = self._last_scheduler.get_completed_tasks()
171
+ if completed:
172
+ last = completed[-1]
173
+ response = getattr(last, "result", None) or ""
174
+ if len(completed) > 1 and not response.strip():
175
+ response = "\n\n".join(
176
+ getattr(t, "result", "") or "" for t in completed
177
+ )
178
+ rv.set_exchange(self._last_prompt, response)
179
+ except Exception:
180
+ pass
181
+ self.notify("Done.", severity="information")
182
+
183
+ def _read_step_status(self) -> str:
184
+ """Read event log and return a friendly, sequential step status for the current run."""
185
+ path = getattr(self, "_event_log_path", None)
186
+ if not path or not os.path.isfile(path):
187
+ return "Starting…"
188
+ events = []
189
+ try:
190
+ from devsper.types.event import Event
191
+
192
+ with open(path, "r") as f:
193
+ for line in f:
194
+ line = line.strip()
195
+ if not line:
196
+ continue
197
+ try:
198
+ events.append(Event.model_validate_json(line))
199
+ except Exception:
200
+ continue
201
+ except Exception:
202
+ return "Running…"
203
+ if not events:
204
+ return "Starting…"
205
+
206
+ # task_id → description so the UI can label each step
207
+ task_descriptions: dict[str, str] = {}
208
+ for e in events:
209
+ if getattr(e.type, "value", None) != "task_created":
210
+ continue
211
+ p = e.payload or {}
212
+ tid = p.get("task_id")
213
+ desc = p.get("description")
214
+ if tid and desc:
215
+ task_descriptions[tid] = (desc or "").strip()
216
+
217
+ def _truncate(s: str, max_len: int = 48) -> str:
218
+ s = (s or "").strip()
219
+ if len(s) <= max_len:
220
+ return s
221
+ return s[: max_len - 1].rstrip() + "…"
222
+
223
+ last = events[-1]
224
+ ev_type = getattr(last.type, "value", str(last.type))
225
+ payload = last.payload or {}
226
+ task_id = (payload.get("task_id") or "").strip()
227
+ desc = task_descriptions.get(task_id) if task_id else None
228
+ total_tasks = sum(1 for e in events if getattr(e.type, "value", None) == "task_created")
229
+ completed = sum(1 for e in events if getattr(e.type, "value", None) == "task_completed")
230
+ current_step = completed + 1 if ev_type in ("agent_started", "task_started") else completed
231
+
232
+ if ev_type == "swarm_started":
233
+ return "Starting…"
234
+ if ev_type == "planner_started":
235
+ return "Planning your request…"
236
+ if ev_type == "task_created":
237
+ return f"Planned {total_tasks} step(s)…"
238
+ if ev_type == "planner_finished":
239
+ n = payload.get("subtask_count", total_tasks) or total_tasks
240
+ return f"Ready. Executing step 1 of {n}…"
241
+ if ev_type == "executor_started":
242
+ if total_tasks > 0:
243
+ return f"Executing step 1 of {total_tasks}…"
244
+ return "Executing…"
245
+ if ev_type in ("agent_started", "task_started"):
246
+ if total_tasks > 0 and current_step <= total_tasks:
247
+ step_label = f"Step {current_step} of {total_tasks}: "
248
+ else:
249
+ step_label = ""
250
+ if desc:
251
+ return step_label + _truncate(desc)
252
+ return (step_label or "Working on task…").rstrip(": ") or "Working on task…"
253
+ if ev_type in ("task_completed", "agent_finished"):
254
+ if total_tasks > 0:
255
+ if completed < total_tasks:
256
+ next_n = completed + 1
257
+ return f"Finished step {completed} of {total_tasks}. Executing step {next_n}…"
258
+ return f"Finished step {completed} of {total_tasks}. Assembling result…"
259
+ return "Finished. Assembling result…"
260
+ if ev_type == "executor_finished":
261
+ return "Assembling final result…"
262
+ if ev_type == "swarm_finished":
263
+ return "Done. Here’s your result."
264
+ return "Running…"
265
+
266
+ def _start_loading_timer(self) -> None:
267
+ """Tick spinner and update step status from event log."""
268
+ self._stop_loading_timer()
269
+
270
+ def tick() -> None:
271
+ if not (self._run_thread and self._run_thread.is_alive()):
272
+ self._stop_loading_timer()
273
+ return
274
+ try:
275
+ rv = self._get_results_view()
276
+ if rv is not None:
277
+ step = self._read_step_status()
278
+ if hasattr(rv, "set_loading"):
279
+ rv.set_loading(True, step)
280
+ if hasattr(rv, "tick_loading"):
281
+ rv.tick_loading()
282
+ except Exception:
283
+ pass
284
+
285
+ self._loading_timer = self.set_interval(0.25, tick)
286
+
287
+ def _stop_loading_timer(self) -> None:
288
+ if getattr(self, "_loading_timer", None) is not None:
289
+ try:
290
+ self._loading_timer.stop()
291
+ except Exception:
292
+ pass
293
+ self._loading_timer = None
294
+
295
+ def _get_prompt_from_input(self) -> str:
296
+ try:
297
+ inp = self.query_one("#prompt-input", Input)
298
+ val = (inp.value or "").strip()
299
+ if val:
300
+ return val
301
+ except Exception:
302
+ pass
303
+ return "Summarize the concept of swarm intelligence in one paragraph."
304
+
305
+ def _start_swarm_run(self, prompt: str) -> None:
306
+ """Start swarm with the given prompt (call only when not already running)."""
307
+ self._last_prompt = (prompt or "").strip()
308
+ try:
309
+ rv = self._get_results_view()
310
+ if rv is not None and hasattr(rv, "set_loading"):
311
+ rv.set_loading(True, "Starting…")
312
+ except Exception:
313
+ pass
314
+ self._run_thread = threading.Thread(
315
+ target=self._run_swarm_worker, args=(prompt,), daemon=True
316
+ )
317
+ self._run_thread.start()
318
+ self._start_loading_timer()
319
+
320
+ def action_run_swarm(self) -> None:
321
+ """Run swarm with prompt from input (or default). Enter or r to run."""
322
+ if self._run_thread and self._run_thread.is_alive():
323
+ self.notify("Wait for current run to finish.", severity="warning")
324
+ return
325
+ prompt = self._get_prompt_from_input()
326
+ self._start_swarm_run(prompt)
327
+
328
+ def on_input_submitted(self, event: Input.Submitted) -> None:
329
+ """Run swarm when user presses Enter in the prompt input."""
330
+ if event.input.id != "prompt-input":
331
+ return
332
+ if self._run_thread and self._run_thread.is_alive():
333
+ self.notify("Wait for current run to finish.", severity="warning")
334
+ return
335
+ prompt = (event.input.value or "").strip()
336
+ if not prompt:
337
+ self.notify("Type a task above, then Enter or r to run.", severity="warning")
338
+ return
339
+ self._start_swarm_run(prompt)
340
+
341
+ def action_focus_output(self) -> None:
342
+ try:
343
+ self.set_focus(self.query_one("#results-view"))
344
+ except Exception:
345
+ pass
346
+
347
+ def action_unfocus_input(self) -> None:
348
+ """Move focus off the input so r / q work. Press Esc when stuck in the input."""
349
+ try:
350
+ focused = self.focused
351
+ if focused is not None and getattr(focused, "id", None) == "prompt-input":
352
+ out = self.query_one("#results-view")
353
+ if out.can_focus:
354
+ self.set_focus(out)
355
+ except Exception:
356
+ pass
357
+
358
+ def action_dashboard(self) -> None:
359
+ """Open dashboard screen (tasks, swarm graph, memory, logs)."""
360
+ self.push_screen(
361
+ DashboardScreen(
362
+ app_ref=self,
363
+ event_log_path=getattr(self, "_event_log_path", None),
364
+ )
365
+ )
366
+
367
+ def action_toggle_pause(self) -> None:
368
+ """Toggle pause/resume for the current swarm run."""
369
+ swarm = getattr(self, "_current_swarm", None)
370
+ if swarm is None:
371
+ self.notify("No run in progress.", severity="warning")
372
+ return
373
+ self._paused = not self._paused
374
+ if self._paused:
375
+ swarm.pause()
376
+ self.sub_title = "[yellow]⏸ PAUSED[/]"
377
+ self.notify("Paused: current tasks will finish, no new tasks start.", severity="information")
378
+ else:
379
+ swarm.resume()
380
+ self.sub_title = self._default_subtitle
381
+ self.notify("Resumed.", severity="information")
382
+
383
+ def action_inject_note(self) -> None:
384
+ """Open overlay to inject a note to the swarm (stored as high-priority memory)."""
385
+ from devsper.tui.inject_screen import InjectScreen
386
+ self.push_screen(InjectScreen())
387
+
388
+ def action_quit(self) -> None:
389
+ self.exit()
390
+
391
+
392
+ def run_tui(events_folder: str = ".devsper/events") -> None:
393
+ """Entry point to run the TUI."""
394
+ app = devsperTUI(events_folder=events_folder)
395
+ app.run()
@@ -0,0 +1,290 @@
1
+ """
2
+ Dashboard screen: Tasks, Swarm Graph, Memory, Logs.
3
+
4
+ Shown when user presses `d`; Esc or q to return to main (prompt + output) view.
5
+ """
6
+
7
+ from textual.app import ComposeResult
8
+ from textual.containers import Container, Horizontal, Vertical
9
+ from textual.screen import Screen
10
+ from textual.widgets import Static
11
+
12
+ from devsper.tui.task_view import TaskView
13
+ from devsper.tui.task_detail_screen import TaskDetailScreen
14
+ from devsper.tui.swarm_view import SwarmView
15
+ from devsper.tui.memory_view import MemoryView
16
+ from devsper.tui.logs_view import LogsView
17
+ from devsper.tui.activity_feed_view import ActivityFeedView
18
+ from devsper.tui.knowledge_graph_view import KnowledgeGraphView
19
+ from devsper.tui.performance_view import PerformanceView
20
+ from devsper.tui.reasoning_graph_view import ReasoningGraphView
21
+ from devsper.tui.agent_role_view import AgentRoleActivityView
22
+ from devsper.tui.adaptive_tasks_view import AdaptiveTasksView
23
+ from devsper.tui.dev_view import DevView
24
+
25
+
26
+ class DashboardScreen(Screen[None]):
27
+ """Full-screen dashboard: tasks, swarm graph, memory, logs. Esc to close."""
28
+
29
+ BINDINGS = [
30
+ ("escape", "back", "Back to chat"),
31
+ ("q", "back", "Back to chat"),
32
+ ("enter", "open_task_detail", "Task detail"),
33
+ ]
34
+
35
+ CSS = """
36
+ #dashboard-container {
37
+ height: 100%;
38
+ padding: 0 2 1 2;
39
+ layout: vertical;
40
+ }
41
+ #dashboard-header {
42
+ color: #6EE7B7;
43
+ text-style: bold;
44
+ padding: 1 2;
45
+ margin-bottom: 1;
46
+ border: heavy #6EE7B7;
47
+ }
48
+ #dashboard-top {
49
+ height: 1fr;
50
+ min-height: 10;
51
+ }
52
+ #dashboard-mid {
53
+ height: 1fr;
54
+ min-height: 8;
55
+ }
56
+ .d-panel {
57
+ width: 1fr;
58
+ height: 1fr;
59
+ min-height: 6;
60
+ border: solid #6EE7B7;
61
+ padding: 1 2;
62
+ margin: 0 1 1 1;
63
+ }
64
+ .d-panel-title {
65
+ text-style: bold;
66
+ color: #6EE7B7;
67
+ margin-bottom: 1;
68
+ }
69
+ #dashboard-logs {
70
+ height: 1fr;
71
+ min-height: 6;
72
+ border: solid #6EE7B7;
73
+ padding: 1 2;
74
+ margin: 0 1 1 1;
75
+ }
76
+ # v1.2 panels
77
+ #dashboard-reasoning-row { height: auto; min-height: 6; }
78
+ TaskView, SwarmView, MemoryView, LogsView, ActivityFeedView, KnowledgeGraphView, PerformanceView,
79
+ ReasoningGraphView, AgentRoleActivityView, AdaptiveTasksView, DevView {
80
+ scrollbar-size: 1 1;
81
+ overflow-y: auto;
82
+ height: 1fr;
83
+ }
84
+ """
85
+
86
+ def __init__(
87
+ self,
88
+ app_ref: object,
89
+ event_log_path: str | None = None,
90
+ *args,
91
+ **kwargs,
92
+ ) -> None:
93
+ super().__init__(*args, **kwargs)
94
+ self._app_ref = app_ref
95
+ self._event_log_path = event_log_path
96
+
97
+ def compose(self) -> ComposeResult:
98
+ with Container(id="dashboard-container"):
99
+ yield Static(
100
+ " Dashboard — Tasks | Swarm | Memory | Activity | KG | Perf | Reasoning | Roles | Adaptive | Dev | Logs — Esc to back",
101
+ id="dashboard-header",
102
+ )
103
+ with Horizontal(id="dashboard-top"):
104
+ with Vertical(classes="d-panel"):
105
+ yield Static("Tasks", classes="d-panel-title")
106
+ yield TaskView(id="task-view")
107
+ with Vertical(classes="d-panel"):
108
+ yield Static("Swarm Graph", classes="d-panel-title")
109
+ yield SwarmView(id="swarm-view")
110
+ with Vertical(classes="d-panel"):
111
+ yield Static("Memory", classes="d-panel-title")
112
+ yield MemoryView(id="memory-view")
113
+ with Horizontal(id="dashboard-mid"):
114
+ with Vertical(classes="d-panel"):
115
+ yield Static("Activity Feed", classes="d-panel-title")
116
+ yield ActivityFeedView(id="activity-feed-view")
117
+ with Vertical(classes="d-panel"):
118
+ yield Static("Knowledge Graph", classes="d-panel-title")
119
+ yield KnowledgeGraphView(id="knowledge-graph-view")
120
+ with Vertical(classes="d-panel"):
121
+ yield Static(
122
+ "Performance (speculative | cache | tools)",
123
+ classes="d-panel-title",
124
+ )
125
+ yield PerformanceView(id="performance-view")
126
+ with Horizontal(id="dashboard-reasoning-row"):
127
+ with Vertical(classes="d-panel"):
128
+ yield Static("Reasoning Graph", classes="d-panel-title")
129
+ yield ReasoningGraphView(id="reasoning-graph-view")
130
+ with Vertical(classes="d-panel"):
131
+ yield Static("Agent Role Activity", classes="d-panel-title")
132
+ yield AgentRoleActivityView(id="agent-role-view")
133
+ with Vertical(classes="d-panel"):
134
+ yield Static("Adaptive Task Creation", classes="d-panel-title")
135
+ yield AdaptiveTasksView(id="adaptive-tasks-view")
136
+ with Horizontal(id="dashboard-dev-row"):
137
+ with Vertical(classes="d-panel"):
138
+ yield Static("Dev — Repository tree | Test results | File changes", classes="d-panel-title")
139
+ yield DevView(id="dev-view")
140
+ with Vertical(id="dashboard-logs"):
141
+ yield Static("Logs", classes="d-panel-title")
142
+ yield LogsView(id="logs-view")
143
+
144
+ def on_mount(self) -> None:
145
+ self._refresh_all()
146
+
147
+ def _refresh_all(self) -> None:
148
+ app = self._app_ref
149
+ events_folder = getattr(app, "_events_folder", ".devsper/events")
150
+ try:
151
+ lv = self.query_one("#logs-view", LogsView)
152
+ lv.set_events_folder(events_folder)
153
+ if getattr(self, "_event_log_path", None):
154
+ lv.set_log_path(self._event_log_path)
155
+ lv.refresh_logs()
156
+ except Exception:
157
+ pass
158
+ try:
159
+ af = self.query_one("#activity-feed-view", ActivityFeedView)
160
+ af.set_events_folder(events_folder)
161
+ if getattr(self, "_event_log_path", None):
162
+ af.set_log_path(self._event_log_path)
163
+ af.refresh_events()
164
+ except Exception:
165
+ pass
166
+ try:
167
+ kg = self.query_one("#knowledge-graph-view", KnowledgeGraphView)
168
+ kg.load_from_memory()
169
+ except Exception:
170
+ pass
171
+ try:
172
+ mv = self.query_one("#memory-view", MemoryView)
173
+ mv.load_from_store()
174
+ except Exception:
175
+ pass
176
+ scheduler = getattr(app, "_last_scheduler", None)
177
+ if scheduler is not None:
178
+ try:
179
+ sv = self.query_one("#swarm-view", SwarmView)
180
+ sv.set_scheduler(scheduler)
181
+ except Exception:
182
+ pass
183
+ tasks = []
184
+ try:
185
+ graph = scheduler._graph
186
+ for nid in graph.nodes():
187
+ task = scheduler._tasks.get(nid)
188
+ if task:
189
+ status = getattr(task.status, "name", str(task.status))
190
+ tasks.append(
191
+ {
192
+ "task_id": task.id,
193
+ "description": getattr(task, "description", "") or "",
194
+ "status": status.lower(),
195
+ "runtime": "-",
196
+ "worker": "agent",
197
+ "result": getattr(task, "result", "") or "",
198
+ "error": getattr(task, "result", "") if status == "FAILED" else None,
199
+ "role": getattr(task, "role", None),
200
+ }
201
+ )
202
+ except Exception:
203
+ pass
204
+ if tasks:
205
+ try:
206
+ tv = self.query_one("#task-view", TaskView)
207
+ tv.set_tasks(tasks)
208
+ except Exception:
209
+ pass
210
+ try:
211
+ pv = self.query_one("#performance-view", PerformanceView)
212
+ speculative_count = 0
213
+ if scheduler is not None:
214
+ speculative_count = sum(
215
+ 1
216
+ for t in scheduler._tasks.values()
217
+ if getattr(t, "speculative", False)
218
+ )
219
+ try:
220
+ from devsper.config import get_config
221
+
222
+ cfg = get_config()
223
+ speculative_enabled = getattr(cfg.swarm, "speculative_execution", False)
224
+ except Exception:
225
+ speculative_enabled = False
226
+ try:
227
+ from devsper.cache import TaskCache
228
+
229
+ cache_entries = TaskCache().stats()["entries"]
230
+ except Exception:
231
+ cache_entries = 0
232
+ try:
233
+ from devsper.analytics import get_default_analytics
234
+
235
+ tool_stats = get_default_analytics().get_stats()
236
+ except Exception:
237
+ tool_stats = None
238
+ pv.set_stats(
239
+ speculative_enabled=speculative_enabled,
240
+ speculative_count=speculative_count,
241
+ cache_entries=cache_entries,
242
+ tool_stats=tool_stats,
243
+ )
244
+ except Exception:
245
+ pass
246
+ # v1.2: reasoning graph, agent roles, adaptive tasks
247
+ try:
248
+ rgv = self.query_one("#reasoning-graph-view", ReasoningGraphView)
249
+ reasoning_store = getattr(app, "_last_reasoning_store", None)
250
+ rgv.set_reasoning_store(reasoning_store)
251
+ rgv.load_from_store()
252
+ except Exception:
253
+ pass
254
+ try:
255
+ arv = self.query_one("#agent-role-view", AgentRoleActivityView)
256
+ tasks_with_roles = []
257
+ if scheduler is not None:
258
+ for t in scheduler._tasks.values():
259
+ tasks_with_roles.append({
260
+ "task_id": t.id,
261
+ "role": getattr(t, "role", None),
262
+ "status": getattr(t.status, "name", str(t.status)),
263
+ })
264
+ arv.set_tasks_with_roles(tasks_with_roles)
265
+ except Exception:
266
+ pass
267
+ try:
268
+ atv = self.query_one("#adaptive-tasks-view", AdaptiveTasksView)
269
+ atv.set_events_folder(events_folder)
270
+ atv.set_log_path(getattr(self, "_event_log_path", None))
271
+ atv.refresh_adaptive_events()
272
+ except Exception:
273
+ pass
274
+
275
+ def action_back(self) -> None:
276
+ self.dismiss(None)
277
+
278
+ def action_open_task_detail(self) -> None:
279
+ """Open task detail overlay for the selected task in TaskView."""
280
+ try:
281
+ tv = self.query_one("#task-view", TaskView)
282
+ task = tv.get_selected_task()
283
+ if task:
284
+ self.app.push_screen(TaskDetailScreen(task, self._app_ref))
285
+ except Exception:
286
+ pass
287
+
288
+ def on_task_view_task_selected(self, event: TaskView.TaskSelected) -> None:
289
+ """When TaskView emits TaskSelected (e.g. Enter on list), open detail."""
290
+ self.app.push_screen(TaskDetailScreen(event.task, self._app_ref))