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,361 @@
1
+ """Contextual Pattern Injection
2
+
3
+ Filters and injects only relevant patterns based on current context.
4
+ Instead of loading all patterns, this module selects patterns that
5
+ are most likely to be useful for the current task.
6
+
7
+ Usage:
8
+ from attune_llm.contextual_patterns import ContextualPatternInjector
9
+
10
+ injector = ContextualPatternInjector("./patterns")
11
+
12
+ # Get relevant patterns for a Python file with an async error
13
+ relevant = injector.get_relevant_patterns(
14
+ file_path="src/api.py",
15
+ error_type="async_timing",
16
+ max_patterns=5
17
+ )
18
+
19
+ Author: Empathy Framework Team
20
+ Version: 2.1.3
21
+ License: Fair Source 0.9
22
+ """
23
+
24
+ import json
25
+ import logging
26
+ import subprocess
27
+ from datetime import datetime
28
+ from pathlib import Path
29
+ from typing import Any
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+
34
+ class ContextualPatternInjector:
35
+ """Injects only relevant patterns based on context.
36
+
37
+ Reduces cognitive load by filtering patterns to those
38
+ most likely to help with the current task.
39
+ """
40
+
41
+ def __init__(self, patterns_dir: str = "./patterns"):
42
+ self.patterns_dir = Path(patterns_dir)
43
+ self._debugging_dirs = ["debugging", "debugging_demo", "repo_test/debugging"]
44
+ self._security_dirs = ["security", "security_demo", "repo_test/security"]
45
+ self._cache: dict[str, list[dict]] = {}
46
+
47
+ def get_relevant_patterns(
48
+ self,
49
+ file_path: str | None = None,
50
+ error_type: str | None = None,
51
+ error_message: str | None = None,
52
+ max_patterns: int = 5,
53
+ include_security: bool = True,
54
+ ) -> str:
55
+ """Get relevant patterns formatted as markdown.
56
+
57
+ Args:
58
+ file_path: Current file being worked on
59
+ error_type: Type of error (null_reference, async_timing, etc.)
60
+ error_message: Error message text
61
+ max_patterns: Maximum patterns to include
62
+ include_security: Whether to include security decisions
63
+
64
+ Returns:
65
+ Markdown string with relevant patterns
66
+
67
+ """
68
+ all_bugs = self._load_all_bugs()
69
+ all_security = self._load_all_security() if include_security else []
70
+
71
+ # Score and filter patterns
72
+ scored_bugs = self._score_bugs(all_bugs, file_path, error_type, error_message)
73
+ top_bugs = scored_bugs[:max_patterns]
74
+
75
+ # Filter security decisions by file extension
76
+ relevant_security = self._filter_security(all_security, file_path)
77
+
78
+ return self._format_markdown(top_bugs, relevant_security[:3])
79
+
80
+ def get_patterns_for_review(
81
+ self,
82
+ files: list[str],
83
+ max_per_file: int = 3,
84
+ ) -> dict[str, list[dict]]:
85
+ """Get relevant patterns for code review of multiple files.
86
+
87
+ Args:
88
+ files: List of file paths being reviewed
89
+ max_per_file: Maximum patterns per file
90
+
91
+ Returns:
92
+ Dict mapping file paths to relevant patterns
93
+
94
+ """
95
+ all_bugs = self._load_all_bugs()
96
+ result = {}
97
+
98
+ for file_path in files:
99
+ file_ext = Path(file_path).suffix
100
+ relevant = [
101
+ bug
102
+ for bug in all_bugs
103
+ if self._file_type_matches(bug.get("file_path", ""), file_ext)
104
+ and bug.get("status") == "resolved"
105
+ ]
106
+ result[file_path] = relevant[:max_per_file]
107
+
108
+ return result
109
+
110
+ def get_patterns_from_git_changes(self, max_patterns: int = 5) -> str:
111
+ """Get relevant patterns based on recently changed files.
112
+
113
+ Returns:
114
+ Markdown with patterns relevant to git changes
115
+
116
+ """
117
+ changed_files = self._get_git_changed_files()
118
+ if not changed_files:
119
+ return "No recent git changes detected.\n"
120
+
121
+ # Collect file types
122
+ extensions = set()
123
+ for f in changed_files:
124
+ ext = Path(f).suffix
125
+ if ext:
126
+ extensions.add(ext)
127
+
128
+ all_bugs = self._load_all_bugs()
129
+
130
+ # Filter by file types in changes
131
+ relevant = []
132
+ for bug in all_bugs:
133
+ bug_ext = Path(bug.get("file_path", "")).suffix
134
+ if bug_ext in extensions and bug.get("status") == "resolved":
135
+ relevant.append(bug)
136
+
137
+ return self._format_markdown(relevant[:max_patterns], [])
138
+
139
+ def _load_all_bugs(self) -> list[dict[str, Any]]:
140
+ """Load all bug patterns from storage."""
141
+ if "bugs" in self._cache:
142
+ return self._cache["bugs"]
143
+
144
+ bugs = []
145
+ for debug_dir in self._debugging_dirs:
146
+ dir_path = self.patterns_dir / debug_dir
147
+ if not dir_path.exists():
148
+ continue
149
+
150
+ for json_file in dir_path.glob("bug_*.json"):
151
+ try:
152
+ with open(json_file, encoding="utf-8") as f:
153
+ bug = json.load(f)
154
+ bug["_source"] = str(json_file)
155
+ bugs.append(bug)
156
+ except (json.JSONDecodeError, OSError):
157
+ continue
158
+
159
+ self._cache["bugs"] = bugs
160
+ return bugs
161
+
162
+ def _load_all_security(self) -> list[dict[str, Any]]:
163
+ """Load all security decisions from storage."""
164
+ if "security" in self._cache:
165
+ return self._cache["security"]
166
+
167
+ decisions = []
168
+ for sec_dir in self._security_dirs:
169
+ decisions_file = self.patterns_dir / sec_dir / "team_decisions.json"
170
+ if not decisions_file.exists():
171
+ continue
172
+
173
+ try:
174
+ with open(decisions_file, encoding="utf-8") as f:
175
+ data = json.load(f)
176
+ decisions.extend(data.get("decisions", []))
177
+ except (json.JSONDecodeError, OSError):
178
+ continue
179
+
180
+ self._cache["security"] = decisions
181
+ return decisions
182
+
183
+ def _score_bugs(
184
+ self,
185
+ bugs: list[dict],
186
+ file_path: str | None,
187
+ error_type: str | None,
188
+ error_message: str | None,
189
+ ) -> list[dict]:
190
+ """Score bugs by relevance to current context."""
191
+ scored = []
192
+
193
+ for bug in bugs:
194
+ score = 0.0
195
+
196
+ # Resolved bugs are more valuable
197
+ if bug.get("status") == "resolved":
198
+ score += 0.3
199
+
200
+ # Error type match is strongest signal
201
+ if error_type and bug.get("error_type") == error_type:
202
+ score += 0.5
203
+
204
+ # File extension match
205
+ if file_path:
206
+ current_ext = Path(file_path).suffix
207
+ bug_ext = Path(bug.get("file_path", "")).suffix
208
+ if current_ext == bug_ext:
209
+ score += 0.2
210
+
211
+ # Error message similarity (simple keyword match)
212
+ if error_message:
213
+ bug_msg = bug.get("error_message", "").lower()
214
+ error_lower = error_message.lower()
215
+ common_words = set(bug_msg.split()) & set(error_lower.split())
216
+ if common_words:
217
+ score += min(len(common_words) * 0.05, 0.2)
218
+
219
+ # Recent bugs slightly preferred
220
+ try:
221
+ bug_date = datetime.fromisoformat(bug.get("date", "").replace("Z", "+00:00"))
222
+ days_old = (datetime.now(bug_date.tzinfo) - bug_date).days
223
+ if days_old < 30:
224
+ score += 0.1
225
+ except (ValueError, TypeError):
226
+ pass
227
+
228
+ bug["_relevance_score"] = score
229
+ scored.append(bug)
230
+
231
+ # Sort by relevance
232
+ return sorted(scored, key=lambda b: b.get("_relevance_score", 0), reverse=True)
233
+
234
+ def _filter_security(
235
+ self,
236
+ decisions: list[dict],
237
+ file_path: str | None,
238
+ ) -> list[dict]:
239
+ """Filter security decisions relevant to current file."""
240
+ if not file_path:
241
+ return decisions[:3] # Return top 3 general
242
+
243
+ # Map file extensions to security concern areas
244
+ ext_security_map = {
245
+ ".py": ["sql_injection", "command_injection", "path_traversal"],
246
+ ".js": ["xss", "insecure_random"],
247
+ ".ts": ["xss", "insecure_random"],
248
+ ".tsx": ["xss"],
249
+ ".sql": ["sql_injection"],
250
+ }
251
+
252
+ current_ext = Path(file_path).suffix
253
+ relevant_types = ext_security_map.get(current_ext, [])
254
+
255
+ filtered = [d for d in decisions if d.get("finding_hash", "") in relevant_types]
256
+
257
+ return filtered or decisions[:2] # Fallback to top 2
258
+
259
+ def _file_type_matches(self, bug_path: str, target_ext: str) -> bool:
260
+ """Check if bug's file type matches target extension."""
261
+ return Path(bug_path).suffix == target_ext
262
+
263
+ def _get_git_changed_files(self) -> list[str]:
264
+ """Get list of recently changed files from git."""
265
+ try:
266
+ result = subprocess.run(
267
+ ["git", "diff", "--name-only", "HEAD~5", "HEAD"],
268
+ check=False,
269
+ capture_output=True,
270
+ text=True,
271
+ timeout=5,
272
+ )
273
+ if result.returncode == 0:
274
+ return [f.strip() for f in result.stdout.strip().split("\n") if f.strip()]
275
+ except subprocess.SubprocessError as e:
276
+ logger.debug(f"Git command failed: {e}")
277
+ except Exception: # noqa: BLE001
278
+ # INTENTIONAL: Git availability detection - don't crash on git errors
279
+ logger.debug("Could not get git changed files (expected in non-git directories)")
280
+ return []
281
+
282
+ def _format_markdown(
283
+ self,
284
+ bugs: list[dict],
285
+ security: list[dict],
286
+ ) -> str:
287
+ """Format patterns as concise markdown."""
288
+ lines = [
289
+ "# Relevant Patterns",
290
+ "",
291
+ ]
292
+
293
+ if bugs:
294
+ lines.append("## Bug Patterns")
295
+ lines.append("")
296
+ for bug in bugs:
297
+ status = bug.get("status", "unknown")
298
+ icon = "✓" if status == "resolved" else "?"
299
+ lines.append(f"- **{bug.get('bug_id', 'unknown')}** [{icon}]")
300
+ lines.append(f" - Type: {bug.get('error_type', 'unknown')}")
301
+ if bug.get("root_cause"):
302
+ lines.append(f" - Cause: {bug.get('root_cause')}")
303
+ if bug.get("fix_applied"):
304
+ lines.append(f" - Fix: {bug.get('fix_applied')}")
305
+ if bug.get("fix_code"):
306
+ lines.append(f" - Code: `{bug.get('fix_code')}`")
307
+ lines.append("")
308
+ else:
309
+ lines.append("*No matching bug patterns.*")
310
+ lines.append("")
311
+
312
+ if security:
313
+ lines.append("## Security Decisions")
314
+ lines.append("")
315
+ for decision in security:
316
+ lines.append(
317
+ f"- **{decision.get('finding_hash', '?')}**: {decision.get('decision', '?')}",
318
+ )
319
+ lines.append(f" - Reason: {decision.get('reason', 'N/A')}")
320
+ lines.append("")
321
+
322
+ return "\n".join(lines)
323
+
324
+ def clear_cache(self) -> None:
325
+ """Clear the pattern cache."""
326
+ self._cache.clear()
327
+
328
+
329
+ def main():
330
+ """CLI entry point for contextual patterns."""
331
+ import argparse
332
+
333
+ parser = argparse.ArgumentParser(description="Get contextually relevant patterns")
334
+ parser.add_argument("--file", help="Current file path")
335
+ parser.add_argument("--error-type", help="Error type (null_reference, async_timing, etc.)")
336
+ parser.add_argument("--error-message", help="Error message text")
337
+ parser.add_argument("--max", type=int, default=5, help="Max patterns to show")
338
+ parser.add_argument("--git", action="store_true", help="Use git changes for context")
339
+ parser.add_argument("--patterns-dir", default="./patterns", help="Patterns directory")
340
+
341
+ args = parser.parse_args()
342
+
343
+ logging.basicConfig(level=logging.INFO)
344
+
345
+ injector = ContextualPatternInjector(args.patterns_dir)
346
+
347
+ if args.git:
348
+ print(injector.get_patterns_from_git_changes(args.max))
349
+ else:
350
+ print(
351
+ injector.get_relevant_patterns(
352
+ file_path=args.file,
353
+ error_type=args.error_type,
354
+ error_message=args.error_message,
355
+ max_patterns=args.max,
356
+ ),
357
+ )
358
+
359
+
360
+ if __name__ == "__main__":
361
+ main()