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,520 @@
1
+ """Report generation and result storage for progressive workflows.
2
+
3
+ This module provides utilities for:
4
+ 1. Generating human-readable progression reports
5
+ 2. Saving detailed results to disk
6
+ 3. Formatting cost analysis
7
+ 4. Creating progression visualizations
8
+ """
9
+
10
+ import json
11
+ import logging
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+ from attune.config import _validate_file_path
16
+ from attune.workflows.progressive.core import ProgressiveWorkflowResult, Tier
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ def generate_progression_report(result: ProgressiveWorkflowResult) -> str:
22
+ """Generate human-readable progression report.
23
+
24
+ Creates a detailed ASCII report showing:
25
+ - Tier-by-tier breakdown
26
+ - Quality scores and success rates
27
+ - Cost analysis and savings
28
+ - Escalation decisions
29
+ - Final results summary
30
+
31
+ Args:
32
+ result: Progressive workflow result
33
+
34
+ Returns:
35
+ Formatted report string
36
+
37
+ Example:
38
+ >>> print(generate_progression_report(result))
39
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
40
+ 🎯 PROGRESSIVE ESCALATION REPORT
41
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
42
+ ...
43
+ """
44
+ report = []
45
+
46
+ # Header
47
+ report.append("━" * 60)
48
+ report.append("🎯 PROGRESSIVE ESCALATION REPORT")
49
+ report.append("━" * 60)
50
+ report.append("")
51
+
52
+ # Summary
53
+ report.append(f"Workflow: {result.workflow_name}")
54
+ report.append(f"Task ID: {result.task_id}")
55
+ report.append(f"Duration: {_format_duration(result.total_duration)}")
56
+ report.append(f"Total Cost: ${result.total_cost:.2f}")
57
+ report.append("")
58
+
59
+ # Cost savings
60
+ if result.cost_savings > 0:
61
+ report.append(
62
+ f"Cost Savings: ${result.cost_savings:.2f} ({result.cost_savings_percent:.0f}% vs all-Premium)"
63
+ )
64
+ report.append("")
65
+
66
+ report.append("TIER BREAKDOWN:")
67
+ report.append("")
68
+
69
+ # Tier-by-tier breakdown
70
+ for tier_result in result.tier_results:
71
+ tier_emoji = {Tier.CHEAP: "💰", Tier.CAPABLE: "📊", Tier.PREMIUM: "💎"}[tier_result.tier]
72
+
73
+ report.append(f"{tier_emoji} {tier_result.tier.value.upper()} Tier ({tier_result.model})")
74
+ report.append(f" • Items: {len(tier_result.generated_items)}")
75
+ report.append(f" • Attempts: {tier_result.attempt}")
76
+
77
+ success_count = tier_result.success_count
78
+ total_items = len(tier_result.generated_items)
79
+ success_rate = tier_result.success_rate * 100
80
+
81
+ report.append(f" • Success: {success_count}/{total_items} ({success_rate:.0f}%)")
82
+ report.append(f" • Quality: CQS={tier_result.quality_score:.1f}")
83
+ report.append(f" • Cost: ${tier_result.cost:.2f}")
84
+ report.append(f" • Duration: {_format_duration(tier_result.duration)}")
85
+
86
+ if tier_result.escalated:
87
+ report.append(f" • Escalated: {tier_result.escalation_reason}")
88
+
89
+ report.append("")
90
+
91
+ report.append("━" * 60)
92
+ report.append("")
93
+ report.append("FINAL RESULTS:")
94
+
95
+ total_items = sum(len(r.generated_items) for r in result.tier_results)
96
+ total_successful = sum(r.success_count for r in result.tier_results)
97
+
98
+ status_icon = "✅" if result.success else "❌"
99
+ status_text = "Success" if result.success else "Incomplete"
100
+
101
+ report.append(f"{status_icon} {total_successful}/{total_items} items completed")
102
+ report.append(f"{status_icon} Overall CQS: {result.final_result.quality_score:.0f}")
103
+ report.append(f"{status_icon} Status: {status_text}")
104
+ report.append("")
105
+
106
+ report.append("━" * 60)
107
+ report.append("")
108
+ report.append("Detailed results saved to:")
109
+ report.append(f".attune/progressive_runs/{result.task_id}/")
110
+ report.append("")
111
+
112
+ return "\n".join(report)
113
+
114
+
115
+ def save_results_to_disk(result: ProgressiveWorkflowResult, storage_path: str) -> None:
116
+ """Save detailed results to disk.
117
+
118
+ Creates a directory structure:
119
+ <storage_path>/<task_id>/
120
+ ├── summary.json
121
+ ├── tier_0_cheap.json
122
+ ├── tier_1_capable.json
123
+ ├── tier_2_premium.json (if used)
124
+ └── report.txt
125
+
126
+ Args:
127
+ result: Progressive workflow result
128
+ storage_path: Base directory for storage
129
+
130
+ Example:
131
+ >>> save_results_to_disk(result, ".attune/progressive_runs")
132
+ # Creates .attune/progressive_runs/test-gen-20260117-143022/...
133
+ """
134
+ task_dir = Path(storage_path) / result.task_id
135
+ task_dir.mkdir(parents=True, exist_ok=True)
136
+
137
+ try:
138
+ # Validate task directory path for security
139
+ validated_dir = _validate_file_path(str(task_dir))
140
+
141
+ # Save summary
142
+ summary = {
143
+ "workflow": result.workflow_name,
144
+ "task_id": result.task_id,
145
+ "timestamp": (
146
+ result.tier_results[0].timestamp.isoformat() if result.tier_results else None
147
+ ),
148
+ "total_cost": result.total_cost,
149
+ "total_duration": result.total_duration,
150
+ "cost_savings": result.cost_savings,
151
+ "cost_savings_percent": result.cost_savings_percent,
152
+ "success": result.success,
153
+ "tier_count": len(result.tier_results),
154
+ "final_cqs": result.final_result.quality_score if result.final_result else 0,
155
+ }
156
+
157
+ summary_file = validated_dir / "summary.json"
158
+ summary_file.write_text(json.dumps(summary, indent=2))
159
+
160
+ # Save each tier result
161
+ for i, tier_result in enumerate(result.tier_results):
162
+ tier_data = {
163
+ "tier": tier_result.tier.value,
164
+ "model": tier_result.model,
165
+ "attempt": tier_result.attempt,
166
+ "timestamp": tier_result.timestamp.isoformat(),
167
+ "quality_score": tier_result.quality_score,
168
+ "success_count": tier_result.success_count,
169
+ "success_rate": tier_result.success_rate,
170
+ "cost": tier_result.cost,
171
+ "duration": tier_result.duration,
172
+ "escalated": tier_result.escalated,
173
+ "escalation_reason": tier_result.escalation_reason,
174
+ "failure_analysis": {
175
+ "syntax_errors": len(tier_result.failure_analysis.syntax_errors),
176
+ "test_pass_rate": tier_result.failure_analysis.test_pass_rate,
177
+ "coverage": tier_result.failure_analysis.coverage_percent,
178
+ "assertion_depth": tier_result.failure_analysis.assertion_depth,
179
+ "confidence": tier_result.failure_analysis.confidence_score,
180
+ },
181
+ "item_count": len(tier_result.generated_items),
182
+ }
183
+
184
+ tier_file = validated_dir / f"tier_{i}_{tier_result.tier.value}.json"
185
+ tier_file.write_text(json.dumps(tier_data, indent=2))
186
+
187
+ # Save human-readable report
188
+ report_file = validated_dir / "report.txt"
189
+ report_file.write_text(generate_progression_report(result))
190
+
191
+ logger.info(f"Saved progressive results to {validated_dir}")
192
+
193
+ except ValueError as e:
194
+ logger.error(f"Failed to save results: {e}")
195
+ raise
196
+
197
+
198
+ def _format_duration(seconds: float) -> str:
199
+ """Format duration in human-readable form.
200
+
201
+ Args:
202
+ seconds: Duration in seconds
203
+
204
+ Returns:
205
+ Formatted string (e.g., "1m 23s", "45s")
206
+
207
+ Example:
208
+ >>> _format_duration(83.5)
209
+ '1m 24s'
210
+ >>> _format_duration(12.3)
211
+ '12s'
212
+ """
213
+ if seconds < 60:
214
+ return f"{int(seconds)}s"
215
+
216
+ minutes = int(seconds // 60)
217
+ remaining_seconds = int(seconds % 60)
218
+
219
+ return f"{minutes}m {remaining_seconds}s"
220
+
221
+
222
+ def load_result_from_disk(
223
+ task_id: str, storage_path: str = ".attune/progressive_runs"
224
+ ) -> dict[str, Any]:
225
+ """Load saved result from disk.
226
+
227
+ Args:
228
+ task_id: Task ID to load
229
+ storage_path: Base storage directory
230
+
231
+ Returns:
232
+ Dictionary with summary and tier results
233
+
234
+ Raises:
235
+ FileNotFoundError: If task_id not found
236
+
237
+ Example:
238
+ >>> result = load_result_from_disk("test-gen-20260117-143022")
239
+ >>> print(result["summary"]["total_cost"])
240
+ 0.95
241
+ """
242
+ task_dir = Path(storage_path) / task_id
243
+
244
+ if not task_dir.exists():
245
+ raise FileNotFoundError(f"Task {task_id} not found in {storage_path}")
246
+
247
+ # Load summary
248
+ summary_file = task_dir / "summary.json"
249
+ if not summary_file.exists():
250
+ raise FileNotFoundError(f"Summary file not found for task {task_id}")
251
+
252
+ summary = json.loads(summary_file.read_text())
253
+
254
+ # Load tier results
255
+ tier_results = []
256
+ for tier_file in sorted(task_dir.glob("tier_*.json")):
257
+ tier_data = json.loads(tier_file.read_text())
258
+ tier_results.append(tier_data)
259
+
260
+ # Load report
261
+ report_file = task_dir / "report.txt"
262
+ report = report_file.read_text() if report_file.exists() else ""
263
+
264
+ return {"summary": summary, "tier_results": tier_results, "report": report}
265
+
266
+
267
+ def list_saved_results(storage_path: str = ".attune/progressive_runs") -> list[dict[str, Any]]:
268
+ """List all saved progressive results.
269
+
270
+ Args:
271
+ storage_path: Base storage directory
272
+
273
+ Returns:
274
+ List of result summaries sorted by timestamp (newest first)
275
+
276
+ Example:
277
+ >>> results = list_saved_results()
278
+ >>> for r in results:
279
+ ... print(f"{r['task_id']}: ${r['total_cost']:.2f}")
280
+ """
281
+ storage_dir = Path(storage_path)
282
+
283
+ if not storage_dir.exists():
284
+ return []
285
+
286
+ summaries = []
287
+
288
+ for task_dir in storage_dir.iterdir():
289
+ if not task_dir.is_dir():
290
+ continue
291
+
292
+ summary_file = task_dir / "summary.json"
293
+ if not summary_file.exists():
294
+ continue
295
+
296
+ try:
297
+ summary = json.loads(summary_file.read_text())
298
+ summaries.append(summary)
299
+ except (json.JSONDecodeError, OSError) as e:
300
+ logger.warning(f"Failed to load summary from {task_dir}: {e}")
301
+
302
+ # Sort by timestamp (newest first)
303
+ summaries.sort(key=lambda s: s.get("timestamp", ""), reverse=True)
304
+
305
+ return summaries
306
+
307
+
308
+ def cleanup_old_results(
309
+ storage_path: str = ".attune/progressive_runs", retention_days: int = 30, dry_run: bool = False
310
+ ) -> tuple[int, int]:
311
+ """Clean up old progressive workflow results.
312
+
313
+ Args:
314
+ storage_path: Base storage directory
315
+ retention_days: Number of days to retain results (default: 30)
316
+ dry_run: If True, only report what would be deleted without deleting
317
+
318
+ Returns:
319
+ Tuple of (deleted_count, retained_count)
320
+
321
+ Example:
322
+ >>> deleted, retained = cleanup_old_results(retention_days=7)
323
+ >>> print(f"Deleted {deleted} old results, kept {retained}")
324
+ """
325
+ from datetime import datetime, timedelta
326
+
327
+ storage_dir = Path(storage_path)
328
+
329
+ if not storage_dir.exists():
330
+ return (0, 0)
331
+
332
+ cutoff_date = datetime.now() - timedelta(days=retention_days)
333
+ deleted_count = 0
334
+ retained_count = 0
335
+
336
+ for task_dir in storage_dir.iterdir():
337
+ if not task_dir.is_dir():
338
+ continue
339
+
340
+ summary_file = task_dir / "summary.json"
341
+ if not summary_file.exists():
342
+ continue
343
+
344
+ try:
345
+ summary = json.loads(summary_file.read_text())
346
+ timestamp_str = summary.get("timestamp")
347
+
348
+ if not timestamp_str:
349
+ logger.warning(f"No timestamp in {task_dir}, skipping")
350
+ retained_count += 1
351
+ continue
352
+
353
+ timestamp = datetime.fromisoformat(timestamp_str)
354
+
355
+ if timestamp < cutoff_date:
356
+ # Old result, delete it
357
+ if not dry_run:
358
+ import shutil
359
+
360
+ shutil.rmtree(task_dir)
361
+ logger.info(f"Deleted old result: {task_dir.name}")
362
+ else:
363
+ logger.info(f"Would delete: {task_dir.name}")
364
+ deleted_count += 1
365
+ else:
366
+ retained_count += 1
367
+
368
+ except (json.JSONDecodeError, ValueError, OSError) as e:
369
+ logger.warning(f"Error processing {task_dir}: {e}")
370
+ retained_count += 1
371
+
372
+ return (deleted_count, retained_count)
373
+
374
+
375
+ def generate_cost_analytics(storage_path: str = ".attune/progressive_runs") -> dict[str, Any]:
376
+ """Generate cost optimization analytics from saved results.
377
+
378
+ Analyzes historical progressive workflow runs to provide insights:
379
+ - Total cost savings
380
+ - Average escalation rate
381
+ - Most cost-effective workflow types
382
+ - Tier usage distribution
383
+ - Success rates by tier
384
+
385
+ Args:
386
+ storage_path: Base storage directory
387
+
388
+ Returns:
389
+ Dictionary with analytics data
390
+
391
+ Example:
392
+ >>> analytics = generate_cost_analytics()
393
+ >>> print(f"Total savings: ${analytics['total_savings']:.2f}")
394
+ >>> print(f"Avg escalation rate: {analytics['avg_escalation_rate']:.1%}")
395
+ """
396
+ results = list_saved_results(storage_path)
397
+
398
+ if not results:
399
+ return {
400
+ "total_runs": 0,
401
+ "total_cost": 0.0,
402
+ "total_savings": 0.0,
403
+ "avg_savings_percent": 0.0,
404
+ }
405
+
406
+ total_runs = len(results)
407
+ total_cost = sum(r.get("total_cost", 0) for r in results)
408
+ total_savings = sum(r.get("cost_savings", 0) for r in results)
409
+
410
+ # Calculate average savings percent (weighted by cost)
411
+ weighted_savings = sum(
412
+ r.get("cost_savings_percent", 0) * r.get("total_cost", 0) for r in results
413
+ )
414
+ avg_savings_percent = weighted_savings / total_cost if total_cost > 0 else 0
415
+
416
+ # Tier usage statistics
417
+ tier_usage = {"cheap": 0, "capable": 0, "premium": 0}
418
+ tier_costs = {"cheap": 0.0, "capable": 0.0, "premium": 0.0}
419
+ escalation_count = 0
420
+
421
+ for result in results:
422
+ tier_count = result.get("tier_count", 0)
423
+ if tier_count > 1:
424
+ escalation_count += 1
425
+
426
+ escalation_rate = escalation_count / total_runs if total_runs > 0 else 0
427
+
428
+ # Success rate
429
+ successful_runs = sum(1 for r in results if r.get("success", False))
430
+ success_rate = successful_runs / total_runs if total_runs > 0 else 0
431
+
432
+ # Average final CQS
433
+ avg_cqs = sum(r.get("final_cqs", 0) for r in results) / total_runs if total_runs > 0 else 0
434
+
435
+ # Per-workflow analytics
436
+ workflow_stats: dict[str, dict[str, Any]] = {}
437
+ for result in results:
438
+ workflow = result.get("workflow", "unknown")
439
+ if workflow not in workflow_stats:
440
+ workflow_stats[workflow] = {
441
+ "runs": 0,
442
+ "total_cost": 0.0,
443
+ "total_savings": 0.0,
444
+ "successes": 0,
445
+ }
446
+
447
+ stats = workflow_stats[workflow]
448
+ stats["runs"] += 1
449
+ stats["total_cost"] += result.get("total_cost", 0)
450
+ stats["total_savings"] += result.get("cost_savings", 0)
451
+ if result.get("success", False):
452
+ stats["successes"] += 1
453
+
454
+ # Calculate per-workflow averages
455
+ for stats in workflow_stats.values():
456
+ stats["avg_cost"] = stats["total_cost"] / stats["runs"]
457
+ stats["avg_savings"] = stats["total_savings"] / stats["runs"]
458
+ stats["success_rate"] = stats["successes"] / stats["runs"]
459
+
460
+ return {
461
+ "total_runs": total_runs,
462
+ "total_cost": round(total_cost, 2),
463
+ "total_savings": round(total_savings, 2),
464
+ "avg_savings_percent": round(avg_savings_percent, 1),
465
+ "escalation_rate": round(escalation_rate, 2),
466
+ "success_rate": round(success_rate, 2),
467
+ "avg_final_cqs": round(avg_cqs, 1),
468
+ "tier_usage": tier_usage,
469
+ "tier_costs": tier_costs,
470
+ "workflow_stats": workflow_stats,
471
+ }
472
+
473
+
474
+ def format_cost_analytics_report(analytics: dict[str, Any]) -> str:
475
+ """Format cost analytics as human-readable report.
476
+
477
+ Args:
478
+ analytics: Analytics data from generate_cost_analytics()
479
+
480
+ Returns:
481
+ Formatted report string
482
+
483
+ Example:
484
+ >>> analytics = generate_cost_analytics()
485
+ >>> print(format_cost_analytics_report(analytics))
486
+ """
487
+ report = []
488
+
489
+ report.append("━" * 60)
490
+ report.append("📊 PROGRESSIVE ESCALATION ANALYTICS")
491
+ report.append("━" * 60)
492
+ report.append("")
493
+
494
+ # Overall statistics
495
+ report.append("OVERALL STATISTICS:")
496
+ report.append(f" Total Runs: {analytics['total_runs']}")
497
+ report.append(f" Total Cost: ${analytics['total_cost']:.2f}")
498
+ report.append(f" Total Savings: ${analytics['total_savings']:.2f}")
499
+ report.append(f" Avg Savings: {analytics['avg_savings_percent']:.1f}%")
500
+ report.append(f" Escalation Rate: {analytics['escalation_rate']:.1%}")
501
+ report.append(f" Success Rate: {analytics['success_rate']:.1%}")
502
+ report.append(f" Avg Final CQS: {analytics['avg_final_cqs']:.1f}")
503
+ report.append("")
504
+
505
+ # Per-workflow breakdown
506
+ if analytics.get("workflow_stats"):
507
+ report.append("PER-WORKFLOW BREAKDOWN:")
508
+ report.append("")
509
+
510
+ for workflow, stats in sorted(analytics["workflow_stats"].items()):
511
+ report.append(f" {workflow}:")
512
+ report.append(f" Runs: {stats['runs']}")
513
+ report.append(f" Avg Cost: ${stats['avg_cost']:.2f}")
514
+ report.append(f" Avg Savings: ${stats['avg_savings']:.2f}")
515
+ report.append(f" Success Rate: {stats['success_rate']:.1%}")
516
+ report.append("")
517
+
518
+ report.append("━" * 60)
519
+
520
+ return "\n".join(report)