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,89 @@
1
+ {
2
+ "version": "1.0",
3
+ "updated_at": "2026-01-07T06:30:43.930352",
4
+ "node_count": 5,
5
+ "edge_count": 0,
6
+ "nodes": [
7
+ {
8
+ "id": "refactoring_analysis_20260107063043_663dbce03854",
9
+ "type": "pattern",
10
+ "name": "refactor:workflows/bug_predict.py",
11
+ "description": "Found 1 refactoring opportunities:\n - 1 medium impact\n\nTop categories:\n - other: 1",
12
+ "source_wizard": "refactoring_crew",
13
+ "source_file": "",
14
+ "source_line": null,
15
+ "severity": "",
16
+ "confidence": 1.0,
17
+ "metadata": {},
18
+ "tags": [],
19
+ "created_at": "2026-01-07T06:30:43.460922",
20
+ "updated_at": "2026-01-07T06:30:43.460924",
21
+ "status": "open"
22
+ },
23
+ {
24
+ "id": "refactoring_analysis_20260107063043_fc92406de1d5",
25
+ "type": "pattern",
26
+ "name": "refactor:monitoring/alerts_cli.py",
27
+ "description": "Found 1 refactoring opportunities:\n - 1 medium impact\n\nTop categories:\n - other: 1",
28
+ "source_wizard": "refactoring_crew",
29
+ "source_file": "",
30
+ "source_line": null,
31
+ "severity": "",
32
+ "confidence": 1.0,
33
+ "metadata": {},
34
+ "tags": [],
35
+ "created_at": "2026-01-07T06:30:43.593291",
36
+ "updated_at": "2026-01-07T06:30:43.593291",
37
+ "status": "open"
38
+ },
39
+ {
40
+ "id": "refactoring_analysis_20260107063043_5cce2d4230a4",
41
+ "type": "pattern",
42
+ "name": "refactor:memory/edges.py",
43
+ "description": "Found 1 refactoring opportunities:\n - 1 medium impact\n\nTop categories:\n - other: 1",
44
+ "source_wizard": "refactoring_crew",
45
+ "source_file": "",
46
+ "source_line": null,
47
+ "severity": "",
48
+ "confidence": 1.0,
49
+ "metadata": {},
50
+ "tags": [],
51
+ "created_at": "2026-01-07T06:30:43.682805",
52
+ "updated_at": "2026-01-07T06:30:43.682806",
53
+ "status": "open"
54
+ },
55
+ {
56
+ "id": "refactoring_analysis_20260107063043_0ef136ce11fb",
57
+ "type": "pattern",
58
+ "name": "refactor:workflows/refactor_plan.py",
59
+ "description": "Found 1 refactoring opportunities:\n - 1 medium impact\n\nTop categories:\n - other: 1",
60
+ "source_wizard": "refactoring_crew",
61
+ "source_file": "",
62
+ "source_line": null,
63
+ "severity": "",
64
+ "confidence": 1.0,
65
+ "metadata": {},
66
+ "tags": [],
67
+ "created_at": "2026-01-07T06:30:43.796584",
68
+ "updated_at": "2026-01-07T06:30:43.796586",
69
+ "status": "open"
70
+ },
71
+ {
72
+ "id": "refactoring_analysis_20260107063043_3c6673a7bb17",
73
+ "type": "pattern",
74
+ "name": "refactor:workflows/new_sample_workflow1.py",
75
+ "description": "Found 1 refactoring opportunities:\n - 1 medium impact\n\nTop categories:\n - other: 1",
76
+ "source_wizard": "refactoring_crew",
77
+ "source_file": "",
78
+ "source_line": null,
79
+ "severity": "",
80
+ "confidence": 1.0,
81
+ "metadata": {},
82
+ "tags": [],
83
+ "created_at": "2026-01-07T06:30:43.930183",
84
+ "updated_at": "2026-01-07T06:30:43.930183",
85
+ "status": "open"
86
+ }
87
+ ],
88
+ "edges": []
89
+ }
attune/persistence.py ADDED
@@ -0,0 +1,564 @@
1
+ """Persistence Layer for Empathy Framework
2
+
3
+ Provides:
4
+ - Pattern library save/load (JSON, SQLite)
5
+ - Collaboration state persistence
6
+ - Metrics and telemetry tracking
7
+
8
+ Copyright 2025 Smart AI Memory, LLC
9
+ Licensed under Fair Source 0.9
10
+ """
11
+
12
+ import json
13
+ import sqlite3
14
+ from datetime import datetime
15
+ from pathlib import Path
16
+ from typing import Any
17
+
18
+ from .config import _validate_file_path
19
+ from .core import CollaborationState
20
+ from .pattern_library import Pattern, PatternLibrary
21
+
22
+
23
+ class PatternPersistence:
24
+ """Save and load PatternLibrary to/from files
25
+
26
+ Supports:
27
+ - JSON format (human-readable, good for backups)
28
+ - SQLite format (queryable, good for production)
29
+ """
30
+
31
+ @staticmethod
32
+ def save_to_json(library: PatternLibrary, filepath: str):
33
+ """Save pattern library to JSON file
34
+
35
+ Args:
36
+ library: PatternLibrary instance to save
37
+ filepath: Path to JSON file
38
+
39
+ Example:
40
+ >>> library = PatternLibrary()
41
+ >>> PatternPersistence.save_to_json(library, "patterns.json")
42
+
43
+ """
44
+ patterns_list: list[dict[str, Any]] = []
45
+ data: dict[str, Any] = {
46
+ "patterns": patterns_list,
47
+ "agent_contributions": library.agent_contributions,
48
+ "metadata": {
49
+ "saved_at": datetime.now().isoformat(),
50
+ "pattern_count": len(library.patterns),
51
+ "version": "1.0",
52
+ },
53
+ }
54
+
55
+ # Serialize each pattern
56
+ for _pattern_id, pattern in library.patterns.items():
57
+ patterns_list.append(
58
+ {
59
+ "id": pattern.id,
60
+ "agent_id": pattern.agent_id,
61
+ "pattern_type": pattern.pattern_type,
62
+ "name": pattern.name,
63
+ "description": pattern.description,
64
+ "context": pattern.context,
65
+ "code": pattern.code,
66
+ "confidence": pattern.confidence,
67
+ "usage_count": pattern.usage_count,
68
+ "success_count": pattern.success_count,
69
+ "failure_count": pattern.failure_count,
70
+ "tags": pattern.tags,
71
+ "discovered_at": pattern.discovered_at.isoformat(),
72
+ "last_used": pattern.last_used.isoformat() if pattern.last_used else None,
73
+ },
74
+ )
75
+
76
+ # Write to file
77
+ validated_path = _validate_file_path(filepath)
78
+ with open(validated_path, "w") as f:
79
+ json.dump(data, f, indent=2)
80
+
81
+ @staticmethod
82
+ def load_from_json(filepath: str) -> PatternLibrary:
83
+ """Load pattern library from JSON file
84
+
85
+ Args:
86
+ filepath: Path to JSON file
87
+
88
+ Returns:
89
+ PatternLibrary instance
90
+
91
+ Raises:
92
+ FileNotFoundError: If file doesn't exist
93
+ json.JSONDecodeError: If file is not valid JSON
94
+
95
+ Example:
96
+ >>> library = PatternPersistence.load_from_json("patterns.json")
97
+
98
+ """
99
+ with open(filepath) as f:
100
+ data = json.load(f)
101
+
102
+ library = PatternLibrary()
103
+
104
+ # Restore patterns
105
+ for pattern_data in data["patterns"]:
106
+ pattern = Pattern(
107
+ id=pattern_data["id"],
108
+ agent_id=pattern_data["agent_id"],
109
+ pattern_type=pattern_data["pattern_type"],
110
+ name=pattern_data["name"],
111
+ description=pattern_data["description"],
112
+ context=pattern_data.get("context", {}),
113
+ code=pattern_data.get("code"),
114
+ confidence=pattern_data.get("confidence", 0.5),
115
+ usage_count=pattern_data.get("usage_count", 0),
116
+ success_count=pattern_data.get("success_count", 0),
117
+ failure_count=pattern_data.get("failure_count", 0),
118
+ tags=pattern_data.get("tags", []),
119
+ discovered_at=datetime.fromisoformat(pattern_data["discovered_at"]),
120
+ last_used=(
121
+ datetime.fromisoformat(pattern_data["last_used"])
122
+ if pattern_data.get("last_used")
123
+ else None
124
+ ),
125
+ )
126
+ library.contribute_pattern(pattern.agent_id, pattern)
127
+
128
+ # Restore agent_contributions index
129
+ library.agent_contributions = data.get("agent_contributions", {})
130
+
131
+ return library
132
+
133
+ @staticmethod
134
+ def save_to_sqlite(library: PatternLibrary, db_path: str):
135
+ """Save pattern library to SQLite database
136
+
137
+ Args:
138
+ library: PatternLibrary instance to save
139
+ db_path: Path to SQLite database file
140
+
141
+ Creates tables:
142
+ - patterns: Core pattern data
143
+ - pattern_usage: Usage history
144
+
145
+ Example:
146
+ >>> library = PatternLibrary()
147
+ >>> PatternPersistence.save_to_sqlite(library, "patterns.db")
148
+
149
+ """
150
+ conn = sqlite3.connect(db_path)
151
+ cursor = conn.cursor()
152
+
153
+ # Create tables
154
+ cursor.execute(
155
+ """
156
+ CREATE TABLE IF NOT EXISTS patterns (
157
+ id TEXT PRIMARY KEY,
158
+ agent_id TEXT NOT NULL,
159
+ pattern_type TEXT NOT NULL,
160
+ name TEXT NOT NULL,
161
+ description TEXT,
162
+ context TEXT,
163
+ code TEXT,
164
+ confidence REAL DEFAULT 0.5,
165
+ usage_count INTEGER DEFAULT 0,
166
+ success_count INTEGER DEFAULT 0,
167
+ failure_count INTEGER DEFAULT 0,
168
+ tags TEXT,
169
+ discovered_at TIMESTAMP,
170
+ last_used TIMESTAMP,
171
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
172
+ )
173
+ """,
174
+ )
175
+
176
+ cursor.execute(
177
+ """
178
+ CREATE TABLE IF NOT EXISTS pattern_usage (
179
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
180
+ pattern_id TEXT NOT NULL,
181
+ agent_id TEXT NOT NULL,
182
+ success BOOLEAN NOT NULL,
183
+ used_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
184
+ FOREIGN KEY (pattern_id) REFERENCES patterns(id)
185
+ )
186
+ """,
187
+ )
188
+
189
+ # Insert or update patterns
190
+ for pattern in library.patterns.values():
191
+ cursor.execute(
192
+ """
193
+ INSERT OR REPLACE INTO patterns (
194
+ id, agent_id, pattern_type, name, description, context,
195
+ code, confidence, usage_count, success_count, failure_count,
196
+ tags, discovered_at, last_used, updated_at
197
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
198
+ """,
199
+ (
200
+ pattern.id,
201
+ pattern.agent_id,
202
+ pattern.pattern_type,
203
+ pattern.name,
204
+ pattern.description,
205
+ json.dumps(pattern.context),
206
+ pattern.code,
207
+ pattern.confidence,
208
+ pattern.usage_count,
209
+ pattern.success_count,
210
+ pattern.failure_count,
211
+ json.dumps(pattern.tags),
212
+ pattern.discovered_at.isoformat(),
213
+ pattern.last_used.isoformat() if pattern.last_used else None,
214
+ ),
215
+ )
216
+
217
+ conn.commit()
218
+ conn.close()
219
+
220
+ @staticmethod
221
+ def load_from_sqlite(db_path: str) -> PatternLibrary:
222
+ """Load pattern library from SQLite database
223
+
224
+ Args:
225
+ db_path: Path to SQLite database file
226
+
227
+ Returns:
228
+ PatternLibrary instance
229
+
230
+ Example:
231
+ >>> library = PatternPersistence.load_from_sqlite("patterns.db")
232
+
233
+ """
234
+ conn = sqlite3.connect(db_path)
235
+ conn.row_factory = sqlite3.Row # Access columns by name
236
+ cursor = conn.cursor()
237
+
238
+ library = PatternLibrary()
239
+
240
+ # Load patterns
241
+ cursor.execute("SELECT * FROM patterns")
242
+ rows = cursor.fetchall()
243
+
244
+ for row in rows:
245
+ pattern = Pattern(
246
+ id=row["id"],
247
+ agent_id=row["agent_id"],
248
+ pattern_type=row["pattern_type"],
249
+ name=row["name"],
250
+ description=row["description"],
251
+ context=json.loads(row["context"]),
252
+ code=row["code"],
253
+ confidence=row["confidence"],
254
+ usage_count=row["usage_count"],
255
+ success_count=row["success_count"],
256
+ failure_count=row["failure_count"],
257
+ tags=json.loads(row["tags"]),
258
+ discovered_at=datetime.fromisoformat(row["discovered_at"]),
259
+ last_used=datetime.fromisoformat(row["last_used"]) if row["last_used"] else None,
260
+ )
261
+ library.contribute_pattern(pattern.agent_id, pattern)
262
+
263
+ conn.close()
264
+ return library
265
+
266
+
267
+ class StateManager:
268
+ """Persist collaboration state across sessions
269
+
270
+ Enables:
271
+ - Long-term trust tracking
272
+ - Historical analytics
273
+ - User personalization
274
+ """
275
+
276
+ def __init__(self, storage_path: str = "./empathy_state"):
277
+ self.storage_path = Path(storage_path)
278
+ self.storage_path.mkdir(exist_ok=True, parents=True)
279
+
280
+ def save_state(self, user_id: str, state: CollaborationState):
281
+ """Save user's collaboration state to JSON
282
+
283
+ Args:
284
+ user_id: User identifier
285
+ state: CollaborationState instance
286
+
287
+ Example:
288
+ >>> manager = StateManager()
289
+ >>> manager.save_state("user123", empathy.collaboration_state)
290
+
291
+ """
292
+ filepath = self.storage_path / f"{user_id}.json"
293
+
294
+ data = {
295
+ "user_id": user_id,
296
+ "trust_level": state.trust_level,
297
+ "total_interactions": state.total_interactions,
298
+ "successful_interventions": state.successful_interventions,
299
+ "failed_interventions": state.failed_interventions,
300
+ "session_start": state.session_start.isoformat(),
301
+ "trust_trajectory": state.trust_trajectory,
302
+ "shared_context": state.shared_context,
303
+ "saved_at": datetime.now().isoformat(),
304
+ }
305
+
306
+ validated_path = _validate_file_path(str(filepath))
307
+ with open(validated_path, "w") as f:
308
+ json.dump(data, f, indent=2)
309
+
310
+ def load_state(self, user_id: str) -> CollaborationState | None:
311
+ """Load user's previous state
312
+
313
+ Args:
314
+ user_id: User identifier
315
+
316
+ Returns:
317
+ CollaborationState if found, None otherwise
318
+
319
+ Example:
320
+ >>> manager = StateManager()
321
+ >>> state = manager.load_state("user123")
322
+ >>> if state:
323
+ ... empathy = EmpathyOS(user_id="user123", target_level=4)
324
+ ... empathy.collaboration_state = state
325
+
326
+ """
327
+ filepath = self.storage_path / f"{user_id}.json"
328
+
329
+ if not filepath.exists():
330
+ return None
331
+
332
+ try:
333
+ with open(filepath) as f:
334
+ data = json.load(f)
335
+
336
+ state = CollaborationState()
337
+ state.trust_level = data["trust_level"]
338
+ state.total_interactions = data["total_interactions"]
339
+ state.successful_interventions = data["successful_interventions"]
340
+ state.failed_interventions = data["failed_interventions"]
341
+ state.session_start = datetime.fromisoformat(data["session_start"])
342
+ state.trust_trajectory = data.get("trust_trajectory", [])
343
+ state.shared_context = data.get("shared_context", {})
344
+
345
+ return state
346
+
347
+ except (json.JSONDecodeError, KeyError, ValueError):
348
+ # Corrupted file - return None
349
+ return None
350
+
351
+ def list_users(self) -> list[str]:
352
+ """List all users with saved state
353
+
354
+ Returns:
355
+ List of user IDs
356
+
357
+ Example:
358
+ >>> manager = StateManager()
359
+ >>> users = manager.list_users()
360
+ >>> print(f"Found {len(users)} users")
361
+
362
+ """
363
+ return [p.stem for p in self.storage_path.glob("*.json")]
364
+
365
+ def delete_state(self, user_id: str) -> bool:
366
+ """Delete user's saved state
367
+
368
+ Args:
369
+ user_id: User identifier
370
+
371
+ Returns:
372
+ True if deleted, False if didn't exist
373
+
374
+ Example:
375
+ >>> manager = StateManager()
376
+ >>> deleted = manager.delete_state("user123")
377
+
378
+ """
379
+ filepath = self.storage_path / f"{user_id}.json"
380
+
381
+ if filepath.exists():
382
+ filepath.unlink()
383
+ return True
384
+ return False
385
+
386
+
387
+ class MetricsCollector:
388
+ """Collect and persist empathy framework metrics
389
+
390
+ Tracks:
391
+ - Empathy level usage
392
+ - Success rates by level
393
+ - Average response times
394
+ - Trust trajectory trends
395
+ """
396
+
397
+ def __init__(self, db_path: str = "./metrics.db"):
398
+ self.db_path = db_path
399
+ self._init_database()
400
+
401
+ def _init_database(self):
402
+ """Initialize SQLite database for metrics"""
403
+ conn = sqlite3.connect(self.db_path)
404
+ cursor = conn.cursor()
405
+
406
+ cursor.execute(
407
+ """
408
+ CREATE TABLE IF NOT EXISTS metrics (
409
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
410
+ user_id TEXT NOT NULL,
411
+ empathy_level INTEGER NOT NULL,
412
+ success BOOLEAN NOT NULL,
413
+ response_time_ms REAL,
414
+ timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
415
+ metadata TEXT
416
+ )
417
+ """,
418
+ )
419
+
420
+ cursor.execute(
421
+ """
422
+ CREATE INDEX IF NOT EXISTS idx_user_level
423
+ ON metrics(user_id, empathy_level)
424
+ """,
425
+ )
426
+
427
+ cursor.execute(
428
+ """
429
+ CREATE INDEX IF NOT EXISTS idx_timestamp
430
+ ON metrics(timestamp)
431
+ """,
432
+ )
433
+
434
+ conn.commit()
435
+ conn.close()
436
+
437
+ def record_metric(
438
+ self,
439
+ user_id: str,
440
+ empathy_level: int,
441
+ success: bool,
442
+ response_time_ms: float,
443
+ metadata: dict | None = None,
444
+ ):
445
+ """Record a single metric event
446
+
447
+ Args:
448
+ user_id: User identifier
449
+ empathy_level: 1-5 empathy level used
450
+ success: Whether the operation succeeded
451
+ response_time_ms: Response time in milliseconds
452
+ metadata: Optional additional data
453
+
454
+ Example:
455
+ >>> collector = MetricsCollector()
456
+ >>> collector.record_metric(
457
+ ... user_id="user123",
458
+ ... empathy_level=4,
459
+ ... success=True,
460
+ ... response_time_ms=250.5,
461
+ ... metadata={"bottlenecks_predicted": 3}
462
+ ... )
463
+
464
+ """
465
+ conn = sqlite3.connect(self.db_path)
466
+ cursor = conn.cursor()
467
+
468
+ cursor.execute(
469
+ """
470
+ INSERT INTO metrics (
471
+ user_id, empathy_level, success, response_time_ms, metadata
472
+ ) VALUES (?, ?, ?, ?, ?)
473
+ """,
474
+ (
475
+ user_id,
476
+ empathy_level,
477
+ success,
478
+ response_time_ms,
479
+ json.dumps(metadata) if metadata else None,
480
+ ),
481
+ )
482
+
483
+ conn.commit()
484
+ conn.close()
485
+
486
+ def get_user_stats(self, user_id: str) -> dict:
487
+ """Get aggregated statistics for a user
488
+
489
+ Args:
490
+ user_id: User identifier
491
+
492
+ Returns:
493
+ Dict with statistics
494
+
495
+ Example:
496
+ >>> collector = MetricsCollector()
497
+ >>> stats = collector.get_user_stats("user123")
498
+ >>> print(f"Success rate: {stats['success_rate']:.1%}")
499
+
500
+ """
501
+ conn = sqlite3.connect(self.db_path)
502
+ conn.row_factory = sqlite3.Row
503
+ cursor = conn.cursor()
504
+
505
+ cursor.execute(
506
+ """
507
+ SELECT
508
+ COUNT(*) as total_operations,
509
+ SUM(CASE WHEN success THEN 1 ELSE 0 END) as successes,
510
+ AVG(response_time_ms) as avg_response_time,
511
+ MIN(timestamp) as first_use,
512
+ MAX(timestamp) as last_use
513
+ FROM metrics
514
+ WHERE user_id = ?
515
+ """,
516
+ (user_id,),
517
+ )
518
+
519
+ row = cursor.fetchone()
520
+
521
+ if not row or row["total_operations"] == 0:
522
+ conn.close()
523
+ return {
524
+ "total_operations": 0,
525
+ "success_rate": 0.0,
526
+ "avg_response_time_ms": 0.0,
527
+ "first_use": None,
528
+ "last_use": None,
529
+ }
530
+
531
+ # Get per-level breakdown
532
+ cursor.execute(
533
+ """
534
+ SELECT
535
+ empathy_level,
536
+ COUNT(*) as operations,
537
+ SUM(CASE WHEN success THEN 1 ELSE 0 END) as successes
538
+ FROM metrics
539
+ WHERE user_id = ?
540
+ GROUP BY empathy_level
541
+ ORDER BY empathy_level
542
+ """,
543
+ (user_id,),
544
+ )
545
+
546
+ level_stats = {}
547
+ for level_row in cursor.fetchall():
548
+ level = level_row["empathy_level"]
549
+ ops = level_row["operations"]
550
+ level_stats[f"level_{level}"] = {
551
+ "operations": ops,
552
+ "success_rate": level_row["successes"] / ops if ops > 0 else 0.0,
553
+ }
554
+
555
+ conn.close()
556
+
557
+ return {
558
+ "total_operations": row["total_operations"],
559
+ "success_rate": row["successes"] / row["total_operations"],
560
+ "avg_response_time_ms": row["avg_response_time"],
561
+ "first_use": row["first_use"],
562
+ "last_use": row["last_use"],
563
+ "by_level": level_stats,
564
+ }