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,408 @@
1
+ """{{ wizard_name | title | replace('_', ' ') }} Domain Wizard.
2
+
3
+ Auto-generated by Empathy Framework Scaffolding
4
+ Methodology: {{ methodology }}
5
+ Domain: {{ domain }}
6
+ Patterns: {{ pattern_ids | join(', ') }}
7
+ Empathy Level: {{ empathy_level | default(2) }}
8
+ Generated: {{ timestamp }}
9
+ """
10
+
11
+ import logging
12
+ from typing import Any
13
+
14
+ from fastapi import APIRouter, HTTPException
15
+ from pydantic import BaseModel, Field
16
+
17
+ from empathy_llm_toolkit.memory_manager import MemoryManager
18
+ from empathy_llm_toolkit.wizards.base_wizard import WizardConfig
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ router = APIRouter(prefix="/{{ wizard_name }}", tags=["{{ wizard_name }}"])
23
+
24
+
25
+ # Wizard Configuration
26
+ WIZARD_CONFIG = WizardConfig(
27
+ wizard_id="{{ wizard_name }}",
28
+ name="{{ wizard_name | title | replace('_', ' ') }}",
29
+ description="{{ description | default('Domain wizard for ' + domain) }}",
30
+ domain="{{ domain }}",
31
+ empathy_level={{ empathy_level | default(2) }},
32
+ {% if 'educational_banner' in pattern_ids %}
33
+ show_educational_banner=True,
34
+ {% endif %}
35
+ )
36
+
37
+
38
+ # Request/Response Models
39
+ {% if 'linear_flow' in pattern_ids %}
40
+ class StartRequest(BaseModel):
41
+ """Request to start wizard."""
42
+ context: dict[str, Any] = Field(default_factory=dict, description="Initial context")
43
+
44
+
45
+ class StartResponse(BaseModel):
46
+ """Response from starting wizard."""
47
+ wizard_id: str
48
+ current_step: int
49
+ total_steps: int
50
+ {% if 'educational_banner' in pattern_ids %}
51
+ educational_banner: dict[str, Any] | None = None
52
+ {% endif %}
53
+
54
+
55
+ class StepSubmission(BaseModel):
56
+ """Step data submission."""
57
+ step: int
58
+ data: dict[str, Any]
59
+
60
+
61
+ class StepResult(BaseModel):
62
+ """Step submission result."""
63
+ wizard_id: str
64
+ current_step: int
65
+ total_steps: int
66
+ completed: bool = False
67
+ {% if 'user_guidance' in pattern_ids %}
68
+ next_step_guidance: str | None = None
69
+ {% endif %}
70
+ {% endif %}
71
+
72
+
73
+ {% if 'approval' in pattern_ids %}
74
+ class PreviewRequest(BaseModel):
75
+ """Request to generate preview."""
76
+ pass
77
+
78
+
79
+ class PreviewResult(BaseModel):
80
+ """Preview generation result."""
81
+ wizard_id: str
82
+ preview_report: dict[str, Any]
83
+ {% if 'user_guidance' in pattern_ids %}
84
+ approval_guidance: str
85
+ {% endif %}
86
+
87
+
88
+ class SaveRequest(BaseModel):
89
+ """Request to save with approval."""
90
+ approval: dict[str, Any] = Field(..., description="User approval data")
91
+
92
+
93
+ class SaveResult(BaseModel):
94
+ """Save result."""
95
+ wizard_id: str
96
+ completed: bool
97
+ final_report: dict[str, Any]
98
+ {% endif %}
99
+
100
+
101
+ # In-memory session storage (replace with Redis in production)
102
+ sessions: dict[str, dict[str, Any]] = {}
103
+
104
+
105
+ {% if 'linear_flow' in pattern_ids %}
106
+ @router.post("/start", response_model=StartResponse)
107
+ async def start_wizard(request: StartRequest) -> StartResponse:
108
+ """Start a new wizard session.
109
+
110
+ Args:
111
+ request: Start request with initial context
112
+
113
+ Returns:
114
+ Wizard session info
115
+
116
+ Raises:
117
+ HTTPException: If initialization fails
118
+ """
119
+ try:
120
+ wizard_id = f"{{ wizard_name }}_{len(sessions) + 1}"
121
+
122
+ # Initialize session
123
+ session = {
124
+ "wizard_id": wizard_id,
125
+ "current_step": 1,
126
+ "total_steps": {{ total_steps | default(5) }},
127
+ "context": request.context,
128
+ "step_data": {},
129
+ "completed": False,
130
+ }
131
+
132
+ sessions[wizard_id] = session
133
+
134
+ response = StartResponse(
135
+ wizard_id=wizard_id,
136
+ current_step=1,
137
+ total_steps={{ total_steps | default(5) }},
138
+ )
139
+
140
+ {% if 'educational_banner' in pattern_ids %}
141
+ # Add educational banner for Level {{ empathy_level | default(2) }}
142
+ response.educational_banner = {
143
+ "message": "{{ educational_message | default('This wizard will guide you through the process step by step.') }}",
144
+ "level": {{ empathy_level | default(2) }},
145
+ }
146
+ {% endif %}
147
+
148
+ logger.info(f"Started wizard session: {wizard_id}")
149
+ return response
150
+
151
+ except Exception as e:
152
+ logger.exception(f"Failed to start wizard: {e}")
153
+ raise HTTPException(status_code=500, detail=f"Wizard start failed: {str(e)}")
154
+
155
+
156
+ @router.post("/{wizard_id}/step", response_model=StepResult)
157
+ async def submit_step(wizard_id: str, submission: StepSubmission) -> StepResult:
158
+ """Submit data for a wizard step.
159
+
160
+ Args:
161
+ wizard_id: Wizard session ID
162
+ submission: Step data submission
163
+
164
+ Returns:
165
+ Step result with next step info
166
+
167
+ Raises:
168
+ HTTPException: If session not found or validation fails
169
+ """
170
+ # Validate session
171
+ if wizard_id not in sessions:
172
+ raise HTTPException(status_code=404, detail="Session not found")
173
+
174
+ session = sessions[wizard_id]
175
+
176
+ {% if 'step_validation' in pattern_ids %}
177
+ # Validate step sequence
178
+ if submission.step != session["current_step"]:
179
+ raise HTTPException(
180
+ status_code=400,
181
+ detail=f"Expected step {session['current_step']}, got {submission.step}"
182
+ )
183
+ {% endif %}
184
+
185
+ try:
186
+ # Store step data
187
+ session["step_data"][submission.step] = submission.data
188
+
189
+ # Move to next step
190
+ session["current_step"] = submission.step + 1
191
+
192
+ # Check if completed
193
+ completed = session["current_step"] > session["total_steps"]
194
+ session["completed"] = completed
195
+
196
+ result = StepResult(
197
+ wizard_id=wizard_id,
198
+ current_step=session["current_step"],
199
+ total_steps=session["total_steps"],
200
+ completed=completed,
201
+ )
202
+
203
+ {% if 'user_guidance' in pattern_ids %}
204
+ # Provide guidance for next step (Level {{ empathy_level | default(2) }} Empathy)
205
+ if not completed:
206
+ result.next_step_guidance = await _get_step_guidance(
207
+ session["current_step"],
208
+ session["step_data"]
209
+ )
210
+ {% endif %}
211
+
212
+ logger.info(f"Step {submission.step} submitted for {wizard_id}")
213
+ return result
214
+
215
+ except Exception as e:
216
+ logger.exception(f"Step submission failed: {e}")
217
+ raise HTTPException(status_code=500, detail=f"Step submission failed: {str(e)}")
218
+ {% endif %}
219
+
220
+
221
+ {% if 'approval' in pattern_ids %}
222
+ @router.post("/{wizard_id}/preview", response_model=PreviewResult)
223
+ async def generate_preview(wizard_id: str, request: PreviewRequest) -> PreviewResult:
224
+ """Generate preview for user review.
225
+
226
+ Args:
227
+ wizard_id: Wizard session ID
228
+ request: Preview request
229
+
230
+ Returns:
231
+ Preview report for user review
232
+
233
+ Raises:
234
+ HTTPException: If session not found or not ready for preview
235
+ """
236
+ if wizard_id not in sessions:
237
+ raise HTTPException(status_code=404, detail="Session not found")
238
+
239
+ session = sessions[wizard_id]
240
+
241
+ # Validate all steps completed
242
+ if not session.get("completed"):
243
+ raise HTTPException(status_code=400, detail="All steps must be completed before preview")
244
+
245
+ try:
246
+ # Generate preview
247
+ preview_report = await _generate_preview_report(session["step_data"])
248
+
249
+ # Store preview in session
250
+ session["preview_report"] = preview_report
251
+
252
+ result = PreviewResult(
253
+ wizard_id=wizard_id,
254
+ preview_report=preview_report,
255
+ )
256
+
257
+ {% if 'user_guidance' in pattern_ids %}
258
+ # Provide approval guidance (Level {{ empathy_level | default(2) }} Empathy)
259
+ result.approval_guidance = (
260
+ "Please review the preview carefully. "
261
+ "You can edit any information before final approval."
262
+ )
263
+ {% endif %}
264
+
265
+ logger.info(f"Preview generated for {wizard_id}")
266
+ return result
267
+
268
+ except Exception as e:
269
+ logger.exception(f"Preview generation failed: {e}")
270
+ raise HTTPException(status_code=500, detail=f"Preview generation failed: {str(e)}")
271
+
272
+
273
+ @router.post("/{wizard_id}/save", response_model=SaveResult)
274
+ async def save_with_approval(wizard_id: str, request: SaveRequest) -> SaveResult:
275
+ """Save wizard data with user approval.
276
+
277
+ Args:
278
+ wizard_id: Wizard session ID
279
+ request: Save request with approval
280
+
281
+ Returns:
282
+ Final save result
283
+
284
+ Raises:
285
+ HTTPException: If session not found or approval missing
286
+ """
287
+ if wizard_id not in sessions:
288
+ raise HTTPException(status_code=404, detail="Session not found")
289
+
290
+ session = sessions[wizard_id]
291
+
292
+ # Validate preview was generated
293
+ if "preview_report" not in session:
294
+ raise HTTPException(status_code=400, detail="Preview must be generated before saving")
295
+
296
+ # Validate approval
297
+ if not request.approval.get("user_approved"):
298
+ raise HTTPException(status_code=400, detail="User approval required")
299
+
300
+ try:
301
+ # Generate final report
302
+ final_report = await _generate_final_report(
303
+ session["step_data"],
304
+ session["preview_report"]
305
+ )
306
+
307
+ # Mark as finalized
308
+ session["final_report"] = final_report
309
+ session["finalized"] = True
310
+
311
+ logger.info(f"Wizard {wizard_id} saved with approval")
312
+
313
+ return SaveResult(
314
+ wizard_id=wizard_id,
315
+ completed=True,
316
+ final_report=final_report,
317
+ )
318
+
319
+ except Exception as e:
320
+ logger.exception(f"Save failed: {e}")
321
+ raise HTTPException(status_code=500, detail=f"Save failed: {str(e)}")
322
+ {% endif %}
323
+
324
+
325
+ @router.get("/{wizard_id}/report", response_model=dict[str, Any])
326
+ async def get_report(wizard_id: str) -> dict[str, Any]:
327
+ """Get wizard report.
328
+
329
+ Args:
330
+ wizard_id: Wizard session ID
331
+
332
+ Returns:
333
+ Complete wizard report
334
+
335
+ Raises:
336
+ HTTPException: If session not found
337
+ """
338
+ if wizard_id not in sessions:
339
+ raise HTTPException(status_code=404, detail="Session not found")
340
+
341
+ session = sessions[wizard_id]
342
+
343
+ return {
344
+ "wizard_id": wizard_id,
345
+ "step_data": session.get("step_data", {}),
346
+ {% if 'approval' in pattern_ids %}
347
+ "preview_report": session.get("preview_report"),
348
+ "final_report": session.get("final_report"),
349
+ "finalized": session.get("finalized", False),
350
+ {% endif %}
351
+ }
352
+
353
+
354
+ # Helper functions
355
+ {% if 'user_guidance' in pattern_ids %}
356
+ async def _get_step_guidance(step: int, step_data: dict[int, Any]) -> str:
357
+ """Get guidance for next step (Level {{ empathy_level | default(2) }} Empathy).
358
+
359
+ Args:
360
+ step: Current step number
361
+ step_data: Previous step data
362
+
363
+ Returns:
364
+ Guidance message
365
+ """
366
+ # TODO: Implement actual guidance generation
367
+ return f"Please complete step {step} with the required information."
368
+ {% endif %}
369
+
370
+
371
+ {% if 'approval' in pattern_ids %}
372
+ async def _generate_preview_report(step_data: dict[int, Any]) -> dict[str, Any]:
373
+ """Generate preview report.
374
+
375
+ Args:
376
+ step_data: All collected step data
377
+
378
+ Returns:
379
+ Preview report
380
+ """
381
+ # TODO: Implement actual preview generation
382
+ return {
383
+ "summary": "Preview of collected data",
384
+ "data": step_data,
385
+ }
386
+
387
+
388
+ async def _generate_final_report(
389
+ step_data: dict[int, Any],
390
+ preview_report: dict[str, Any]
391
+ ) -> dict[str, Any]:
392
+ """Generate final report after approval.
393
+
394
+ Args:
395
+ step_data: All collected step data
396
+ preview_report: Previously generated preview
397
+
398
+ Returns:
399
+ Final report
400
+ """
401
+ # TODO: Implement actual final report generation
402
+ return {
403
+ "summary": "Final report",
404
+ "data": step_data,
405
+ "preview": preview_report,
406
+ "finalized_at": "2025-01-05T00:00:00Z",
407
+ }
408
+ {% endif %}
@@ -0,0 +1,203 @@
1
+ """{{ wizard_class }} - Generated by Pattern-Compose
2
+
3
+ Domain: {{ domain}}
4
+ Patterns: {{ ', '.join(pattern_ids) }}
5
+ Generated: Auto-generated by Empathy Framework
6
+ """
7
+
8
+ from datetime import datetime
9
+ from typing import Any
10
+ from uuid import uuid4
11
+
12
+ from fastapi import APIRouter, HTTPException
13
+ from pydantic import BaseModel
14
+
15
+
16
+ router = APIRouter(
17
+ prefix="/wizards/{{ wizard_name }}",
18
+ tags=["wizards"],
19
+ )
20
+
21
+
22
+ # Request/Response Models
23
+ class WizardRequest(BaseModel):
24
+ """Request model for wizard."""
25
+ input: str
26
+ context: dict[str, Any] | None = None
27
+
28
+
29
+ class WizardResponse(BaseModel):
30
+ """Response model for wizard."""
31
+ success: bool
32
+ output: str
33
+ wizard_id: str | None = None
34
+ error: str | None = None
35
+
36
+
37
+ # Session storage (Redis in production, memory for development)
38
+ _wizard_sessions: dict[str, dict[str, Any]] = {}
39
+
40
+
41
+ @router.post("/start")
42
+ async def start_wizard():
43
+ """Start {{ wizard_name }} wizard session.
44
+
45
+ Returns wizard_id and first step configuration.
46
+ """
47
+ wizard_id = str(uuid4())
48
+
49
+ session_data = {
50
+ "wizard_id": wizard_id,
51
+ "wizard_type": "{{ wizard_name }}",
52
+ "current_step": 1,
53
+ "total_steps": 5, # TODO: Adjust based on your wizard
54
+ "collected_data": {},
55
+ "created_at": datetime.now().isoformat(),
56
+ }
57
+
58
+ _wizard_sessions[wizard_id] = session_data
59
+
60
+ return {
61
+ "wizard_id": wizard_id,
62
+ "current_step": 1,
63
+ "total_steps": 5,
64
+ "message": "Wizard started successfully",
65
+ }
66
+
67
+
68
+ @router.post("/{wizard_id}/step")
69
+ async def submit_step(wizard_id: str, step_data: dict[str, Any]):
70
+ """Submit data for current step.
71
+
72
+ Validates step sequence and stores data.
73
+ """
74
+ if wizard_id not in _wizard_sessions:
75
+ raise HTTPException(404, "Wizard session not found")
76
+
77
+ session = _wizard_sessions[wizard_id]
78
+ current_step = session["current_step"]
79
+ total_steps = session["total_steps"]
80
+
81
+ # Validate step number
82
+ submitted_step = step_data.get("step", current_step)
83
+ if submitted_step != current_step:
84
+ raise HTTPException(
85
+ 422,
86
+ f"Expected step {current_step}, got step {submitted_step}"
87
+ )
88
+
89
+ # Store data
90
+ session["collected_data"].update(step_data.get("data", {}))
91
+ session["updated_at"] = datetime.now().isoformat()
92
+
93
+ # Advance to next step
94
+ if current_step < total_steps:
95
+ session["current_step"] = current_step + 1
96
+
97
+ return {
98
+ "wizard_id": wizard_id,
99
+ "current_step": session["current_step"],
100
+ "total_steps": total_steps,
101
+ "message": f"Step {current_step} completed",
102
+ }
103
+
104
+
105
+ {% if has_approval %}
106
+ @router.post("/{wizard_id}/preview")
107
+ async def preview_report(wizard_id: str):
108
+ """Generate preview without finalizing.
109
+
110
+ Allows user to review before explicit approval.
111
+ """
112
+ if wizard_id not in _wizard_sessions:
113
+ raise HTTPException(404, "Wizard session not found")
114
+
115
+ session = _wizard_sessions[wizard_id]
116
+
117
+ if session["current_step"] != session["total_steps"]:
118
+ raise HTTPException(400, "Complete all steps before preview")
119
+
120
+ # Generate preview
121
+ preview = _generate_report(session["collected_data"])
122
+ session["preview_report"] = preview
123
+ session["preview_generated_at"] = datetime.now().isoformat()
124
+
125
+ return {
126
+ "preview": preview,
127
+ "message": "Preview generated. Review and approve to finalize.",
128
+ }
129
+
130
+
131
+ @router.post("/{wizard_id}/save")
132
+ async def save_report(wizard_id: str, approval: dict[str, Any]):
133
+ """Finalize report with user approval.
134
+
135
+ Requires preview generated and explicit user approval.
136
+ """
137
+ if wizard_id not in _wizard_sessions:
138
+ raise HTTPException(404, "Wizard session not found")
139
+
140
+ session = _wizard_sessions[wizard_id]
141
+
142
+ # Verify preview generated
143
+ if "preview_report" not in session:
144
+ raise HTTPException(
145
+ 400,
146
+ "Must generate preview before saving. Call /preview first."
147
+ )
148
+
149
+ # Verify user approval
150
+ if not approval.get("user_approved", False):
151
+ raise HTTPException(
152
+ 400,
153
+ "User approval required. Set 'user_approved': true"
154
+ )
155
+
156
+ # Mark as complete
157
+ session["completed"] = True
158
+ session["completed_at"] = datetime.now().isoformat()
159
+ session["final_report"] = session["preview_report"]
160
+
161
+ return {
162
+ "wizard_id": wizard_id,
163
+ "completed": True,
164
+ "report": session["final_report"],
165
+ "message": "Report finalized successfully",
166
+ }
167
+ {% endif %}
168
+
169
+
170
+ @router.get("/{wizard_id}/report")
171
+ async def get_report(wizard_id: str):
172
+ """Retrieve completed report.
173
+
174
+ Only available after wizard is completed.
175
+ """
176
+ if wizard_id not in _wizard_sessions:
177
+ raise HTTPException(404, "Wizard session not found")
178
+
179
+ session = _wizard_sessions[wizard_id]
180
+
181
+ if not session.get("completed", False):
182
+ raise HTTPException(422, "Wizard not yet completed")
183
+
184
+ return {
185
+ "wizard_id": wizard_id,
186
+ "report": _generate_report(session["collected_data"]),
187
+ }
188
+
189
+
190
+ def _generate_report(collected_data: dict[str, Any]) -> dict[str, Any]:
191
+ """Generate report from collected data.
192
+
193
+ TODO: Customize report generation for your wizard.
194
+ """
195
+ return {
196
+ "data": collected_data,
197
+ "generated_at": datetime.now().isoformat(),
198
+ "wizard_type": "{{ wizard_name }}",
199
+ }
200
+
201
+
202
+ # Export router
203
+ __all__ = ["router"]