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,208 @@
1
+ """Prompt Templates
2
+
3
+ Provides protocol and implementations for prompt templates,
4
+ including XML-structured prompts.
5
+
6
+ Copyright 2025 Smart-AI-Memory
7
+ Licensed under Fair Source License 0.9
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass, field
13
+ from typing import Any, Protocol
14
+
15
+ from .context import PromptContext
16
+
17
+
18
+ class PromptTemplate(Protocol):
19
+ """Protocol for prompt templates."""
20
+
21
+ def render(self, context: PromptContext) -> str:
22
+ """Render the template with given context.
23
+
24
+ Args:
25
+ context: The prompt context containing role, goal, instructions, etc.
26
+
27
+ Returns:
28
+ The rendered prompt string.
29
+
30
+ """
31
+ ...
32
+
33
+
34
+ @dataclass
35
+ class PlainTextPromptTemplate:
36
+ """Simple plain text prompt template.
37
+
38
+ Renders prompts in a straightforward text format without XML structure.
39
+ """
40
+
41
+ name: str
42
+ include_role: bool = True
43
+ include_constraints: bool = True
44
+
45
+ def render(self, context: PromptContext) -> str:
46
+ """Render as plain text prompt."""
47
+ parts = []
48
+
49
+ if self.include_role:
50
+ parts.append(f"You are a {context.role}.")
51
+ parts.append("")
52
+
53
+ parts.append(f"Goal: {context.goal}")
54
+ parts.append("")
55
+
56
+ if context.instructions:
57
+ parts.append("Instructions:")
58
+ for i, inst in enumerate(context.instructions, 1):
59
+ parts.append(f"{i}. {inst}")
60
+ parts.append("")
61
+
62
+ if self.include_constraints and context.constraints:
63
+ parts.append("Guidelines:")
64
+ for constraint in context.constraints:
65
+ parts.append(f"- {constraint}")
66
+ parts.append("")
67
+
68
+ if context.input_payload:
69
+ parts.append(f"Input ({context.input_type}):")
70
+ parts.append(context.input_payload)
71
+
72
+ return "\n".join(parts)
73
+
74
+
75
+ @dataclass
76
+ class XmlPromptTemplate:
77
+ """XML-structured prompt template.
78
+
79
+ Renders prompts in XML format for consistent parsing and
80
+ structured LLM interactions.
81
+ """
82
+
83
+ name: str
84
+ schema_version: str = "1.0"
85
+ response_format: str | None = None
86
+ extra_tags: dict[str, str] = field(default_factory=dict)
87
+
88
+ def render(self, context: PromptContext) -> str:
89
+ """Render XML prompt from context.
90
+
91
+ Args:
92
+ context: The prompt context.
93
+
94
+ Returns:
95
+ XML-formatted prompt string.
96
+
97
+ """
98
+ # Build instructions XML
99
+ instructions_xml = self._render_instructions(context.instructions)
100
+
101
+ # Build constraints XML
102
+ constraints_xml = self._render_constraints(context.constraints)
103
+
104
+ # Build extra context XML if present
105
+ extra_xml = self._render_extra(context.extra)
106
+
107
+ # Build input section with CDATA for safety
108
+ input_content = self._escape_cdata(context.input_payload)
109
+
110
+ prompt = f"""<request schema="{self.schema_version}">
111
+ <role>{self._escape_xml(context.role)}</role>
112
+ <goal>{self._escape_xml(context.goal)}</goal>
113
+ <instructions>
114
+ {instructions_xml}
115
+ </instructions>
116
+ <constraints>
117
+ {constraints_xml}
118
+ </constraints>{extra_xml}
119
+ <input type="{context.input_type}">
120
+ <![CDATA[
121
+ {input_content}
122
+ ]]>
123
+ </input>
124
+ </request>"""
125
+
126
+ # Add response format instructions if specified
127
+ if self.response_format:
128
+ prompt += f"\n\n{self._response_instructions()}"
129
+
130
+ return prompt
131
+
132
+ def _render_instructions(self, instructions: list[str]) -> str:
133
+ """Render instructions as XML steps."""
134
+ if not instructions:
135
+ return " <!-- No specific instructions -->"
136
+ lines = []
137
+ for i, inst in enumerate(instructions, 1):
138
+ escaped = self._escape_xml(inst)
139
+ lines.append(f" <step>{i}. {escaped}</step>")
140
+ return "\n".join(lines)
141
+
142
+ def _render_constraints(self, constraints: list[str]) -> str:
143
+ """Render constraints as XML rules."""
144
+ if not constraints:
145
+ return " <!-- No specific constraints -->"
146
+ lines = []
147
+ for constraint in constraints:
148
+ escaped = self._escape_xml(constraint)
149
+ lines.append(f" <rule>{escaped}</rule>")
150
+ return "\n".join(lines)
151
+
152
+ def _render_extra(self, extra: dict[str, Any]) -> str:
153
+ """Render extra context as XML if present."""
154
+ if not extra:
155
+ return ""
156
+
157
+ lines = ["\n <context>"]
158
+ for key, value in extra.items():
159
+ if value: # Only include non-empty values
160
+ escaped_key = self._escape_xml(str(key))
161
+ escaped_value = self._escape_xml(str(value))
162
+ lines.append(f" <{escaped_key}>{escaped_value}</{escaped_key}>")
163
+ lines.append(" </context>")
164
+
165
+ return "\n".join(lines)
166
+
167
+ def _response_instructions(self) -> str:
168
+ """Generate response format instructions."""
169
+ return f"""Please respond using ONLY this XML format (no other text before or after):
170
+
171
+ {self.response_format}
172
+
173
+ Important:
174
+ - Use the exact XML structure shown above
175
+ - Include all required tags even if empty
176
+ - Use severity values: critical, high, medium, low, info
177
+ - Wrap code examples in CDATA sections"""
178
+
179
+ def _escape_xml(self, text: str) -> str:
180
+ """Escape special XML characters."""
181
+ if not text:
182
+ return ""
183
+ return (
184
+ text.replace("&", "&amp;")
185
+ .replace("<", "&lt;")
186
+ .replace(">", "&gt;")
187
+ .replace('"', "&quot;")
188
+ .replace("'", "&apos;")
189
+ )
190
+
191
+ def _escape_cdata(self, text: str) -> str:
192
+ """Escape text for use in CDATA section.
193
+
194
+ CDATA sections can contain anything except the closing sequence ]]>
195
+ """
196
+ if not text:
197
+ return ""
198
+ # Replace ]]> with ]]]]><![CDATA[> to escape it
199
+ return text.replace("]]>", "]]]]><![CDATA[>")
200
+
201
+ def with_response_format(self, response_format: str) -> XmlPromptTemplate:
202
+ """Return a new template with the specified response format."""
203
+ return XmlPromptTemplate(
204
+ name=self.name,
205
+ schema_version=self.schema_version,
206
+ response_format=response_format,
207
+ extra_tags=self.extra_tags.copy(),
208
+ )
attune/redis_config.py ADDED
@@ -0,0 +1,302 @@
1
+ """Redis Configuration for Empathy Framework
2
+
3
+ Handles connection to Redis from environment variables.
4
+ Supports Railway, redis.com, local Docker, managed Redis, or mock mode.
5
+
6
+ Environment Variables:
7
+ REDIS_URL: Full Redis URL (redis://user:pass@host:port)
8
+ REDIS_HOST: Redis host (default: localhost)
9
+ REDIS_PORT: Redis port (default: 6379)
10
+ REDIS_PASSWORD: Redis password (optional)
11
+ REDIS_DB: Redis database number (default: 0)
12
+ EMPATHY_REDIS_MOCK: Set to "true" to use mock mode
13
+
14
+ # SSL/TLS (for managed Redis services)
15
+ REDIS_SSL: Set to "true" to enable SSL
16
+ REDIS_SSL_CERT_REQS: Certificate requirement ("required", "optional", "none")
17
+ REDIS_SSL_CA_CERTS: Path to CA certificate file
18
+ REDIS_SSL_CERTFILE: Path to client certificate
19
+ REDIS_SSL_KEYFILE: Path to client key
20
+
21
+ # Connection settings
22
+ REDIS_SOCKET_TIMEOUT: Socket timeout in seconds (default: 5.0)
23
+ REDIS_MAX_CONNECTIONS: Connection pool size (default: 10)
24
+
25
+ # Retry settings
26
+ REDIS_RETRY_MAX_ATTEMPTS: Max retry attempts (default: 3)
27
+ REDIS_RETRY_BASE_DELAY: Base retry delay in seconds (default: 0.1)
28
+ REDIS_RETRY_MAX_DELAY: Max retry delay in seconds (default: 2.0)
29
+
30
+ # Sentinel (for high availability)
31
+ REDIS_SENTINEL_HOSTS: Comma-separated host:port pairs
32
+ REDIS_SENTINEL_MASTER: Sentinel master name
33
+
34
+ Railway Auto-Detection:
35
+ When deployed on Railway, REDIS_URL is automatically set.
36
+ For Railway Redis with SSL, the URL starts with "rediss://"
37
+
38
+ Usage:
39
+ from attune.redis_config import get_redis_memory
40
+
41
+ # Automatically uses environment variables
42
+ memory = get_redis_memory()
43
+
44
+ # Or with explicit URL (SSL auto-detected from rediss://)
45
+ memory = get_redis_memory(url="rediss://user:pass@managed-redis.com:6379")
46
+
47
+ # Or with explicit config
48
+ from attune.memory.short_term import RedisConfig
49
+ config = RedisConfig(host="localhost", ssl=True)
50
+ memory = get_redis_memory(config=config)
51
+
52
+ Copyright 2025 Smart AI Memory, LLC
53
+ Licensed under Fair Source 0.9
54
+ """
55
+
56
+ import os
57
+ from urllib.parse import urlparse
58
+
59
+ from .memory.short_term import RedisConfig, RedisShortTermMemory
60
+
61
+
62
+ def parse_redis_url(url: str) -> dict:
63
+ """Parse Redis URL into connection parameters.
64
+
65
+ Supports:
66
+ - redis://user:pass@host:port/db (standard)
67
+ - rediss://user:pass@host:port/db (SSL enabled)
68
+
69
+ Args:
70
+ url: Redis URL (redis:// or rediss://)
71
+
72
+ Returns:
73
+ Dict with host, port, password, db, ssl
74
+
75
+ """
76
+ parsed = urlparse(url)
77
+
78
+ # Detect SSL from scheme
79
+ ssl = parsed.scheme == "rediss"
80
+
81
+ return {
82
+ "host": parsed.hostname or "localhost",
83
+ "port": parsed.port or 6379,
84
+ "password": parsed.password,
85
+ "db": int(parsed.path.lstrip("/") or 0) if parsed.path else 0,
86
+ "ssl": ssl,
87
+ }
88
+
89
+
90
+ def get_redis_config() -> RedisConfig:
91
+ """Get Redis configuration from environment variables.
92
+
93
+ Priority:
94
+ 1. REDIS_URL (full URL, used by Railway/Heroku/managed services)
95
+ 2. Individual env vars (REDIS_HOST, REDIS_PORT, etc.)
96
+ 3. Defaults (localhost:6379)
97
+
98
+ Returns:
99
+ RedisConfig with all connection parameters
100
+
101
+ """
102
+ # Check for mock mode
103
+ if os.getenv("EMPATHY_REDIS_MOCK", "").lower() == "true":
104
+ return RedisConfig(use_mock=True)
105
+
106
+ # Check for full URL (Railway, Heroku, managed services)
107
+ redis_url = os.getenv("REDIS_URL") or os.getenv("REDIS_PRIVATE_URL")
108
+ if redis_url:
109
+ url_config = parse_redis_url(redis_url)
110
+ return RedisConfig(
111
+ host=url_config["host"],
112
+ port=url_config["port"],
113
+ password=url_config["password"],
114
+ db=url_config["db"],
115
+ ssl=url_config.get("ssl", False),
116
+ use_mock=False,
117
+ # Apply additional env var overrides
118
+ socket_timeout=float(os.getenv("REDIS_SOCKET_TIMEOUT", "5.0")),
119
+ max_connections=int(os.getenv("REDIS_MAX_CONNECTIONS", "10")),
120
+ retry_max_attempts=int(os.getenv("REDIS_RETRY_MAX_ATTEMPTS", "3")),
121
+ retry_base_delay=float(os.getenv("REDIS_RETRY_BASE_DELAY", "0.1")),
122
+ retry_max_delay=float(os.getenv("REDIS_RETRY_MAX_DELAY", "2.0")),
123
+ )
124
+
125
+ # Build config from individual env vars
126
+ return RedisConfig(
127
+ host=os.getenv("REDIS_HOST", "localhost"),
128
+ port=int(os.getenv("REDIS_PORT", "6379")),
129
+ password=os.getenv("REDIS_PASSWORD"),
130
+ db=int(os.getenv("REDIS_DB", "0")),
131
+ use_mock=False,
132
+ # SSL settings
133
+ ssl=os.getenv("REDIS_SSL", "").lower() == "true",
134
+ ssl_cert_reqs=os.getenv("REDIS_SSL_CERT_REQS"),
135
+ ssl_ca_certs=os.getenv("REDIS_SSL_CA_CERTS"),
136
+ ssl_certfile=os.getenv("REDIS_SSL_CERTFILE"),
137
+ ssl_keyfile=os.getenv("REDIS_SSL_KEYFILE"),
138
+ # Connection settings
139
+ socket_timeout=float(os.getenv("REDIS_SOCKET_TIMEOUT", "5.0")),
140
+ socket_connect_timeout=float(os.getenv("REDIS_SOCKET_CONNECT_TIMEOUT", "5.0")),
141
+ max_connections=int(os.getenv("REDIS_MAX_CONNECTIONS", "10")),
142
+ # Retry settings
143
+ retry_on_timeout=os.getenv("REDIS_RETRY_ON_TIMEOUT", "true").lower() == "true",
144
+ retry_max_attempts=int(os.getenv("REDIS_RETRY_MAX_ATTEMPTS", "3")),
145
+ retry_base_delay=float(os.getenv("REDIS_RETRY_BASE_DELAY", "0.1")),
146
+ retry_max_delay=float(os.getenv("REDIS_RETRY_MAX_DELAY", "2.0")),
147
+ )
148
+
149
+
150
+ def get_redis_config_dict() -> dict:
151
+ """Get Redis configuration as a dictionary (legacy compatibility).
152
+
153
+ Returns:
154
+ Dict with connection parameters
155
+
156
+ """
157
+ config = get_redis_config()
158
+ return {
159
+ "host": config.host,
160
+ "port": config.port,
161
+ "password": config.password,
162
+ "db": config.db,
163
+ "use_mock": config.use_mock,
164
+ "ssl": config.ssl,
165
+ }
166
+
167
+
168
+ def get_redis_memory(
169
+ url: str | None = None,
170
+ use_mock: bool | None = None,
171
+ config: RedisConfig | None = None,
172
+ ) -> RedisShortTermMemory:
173
+ """Create a RedisShortTermMemory instance with environment-based config.
174
+
175
+ Args:
176
+ url: Optional explicit Redis URL (overrides env vars)
177
+ use_mock: Optional explicit mock mode (overrides env vars)
178
+ config: Optional explicit RedisConfig (overrides all other options)
179
+
180
+ Returns:
181
+ Configured RedisShortTermMemory instance
182
+
183
+ Examples:
184
+ # Auto-configure from environment
185
+ memory = get_redis_memory()
186
+
187
+ # Explicit URL (SSL auto-detected from rediss://)
188
+ memory = get_redis_memory(url="rediss://user:pass@managed-redis.com:6379")
189
+
190
+ # Force mock mode
191
+ memory = get_redis_memory(use_mock=True)
192
+
193
+ # Explicit config with all options
194
+ from attune.memory.short_term import RedisConfig
195
+ config = RedisConfig(
196
+ host="redis.example.com",
197
+ port=6379,
198
+ ssl=True,
199
+ retry_max_attempts=5,
200
+ )
201
+ memory = get_redis_memory(config=config)
202
+
203
+ """
204
+ # Explicit config takes highest priority
205
+ if config is not None:
206
+ return RedisShortTermMemory(config=config)
207
+
208
+ # Explicit mock mode
209
+ if use_mock is True:
210
+ return RedisShortTermMemory(use_mock=True)
211
+
212
+ # Explicit URL
213
+ if url:
214
+ url_config = parse_redis_url(url)
215
+ redis_config = RedisConfig(
216
+ host=url_config["host"],
217
+ port=url_config["port"],
218
+ password=url_config["password"],
219
+ db=url_config["db"],
220
+ ssl=url_config.get("ssl", False),
221
+ use_mock=False,
222
+ )
223
+ return RedisShortTermMemory(config=redis_config)
224
+
225
+ # Environment-based config
226
+ env_config = get_redis_config()
227
+ return RedisShortTermMemory(config=env_config)
228
+
229
+
230
+ def check_redis_connection() -> dict:
231
+ """Check Redis connection and return status.
232
+
233
+ Returns:
234
+ Dict with connection status and info
235
+
236
+ Example:
237
+ >>> status = check_redis_connection()
238
+ >>> if status["connected"]:
239
+ ... print(f"Connected to {status['host']}:{status['port']}")
240
+
241
+ """
242
+ config = get_redis_config()
243
+
244
+ result = {
245
+ "config_source": "environment",
246
+ "use_mock": config.use_mock,
247
+ "host": config.host,
248
+ "port": config.port,
249
+ "has_password": bool(config.password),
250
+ "db": config.db,
251
+ "connected": False,
252
+ "error": None,
253
+ }
254
+
255
+ # Determine config source
256
+ if os.getenv("REDIS_URL"):
257
+ result["config_source"] = "REDIS_URL"
258
+ elif os.getenv("REDIS_PRIVATE_URL"):
259
+ result["config_source"] = "REDIS_PRIVATE_URL"
260
+ elif os.getenv("REDIS_HOST"):
261
+ result["config_source"] = "REDIS_HOST"
262
+
263
+ if result["use_mock"]:
264
+ result["connected"] = True
265
+ result["config_source"] = "mock_mode"
266
+ return result
267
+
268
+ try:
269
+ memory = get_redis_memory()
270
+ result["connected"] = memory.ping()
271
+ if result["connected"]:
272
+ stats = memory.get_stats()
273
+ result["memory_used"] = stats.get("used_memory")
274
+ result["total_keys"] = stats.get("total_keys")
275
+ except Exception as e:
276
+ result["error"] = str(e)
277
+
278
+ return result
279
+
280
+
281
+ # Convenience function for Railway deployments
282
+ def get_railway_redis() -> RedisShortTermMemory:
283
+ """Get Redis configured for Railway deployment.
284
+
285
+ Railway automatically sets REDIS_URL when you add a Redis service.
286
+
287
+ Returns:
288
+ RedisShortTermMemory configured for Railway
289
+
290
+ Raises:
291
+ EnvironmentError: If REDIS_URL is not set
292
+
293
+ """
294
+ redis_url = os.getenv("REDIS_URL") or os.getenv("REDIS_PRIVATE_URL")
295
+
296
+ if not redis_url:
297
+ raise OSError(
298
+ "REDIS_URL not found. Make sure Redis is added to your Railway project.\n"
299
+ "Run: railway add --database redis",
300
+ )
301
+
302
+ return get_redis_memory(url=redis_url)