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,579 @@
1
+ """Trust Circuit Breaker
2
+
3
+ A cross-domain transfer of the circuit breaker pattern from reliability engineering
4
+ to human-AI trust management. Just as circuit breakers protect systems from cascading
5
+ failures, trust circuit breakers protect the AI-user relationship from trust erosion.
6
+
7
+ Pattern Origin: src/attune/resilience/circuit_breaker.py
8
+ Transfer Documentation: patterns/cross-domain/circuit-breaker-to-trust.md
9
+
10
+ Level: 5 (Systems Thinking) - Applying patterns across domains
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import logging
16
+ from collections.abc import Callable
17
+ from dataclasses import dataclass, field
18
+ from datetime import datetime, timedelta
19
+ from enum import Enum
20
+ from typing import Any
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ # =============================================================================
26
+ # Trust States (mapped from circuit breaker states)
27
+ # =============================================================================
28
+
29
+
30
+ class TrustState(Enum):
31
+ """Trust states mapped from circuit breaker states.
32
+
33
+ Circuit Breaker → Trust Mapping:
34
+ - CLOSED (normal) → FULL_AUTONOMY (AI acts freely)
35
+ - OPEN (failing fast) → REDUCED_AUTONOMY (require confirmation)
36
+ - HALF_OPEN (testing) → SUPERVISED (monitored recovery)
37
+ """
38
+
39
+ FULL_AUTONOMY = "full_autonomy"
40
+ """AI can act without confirmation. User trusts AI decisions."""
41
+
42
+ REDUCED_AUTONOMY = "reduced_autonomy"
43
+ """AI must confirm significant actions. Trust has been damaged."""
44
+
45
+ SUPERVISED = "supervised"
46
+ """AI is being tested for trust recovery. Partial confirmation needed."""
47
+
48
+
49
+ # =============================================================================
50
+ # Trust Events
51
+ # =============================================================================
52
+
53
+
54
+ class TrustDamageType(Enum):
55
+ """Types of events that damage trust."""
56
+
57
+ WRONG_ANSWER = "wrong_answer"
58
+ """AI provided incorrect information."""
59
+
60
+ IGNORED_PREFERENCE = "ignored_preference"
61
+ """AI acted against user's stated preferences."""
62
+
63
+ UNEXPECTED_ACTION = "unexpected_action"
64
+ """AI did something user didn't expect or want."""
65
+
66
+ SLOW_RESPONSE = "slow_response"
67
+ """AI was too slow, breaking flow."""
68
+
69
+ MISUNDERSTOOD_INTENT = "misunderstood_intent"
70
+ """AI misinterpreted what user wanted."""
71
+
72
+ REPETITIVE_ERROR = "repetitive_error"
73
+ """AI made the same mistake again."""
74
+
75
+
76
+ @dataclass
77
+ class TrustDamageEvent:
78
+ """Record of an event that damaged trust."""
79
+
80
+ event_type: TrustDamageType
81
+ timestamp: datetime = field(default_factory=datetime.now)
82
+ context: str = ""
83
+ severity: float = 1.0 # 0.0 to 1.0, higher = more damage
84
+ user_explicit: bool = False # User explicitly indicated damage
85
+
86
+ def __post_init__(self):
87
+ if isinstance(self.event_type, str):
88
+ self.event_type = TrustDamageType(self.event_type)
89
+
90
+
91
+ @dataclass
92
+ class TrustRecoveryEvent:
93
+ """Record of an event that builds trust."""
94
+
95
+ timestamp: datetime = field(default_factory=datetime.now)
96
+ context: str = ""
97
+ user_explicit: bool = False # User explicitly praised AI
98
+
99
+
100
+ # =============================================================================
101
+ # Configuration
102
+ # =============================================================================
103
+
104
+
105
+ @dataclass
106
+ class TrustConfig:
107
+ """Configuration for trust circuit breaker.
108
+
109
+ Mapped from circuit breaker config with trust-specific adaptations.
110
+ """
111
+
112
+ # Damage thresholds (mapped from failure_threshold)
113
+ damage_threshold: int = 3
114
+ """Number of trust-damaging events before reducing autonomy."""
115
+
116
+ damage_window_hours: float = 24.0
117
+ """Time window for counting damage events (recent damage matters more)."""
118
+
119
+ # Recovery settings (mapped from reset_timeout)
120
+ recovery_period_hours: float = 24.0
121
+ """Minimum time in reduced autonomy before testing recovery."""
122
+
123
+ supervised_successes_required: int = 5
124
+ """Successful interactions in supervised mode before full recovery."""
125
+
126
+ # Severity weights
127
+ severity_weights: dict[TrustDamageType, float] = field(
128
+ default_factory=lambda: {
129
+ TrustDamageType.WRONG_ANSWER: 1.0,
130
+ TrustDamageType.IGNORED_PREFERENCE: 1.5, # Preferences are important
131
+ TrustDamageType.UNEXPECTED_ACTION: 1.2,
132
+ TrustDamageType.SLOW_RESPONSE: 0.3, # Minor
133
+ TrustDamageType.MISUNDERSTOOD_INTENT: 0.8,
134
+ TrustDamageType.REPETITIVE_ERROR: 2.0, # Very damaging
135
+ },
136
+ )
137
+
138
+ # Domain-specific settings
139
+ domain_isolation: bool = True
140
+ """If True, trust is tracked per-domain (code review vs documentation)."""
141
+
142
+ # Actions requiring confirmation in each state
143
+ high_impact_actions: list[str] = field(
144
+ default_factory=lambda: [
145
+ "file_write",
146
+ "file_delete",
147
+ "git_commit",
148
+ "external_api_call",
149
+ "code_execution",
150
+ ],
151
+ )
152
+
153
+
154
+ # =============================================================================
155
+ # Trust Circuit Breaker
156
+ # =============================================================================
157
+
158
+
159
+ class TrustCircuitBreaker:
160
+ """Circuit breaker for AI autonomy based on user trust.
161
+
162
+ Cross-domain transfer: Uses the same state machine as reliability
163
+ circuit breakers, but applied to trust management.
164
+
165
+ State Transitions:
166
+ ```
167
+ FULL_AUTONOMY ──(damage threshold)──→ REDUCED_AUTONOMY
168
+ ↑ │
169
+ │ (recovery period)
170
+ │ ↓
171
+ └──(supervised successes)─── SUPERVISED
172
+ ```
173
+ """
174
+
175
+ def __init__(
176
+ self,
177
+ user_id: str,
178
+ config: TrustConfig | None = None,
179
+ domain: str = "general",
180
+ ):
181
+ self.user_id = user_id
182
+ self.config = config or TrustConfig()
183
+ self.domain = domain
184
+
185
+ # State tracking
186
+ self._state = TrustState.FULL_AUTONOMY
187
+ self._damage_events: list[TrustDamageEvent] = []
188
+ self._recovery_events: list[TrustRecoveryEvent] = []
189
+ self._state_changed_at: datetime = datetime.now()
190
+ self._supervised_successes: int = 0
191
+
192
+ # Callbacks
193
+ self._on_state_change: Callable[[TrustState, TrustState], None] | None = None
194
+
195
+ # =========================================================================
196
+ # State Properties
197
+ # =========================================================================
198
+
199
+ @property
200
+ def state(self) -> TrustState:
201
+ """Get current trust state, checking for recovery eligibility."""
202
+ self._check_recovery_eligibility()
203
+ return self._state
204
+
205
+ @property
206
+ def damage_score(self) -> float:
207
+ """Calculate current damage score (weighted sum of recent events).
208
+
209
+ Higher score = more damage. Threshold triggers state change.
210
+ """
211
+ window_start = datetime.now() - timedelta(hours=self.config.damage_window_hours)
212
+ recent_events = [e for e in self._damage_events if e.timestamp > window_start]
213
+
214
+ score = 0.0
215
+ for event in recent_events:
216
+ weight = self.config.severity_weights.get(event.event_type, 1.0)
217
+ # More recent events count more (time decay)
218
+ age_hours = (datetime.now() - event.timestamp).total_seconds() / 3600
219
+ recency_factor = max(0.5, 1.0 - (age_hours / self.config.damage_window_hours))
220
+ score += event.severity * weight * recency_factor
221
+
222
+ return score
223
+
224
+ @property
225
+ def can_act_freely(self) -> bool:
226
+ """Check if AI can act without confirmation."""
227
+ return self.state == TrustState.FULL_AUTONOMY
228
+
229
+ @property
230
+ def time_in_current_state(self) -> timedelta:
231
+ """How long we've been in the current state."""
232
+ return datetime.now() - self._state_changed_at
233
+
234
+ # =========================================================================
235
+ # Decision Methods
236
+ # =========================================================================
237
+
238
+ def should_require_confirmation(self, action: str) -> bool:
239
+ """Check if an action requires user confirmation.
240
+
241
+ Args:
242
+ action: The action being considered (e.g., "file_write", "suggest")
243
+
244
+ Returns:
245
+ True if confirmation should be requested
246
+
247
+ """
248
+ current_state = self.state
249
+
250
+ if current_state == TrustState.FULL_AUTONOMY:
251
+ return False
252
+
253
+ if current_state == TrustState.REDUCED_AUTONOMY:
254
+ return True # All actions need confirmation
255
+
256
+ if current_state == TrustState.SUPERVISED:
257
+ # Only high-impact actions need confirmation
258
+ return action in self.config.high_impact_actions
259
+
260
+ return True # Default to safe
261
+
262
+ def get_autonomy_level(self) -> dict[str, Any]:
263
+ """Get detailed autonomy level information for UI display.
264
+
265
+ Returns dict with state, allowed actions, and recovery progress.
266
+ """
267
+ state = self.state
268
+
269
+ return {
270
+ "state": state.value,
271
+ "can_act_freely": state == TrustState.FULL_AUTONOMY,
272
+ "damage_score": round(self.damage_score, 2),
273
+ "damage_threshold": self.config.damage_threshold,
274
+ "time_in_state_hours": round(self.time_in_current_state.total_seconds() / 3600, 1),
275
+ "recovery_progress": self._get_recovery_progress(),
276
+ "recent_damage_count": len(
277
+ [
278
+ e
279
+ for e in self._damage_events
280
+ if e.timestamp > datetime.now() - timedelta(hours=24)
281
+ ],
282
+ ),
283
+ }
284
+
285
+ def _get_recovery_progress(self) -> dict[str, Any]:
286
+ """Get progress toward trust recovery."""
287
+ if self._state == TrustState.FULL_AUTONOMY:
288
+ return {"status": "full_trust", "progress": 1.0}
289
+
290
+ if self._state == TrustState.REDUCED_AUTONOMY:
291
+ time_remaining = (
292
+ timedelta(hours=self.config.recovery_period_hours) - self.time_in_current_state
293
+ )
294
+ if time_remaining.total_seconds() > 0:
295
+ return {
296
+ "status": "cooling_off",
297
+ "progress": self.time_in_current_state.total_seconds()
298
+ / (self.config.recovery_period_hours * 3600),
299
+ "time_remaining_hours": round(time_remaining.total_seconds() / 3600, 1),
300
+ }
301
+ return {"status": "ready_for_supervised", "progress": 0.5}
302
+
303
+ if self._state == TrustState.SUPERVISED:
304
+ return {
305
+ "status": "supervised_testing",
306
+ "progress": 0.5
307
+ + (0.5 * self._supervised_successes / self.config.supervised_successes_required),
308
+ "successes": self._supervised_successes,
309
+ "required": self.config.supervised_successes_required,
310
+ }
311
+
312
+ return {"status": "unknown", "progress": 0.0}
313
+
314
+ # =========================================================================
315
+ # Event Recording
316
+ # =========================================================================
317
+
318
+ def record_damage(
319
+ self,
320
+ event_type: TrustDamageType | str,
321
+ context: str = "",
322
+ severity: float = 1.0,
323
+ user_explicit: bool = False,
324
+ ) -> TrustState:
325
+ """Record an event that damaged trust.
326
+
327
+ This is analogous to recording a failure in the reliability circuit breaker.
328
+
329
+ Args:
330
+ event_type: Type of trust damage
331
+ context: Description of what happened
332
+ severity: 0.0-1.0, how severe the damage was
333
+ user_explicit: True if user explicitly indicated damage
334
+
335
+ Returns:
336
+ The new trust state after recording
337
+
338
+ """
339
+ if isinstance(event_type, str):
340
+ event_type = TrustDamageType(event_type)
341
+
342
+ event = TrustDamageEvent(
343
+ event_type=event_type,
344
+ context=context,
345
+ severity=severity,
346
+ user_explicit=user_explicit,
347
+ )
348
+ self._damage_events.append(event)
349
+
350
+ logger.info(
351
+ f"Trust damage recorded for user {self.user_id}: "
352
+ f"{event_type.value} (severity={severity})",
353
+ )
354
+
355
+ # Check if we should transition to reduced autonomy
356
+ # Use small epsilon for floating point comparison (recency factor can cause tiny errors)
357
+ if self._state == TrustState.FULL_AUTONOMY:
358
+ if self.damage_score >= (self.config.damage_threshold - 0.01):
359
+ self._transition_to_reduced_autonomy()
360
+
361
+ # If in supervised mode, a damage event resets progress
362
+ elif self._state == TrustState.SUPERVISED:
363
+ self._supervised_successes = max(0, self._supervised_successes - 2)
364
+ logger.info(
365
+ f"Trust damage in supervised mode, successes reset to {self._supervised_successes}",
366
+ )
367
+
368
+ return self._state
369
+
370
+ def record_success(self, context: str = "", user_explicit: bool = False) -> TrustState:
371
+ """Record a successful/positive interaction.
372
+
373
+ This is analogous to recording a success in the reliability circuit breaker.
374
+
375
+ Args:
376
+ context: Description of the positive interaction
377
+ user_explicit: True if user explicitly praised the AI
378
+
379
+ Returns:
380
+ The new trust state after recording
381
+
382
+ """
383
+ event = TrustRecoveryEvent(
384
+ context=context,
385
+ user_explicit=user_explicit,
386
+ )
387
+ self._recovery_events.append(event)
388
+
389
+ # In supervised mode, successes count toward recovery
390
+ if self._state == TrustState.SUPERVISED:
391
+ self._supervised_successes += 1
392
+ logger.info(
393
+ f"Trust success in supervised mode: "
394
+ f"{self._supervised_successes}/{self.config.supervised_successes_required}",
395
+ )
396
+
397
+ if self._supervised_successes >= self.config.supervised_successes_required:
398
+ self._transition_to_full_autonomy()
399
+
400
+ return self._state
401
+
402
+ # =========================================================================
403
+ # State Transitions
404
+ # =========================================================================
405
+
406
+ def _check_recovery_eligibility(self) -> None:
407
+ """Check if we should transition from reduced to supervised."""
408
+ if self._state != TrustState.REDUCED_AUTONOMY:
409
+ return
410
+
411
+ time_in_state = self.time_in_current_state
412
+ recovery_period = timedelta(hours=self.config.recovery_period_hours)
413
+
414
+ if time_in_state >= recovery_period:
415
+ self._transition_to_supervised()
416
+
417
+ def _transition_to_reduced_autonomy(self) -> None:
418
+ """Transition to reduced autonomy (circuit opens)."""
419
+ old_state = self._state
420
+ self._state = TrustState.REDUCED_AUTONOMY
421
+ self._state_changed_at = datetime.now()
422
+ self._supervised_successes = 0
423
+
424
+ logger.warning(
425
+ f"Trust circuit opened for user {self.user_id}: {old_state.value} → {self._state.value}",
426
+ )
427
+
428
+ if self._on_state_change:
429
+ self._on_state_change(old_state, self._state)
430
+
431
+ def _transition_to_supervised(self) -> None:
432
+ """Transition to supervised mode (circuit half-opens)."""
433
+ old_state = self._state
434
+ self._state = TrustState.SUPERVISED
435
+ self._state_changed_at = datetime.now()
436
+ self._supervised_successes = 0
437
+
438
+ logger.info(
439
+ f"Trust circuit half-opened for user {self.user_id}: "
440
+ f"{old_state.value} → {self._state.value}",
441
+ )
442
+
443
+ if self._on_state_change:
444
+ self._on_state_change(old_state, self._state)
445
+
446
+ def _transition_to_full_autonomy(self) -> None:
447
+ """Transition to full autonomy (circuit closes)."""
448
+ old_state = self._state
449
+ self._state = TrustState.FULL_AUTONOMY
450
+ self._state_changed_at = datetime.now()
451
+
452
+ # Clear old damage events
453
+ cutoff = datetime.now() - timedelta(hours=self.config.damage_window_hours * 2)
454
+ self._damage_events = [e for e in self._damage_events if e.timestamp > cutoff]
455
+
456
+ logger.info(
457
+ f"Trust circuit closed for user {self.user_id}: {old_state.value} → {self._state.value}",
458
+ )
459
+
460
+ if self._on_state_change:
461
+ self._on_state_change(old_state, self._state)
462
+
463
+ # =========================================================================
464
+ # Manual Controls
465
+ # =========================================================================
466
+
467
+ def reset(self) -> None:
468
+ """Manually reset trust to full autonomy.
469
+
470
+ Use with caution - this skips the normal recovery process.
471
+ """
472
+ old_state = self._state
473
+ self._state = TrustState.FULL_AUTONOMY
474
+ self._state_changed_at = datetime.now()
475
+ self._damage_events.clear()
476
+ self._supervised_successes = 0
477
+
478
+ logger.info(f"Trust manually reset for user {self.user_id}")
479
+
480
+ if self._on_state_change:
481
+ self._on_state_change(old_state, self._state)
482
+
483
+ def on_state_change(self, callback: Callable[[TrustState, TrustState], None]) -> None:
484
+ """Register a callback for state changes."""
485
+ self._on_state_change = callback
486
+
487
+ # =========================================================================
488
+ # Serialization
489
+ # =========================================================================
490
+
491
+ def to_dict(self) -> dict[str, Any]:
492
+ """Serialize state for persistence."""
493
+ return {
494
+ "user_id": self.user_id,
495
+ "domain": self.domain,
496
+ "state": self._state.value,
497
+ "state_changed_at": self._state_changed_at.isoformat(),
498
+ "supervised_successes": self._supervised_successes,
499
+ "damage_events": [
500
+ {
501
+ "event_type": e.event_type.value,
502
+ "timestamp": e.timestamp.isoformat(),
503
+ "context": e.context,
504
+ "severity": e.severity,
505
+ "user_explicit": e.user_explicit,
506
+ }
507
+ for e in self._damage_events
508
+ ],
509
+ "config": {
510
+ "damage_threshold": self.config.damage_threshold,
511
+ "recovery_period_hours": self.config.recovery_period_hours,
512
+ "supervised_successes_required": self.config.supervised_successes_required,
513
+ },
514
+ }
515
+
516
+ @classmethod
517
+ def from_dict(cls, data: dict[str, Any]) -> TrustCircuitBreaker:
518
+ """Restore from serialized state."""
519
+ config = TrustConfig(
520
+ damage_threshold=data["config"]["damage_threshold"],
521
+ recovery_period_hours=data["config"]["recovery_period_hours"],
522
+ supervised_successes_required=data["config"]["supervised_successes_required"],
523
+ )
524
+
525
+ instance = cls(
526
+ user_id=data["user_id"],
527
+ config=config,
528
+ domain=data.get("domain", "general"),
529
+ )
530
+
531
+ instance._state = TrustState(data["state"])
532
+ instance._state_changed_at = datetime.fromisoformat(data["state_changed_at"])
533
+ instance._supervised_successes = data.get("supervised_successes", 0)
534
+
535
+ for e in data.get("damage_events", []):
536
+ instance._damage_events.append(
537
+ TrustDamageEvent(
538
+ event_type=TrustDamageType(e["event_type"]),
539
+ timestamp=datetime.fromisoformat(e["timestamp"]),
540
+ context=e.get("context", ""),
541
+ severity=e.get("severity", 1.0),
542
+ user_explicit=e.get("user_explicit", False),
543
+ ),
544
+ )
545
+
546
+ return instance
547
+
548
+
549
+ # =============================================================================
550
+ # Convenience Functions
551
+ # =============================================================================
552
+
553
+
554
+ def create_trust_breaker(
555
+ user_id: str,
556
+ domain: str = "general",
557
+ strict: bool = False,
558
+ ) -> TrustCircuitBreaker:
559
+ """Create a trust circuit breaker with preset configurations.
560
+
561
+ Args:
562
+ user_id: User identifier
563
+ domain: Domain for trust tracking (if domain_isolation enabled)
564
+ strict: If True, use stricter thresholds (fewer mistakes allowed)
565
+
566
+ Returns:
567
+ Configured TrustCircuitBreaker instance
568
+
569
+ """
570
+ if strict:
571
+ config = TrustConfig(
572
+ damage_threshold=2,
573
+ recovery_period_hours=48.0,
574
+ supervised_successes_required=10,
575
+ )
576
+ else:
577
+ config = TrustConfig() # Defaults
578
+
579
+ return TrustCircuitBreaker(user_id=user_id, config=config, domain=domain)