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,302 @@
1
+ """Simplified long-term storage without security pipeline
2
+
3
+ Provides basic CRUD operations for long-term persistent storage without
4
+ the full security pipeline of SecureMemDocsIntegration. Suitable for
5
+ simple storage needs where PII scrubbing and encryption are not required.
6
+
7
+ Extracted from long_term.py for better modularity and testability.
8
+
9
+ Features:
10
+ - JSON file-based storage
11
+ - Classification support (PUBLIC/INTERNAL/SENSITIVE)
12
+ - Simple key-value interface
13
+ - List keys by classification
14
+ - Path validation for security
15
+
16
+ Copyright 2025 Smart AI Memory, LLC
17
+ Licensed under Fair Source 0.9
18
+ """
19
+
20
+ import json
21
+ from datetime import datetime
22
+ from pathlib import Path
23
+ from typing import Any
24
+
25
+ import structlog
26
+
27
+ from attune.config import _validate_file_path
28
+
29
+ from .long_term_types import Classification
30
+
31
+ logger = structlog.get_logger(__name__)
32
+
33
+
34
+ class LongTermMemory:
35
+ """Simplified long-term persistent storage interface.
36
+
37
+ Provides basic CRUD operations for long-term memory storage without
38
+ the full security pipeline of SecureMemDocsIntegration. Suitable for
39
+ simple persistent storage needs where PII scrubbing and encryption
40
+ are not required.
41
+
42
+ Features:
43
+ - JSON file-based storage
44
+ - Classification support (PUBLIC/INTERNAL/SENSITIVE)
45
+ - Simple key-value interface
46
+ - List keys by classification
47
+
48
+ Example:
49
+ >>> memory = LongTermMemory(storage_path="./data")
50
+ >>> memory.store("config", {"setting": "value"}, classification="INTERNAL")
51
+ >>> data = memory.retrieve("config")
52
+ >>> keys = memory.list_keys(classification="INTERNAL")
53
+
54
+ Note:
55
+ For enterprise features (PII scrubbing, encryption, audit logging),
56
+ use SecureMemDocsIntegration instead.
57
+ """
58
+
59
+ def __init__(self, storage_path: str = "./long_term_storage"):
60
+ """Initialize long-term memory storage.
61
+
62
+ Args:
63
+ storage_path: Directory path for JSON storage
64
+
65
+ """
66
+ self.storage_path = Path(storage_path)
67
+ self.storage_path.mkdir(parents=True, exist_ok=True)
68
+ logger.info("long_term_memory_initialized", storage_path=str(self.storage_path))
69
+
70
+ def store(
71
+ self,
72
+ key: str,
73
+ data: Any,
74
+ classification: str | Classification | None = None,
75
+ ) -> bool:
76
+ """Store data in long-term memory.
77
+
78
+ Args:
79
+ key: Storage key
80
+ data: Data to store (must be JSON-serializable)
81
+ classification: Data classification (PUBLIC/INTERNAL/SENSITIVE)
82
+
83
+ Returns:
84
+ True if stored successfully, False otherwise
85
+
86
+ Raises:
87
+ ValueError: If key is empty or data is not JSON-serializable
88
+ TypeError: If data cannot be serialized to JSON
89
+
90
+ Example:
91
+ >>> memory = LongTermMemory()
92
+ >>> memory.store("user_prefs", {"theme": "dark"}, "INTERNAL")
93
+ True
94
+
95
+ """
96
+ if not key or not key.strip():
97
+ raise ValueError(f"key cannot be empty. Got: {key!r}")
98
+
99
+ # Validate key for path traversal attacks
100
+ if ".." in key or key.startswith("/") or "\x00" in key:
101
+ logger.error("path_traversal_attempt", key=key)
102
+ return False
103
+
104
+ try:
105
+ # Convert classification to string
106
+ classification_str = "INTERNAL" # Default
107
+ if classification is not None:
108
+ if isinstance(classification, Classification):
109
+ classification_str = classification.value
110
+ elif isinstance(classification, str):
111
+ # Validate classification string
112
+ try:
113
+ Classification[classification.upper()]
114
+ classification_str = classification.upper()
115
+ except KeyError:
116
+ logger.warning(
117
+ "invalid_classification",
118
+ classification=classification,
119
+ using_default="INTERNAL",
120
+ )
121
+
122
+ # Create storage record
123
+ record = {
124
+ "key": key,
125
+ "data": data,
126
+ "classification": classification_str,
127
+ "created_at": datetime.utcnow().isoformat() + "Z",
128
+ "updated_at": datetime.utcnow().isoformat() + "Z",
129
+ }
130
+
131
+ # Store to JSON file
132
+ file_path = self.storage_path / f"{key}.json"
133
+ validated_file_path = _validate_file_path(str(file_path))
134
+ with validated_file_path.open("w", encoding="utf-8") as f:
135
+ json.dump(record, f, indent=2)
136
+
137
+ logger.debug("data_stored", key=key, classification=classification_str)
138
+ return True
139
+
140
+ except (TypeError, ValueError) as e:
141
+ logger.error("store_failed", key=key, error=str(e))
142
+ raise
143
+ except (OSError, PermissionError) as e:
144
+ logger.error("storage_io_error", key=key, error=str(e))
145
+ return False
146
+
147
+ def retrieve(self, key: str) -> Any | None:
148
+ """Retrieve data from long-term memory.
149
+
150
+ Args:
151
+ key: Storage key
152
+
153
+ Returns:
154
+ Stored data or None if not found
155
+
156
+ Raises:
157
+ ValueError: If key is empty
158
+
159
+ Example:
160
+ >>> memory = LongTermMemory()
161
+ >>> memory.store("config", {"value": 42})
162
+ >>> data = memory.retrieve("config")
163
+ >>> print(data["value"])
164
+ 42
165
+
166
+ """
167
+ if not key or not key.strip():
168
+ raise ValueError(f"key cannot be empty. Got: {key!r}")
169
+
170
+ try:
171
+ file_path = self.storage_path / f"{key}.json"
172
+
173
+ if not file_path.exists():
174
+ logger.debug("key_not_found", key=key)
175
+ return None
176
+
177
+ with file_path.open(encoding="utf-8") as f:
178
+ record = json.load(f)
179
+
180
+ logger.debug("data_retrieved", key=key)
181
+ return record.get("data")
182
+
183
+ except (OSError, PermissionError, json.JSONDecodeError) as e:
184
+ logger.error("retrieve_failed", key=key, error=str(e))
185
+ return None
186
+
187
+ def delete(self, key: str) -> bool:
188
+ """Delete data from long-term memory.
189
+
190
+ Args:
191
+ key: Storage key
192
+
193
+ Returns:
194
+ True if deleted, False if not found or error
195
+
196
+ Raises:
197
+ ValueError: If key is empty
198
+
199
+ Example:
200
+ >>> memory = LongTermMemory()
201
+ >>> memory.store("temp", {"data": "value"})
202
+ >>> memory.delete("temp")
203
+ True
204
+
205
+ """
206
+ if not key or not key.strip():
207
+ raise ValueError(f"key cannot be empty. Got: {key!r}")
208
+
209
+ try:
210
+ file_path = self.storage_path / f"{key}.json"
211
+
212
+ if not file_path.exists():
213
+ logger.debug("key_not_found_for_deletion", key=key)
214
+ return False
215
+
216
+ file_path.unlink()
217
+ logger.info("data_deleted", key=key)
218
+ return True
219
+
220
+ except (OSError, PermissionError) as e:
221
+ logger.error("delete_failed", key=key, error=str(e))
222
+ return False
223
+
224
+ def list_keys(self, classification: str | Classification | None = None) -> list[str]:
225
+ """List all keys in long-term memory, optionally filtered by classification.
226
+
227
+ Args:
228
+ classification: Filter by classification (PUBLIC/INTERNAL/SENSITIVE)
229
+
230
+ Returns:
231
+ List of storage keys
232
+
233
+ Example:
234
+ >>> memory = LongTermMemory()
235
+ >>> memory.store("public_data", {"x": 1}, "PUBLIC")
236
+ >>> memory.store("internal_data", {"y": 2}, "INTERNAL")
237
+ >>> keys = memory.list_keys(classification="PUBLIC")
238
+ >>> print(keys)
239
+ ['public_data']
240
+
241
+ """
242
+ keys = []
243
+
244
+ # Convert classification to string if needed
245
+ filter_classification = None
246
+ if classification is not None:
247
+ if isinstance(classification, Classification):
248
+ filter_classification = classification.value
249
+ elif isinstance(classification, str):
250
+ try:
251
+ Classification[classification.upper()]
252
+ filter_classification = classification.upper()
253
+ except KeyError:
254
+ logger.warning("invalid_classification_filter", classification=classification)
255
+ return []
256
+
257
+ try:
258
+ for file_path in self.storage_path.glob("*.json"):
259
+ try:
260
+ with file_path.open(encoding="utf-8") as f:
261
+ record = json.load(f)
262
+
263
+ # Apply classification filter if specified
264
+ if filter_classification is not None:
265
+ if record.get("classification") != filter_classification:
266
+ continue
267
+
268
+ keys.append(record.get("key", file_path.stem))
269
+
270
+ except (OSError, json.JSONDecodeError):
271
+ continue
272
+
273
+ except (OSError, PermissionError) as e:
274
+ logger.error("list_keys_failed", error=str(e))
275
+
276
+ return keys
277
+
278
+ def clear(self) -> int:
279
+ """Clear all data from long-term memory.
280
+
281
+ Returns:
282
+ Number of keys deleted
283
+
284
+ Warning:
285
+ This operation cannot be undone!
286
+
287
+ """
288
+ count = 0
289
+ try:
290
+ for file_path in self.storage_path.glob("*.json"):
291
+ try:
292
+ file_path.unlink()
293
+ count += 1
294
+ except (OSError, PermissionError):
295
+ continue
296
+
297
+ logger.warning("long_term_memory_cleared", count=count)
298
+ return count
299
+
300
+ except (OSError, PermissionError) as e:
301
+ logger.error("clear_failed", error=str(e))
302
+ return count
@@ -0,0 +1,15 @@
1
+ """Storage Backends for Empathy Framework Memory
2
+
3
+ Provides pluggable storage backends for pattern persistence:
4
+ - File-based (default): Simple JSON file storage
5
+ - SQLite (planned): Local database for better querying
6
+ - S3/Cloud (planned): Distributed storage for teams
7
+
8
+ Copyright 2025 Smart AI Memory, LLC
9
+ Licensed under Fair Source 0.9
10
+ """
11
+
12
+ # Storage backends will be added here as they're implemented
13
+ # Current implementation uses file-based storage in long_term.py
14
+
15
+ __all__ = []
@@ -0,0 +1,167 @@
1
+ """File-based storage backend for long-term memory patterns
2
+
3
+ Provides simple file-based storage for MemDocs patterns.
4
+ Extracted from long_term.py for better modularity and testability.
5
+
6
+ In production, this can be replaced with actual MemDocs library integration
7
+ or other storage backends (Redis, PostgreSQL, etc.).
8
+
9
+ Key Features:
10
+ - JSON-based file storage
11
+ - Pattern storage with metadata
12
+ - Query support (by classification, creator)
13
+ - Path validation for security
14
+
15
+ Copyright 2025 Smart AI Memory, LLC
16
+ Licensed under Fair Source 0.9
17
+ """
18
+
19
+ import json
20
+ from pathlib import Path
21
+ from typing import Any
22
+
23
+ import structlog
24
+
25
+ from attune.config import _validate_file_path
26
+
27
+ logger = structlog.get_logger(__name__)
28
+
29
+
30
+ class MemDocsStorage:
31
+ """Mock/Simple MemDocs storage backend.
32
+
33
+ In production, this would integrate with the actual MemDocs library.
34
+ For now, provides a simple file-based storage for testing.
35
+ """
36
+
37
+ def __init__(self, storage_dir: str = "./memdocs_storage"):
38
+ """Initialize storage backend.
39
+
40
+ Args:
41
+ storage_dir: Directory for pattern storage
42
+
43
+ """
44
+ self.storage_dir = Path(storage_dir)
45
+ self.storage_dir.mkdir(parents=True, exist_ok=True)
46
+ logger.info("memdocs_storage_initialized", storage_dir=str(self.storage_dir))
47
+
48
+ def store(self, pattern_id: str, content: str, metadata: dict[str, Any]) -> bool:
49
+ """Store a pattern.
50
+
51
+ Args:
52
+ pattern_id: Unique pattern identifier
53
+ content: Pattern content (may be encrypted)
54
+ metadata: Pattern metadata
55
+
56
+ Returns:
57
+ True if successful
58
+
59
+ Raises:
60
+ IOError: If storage fails
61
+
62
+ """
63
+ try:
64
+ pattern_file = self.storage_dir / f"{pattern_id}.json"
65
+
66
+ # Ensure parent directory exists
67
+ pattern_file.parent.mkdir(parents=True, exist_ok=True)
68
+
69
+ pattern_data = {"pattern_id": pattern_id, "content": content, "metadata": metadata}
70
+
71
+ validated_pattern_file = _validate_file_path(str(pattern_file))
72
+ with open(validated_pattern_file, "w", encoding="utf-8") as f:
73
+ json.dump(pattern_data, f, indent=2)
74
+
75
+ logger.debug("pattern_stored", pattern_id=pattern_id)
76
+ return True
77
+
78
+ except (OSError, PermissionError, json.JSONDecodeError) as e:
79
+ logger.error("pattern_storage_failed", pattern_id=pattern_id, error=str(e))
80
+ raise
81
+
82
+ def retrieve(self, pattern_id: str) -> dict[str, Any] | None:
83
+ """Retrieve a pattern.
84
+
85
+ Args:
86
+ pattern_id: Unique pattern identifier
87
+
88
+ Returns:
89
+ Pattern data dictionary or None if not found
90
+
91
+ """
92
+ try:
93
+ pattern_file = self.storage_dir / f"{pattern_id}.json"
94
+
95
+ if not pattern_file.exists():
96
+ logger.warning("pattern_not_found", pattern_id=pattern_id)
97
+ return None
98
+
99
+ with open(pattern_file, encoding="utf-8") as f:
100
+ pattern_data: dict[str, Any] = json.load(f)
101
+
102
+ logger.debug("pattern_retrieved", pattern_id=pattern_id)
103
+ return pattern_data
104
+
105
+ except (OSError, PermissionError, json.JSONDecodeError) as e:
106
+ logger.error("pattern_retrieval_failed", pattern_id=pattern_id, error=str(e))
107
+ return None
108
+
109
+ def delete(self, pattern_id: str) -> bool:
110
+ """Delete a pattern.
111
+
112
+ Args:
113
+ pattern_id: Unique pattern identifier
114
+
115
+ Returns:
116
+ True if deleted, False if not found
117
+
118
+ """
119
+ try:
120
+ pattern_file = self.storage_dir / f"{pattern_id}.json"
121
+
122
+ if not pattern_file.exists():
123
+ return False
124
+
125
+ pattern_file.unlink()
126
+ logger.info("pattern_deleted", pattern_id=pattern_id)
127
+ return True
128
+
129
+ except (OSError, PermissionError) as e:
130
+ logger.error("pattern_deletion_failed", pattern_id=pattern_id, error=str(e))
131
+ return False
132
+
133
+ def list_patterns(
134
+ self,
135
+ classification: str | None = None,
136
+ created_by: str | None = None,
137
+ ) -> list[str]:
138
+ """List pattern IDs matching criteria.
139
+
140
+ Args:
141
+ classification: Filter by classification
142
+ created_by: Filter by creator
143
+
144
+ Returns:
145
+ List of pattern IDs
146
+
147
+ """
148
+ pattern_ids = []
149
+
150
+ for pattern_file in self.storage_dir.glob("*.json"):
151
+ try:
152
+ with open(pattern_file, encoding="utf-8") as f:
153
+ data = json.load(f)
154
+ metadata = data.get("metadata", {})
155
+
156
+ # Apply filters
157
+ if classification and metadata.get("classification") != classification:
158
+ continue
159
+ if created_by and metadata.get("created_by") != created_by:
160
+ continue
161
+
162
+ pattern_ids.append(data.get("pattern_id"))
163
+
164
+ except Exception:
165
+ continue
166
+
167
+ return pattern_ids