attune-ai 2.0.0__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 (457) hide show
  1. attune/__init__.py +358 -0
  2. attune/adaptive/__init__.py +13 -0
  3. attune/adaptive/task_complexity.py +127 -0
  4. attune/agent_monitoring.py +414 -0
  5. attune/cache/__init__.py +117 -0
  6. attune/cache/base.py +166 -0
  7. attune/cache/dependency_manager.py +256 -0
  8. attune/cache/hash_only.py +251 -0
  9. attune/cache/hybrid.py +457 -0
  10. attune/cache/storage.py +285 -0
  11. attune/cache_monitor.py +356 -0
  12. attune/cache_stats.py +298 -0
  13. attune/cli/__init__.py +152 -0
  14. attune/cli/__main__.py +12 -0
  15. attune/cli/commands/__init__.py +1 -0
  16. attune/cli/commands/batch.py +264 -0
  17. attune/cli/commands/cache.py +248 -0
  18. attune/cli/commands/help.py +331 -0
  19. attune/cli/commands/info.py +140 -0
  20. attune/cli/commands/inspect.py +436 -0
  21. attune/cli/commands/inspection.py +57 -0
  22. attune/cli/commands/memory.py +48 -0
  23. attune/cli/commands/metrics.py +92 -0
  24. attune/cli/commands/orchestrate.py +184 -0
  25. attune/cli/commands/patterns.py +207 -0
  26. attune/cli/commands/profiling.py +202 -0
  27. attune/cli/commands/provider.py +98 -0
  28. attune/cli/commands/routing.py +285 -0
  29. attune/cli/commands/setup.py +96 -0
  30. attune/cli/commands/status.py +235 -0
  31. attune/cli/commands/sync.py +166 -0
  32. attune/cli/commands/tier.py +121 -0
  33. attune/cli/commands/utilities.py +114 -0
  34. attune/cli/commands/workflow.py +579 -0
  35. attune/cli/core.py +32 -0
  36. attune/cli/parsers/__init__.py +68 -0
  37. attune/cli/parsers/batch.py +118 -0
  38. attune/cli/parsers/cache.py +65 -0
  39. attune/cli/parsers/help.py +41 -0
  40. attune/cli/parsers/info.py +26 -0
  41. attune/cli/parsers/inspect.py +66 -0
  42. attune/cli/parsers/metrics.py +42 -0
  43. attune/cli/parsers/orchestrate.py +61 -0
  44. attune/cli/parsers/patterns.py +54 -0
  45. attune/cli/parsers/provider.py +40 -0
  46. attune/cli/parsers/routing.py +110 -0
  47. attune/cli/parsers/setup.py +42 -0
  48. attune/cli/parsers/status.py +47 -0
  49. attune/cli/parsers/sync.py +31 -0
  50. attune/cli/parsers/tier.py +33 -0
  51. attune/cli/parsers/workflow.py +77 -0
  52. attune/cli/utils/__init__.py +1 -0
  53. attune/cli/utils/data.py +242 -0
  54. attune/cli/utils/helpers.py +68 -0
  55. attune/cli_legacy.py +3957 -0
  56. attune/cli_minimal.py +1159 -0
  57. attune/cli_router.py +437 -0
  58. attune/cli_unified.py +814 -0
  59. attune/config/__init__.py +66 -0
  60. attune/config/xml_config.py +286 -0
  61. attune/config.py +545 -0
  62. attune/coordination.py +870 -0
  63. attune/core.py +1511 -0
  64. attune/core_modules/__init__.py +15 -0
  65. attune/cost_tracker.py +626 -0
  66. attune/dashboard/__init__.py +41 -0
  67. attune/dashboard/app.py +512 -0
  68. attune/dashboard/simple_server.py +435 -0
  69. attune/dashboard/standalone_server.py +547 -0
  70. attune/discovery.py +306 -0
  71. attune/emergence.py +306 -0
  72. attune/exceptions.py +123 -0
  73. attune/feedback_loops.py +373 -0
  74. attune/hot_reload/README.md +473 -0
  75. attune/hot_reload/__init__.py +62 -0
  76. attune/hot_reload/config.py +83 -0
  77. attune/hot_reload/integration.py +229 -0
  78. attune/hot_reload/reloader.py +298 -0
  79. attune/hot_reload/watcher.py +183 -0
  80. attune/hot_reload/websocket.py +177 -0
  81. attune/levels.py +577 -0
  82. attune/leverage_points.py +441 -0
  83. attune/logging_config.py +261 -0
  84. attune/mcp/__init__.py +10 -0
  85. attune/mcp/server.py +506 -0
  86. attune/memory/__init__.py +237 -0
  87. attune/memory/claude_memory.py +469 -0
  88. attune/memory/config.py +224 -0
  89. attune/memory/control_panel.py +1290 -0
  90. attune/memory/control_panel_support.py +145 -0
  91. attune/memory/cross_session.py +845 -0
  92. attune/memory/edges.py +179 -0
  93. attune/memory/encryption.py +159 -0
  94. attune/memory/file_session.py +770 -0
  95. attune/memory/graph.py +570 -0
  96. attune/memory/long_term.py +913 -0
  97. attune/memory/long_term_types.py +99 -0
  98. attune/memory/mixins/__init__.py +25 -0
  99. attune/memory/mixins/backend_init_mixin.py +249 -0
  100. attune/memory/mixins/capabilities_mixin.py +208 -0
  101. attune/memory/mixins/handoff_mixin.py +208 -0
  102. attune/memory/mixins/lifecycle_mixin.py +49 -0
  103. attune/memory/mixins/long_term_mixin.py +352 -0
  104. attune/memory/mixins/promotion_mixin.py +109 -0
  105. attune/memory/mixins/short_term_mixin.py +182 -0
  106. attune/memory/nodes.py +179 -0
  107. attune/memory/redis_bootstrap.py +540 -0
  108. attune/memory/security/__init__.py +31 -0
  109. attune/memory/security/audit_logger.py +932 -0
  110. attune/memory/security/pii_scrubber.py +640 -0
  111. attune/memory/security/secrets_detector.py +678 -0
  112. attune/memory/short_term.py +2192 -0
  113. attune/memory/simple_storage.py +302 -0
  114. attune/memory/storage/__init__.py +15 -0
  115. attune/memory/storage_backend.py +167 -0
  116. attune/memory/summary_index.py +583 -0
  117. attune/memory/types.py +446 -0
  118. attune/memory/unified.py +182 -0
  119. attune/meta_workflows/__init__.py +74 -0
  120. attune/meta_workflows/agent_creator.py +248 -0
  121. attune/meta_workflows/builtin_templates.py +567 -0
  122. attune/meta_workflows/cli_commands/__init__.py +56 -0
  123. attune/meta_workflows/cli_commands/agent_commands.py +321 -0
  124. attune/meta_workflows/cli_commands/analytics_commands.py +442 -0
  125. attune/meta_workflows/cli_commands/config_commands.py +232 -0
  126. attune/meta_workflows/cli_commands/memory_commands.py +182 -0
  127. attune/meta_workflows/cli_commands/template_commands.py +354 -0
  128. attune/meta_workflows/cli_commands/workflow_commands.py +382 -0
  129. attune/meta_workflows/cli_meta_workflows.py +59 -0
  130. attune/meta_workflows/form_engine.py +292 -0
  131. attune/meta_workflows/intent_detector.py +409 -0
  132. attune/meta_workflows/models.py +569 -0
  133. attune/meta_workflows/pattern_learner.py +738 -0
  134. attune/meta_workflows/plan_generator.py +384 -0
  135. attune/meta_workflows/session_context.py +397 -0
  136. attune/meta_workflows/template_registry.py +229 -0
  137. attune/meta_workflows/workflow.py +984 -0
  138. attune/metrics/__init__.py +12 -0
  139. attune/metrics/collector.py +31 -0
  140. attune/metrics/prompt_metrics.py +194 -0
  141. attune/models/__init__.py +172 -0
  142. attune/models/__main__.py +13 -0
  143. attune/models/adaptive_routing.py +437 -0
  144. attune/models/auth_cli.py +444 -0
  145. attune/models/auth_strategy.py +450 -0
  146. attune/models/cli.py +655 -0
  147. attune/models/empathy_executor.py +354 -0
  148. attune/models/executor.py +257 -0
  149. attune/models/fallback.py +762 -0
  150. attune/models/provider_config.py +282 -0
  151. attune/models/registry.py +472 -0
  152. attune/models/tasks.py +359 -0
  153. attune/models/telemetry/__init__.py +71 -0
  154. attune/models/telemetry/analytics.py +594 -0
  155. attune/models/telemetry/backend.py +196 -0
  156. attune/models/telemetry/data_models.py +431 -0
  157. attune/models/telemetry/storage.py +489 -0
  158. attune/models/token_estimator.py +420 -0
  159. attune/models/validation.py +280 -0
  160. attune/monitoring/__init__.py +52 -0
  161. attune/monitoring/alerts.py +946 -0
  162. attune/monitoring/alerts_cli.py +448 -0
  163. attune/monitoring/multi_backend.py +271 -0
  164. attune/monitoring/otel_backend.py +362 -0
  165. attune/optimization/__init__.py +19 -0
  166. attune/optimization/context_optimizer.py +272 -0
  167. attune/orchestration/__init__.py +67 -0
  168. attune/orchestration/agent_templates.py +707 -0
  169. attune/orchestration/config_store.py +499 -0
  170. attune/orchestration/execution_strategies.py +2111 -0
  171. attune/orchestration/meta_orchestrator.py +1168 -0
  172. attune/orchestration/pattern_learner.py +696 -0
  173. attune/orchestration/real_tools.py +931 -0
  174. attune/pattern_cache.py +187 -0
  175. attune/pattern_library.py +542 -0
  176. attune/patterns/debugging/all_patterns.json +81 -0
  177. attune/patterns/debugging/workflow_20260107_1770825e.json +77 -0
  178. attune/patterns/refactoring_memory.json +89 -0
  179. attune/persistence.py +564 -0
  180. attune/platform_utils.py +265 -0
  181. attune/plugins/__init__.py +28 -0
  182. attune/plugins/base.py +361 -0
  183. attune/plugins/registry.py +268 -0
  184. attune/project_index/__init__.py +32 -0
  185. attune/project_index/cli.py +335 -0
  186. attune/project_index/index.py +667 -0
  187. attune/project_index/models.py +504 -0
  188. attune/project_index/reports.py +474 -0
  189. attune/project_index/scanner.py +777 -0
  190. attune/project_index/scanner_parallel.py +291 -0
  191. attune/prompts/__init__.py +61 -0
  192. attune/prompts/config.py +77 -0
  193. attune/prompts/context.py +177 -0
  194. attune/prompts/parser.py +285 -0
  195. attune/prompts/registry.py +313 -0
  196. attune/prompts/templates.py +208 -0
  197. attune/redis_config.py +302 -0
  198. attune/redis_memory.py +799 -0
  199. attune/resilience/__init__.py +56 -0
  200. attune/resilience/circuit_breaker.py +256 -0
  201. attune/resilience/fallback.py +179 -0
  202. attune/resilience/health.py +300 -0
  203. attune/resilience/retry.py +209 -0
  204. attune/resilience/timeout.py +135 -0
  205. attune/routing/__init__.py +43 -0
  206. attune/routing/chain_executor.py +433 -0
  207. attune/routing/classifier.py +217 -0
  208. attune/routing/smart_router.py +234 -0
  209. attune/routing/workflow_registry.py +343 -0
  210. attune/scaffolding/README.md +589 -0
  211. attune/scaffolding/__init__.py +35 -0
  212. attune/scaffolding/__main__.py +14 -0
  213. attune/scaffolding/cli.py +240 -0
  214. attune/scaffolding/templates/base_wizard.py.jinja2 +121 -0
  215. attune/scaffolding/templates/coach_wizard.py.jinja2 +321 -0
  216. attune/scaffolding/templates/domain_wizard.py.jinja2 +408 -0
  217. attune/scaffolding/templates/linear_flow_wizard.py.jinja2 +203 -0
  218. attune/socratic/__init__.py +256 -0
  219. attune/socratic/ab_testing.py +958 -0
  220. attune/socratic/blueprint.py +533 -0
  221. attune/socratic/cli.py +703 -0
  222. attune/socratic/collaboration.py +1114 -0
  223. attune/socratic/domain_templates.py +924 -0
  224. attune/socratic/embeddings.py +738 -0
  225. attune/socratic/engine.py +794 -0
  226. attune/socratic/explainer.py +682 -0
  227. attune/socratic/feedback.py +772 -0
  228. attune/socratic/forms.py +629 -0
  229. attune/socratic/generator.py +732 -0
  230. attune/socratic/llm_analyzer.py +637 -0
  231. attune/socratic/mcp_server.py +702 -0
  232. attune/socratic/session.py +312 -0
  233. attune/socratic/storage.py +667 -0
  234. attune/socratic/success.py +730 -0
  235. attune/socratic/visual_editor.py +860 -0
  236. attune/socratic/web_ui.py +958 -0
  237. attune/telemetry/__init__.py +39 -0
  238. attune/telemetry/agent_coordination.py +475 -0
  239. attune/telemetry/agent_tracking.py +367 -0
  240. attune/telemetry/approval_gates.py +545 -0
  241. attune/telemetry/cli.py +1231 -0
  242. attune/telemetry/commands/__init__.py +14 -0
  243. attune/telemetry/commands/dashboard_commands.py +696 -0
  244. attune/telemetry/event_streaming.py +409 -0
  245. attune/telemetry/feedback_loop.py +567 -0
  246. attune/telemetry/usage_tracker.py +591 -0
  247. attune/templates.py +754 -0
  248. attune/test_generator/__init__.py +38 -0
  249. attune/test_generator/__main__.py +14 -0
  250. attune/test_generator/cli.py +234 -0
  251. attune/test_generator/generator.py +355 -0
  252. attune/test_generator/risk_analyzer.py +216 -0
  253. attune/test_generator/templates/unit_test.py.jinja2 +272 -0
  254. attune/tier_recommender.py +384 -0
  255. attune/tools.py +183 -0
  256. attune/trust/__init__.py +28 -0
  257. attune/trust/circuit_breaker.py +579 -0
  258. attune/trust_building.py +527 -0
  259. attune/validation/__init__.py +19 -0
  260. attune/validation/xml_validator.py +281 -0
  261. attune/vscode_bridge.py +173 -0
  262. attune/workflow_commands.py +780 -0
  263. attune/workflow_patterns/__init__.py +33 -0
  264. attune/workflow_patterns/behavior.py +249 -0
  265. attune/workflow_patterns/core.py +76 -0
  266. attune/workflow_patterns/output.py +99 -0
  267. attune/workflow_patterns/registry.py +255 -0
  268. attune/workflow_patterns/structural.py +288 -0
  269. attune/workflows/__init__.py +539 -0
  270. attune/workflows/autonomous_test_gen.py +1268 -0
  271. attune/workflows/base.py +2667 -0
  272. attune/workflows/batch_processing.py +342 -0
  273. attune/workflows/bug_predict.py +1084 -0
  274. attune/workflows/builder.py +273 -0
  275. attune/workflows/caching.py +253 -0
  276. attune/workflows/code_review.py +1048 -0
  277. attune/workflows/code_review_adapters.py +312 -0
  278. attune/workflows/code_review_pipeline.py +722 -0
  279. attune/workflows/config.py +645 -0
  280. attune/workflows/dependency_check.py +644 -0
  281. attune/workflows/document_gen/__init__.py +25 -0
  282. attune/workflows/document_gen/config.py +30 -0
  283. attune/workflows/document_gen/report_formatter.py +162 -0
  284. attune/workflows/document_gen/workflow.py +1426 -0
  285. attune/workflows/document_manager.py +216 -0
  286. attune/workflows/document_manager_README.md +134 -0
  287. attune/workflows/documentation_orchestrator.py +1205 -0
  288. attune/workflows/history.py +510 -0
  289. attune/workflows/keyboard_shortcuts/__init__.py +39 -0
  290. attune/workflows/keyboard_shortcuts/generators.py +391 -0
  291. attune/workflows/keyboard_shortcuts/parsers.py +416 -0
  292. attune/workflows/keyboard_shortcuts/prompts.py +295 -0
  293. attune/workflows/keyboard_shortcuts/schema.py +193 -0
  294. attune/workflows/keyboard_shortcuts/workflow.py +509 -0
  295. attune/workflows/llm_base.py +363 -0
  296. attune/workflows/manage_docs.py +87 -0
  297. attune/workflows/manage_docs_README.md +134 -0
  298. attune/workflows/manage_documentation.py +821 -0
  299. attune/workflows/new_sample_workflow1.py +149 -0
  300. attune/workflows/new_sample_workflow1_README.md +150 -0
  301. attune/workflows/orchestrated_health_check.py +849 -0
  302. attune/workflows/orchestrated_release_prep.py +600 -0
  303. attune/workflows/output.py +413 -0
  304. attune/workflows/perf_audit.py +863 -0
  305. attune/workflows/pr_review.py +762 -0
  306. attune/workflows/progress.py +785 -0
  307. attune/workflows/progress_server.py +322 -0
  308. attune/workflows/progressive/README 2.md +454 -0
  309. attune/workflows/progressive/README.md +454 -0
  310. attune/workflows/progressive/__init__.py +82 -0
  311. attune/workflows/progressive/cli.py +219 -0
  312. attune/workflows/progressive/core.py +488 -0
  313. attune/workflows/progressive/orchestrator.py +723 -0
  314. attune/workflows/progressive/reports.py +520 -0
  315. attune/workflows/progressive/telemetry.py +274 -0
  316. attune/workflows/progressive/test_gen.py +495 -0
  317. attune/workflows/progressive/workflow.py +589 -0
  318. attune/workflows/refactor_plan.py +694 -0
  319. attune/workflows/release_prep.py +895 -0
  320. attune/workflows/release_prep_crew.py +969 -0
  321. attune/workflows/research_synthesis.py +404 -0
  322. attune/workflows/routing.py +168 -0
  323. attune/workflows/secure_release.py +593 -0
  324. attune/workflows/security_adapters.py +297 -0
  325. attune/workflows/security_audit.py +1329 -0
  326. attune/workflows/security_audit_phase3.py +355 -0
  327. attune/workflows/seo_optimization.py +633 -0
  328. attune/workflows/step_config.py +234 -0
  329. attune/workflows/telemetry_mixin.py +269 -0
  330. attune/workflows/test5.py +125 -0
  331. attune/workflows/test5_README.md +158 -0
  332. attune/workflows/test_coverage_boost_crew.py +849 -0
  333. attune/workflows/test_gen/__init__.py +52 -0
  334. attune/workflows/test_gen/ast_analyzer.py +249 -0
  335. attune/workflows/test_gen/config.py +88 -0
  336. attune/workflows/test_gen/data_models.py +38 -0
  337. attune/workflows/test_gen/report_formatter.py +289 -0
  338. attune/workflows/test_gen/test_templates.py +381 -0
  339. attune/workflows/test_gen/workflow.py +655 -0
  340. attune/workflows/test_gen.py +54 -0
  341. attune/workflows/test_gen_behavioral.py +477 -0
  342. attune/workflows/test_gen_parallel.py +341 -0
  343. attune/workflows/test_lifecycle.py +526 -0
  344. attune/workflows/test_maintenance.py +627 -0
  345. attune/workflows/test_maintenance_cli.py +590 -0
  346. attune/workflows/test_maintenance_crew.py +840 -0
  347. attune/workflows/test_runner.py +622 -0
  348. attune/workflows/tier_tracking.py +531 -0
  349. attune/workflows/xml_enhanced_crew.py +285 -0
  350. attune_ai-2.0.0.dist-info/METADATA +1026 -0
  351. attune_ai-2.0.0.dist-info/RECORD +457 -0
  352. attune_ai-2.0.0.dist-info/WHEEL +5 -0
  353. attune_ai-2.0.0.dist-info/entry_points.txt +26 -0
  354. attune_ai-2.0.0.dist-info/licenses/LICENSE +201 -0
  355. attune_ai-2.0.0.dist-info/licenses/LICENSE_CHANGE_ANNOUNCEMENT.md +101 -0
  356. attune_ai-2.0.0.dist-info/top_level.txt +5 -0
  357. attune_healthcare/__init__.py +13 -0
  358. attune_healthcare/monitors/__init__.py +9 -0
  359. attune_healthcare/monitors/clinical_protocol_monitor.py +315 -0
  360. attune_healthcare/monitors/monitoring/__init__.py +44 -0
  361. attune_healthcare/monitors/monitoring/protocol_checker.py +300 -0
  362. attune_healthcare/monitors/monitoring/protocol_loader.py +214 -0
  363. attune_healthcare/monitors/monitoring/sensor_parsers.py +306 -0
  364. attune_healthcare/monitors/monitoring/trajectory_analyzer.py +389 -0
  365. attune_llm/README.md +553 -0
  366. attune_llm/__init__.py +28 -0
  367. attune_llm/agent_factory/__init__.py +53 -0
  368. attune_llm/agent_factory/adapters/__init__.py +85 -0
  369. attune_llm/agent_factory/adapters/autogen_adapter.py +312 -0
  370. attune_llm/agent_factory/adapters/crewai_adapter.py +483 -0
  371. attune_llm/agent_factory/adapters/haystack_adapter.py +298 -0
  372. attune_llm/agent_factory/adapters/langchain_adapter.py +362 -0
  373. attune_llm/agent_factory/adapters/langgraph_adapter.py +333 -0
  374. attune_llm/agent_factory/adapters/native.py +228 -0
  375. attune_llm/agent_factory/adapters/wizard_adapter.py +423 -0
  376. attune_llm/agent_factory/base.py +305 -0
  377. attune_llm/agent_factory/crews/__init__.py +67 -0
  378. attune_llm/agent_factory/crews/code_review.py +1113 -0
  379. attune_llm/agent_factory/crews/health_check.py +1262 -0
  380. attune_llm/agent_factory/crews/refactoring.py +1128 -0
  381. attune_llm/agent_factory/crews/security_audit.py +1018 -0
  382. attune_llm/agent_factory/decorators.py +287 -0
  383. attune_llm/agent_factory/factory.py +558 -0
  384. attune_llm/agent_factory/framework.py +193 -0
  385. attune_llm/agent_factory/memory_integration.py +328 -0
  386. attune_llm/agent_factory/resilient.py +320 -0
  387. attune_llm/agents_md/__init__.py +22 -0
  388. attune_llm/agents_md/loader.py +218 -0
  389. attune_llm/agents_md/parser.py +271 -0
  390. attune_llm/agents_md/registry.py +307 -0
  391. attune_llm/claude_memory.py +466 -0
  392. attune_llm/cli/__init__.py +8 -0
  393. attune_llm/cli/sync_claude.py +487 -0
  394. attune_llm/code_health.py +1313 -0
  395. attune_llm/commands/__init__.py +51 -0
  396. attune_llm/commands/context.py +375 -0
  397. attune_llm/commands/loader.py +301 -0
  398. attune_llm/commands/models.py +231 -0
  399. attune_llm/commands/parser.py +371 -0
  400. attune_llm/commands/registry.py +429 -0
  401. attune_llm/config/__init__.py +29 -0
  402. attune_llm/config/unified.py +291 -0
  403. attune_llm/context/__init__.py +22 -0
  404. attune_llm/context/compaction.py +455 -0
  405. attune_llm/context/manager.py +434 -0
  406. attune_llm/contextual_patterns.py +361 -0
  407. attune_llm/core.py +907 -0
  408. attune_llm/git_pattern_extractor.py +435 -0
  409. attune_llm/hooks/__init__.py +24 -0
  410. attune_llm/hooks/config.py +306 -0
  411. attune_llm/hooks/executor.py +289 -0
  412. attune_llm/hooks/registry.py +302 -0
  413. attune_llm/hooks/scripts/__init__.py +39 -0
  414. attune_llm/hooks/scripts/evaluate_session.py +201 -0
  415. attune_llm/hooks/scripts/first_time_init.py +285 -0
  416. attune_llm/hooks/scripts/pre_compact.py +207 -0
  417. attune_llm/hooks/scripts/session_end.py +183 -0
  418. attune_llm/hooks/scripts/session_start.py +163 -0
  419. attune_llm/hooks/scripts/suggest_compact.py +225 -0
  420. attune_llm/learning/__init__.py +30 -0
  421. attune_llm/learning/evaluator.py +438 -0
  422. attune_llm/learning/extractor.py +514 -0
  423. attune_llm/learning/storage.py +560 -0
  424. attune_llm/levels.py +227 -0
  425. attune_llm/pattern_confidence.py +414 -0
  426. attune_llm/pattern_resolver.py +272 -0
  427. attune_llm/pattern_summary.py +350 -0
  428. attune_llm/providers.py +967 -0
  429. attune_llm/routing/__init__.py +32 -0
  430. attune_llm/routing/model_router.py +362 -0
  431. attune_llm/security/IMPLEMENTATION_SUMMARY.md +413 -0
  432. attune_llm/security/PHASE2_COMPLETE.md +384 -0
  433. attune_llm/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
  434. attune_llm/security/QUICK_REFERENCE.md +316 -0
  435. attune_llm/security/README.md +262 -0
  436. attune_llm/security/__init__.py +62 -0
  437. attune_llm/security/audit_logger.py +929 -0
  438. attune_llm/security/audit_logger_example.py +152 -0
  439. attune_llm/security/pii_scrubber.py +640 -0
  440. attune_llm/security/secrets_detector.py +678 -0
  441. attune_llm/security/secrets_detector_example.py +304 -0
  442. attune_llm/security/secure_memdocs.py +1192 -0
  443. attune_llm/security/secure_memdocs_example.py +278 -0
  444. attune_llm/session_status.py +745 -0
  445. attune_llm/state.py +246 -0
  446. attune_llm/utils/__init__.py +5 -0
  447. attune_llm/utils/tokens.py +349 -0
  448. attune_software/SOFTWARE_PLUGIN_README.md +57 -0
  449. attune_software/__init__.py +13 -0
  450. attune_software/cli/__init__.py +120 -0
  451. attune_software/cli/inspect.py +362 -0
  452. attune_software/cli.py +574 -0
  453. attune_software/plugin.py +188 -0
  454. workflow_scaffolding/__init__.py +11 -0
  455. workflow_scaffolding/__main__.py +12 -0
  456. workflow_scaffolding/cli.py +206 -0
  457. workflow_scaffolding/generator.py +265 -0
@@ -0,0 +1,435 @@
1
+ """Simple Dashboard Server - Zero External Dependencies.
2
+
3
+ Uses only Python standard library (http.server, json) to serve the dashboard.
4
+ No FastAPI, Flask, or other web frameworks required.
5
+
6
+ Copyright 2025 Smart-AI-Memory
7
+ Licensed under Fair Source License 0.9
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import logging
14
+ from datetime import datetime
15
+ from http.server import BaseHTTPRequestHandler, HTTPServer
16
+ from pathlib import Path
17
+ from urllib.parse import parse_qs, urlparse
18
+
19
+ from attune.telemetry import (
20
+ ApprovalGate,
21
+ CoordinationSignals,
22
+ EventStreamer,
23
+ FeedbackLoop,
24
+ HeartbeatCoordinator,
25
+ )
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ class DashboardHandler(BaseHTTPRequestHandler):
31
+ """HTTP request handler for dashboard."""
32
+
33
+ def do_GET(self):
34
+ """Handle GET requests."""
35
+ parsed = urlparse(self.path)
36
+ path = parsed.path
37
+ query = parse_qs(parsed.query)
38
+
39
+ # Route requests
40
+ if path == "/" or path == "/index.html":
41
+ self.serve_file("index.html", "text/html")
42
+ elif path == "/test.html":
43
+ self.serve_file("test.html", "text/html")
44
+ elif path == "/static/style.css":
45
+ self.serve_file("style.css", "text/css")
46
+ elif path == "/static/app.js":
47
+ self.serve_file("app.js", "application/javascript")
48
+ elif path == "/api/health":
49
+ self.api_health()
50
+ elif path == "/api/agents":
51
+ self.api_agents()
52
+ elif path.startswith("/api/agents/"):
53
+ agent_id = path.split("/")[-1]
54
+ self.api_agent_detail(agent_id)
55
+ elif path == "/api/signals":
56
+ limit = int(query.get("limit", [50])[0])
57
+ self.api_signals(limit)
58
+ elif path == "/api/events":
59
+ event_type = query.get("event_type", [None])[0]
60
+ limit = int(query.get("limit", [100])[0])
61
+ self.api_events(event_type, limit)
62
+ elif path == "/api/approvals":
63
+ self.api_approvals()
64
+ elif path == "/api/feedback/workflows":
65
+ self.api_feedback_workflows()
66
+ elif path == "/api/feedback/underperforming":
67
+ threshold = float(query.get("threshold", [0.7])[0])
68
+ self.api_underperforming(threshold)
69
+ else:
70
+ self.send_error(404, "Not Found")
71
+
72
+ def do_POST(self):
73
+ """Handle POST requests."""
74
+ parsed = urlparse(self.path)
75
+ path = parsed.path
76
+
77
+ # Get request body
78
+ content_length = int(self.headers.get("Content-Length", 0))
79
+ body = self.rfile.read(content_length) if content_length > 0 else b"{}"
80
+ data = json.loads(body.decode("utf-8")) if body else {}
81
+
82
+ # Route requests
83
+ if "/approve" in path:
84
+ request_id = path.split("/")[-2]
85
+ self.api_approve(request_id, data.get("reason", "Approved via dashboard"))
86
+ elif "/reject" in path:
87
+ request_id = path.split("/")[-2]
88
+ self.api_reject(request_id, data.get("reason", "Rejected via dashboard"))
89
+ else:
90
+ self.send_error(404, "Not Found")
91
+
92
+ def serve_file(self, filename: str, content_type: str):
93
+ """Serve static file."""
94
+ try:
95
+ static_dir = Path(__file__).parent / "static"
96
+ file_path = static_dir / filename
97
+
98
+ if not file_path.exists():
99
+ self.send_error(404, f"File not found: {filename}")
100
+ return
101
+
102
+ content = file_path.read_bytes()
103
+
104
+ self.send_response(200)
105
+ self.send_header("Content-Type", content_type)
106
+ self.send_header("Content-Length", str(len(content)))
107
+ self.end_headers()
108
+ self.wfile.write(content)
109
+
110
+ except Exception as e:
111
+ logger.error(f"Failed to serve file {filename}: {e}")
112
+ self.send_error(500, str(e))
113
+
114
+ def send_json(self, data: dict | list, status: int = 200):
115
+ """Send JSON response."""
116
+ try:
117
+ content = json.dumps(data).encode("utf-8")
118
+
119
+ self.send_response(status)
120
+ self.send_header("Content-Type", "application/json")
121
+ self.send_header("Content-Length", str(len(content)))
122
+ self.send_header("Access-Control-Allow-Origin", "*") # CORS
123
+ self.end_headers()
124
+ self.wfile.write(content)
125
+
126
+ except Exception as e:
127
+ logger.error(f"Failed to send JSON: {e}")
128
+ self.send_error(500, str(e))
129
+
130
+ # ========================================================================
131
+ # API Endpoints
132
+ # ========================================================================
133
+
134
+ def api_health(self):
135
+ """System health endpoint."""
136
+ try:
137
+ from attune.memory.short_term import RedisShortTermMemory
138
+
139
+ memory = RedisShortTermMemory()
140
+ has_redis = memory._client is not None
141
+
142
+ coordinator = HeartbeatCoordinator(memory=memory)
143
+ active_agents = len(coordinator.get_active_agents()) if has_redis else 0
144
+
145
+ gate = ApprovalGate(memory=memory)
146
+ pending_approvals = len(gate.get_pending_approvals()) if has_redis else 0
147
+
148
+ self.send_json(
149
+ {
150
+ "status": "healthy" if has_redis else "degraded",
151
+ "redis_available": has_redis,
152
+ "active_agents": active_agents,
153
+ "pending_approvals": pending_approvals,
154
+ "timestamp": datetime.utcnow().isoformat(),
155
+ }
156
+ )
157
+ except Exception as e:
158
+ self.send_json({"status": "error", "error": str(e)}, status=500)
159
+
160
+ def api_agents(self):
161
+ """List active agents."""
162
+ try:
163
+ from attune.memory.short_term import RedisShortTermMemory
164
+
165
+ memory = RedisShortTermMemory()
166
+ coordinator = HeartbeatCoordinator(memory=memory)
167
+ active_agents = coordinator.get_active_agents()
168
+
169
+ result = []
170
+ for agent in active_agents:
171
+ result.append(
172
+ {
173
+ "agent_id": agent.agent_id,
174
+ "display_name": agent.display_name,
175
+ "status": agent.status,
176
+ "last_seen": agent.last_beat.isoformat(),
177
+ "progress": agent.progress,
178
+ "current_task": agent.current_task,
179
+ }
180
+ )
181
+
182
+ self.send_json(result)
183
+ except Exception as e:
184
+ logger.error(f"Failed to get agents: {e}")
185
+ self.send_json([], status=500)
186
+
187
+ def api_agent_detail(self, agent_id: str):
188
+ """Get specific agent details."""
189
+ try:
190
+ from attune.memory.short_term import RedisShortTermMemory
191
+
192
+ memory = RedisShortTermMemory()
193
+ coordinator = HeartbeatCoordinator(memory=memory)
194
+ heartbeat = coordinator.get_agent_status(agent_id)
195
+
196
+ if not heartbeat:
197
+ self.send_json({"error": f"Agent {agent_id} not found"}, status=404)
198
+ return
199
+
200
+ self.send_json(
201
+ {
202
+ "agent_id": heartbeat.agent_id,
203
+ "status": heartbeat.status,
204
+ "last_seen": heartbeat.last_beat.isoformat(),
205
+ "progress": heartbeat.progress,
206
+ "current_task": heartbeat.current_task,
207
+ "metadata": heartbeat.metadata,
208
+ }
209
+ )
210
+ except Exception as e:
211
+ self.send_json({"error": str(e)}, status=500)
212
+
213
+ def api_signals(self, limit: int):
214
+ """Get recent coordination signals."""
215
+ try:
216
+ from attune.memory.short_term import RedisShortTermMemory
217
+
218
+ memory = RedisShortTermMemory()
219
+ # Use broadcast target to get all signals (not just for dashboard)
220
+ signals = CoordinationSignals(memory=memory, agent_id="*")
221
+ recent = signals.get_pending_signals()[:limit]
222
+
223
+ result = [
224
+ {
225
+ "signal_type": sig.signal_type,
226
+ "source_agent": sig.source_agent,
227
+ "target_agent": sig.target_agent,
228
+ "timestamp": sig.timestamp.isoformat(),
229
+ "payload": sig.payload,
230
+ }
231
+ for sig in recent
232
+ ]
233
+
234
+ self.send_json(result)
235
+ except Exception as e:
236
+ logger.error(f"Failed to get signals: {e}")
237
+ self.send_json([])
238
+
239
+ def api_events(self, event_type: str | None, limit: int):
240
+ """Get recent events."""
241
+ try:
242
+ from attune.memory.short_term import RedisShortTermMemory
243
+
244
+ memory = RedisShortTermMemory()
245
+ streamer = EventStreamer(memory=memory)
246
+
247
+ if event_type:
248
+ events = list(streamer.get_recent_events(event_type, count=limit))
249
+ else:
250
+ # Get events from multiple streams
251
+ all_events = []
252
+ for evt_type in ["agent_heartbeat", "coordination_signal", "workflow_progress"]:
253
+ events = list(streamer.get_recent_events(evt_type, count=20))
254
+ all_events.extend(events)
255
+
256
+ all_events.sort(key=lambda e: e.timestamp, reverse=True)
257
+ events = all_events[:limit]
258
+
259
+ result = [
260
+ {
261
+ "event_id": evt.event_id,
262
+ "event_type": evt.event_type,
263
+ "timestamp": evt.timestamp.isoformat(),
264
+ "data": evt.data,
265
+ "source": evt.source,
266
+ }
267
+ for evt in events
268
+ ]
269
+
270
+ self.send_json(result)
271
+ except Exception as e:
272
+ logger.error(f"Failed to get events: {e}")
273
+ self.send_json([])
274
+
275
+ def api_approvals(self):
276
+ """Get pending approvals."""
277
+ try:
278
+ from attune.memory.short_term import RedisShortTermMemory
279
+
280
+ memory = RedisShortTermMemory()
281
+ gate = ApprovalGate(memory=memory)
282
+ pending = gate.get_pending_approvals()
283
+
284
+ result = [
285
+ {
286
+ "request_id": req.request_id,
287
+ "approval_type": req.approval_type,
288
+ "agent_id": req.agent_id,
289
+ "context": req.context,
290
+ "timestamp": req.timestamp.isoformat(),
291
+ "timeout_seconds": req.timeout_seconds,
292
+ }
293
+ for req in pending
294
+ ]
295
+
296
+ self.send_json(result)
297
+ except Exception as e:
298
+ logger.error(f"Failed to get approvals: {e}")
299
+ self.send_json([])
300
+
301
+ def api_approve(self, request_id: str, reason: str):
302
+ """Approve request."""
303
+ try:
304
+ from attune.memory.short_term import RedisShortTermMemory
305
+
306
+ memory = RedisShortTermMemory()
307
+ gate = ApprovalGate(memory=memory)
308
+ success = gate.respond_to_approval(
309
+ request_id=request_id, approved=True, responder="dashboard", reason=reason
310
+ )
311
+
312
+ if success:
313
+ self.send_json({"status": "approved", "request_id": request_id})
314
+ else:
315
+ self.send_json({"error": "Failed to approve"}, status=500)
316
+ except Exception as e:
317
+ self.send_json({"error": str(e)}, status=500)
318
+
319
+ def api_reject(self, request_id: str, reason: str):
320
+ """Reject request."""
321
+ try:
322
+ from attune.memory.short_term import RedisShortTermMemory
323
+
324
+ memory = RedisShortTermMemory()
325
+ gate = ApprovalGate(memory=memory)
326
+ success = gate.respond_to_approval(
327
+ request_id=request_id, approved=False, responder="dashboard", reason=reason
328
+ )
329
+
330
+ if success:
331
+ self.send_json({"status": "rejected", "request_id": request_id})
332
+ else:
333
+ self.send_json({"error": "Failed to reject"}, status=500)
334
+ except Exception as e:
335
+ self.send_json({"error": str(e)}, status=500)
336
+
337
+ def api_feedback_workflows(self):
338
+ """Get workflow quality metrics."""
339
+ try:
340
+ from attune.memory.short_term import RedisShortTermMemory
341
+
342
+ memory = RedisShortTermMemory()
343
+ feedback = FeedbackLoop(memory=memory)
344
+
345
+ workflows = ["code-review", "test-generation", "refactoring"]
346
+ results = []
347
+
348
+ for workflow in workflows:
349
+ for stage in ["analysis", "generation", "validation"]:
350
+ for tier in ["cheap", "capable", "premium"]:
351
+ stats = feedback.get_quality_stats(workflow, stage, tier=tier)
352
+ if stats and stats.sample_count > 0:
353
+ results.append(
354
+ {
355
+ "workflow_name": workflow,
356
+ "stage_name": stage,
357
+ "tier": tier,
358
+ "avg_quality": stats.avg_quality,
359
+ "sample_count": stats.sample_count,
360
+ "trend": stats.recent_trend,
361
+ }
362
+ )
363
+
364
+ self.send_json(results)
365
+ except Exception as e:
366
+ logger.error(f"Failed to get quality metrics: {e}")
367
+ self.send_json([])
368
+
369
+ def api_underperforming(self, threshold: float):
370
+ """Get underperforming stages."""
371
+ try:
372
+ from attune.memory.short_term import RedisShortTermMemory
373
+
374
+ memory = RedisShortTermMemory()
375
+ feedback = FeedbackLoop(memory=memory)
376
+
377
+ workflows = ["code-review", "test-generation", "refactoring"]
378
+ all_underperforming = []
379
+
380
+ for workflow in workflows:
381
+ underperforming = feedback.get_underperforming_stages(workflow, quality_threshold=threshold)
382
+ for stage_name, stats in underperforming:
383
+ all_underperforming.append(
384
+ {
385
+ "workflow_name": workflow,
386
+ "stage_name": stage_name,
387
+ "avg_quality": stats.avg_quality,
388
+ "sample_count": stats.sample_count,
389
+ "min_quality": stats.min_quality,
390
+ "max_quality": stats.max_quality,
391
+ "trend": stats.recent_trend,
392
+ }
393
+ )
394
+
395
+ all_underperforming.sort(key=lambda x: x["avg_quality"])
396
+ self.send_json(all_underperforming)
397
+ except Exception as e:
398
+ logger.error(f"Failed to get underperforming: {e}")
399
+ self.send_json([])
400
+
401
+ def log_message(self, format, *args):
402
+ """Suppress default logging."""
403
+ # Override to reduce noise - only log errors
404
+ if args[1][0] in ("4", "5"): # 4xx or 5xx errors
405
+ logger.warning(f"{self.address_string()} - {format % args}")
406
+
407
+
408
+ def run_simple_dashboard(host: str = "127.0.0.1", port: int = 8000):
409
+ """Run dashboard using only Python standard library.
410
+
411
+ No external dependencies required (no FastAPI, Flask, etc).
412
+
413
+ Args:
414
+ host: Host to bind to (default: 127.0.0.1)
415
+ port: Port to bind to (default: 8000)
416
+
417
+ Example:
418
+ >>> from attune.dashboard.simple_server import run_simple_dashboard
419
+ >>> run_simple_dashboard(host="0.0.0.0", port=8080)
420
+ """
421
+ server = HTTPServer((host, port), DashboardHandler)
422
+
423
+ print(f"šŸš€ Agent Coordination Dashboard running at http://{host}:{port}")
424
+ print(f"šŸ“Š Open in browser: http://{host}:{port}")
425
+ print("Press Ctrl+C to stop")
426
+
427
+ try:
428
+ server.serve_forever()
429
+ except KeyboardInterrupt:
430
+ print("\n\nšŸ›‘ Shutting down dashboard...")
431
+ server.shutdown()
432
+
433
+
434
+ if __name__ == "__main__":
435
+ run_simple_dashboard()