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,512 @@
1
+ """Agent Coordination Dashboard - FastAPI Application.
2
+
3
+ Web dashboard for monitoring all 6 Agent Coordination patterns:
4
+ 1. Agent Heartbeat Tracking
5
+ 2. Coordination Signals
6
+ 3. State Synchronization
7
+ 4. Real-Time Event Streaming
8
+ 5. Human Approval Gates
9
+ 6. Agent-to-LLM Feedback Loop
10
+
11
+ Copyright 2025 Smart-AI-Memory
12
+ Licensed under Fair Source License 0.9
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ from datetime import datetime
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect
23
+ from fastapi.responses import HTMLResponse
24
+ from fastapi.staticfiles import StaticFiles
25
+ from pydantic import BaseModel
26
+
27
+ from attune.telemetry import (
28
+ ApprovalGate,
29
+ CoordinationSignals,
30
+ EventStreamer,
31
+ FeedbackLoop,
32
+ HeartbeatCoordinator,
33
+ )
34
+
35
+ logger = logging.getLogger(__name__)
36
+
37
+ # Create FastAPI app
38
+ app = FastAPI(
39
+ title="Empathy Agent Dashboard",
40
+ description="Real-time monitoring dashboard for agent coordination patterns",
41
+ version="1.0.0",
42
+ )
43
+
44
+ # Mount static files
45
+ static_dir = Path(__file__).parent / "static"
46
+ app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
47
+
48
+
49
+ # ============================================================================
50
+ # Models
51
+ # ============================================================================
52
+
53
+
54
+ class AgentStatus(BaseModel):
55
+ """Agent status summary."""
56
+
57
+ agent_id: str
58
+ status: str
59
+ last_seen: str
60
+ progress: float
61
+ current_task: str
62
+
63
+
64
+ class SignalSummary(BaseModel):
65
+ """Coordination signal summary."""
66
+
67
+ signal_type: str
68
+ source_agent: str
69
+ target_agent: str
70
+ timestamp: str
71
+ payload: dict[str, Any]
72
+
73
+
74
+ class ApprovalRequestSummary(BaseModel):
75
+ """Approval request summary."""
76
+
77
+ request_id: str
78
+ approval_type: str
79
+ agent_id: str
80
+ context: dict[str, Any]
81
+ timestamp: str
82
+ timeout_seconds: float
83
+
84
+
85
+ class QualityMetrics(BaseModel):
86
+ """Quality feedback metrics."""
87
+
88
+ workflow_name: str
89
+ stage_name: str
90
+ tier: str
91
+ avg_quality: float
92
+ sample_count: int
93
+ trend: float
94
+
95
+
96
+ # ============================================================================
97
+ # Root Endpoint
98
+ # ============================================================================
99
+
100
+
101
+ @app.get("/", response_class=HTMLResponse)
102
+ async def get_dashboard():
103
+ """Serve dashboard HTML."""
104
+ html_file = static_dir / "index.html"
105
+ if not html_file.exists():
106
+ return """
107
+ <html>
108
+ <head><title>Agent Dashboard</title></head>
109
+ <body>
110
+ <h1>Agent Coordination Dashboard</h1>
111
+ <p>Dashboard UI not found. Please ensure static files are built.</p>
112
+ <p>API Documentation: <a href="/docs">/docs</a></p>
113
+ </body>
114
+ </html>
115
+ """
116
+ return html_file.read_text()
117
+
118
+
119
+ # ============================================================================
120
+ # Pattern 1: Agent Heartbeat Tracking
121
+ # ============================================================================
122
+
123
+
124
+ @app.get("/api/agents", response_model=list[AgentStatus])
125
+ async def get_active_agents():
126
+ """Get all active agents with heartbeats."""
127
+ try:
128
+ coordinator = HeartbeatCoordinator()
129
+ active_agents = coordinator.get_active_agents()
130
+
131
+ result = []
132
+ for agent_id in active_agents:
133
+ heartbeat = coordinator.get_heartbeat(agent_id)
134
+ if heartbeat:
135
+ result.append(
136
+ AgentStatus(
137
+ agent_id=agent_id,
138
+ status=heartbeat.status,
139
+ last_seen=heartbeat.timestamp.isoformat(),
140
+ progress=heartbeat.progress,
141
+ current_task=heartbeat.current_task,
142
+ )
143
+ )
144
+
145
+ return result
146
+ except Exception as e:
147
+ logger.error(f"Failed to get active agents: {e}")
148
+ return []
149
+
150
+
151
+ @app.get("/api/agents/{agent_id}")
152
+ async def get_agent_status(agent_id: str):
153
+ """Get specific agent status."""
154
+ try:
155
+ coordinator = HeartbeatCoordinator()
156
+ heartbeat = coordinator.get_heartbeat(agent_id)
157
+
158
+ if not heartbeat:
159
+ raise HTTPException(status_code=404, detail=f"Agent {agent_id} not found")
160
+
161
+ return {
162
+ "agent_id": agent_id,
163
+ "status": heartbeat.status,
164
+ "last_seen": heartbeat.timestamp.isoformat(),
165
+ "progress": heartbeat.progress,
166
+ "current_task": heartbeat.current_task,
167
+ "metadata": heartbeat.metadata,
168
+ }
169
+ except HTTPException:
170
+ raise
171
+ except Exception as e:
172
+ logger.error(f"Failed to get agent status: {e}")
173
+ raise HTTPException(status_code=500, detail=str(e))
174
+
175
+
176
+ # ============================================================================
177
+ # Pattern 2: Coordination Signals
178
+ # ============================================================================
179
+
180
+
181
+ @app.get("/api/signals", response_model=list[SignalSummary])
182
+ async def get_recent_signals(limit: int = 50):
183
+ """Get recent coordination signals."""
184
+ try:
185
+ signals = CoordinationSignals()
186
+ recent = signals.get_recent_signals(limit=limit)
187
+
188
+ return [
189
+ SignalSummary(
190
+ signal_type=sig.signal_type,
191
+ source_agent=sig.source_agent,
192
+ target_agent=sig.target_agent,
193
+ timestamp=sig.timestamp.isoformat(),
194
+ payload=sig.payload,
195
+ )
196
+ for sig in recent
197
+ ]
198
+ except Exception as e:
199
+ logger.error(f"Failed to get signals: {e}")
200
+ return []
201
+
202
+
203
+ @app.get("/api/signals/{agent_id}")
204
+ async def get_agent_signals(agent_id: str, limit: int = 20):
205
+ """Get signals for specific agent."""
206
+ try:
207
+ signals = CoordinationSignals()
208
+ agent_signals = signals.get_signals_for_agent(agent_id, limit=limit)
209
+
210
+ return [
211
+ {
212
+ "signal_type": sig.signal_type,
213
+ "source_agent": sig.source_agent,
214
+ "target_agent": sig.target_agent,
215
+ "timestamp": sig.timestamp.isoformat(),
216
+ "payload": sig.payload,
217
+ }
218
+ for sig in agent_signals
219
+ ]
220
+ except Exception as e:
221
+ logger.error(f"Failed to get agent signals: {e}")
222
+ return []
223
+
224
+
225
+ # ============================================================================
226
+ # Pattern 4: Real-Time Event Streaming
227
+ # ============================================================================
228
+
229
+
230
+ @app.get("/api/events")
231
+ async def get_recent_events(event_type: str | None = None, limit: int = 100):
232
+ """Get recent events from streams."""
233
+ try:
234
+ streamer = EventStreamer()
235
+
236
+ if event_type:
237
+ events = list(streamer.get_recent_events(event_type, limit=limit))
238
+ else:
239
+ # Get events from multiple common streams
240
+ all_events = []
241
+ for evt_type in ["agent_heartbeat", "coordination_signal", "workflow_progress"]:
242
+ events = list(streamer.get_recent_events(evt_type, limit=20))
243
+ all_events.extend(events)
244
+
245
+ # Sort by timestamp and limit
246
+ all_events.sort(key=lambda e: e.timestamp, reverse=True)
247
+ events = all_events[:limit]
248
+
249
+ return [
250
+ {
251
+ "event_id": evt.event_id,
252
+ "event_type": evt.event_type,
253
+ "timestamp": evt.timestamp.isoformat(),
254
+ "data": evt.data,
255
+ "source": evt.source,
256
+ }
257
+ for evt in events
258
+ ]
259
+ except Exception as e:
260
+ logger.error(f"Failed to get events: {e}")
261
+ return []
262
+
263
+
264
+ # ============================================================================
265
+ # Pattern 5: Human Approval Gates
266
+ # ============================================================================
267
+
268
+
269
+ @app.get("/api/approvals", response_model=list[ApprovalRequestSummary])
270
+ async def get_pending_approvals():
271
+ """Get pending approval requests."""
272
+ try:
273
+ gate = ApprovalGate()
274
+ pending = gate.get_pending_approvals()
275
+
276
+ return [
277
+ ApprovalRequestSummary(
278
+ request_id=req.request_id,
279
+ approval_type=req.approval_type,
280
+ agent_id=req.agent_id,
281
+ context=req.context,
282
+ timestamp=req.timestamp.isoformat(),
283
+ timeout_seconds=req.timeout_seconds,
284
+ )
285
+ for req in pending
286
+ ]
287
+ except Exception as e:
288
+ logger.error(f"Failed to get pending approvals: {e}")
289
+ return []
290
+
291
+
292
+ @app.post("/api/approvals/{request_id}/approve")
293
+ async def approve_request(request_id: str, reason: str = "Approved via dashboard"):
294
+ """Approve a pending request."""
295
+ try:
296
+ gate = ApprovalGate()
297
+ success = gate.respond_to_approval(
298
+ request_id=request_id, approved=True, responder="dashboard", reason=reason
299
+ )
300
+
301
+ if not success:
302
+ raise HTTPException(status_code=500, detail="Failed to record approval")
303
+
304
+ return {"status": "approved", "request_id": request_id}
305
+ except HTTPException:
306
+ raise
307
+ except Exception as e:
308
+ logger.error(f"Failed to approve request: {e}")
309
+ raise HTTPException(status_code=500, detail=str(e))
310
+
311
+
312
+ @app.post("/api/approvals/{request_id}/reject")
313
+ async def reject_request(request_id: str, reason: str = "Rejected via dashboard"):
314
+ """Reject a pending request."""
315
+ try:
316
+ gate = ApprovalGate()
317
+ success = gate.respond_to_approval(
318
+ request_id=request_id, approved=False, responder="dashboard", reason=reason
319
+ )
320
+
321
+ if not success:
322
+ raise HTTPException(status_code=500, detail="Failed to record rejection")
323
+
324
+ return {"status": "rejected", "request_id": request_id}
325
+ except HTTPException:
326
+ raise
327
+ except Exception as e:
328
+ logger.error(f"Failed to reject request: {e}")
329
+ raise HTTPException(status_code=500, detail=str(e))
330
+
331
+
332
+ # ============================================================================
333
+ # Pattern 6: Agent-to-LLM Feedback Loop
334
+ # ============================================================================
335
+
336
+
337
+ @app.get("/api/feedback/workflows")
338
+ async def get_workflow_quality():
339
+ """Get quality metrics for workflows."""
340
+ try:
341
+ feedback = FeedbackLoop()
342
+
343
+ # Get stats for known workflows (in production, this would query all workflows)
344
+ workflows = ["code-review", "test-generation", "refactoring"]
345
+ results = []
346
+
347
+ for workflow in workflows:
348
+ for stage in ["analysis", "generation", "validation"]:
349
+ for tier in ["cheap", "capable", "premium"]:
350
+ stats = feedback.get_quality_stats(workflow, stage, tier=tier)
351
+ if stats and stats.sample_count > 0:
352
+ results.append(
353
+ QualityMetrics(
354
+ workflow_name=workflow,
355
+ stage_name=stage,
356
+ tier=tier,
357
+ avg_quality=stats.avg_quality,
358
+ sample_count=stats.sample_count,
359
+ trend=stats.recent_trend,
360
+ )
361
+ )
362
+
363
+ return results
364
+ except Exception as e:
365
+ logger.error(f"Failed to get workflow quality: {e}")
366
+ return []
367
+
368
+
369
+ @app.get("/api/feedback/underperforming")
370
+ async def get_underperforming_stages(threshold: float = 0.7):
371
+ """Get underperforming workflow stages."""
372
+ try:
373
+ feedback = FeedbackLoop()
374
+
375
+ # Check known workflows
376
+ workflows = ["code-review", "test-generation", "refactoring"]
377
+ all_underperforming = []
378
+
379
+ for workflow in workflows:
380
+ underperforming = feedback.get_underperforming_stages(workflow, quality_threshold=threshold)
381
+ for stage_name, stats in underperforming:
382
+ all_underperforming.append(
383
+ {
384
+ "workflow_name": workflow,
385
+ "stage_name": stage_name,
386
+ "avg_quality": stats.avg_quality,
387
+ "sample_count": stats.sample_count,
388
+ "min_quality": stats.min_quality,
389
+ "max_quality": stats.max_quality,
390
+ "trend": stats.recent_trend,
391
+ }
392
+ )
393
+
394
+ # Sort by worst quality
395
+ all_underperforming.sort(key=lambda x: x["avg_quality"])
396
+
397
+ return all_underperforming
398
+ except Exception as e:
399
+ logger.error(f"Failed to get underperforming stages: {e}")
400
+ return []
401
+
402
+
403
+ # ============================================================================
404
+ # System Health
405
+ # ============================================================================
406
+
407
+
408
+ @app.get("/api/health")
409
+ async def get_system_health():
410
+ """Get overall system health status."""
411
+ try:
412
+ # Check if Redis is available
413
+ coordinator = HeartbeatCoordinator()
414
+ has_redis = coordinator.memory is not None
415
+
416
+ # Get counts
417
+ active_agents = len(coordinator.get_active_agents()) if has_redis else 0
418
+
419
+ gate = ApprovalGate()
420
+ pending_approvals = len(gate.get_pending_approvals()) if has_redis else 0
421
+
422
+ return {
423
+ "status": "healthy" if has_redis else "degraded",
424
+ "redis_available": has_redis,
425
+ "active_agents": active_agents,
426
+ "pending_approvals": pending_approvals,
427
+ "timestamp": datetime.utcnow().isoformat(),
428
+ }
429
+ except Exception as e:
430
+ logger.error(f"Health check failed: {e}")
431
+ return {
432
+ "status": "unhealthy",
433
+ "redis_available": False,
434
+ "error": str(e),
435
+ "timestamp": datetime.utcnow().isoformat(),
436
+ }
437
+
438
+
439
+ # ============================================================================
440
+ # WebSocket for Real-Time Updates
441
+ # ============================================================================
442
+
443
+
444
+ class ConnectionManager:
445
+ """Manage WebSocket connections."""
446
+
447
+ def __init__(self):
448
+ self.active_connections: list[WebSocket] = []
449
+
450
+ async def connect(self, websocket: WebSocket):
451
+ await websocket.accept()
452
+ self.active_connections.append(websocket)
453
+
454
+ def disconnect(self, websocket: WebSocket):
455
+ self.active_connections.remove(websocket)
456
+
457
+ async def broadcast(self, message: dict):
458
+ for connection in self.active_connections:
459
+ try:
460
+ await connection.send_json(message)
461
+ except Exception:
462
+ pass # Client disconnected
463
+
464
+
465
+ manager = ConnectionManager()
466
+
467
+
468
+ @app.websocket("/ws")
469
+ async def websocket_endpoint(websocket: WebSocket):
470
+ """WebSocket endpoint for real-time updates."""
471
+ await manager.connect(websocket)
472
+ try:
473
+ while True:
474
+ # Receive ping to keep connection alive
475
+ data = await websocket.receive_text()
476
+
477
+ # Send updates (in production, this would stream from Redis)
478
+ coordinator = HeartbeatCoordinator()
479
+ active_agents = coordinator.get_active_agents()
480
+
481
+ await websocket.send_json(
482
+ {"type": "agent_update", "agents": [{"agent_id": aid} for aid in active_agents]}
483
+ )
484
+
485
+ except WebSocketDisconnect:
486
+ manager.disconnect(websocket)
487
+
488
+
489
+ # ============================================================================
490
+ # Run Server
491
+ # ============================================================================
492
+
493
+
494
+ def run_dashboard(host: str = "127.0.0.1", port: int = 8000):
495
+ """Run the dashboard server.
496
+
497
+ Args:
498
+ host: Host to bind to
499
+ port: Port to bind to
500
+
501
+ Example:
502
+ >>> from attune.dashboard import run_dashboard
503
+ >>> run_dashboard(host="0.0.0.0", port=8080)
504
+ """
505
+ import uvicorn
506
+
507
+ logger.info(f"Starting dashboard at http://{host}:{port}")
508
+ uvicorn.run(app, host=host, port=port)
509
+
510
+
511
+ if __name__ == "__main__":
512
+ run_dashboard()