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,384 @@
1
+ """
2
+ Real-time tier recommendation system for cascading workflows.
3
+
4
+ This module provides intelligent tier selection based on historical patterns,
5
+ bug types, and file analysis. It can be used programmatically or via CLI.
6
+
7
+ Usage:
8
+ from attune import TierRecommender
9
+
10
+ recommender = TierRecommender()
11
+ tier = recommender.recommend(
12
+ bug_description="integration test failure with import error",
13
+ files_affected=["tests/integration/test_foo.py"]
14
+ )
15
+
16
+ print(f"Recommended tier: {tier.tier}")
17
+ print(f"Confidence: {tier.confidence}")
18
+ print(f"Expected cost: ${tier.expected_cost}")
19
+ """
20
+
21
+ import json
22
+ from collections import defaultdict
23
+ from dataclasses import dataclass
24
+ from pathlib import Path
25
+
26
+ from attune.config import _validate_file_path
27
+
28
+
29
+ @dataclass
30
+ class TierRecommendationResult:
31
+ """Result of tier recommendation."""
32
+
33
+ tier: str # CHEAP, CAPABLE, or PREMIUM
34
+ confidence: float # 0.0-1.0
35
+ reasoning: str
36
+ expected_cost: float
37
+ expected_attempts: float
38
+ similar_patterns_count: int
39
+ fallback_used: bool = False
40
+
41
+
42
+ class TierRecommender:
43
+ """
44
+ Intelligent tier recommendation system.
45
+
46
+ Learns from historical patterns to recommend optimal starting tier
47
+ for new bugs based on:
48
+ - Bug type/description
49
+ - Files affected
50
+ - Historical success rates
51
+ - Cost optimization
52
+ """
53
+
54
+ def __init__(self, patterns_dir: Path | None = None, confidence_threshold: float = 0.7):
55
+ """
56
+ Initialize tier recommender.
57
+
58
+ Args:
59
+ patterns_dir: Directory containing pattern JSON files.
60
+ Defaults to patterns/debugging/
61
+ confidence_threshold: Minimum confidence for non-default recommendations
62
+
63
+ Raises:
64
+ ValueError: If confidence_threshold is out of valid range
65
+ """
66
+ # Pattern 4: Range validation
67
+ if not 0.0 <= confidence_threshold <= 1.0:
68
+ raise ValueError(
69
+ f"confidence_threshold must be between 0.0 and 1.0, got {confidence_threshold}"
70
+ )
71
+
72
+ if patterns_dir is None:
73
+ patterns_dir = Path(__file__).parent.parent.parent / "patterns" / "debugging"
74
+
75
+ self.patterns_dir = Path(patterns_dir)
76
+ self.confidence_threshold = confidence_threshold
77
+ self.patterns = self._load_patterns()
78
+
79
+ # Build indexes for fast lookup
80
+ self._build_indexes()
81
+
82
+ def _load_patterns(self) -> list[dict]:
83
+ """Load all enhanced patterns with tier_progression data."""
84
+ patterns: list[dict] = []
85
+
86
+ if not self.patterns_dir.exists():
87
+ return patterns
88
+
89
+ for file_path in self.patterns_dir.glob("*.json"):
90
+ try:
91
+ validated_path = _validate_file_path(str(file_path))
92
+ with open(validated_path) as f:
93
+ data = json.load(f)
94
+
95
+ # Check if this is an enhanced pattern
96
+ if isinstance(data, dict) and "tier_progression" in data:
97
+ patterns.append(data)
98
+ # Or if it's a patterns array
99
+ elif isinstance(data, dict) and "patterns" in data:
100
+ for pattern in data["patterns"]:
101
+ if "tier_progression" in pattern:
102
+ patterns.append(pattern)
103
+ except (json.JSONDecodeError, KeyError, ValueError):
104
+ continue
105
+
106
+ return patterns
107
+
108
+ def _build_indexes(self):
109
+ """Build indexes for fast pattern lookup."""
110
+ self.bug_type_index: dict[str, list[dict]] = defaultdict(list)
111
+ self.file_pattern_index: dict[str, list[dict]] = defaultdict(list)
112
+
113
+ for pattern in self.patterns:
114
+ # Index by bug type
115
+ bug_type = pattern.get("bug_type", "unknown")
116
+ self.bug_type_index[bug_type].append(pattern)
117
+
118
+ # Index by file patterns
119
+ files = pattern.get("files_affected", [])
120
+ for file in files:
121
+ # Extract file pattern (e.g., "tests/" from "tests/test_foo.py")
122
+ parts = Path(file).parts
123
+ if parts:
124
+ self.file_pattern_index[parts[0]].append(pattern)
125
+
126
+ def recommend(
127
+ self,
128
+ bug_description: str,
129
+ files_affected: list[str] | None = None,
130
+ complexity_hint: int | None = None,
131
+ ) -> TierRecommendationResult:
132
+ """
133
+ Recommend optimal starting tier for a new bug.
134
+
135
+ Args:
136
+ bug_description: Description of the bug/task
137
+ files_affected: List of files involved (optional)
138
+ complexity_hint: Manual complexity score 1-10 (optional)
139
+
140
+ Returns:
141
+ TierRecommendationResult with tier, confidence, and reasoning
142
+
143
+ Raises:
144
+ ValueError: If bug_description is empty or complexity_hint out of range
145
+ TypeError: If files_affected is not a list
146
+ """
147
+ # Pattern 1: String ID validation
148
+ if not bug_description or not bug_description.strip():
149
+ raise ValueError("bug_description cannot be empty")
150
+
151
+ # Pattern 5: Type validation
152
+ if files_affected is not None and not isinstance(files_affected, list):
153
+ raise TypeError(f"files_affected must be list, got {type(files_affected).__name__}")
154
+
155
+ # Pattern 4: Range validation for complexity_hint
156
+ if complexity_hint is not None and not (1 <= complexity_hint <= 10):
157
+ raise ValueError(f"complexity_hint must be between 1 and 10, got {complexity_hint}")
158
+
159
+ # Step 1: Match bug type from description
160
+ bug_type = self._classify_bug_type(bug_description)
161
+
162
+ # Step 2: Find similar patterns
163
+ similar_patterns = self._find_similar_patterns(
164
+ bug_type=bug_type, files_affected=files_affected or []
165
+ )
166
+
167
+ # Step 3: If no similar patterns, use fallback logic
168
+ if not similar_patterns:
169
+ return self._fallback_recommendation(
170
+ bug_description=bug_description, complexity_hint=complexity_hint
171
+ )
172
+
173
+ # Step 4: Analyze tier distribution in similar patterns
174
+ tier_analysis = self._analyze_tier_distribution(similar_patterns)
175
+
176
+ # Step 5: Select tier with highest success rate
177
+ recommended_tier, confidence = self._select_tier(tier_analysis)
178
+
179
+ # Step 6: Calculate expected cost and attempts
180
+ cost_estimate = self._estimate_cost(similar_patterns, recommended_tier)
181
+
182
+ return TierRecommendationResult(
183
+ tier=recommended_tier,
184
+ confidence=confidence,
185
+ reasoning=self._generate_reasoning(
186
+ bug_type=bug_type,
187
+ tier=recommended_tier,
188
+ confidence=confidence,
189
+ similar_count=len(similar_patterns),
190
+ ),
191
+ expected_cost=cost_estimate["avg_cost"],
192
+ expected_attempts=cost_estimate["avg_attempts"],
193
+ similar_patterns_count=len(similar_patterns),
194
+ fallback_used=False,
195
+ )
196
+
197
+ def _classify_bug_type(self, description: str) -> str:
198
+ """Classify bug type from description using keyword matching."""
199
+ desc_lower = description.lower()
200
+
201
+ # Define bug type keywords
202
+ bug_type_keywords = {
203
+ "integration_error": ["integration", "import", "module", "package"],
204
+ "type_mismatch": ["type", "annotation", "mypy", "typing"],
205
+ "import_error": ["import", "module", "cannot import", "no module"],
206
+ "syntax_error": ["syntax", "invalid syntax", "parse error"],
207
+ "runtime_error": ["runtime", "exception", "traceback"],
208
+ "test_failure": ["test fail", "assertion", "pytest"],
209
+ }
210
+
211
+ for bug_type, keywords in bug_type_keywords.items():
212
+ if any(kw in desc_lower for kw in keywords):
213
+ return bug_type
214
+
215
+ return "unknown"
216
+
217
+ def _find_similar_patterns(self, bug_type: str, files_affected: list[str]) -> list[dict]:
218
+ """Find patterns similar to current bug.
219
+
220
+ Raises:
221
+ TypeError: If files_affected is not a list
222
+ """
223
+ # Pattern 5: Type validation
224
+ if not isinstance(files_affected, list):
225
+ raise TypeError(f"files_affected must be list, got {type(files_affected).__name__}")
226
+
227
+ similar = []
228
+
229
+ # Match by bug type
230
+ similar.extend(self.bug_type_index.get(bug_type, []))
231
+
232
+ # Match by file patterns
233
+ if files_affected:
234
+ for file in files_affected:
235
+ parts = Path(file).parts
236
+ if parts:
237
+ file_matches = self.file_pattern_index.get(parts[0], [])
238
+ # Add only if not already in similar list
239
+ for pattern in file_matches:
240
+ if pattern not in similar:
241
+ similar.append(pattern)
242
+
243
+ return similar
244
+
245
+ def _analyze_tier_distribution(self, patterns: list[dict]) -> dict[str, dict]:
246
+ """Analyze tier success rates from similar patterns."""
247
+ tier_stats: dict[str, dict] = defaultdict(
248
+ lambda: {"count": 0, "total_cost": 0.0, "total_attempts": 0}
249
+ )
250
+
251
+ for pattern in patterns:
252
+ tp = pattern["tier_progression"]
253
+ successful_tier = tp["successful_tier"]
254
+
255
+ stats = tier_stats[successful_tier]
256
+ stats["count"] += 1
257
+ stats["total_cost"] += tp["cost_breakdown"]["total_cost"]
258
+ stats["total_attempts"] += tp["total_attempts"]
259
+
260
+ # Calculate averages
261
+ for _tier, stats in tier_stats.items():
262
+ count = stats["count"]
263
+ stats["success_rate"] = count / len(patterns)
264
+ stats["avg_cost"] = stats["total_cost"] / count
265
+ stats["avg_attempts"] = stats["total_attempts"] / count
266
+
267
+ return dict(tier_stats)
268
+
269
+ def _select_tier(self, tier_analysis: dict[str, dict]) -> tuple[str, float]:
270
+ """Select best tier based on success rate and cost."""
271
+ if not tier_analysis:
272
+ return "CHEAP", 0.5
273
+
274
+ # Sort by success rate
275
+ sorted_tiers = sorted(
276
+ tier_analysis.items(), key=lambda x: x[1]["success_rate"], reverse=True
277
+ )
278
+
279
+ best_tier, stats = sorted_tiers[0]
280
+ confidence = stats["success_rate"]
281
+
282
+ return best_tier, confidence
283
+
284
+ def _estimate_cost(self, patterns: list[dict], tier: str) -> dict[str, float]:
285
+ """Estimate cost and attempts for recommended tier."""
286
+ matching = [p for p in patterns if p["tier_progression"]["successful_tier"] == tier]
287
+
288
+ if not matching:
289
+ # Default estimates by tier
290
+ defaults = {
291
+ "CHEAP": {"avg_cost": 0.030, "avg_attempts": 1.5},
292
+ "CAPABLE": {"avg_cost": 0.150, "avg_attempts": 2.5},
293
+ "PREMIUM": {"avg_cost": 0.450, "avg_attempts": 1.0},
294
+ }
295
+ return defaults.get(tier, defaults["CHEAP"])
296
+
297
+ total_cost = sum(p["tier_progression"]["cost_breakdown"]["total_cost"] for p in matching)
298
+ total_attempts = sum(p["tier_progression"]["total_attempts"] for p in matching)
299
+
300
+ return {
301
+ "avg_cost": total_cost / len(matching),
302
+ "avg_attempts": total_attempts / len(matching),
303
+ }
304
+
305
+ def _fallback_recommendation(
306
+ self, bug_description: str, complexity_hint: int | None
307
+ ) -> TierRecommendationResult:
308
+ """Provide fallback recommendation when no historical data available."""
309
+
310
+ # Use complexity hint if provided
311
+ if complexity_hint is not None:
312
+ if complexity_hint <= 3:
313
+ tier = "CHEAP"
314
+ cost = 0.030
315
+ elif complexity_hint <= 7:
316
+ tier = "CAPABLE"
317
+ cost = 0.150
318
+ else:
319
+ tier = "PREMIUM"
320
+ cost = 0.450
321
+
322
+ return TierRecommendationResult(
323
+ tier=tier,
324
+ confidence=0.6,
325
+ reasoning=f"Based on complexity score {complexity_hint}/10",
326
+ expected_cost=cost,
327
+ expected_attempts=2.0,
328
+ similar_patterns_count=0,
329
+ fallback_used=True,
330
+ )
331
+
332
+ # Default: start with CHEAP tier (conservative)
333
+ return TierRecommendationResult(
334
+ tier="CHEAP",
335
+ confidence=0.5,
336
+ reasoning="No historical data - defaulting to CHEAP tier (conservative approach)",
337
+ expected_cost=0.030,
338
+ expected_attempts=1.5,
339
+ similar_patterns_count=0,
340
+ fallback_used=True,
341
+ )
342
+
343
+ def _generate_reasoning(
344
+ self, bug_type: str, tier: str, confidence: float, similar_count: int
345
+ ) -> str:
346
+ """Generate human-readable reasoning for recommendation."""
347
+ percent = int(confidence * 100)
348
+
349
+ if similar_count == 0:
350
+ return "No historical data - defaulting to CHEAP tier"
351
+ elif similar_count == 1:
352
+ return f"1 similar bug ({bug_type}) resolved at {tier} tier"
353
+ else:
354
+ return (
355
+ f"{percent}% of {similar_count} similar bugs ({bug_type}) resolved at {tier} tier"
356
+ )
357
+
358
+ def get_stats(self) -> dict:
359
+ """Get overall statistics about pattern learning."""
360
+ if not self.patterns:
361
+ return {"total_patterns": 0, "message": "No patterns loaded"}
362
+
363
+ # Calculate tier distribution
364
+ tier_dist: dict[str, int] = defaultdict(int)
365
+ bug_type_dist: dict[str, int] = defaultdict(int)
366
+ total_savings = 0.0
367
+
368
+ for pattern in self.patterns:
369
+ tp = pattern["tier_progression"]
370
+ tier_dist[tp["successful_tier"]] += 1
371
+ bug_type_dist[pattern["bug_type"]] += 1
372
+ total_savings += tp["cost_breakdown"]["savings_percent"]
373
+
374
+ return {
375
+ "total_patterns": len(self.patterns),
376
+ "tier_distribution": dict(tier_dist),
377
+ "bug_type_distribution": dict(bug_type_dist),
378
+ "avg_savings_percent": round(total_savings / len(self.patterns), 1),
379
+ "patterns_by_tier": {
380
+ "CHEAP": tier_dist.get("CHEAP", 0),
381
+ "CAPABLE": tier_dist.get("CAPABLE", 0),
382
+ "PREMIUM": tier_dist.get("PREMIUM", 0),
383
+ },
384
+ }
attune/tools.py ADDED
@@ -0,0 +1,183 @@
1
+ """Interactive user prompting tools.
2
+
3
+ Provides tools for asking users questions and getting structured responses.
4
+ This module implements the AskUserQuestion functionality used by the
5
+ meta-orchestrator for interactive agent team creation.
6
+
7
+ Integration with Claude Code:
8
+ When running Python code that calls this function, Claude Code will
9
+ detect the call and use its AskUserQuestion tool to prompt the user
10
+ in the IDE. This is implemented via a request/response IPC mechanism.
11
+
12
+ Created: 2026-01-29
13
+ """
14
+ import json
15
+ import logging
16
+ import os
17
+ import tempfile
18
+ from collections.abc import Callable
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ # Global callback for custom AskUserQuestion implementations
25
+ _custom_ask_function: Callable | None = None
26
+
27
+
28
+ def set_ask_user_question_handler(handler: Callable) -> None:
29
+ """Set a custom handler for AskUserQuestion.
30
+
31
+ This allows integration with different UI systems (CLI, web, IDE).
32
+
33
+ Args:
34
+ handler: Callable that takes questions list and returns response dict
35
+
36
+ Example:
37
+ >>> def my_handler(questions):
38
+ ... # Custom UI logic
39
+ ... return {"Pattern": "sequential"}
40
+ >>> set_ask_user_question_handler(my_handler)
41
+ """
42
+ global _custom_ask_function
43
+ _custom_ask_function = handler
44
+ logger.info("Custom AskUserQuestion handler registered")
45
+
46
+
47
+ def AskUserQuestion(questions: list[dict[str, Any]]) -> dict[str, Any]:
48
+ """Ask user questions and get structured responses.
49
+
50
+ This function supports multiple integration modes:
51
+ 1. Custom handler (via set_ask_user_question_handler)
52
+ 2. Claude Code IPC (when running in Claude Code environment)
53
+ 3. Fallback to NotImplementedError (prompts caller to use automatic mode)
54
+
55
+ Args:
56
+ questions: List of question dictionaries, each with:
57
+ - header: Short label for the question (str, max 12 chars)
58
+ - question: Full question text (str)
59
+ - multiSelect: Allow multiple selections (bool)
60
+ - options: List of option dicts with label and description
61
+
62
+ Returns:
63
+ Dictionary mapping question headers to selected answers
64
+
65
+ Raises:
66
+ NotImplementedError: If no handler available and not in Claude Code
67
+ RuntimeError: If user cancels or interaction fails
68
+
69
+ Example:
70
+ >>> response = AskUserQuestion(
71
+ ... questions=[{
72
+ ... "header": "Pattern",
73
+ ... "question": "Which pattern to use?",
74
+ ... "multiSelect": False,
75
+ ... "options": [
76
+ ... {"label": "sequential", "description": "One after another"},
77
+ ... {"label": "parallel", "description": "All at once"}
78
+ ... ]
79
+ ... }]
80
+ ... )
81
+ >>> response
82
+ {"Pattern": "sequential"}
83
+ """
84
+ # Mode 1: Custom handler
85
+ if _custom_ask_function is not None:
86
+ logger.info("Using custom AskUserQuestion handler")
87
+ return _custom_ask_function(questions)
88
+
89
+ # Mode 2: Claude Code IPC
90
+ # When running inside Claude Code, we can use a file-based IPC mechanism
91
+ if _is_running_in_claude_code():
92
+ logger.info("Using Claude Code IPC for AskUserQuestion")
93
+ return _ask_via_claude_code_ipc(questions)
94
+
95
+ # Mode 3: Fallback - raise error with helpful message
96
+ logger.warning("No AskUserQuestion handler available")
97
+ raise NotImplementedError(
98
+ "AskUserQuestion requires either:\n"
99
+ "1. Custom handler via set_ask_user_question_handler()\n"
100
+ "2. Running in Claude Code environment\n"
101
+ "3. Using interactive=False for automatic mode\n\n"
102
+ "Use: orchestrator.analyze_and_compose(task, interactive=False)"
103
+ )
104
+
105
+
106
+ def _is_running_in_claude_code() -> bool:
107
+ """Check if code is running inside Claude Code environment.
108
+
109
+ Returns:
110
+ True if running in Claude Code, False otherwise
111
+ """
112
+ # Check for Claude Code environment markers
113
+ return (
114
+ os.getenv("CLAUDE_CODE_SESSION") is not None
115
+ or os.getenv("CLAUDE_AGENT_MODE") is not None
116
+ or Path("/tmp/.claude-code").exists()
117
+ )
118
+
119
+
120
+ def _ask_via_claude_code_ipc(questions: list[dict[str, Any]]) -> dict[str, Any]:
121
+ """Ask user questions via Claude Code IPC mechanism.
122
+
123
+ This creates a request file that Claude Code monitors, then waits for
124
+ the response file to be created with the user's answers.
125
+
126
+ Args:
127
+ questions: List of question dictionaries
128
+
129
+ Returns:
130
+ User's responses as a dictionary
131
+
132
+ Raises:
133
+ RuntimeError: If communication fails or times out
134
+ """
135
+ import time
136
+ import uuid
137
+
138
+ request_id = str(uuid.uuid4())
139
+ ipc_dir = Path(tempfile.gettempdir()) / ".claude-code-ipc"
140
+ ipc_dir.mkdir(exist_ok=True)
141
+
142
+ request_file = ipc_dir / f"ask-request-{request_id}.json"
143
+ response_file = ipc_dir / f"ask-response-{request_id}.json"
144
+
145
+ try:
146
+ # Write request
147
+ request_data = {
148
+ "request_id": request_id,
149
+ "questions": questions,
150
+ "timestamp": time.time(),
151
+ }
152
+
153
+ request_file.write_text(json.dumps(request_data, indent=2))
154
+ logger.info(f"Wrote IPC request: {request_file}")
155
+
156
+ # Wait for response (max 60 seconds)
157
+ timeout = 60
158
+ start_time = time.time()
159
+
160
+ while time.time() - start_time < timeout:
161
+ if response_file.exists():
162
+ # Read response
163
+ response_data = json.loads(response_file.read_text())
164
+ logger.info(f"Received IPC response: {response_data}")
165
+
166
+ # Cleanup
167
+ request_file.unlink(missing_ok=True)
168
+ response_file.unlink(missing_ok=True)
169
+
170
+ return response_data.get("answers", {})
171
+
172
+ time.sleep(0.1) # Poll every 100ms
173
+
174
+ raise RuntimeError(
175
+ f"Timeout waiting for user response (waited {timeout}s). "
176
+ "User may have cancelled or Claude Code IPC is not active."
177
+ )
178
+
179
+ except Exception as e:
180
+ # Cleanup on error
181
+ request_file.unlink(missing_ok=True)
182
+ response_file.unlink(missing_ok=True)
183
+ raise RuntimeError(f"Claude Code IPC failed: {e}") from e
@@ -0,0 +1,28 @@
1
+ """Trust Management Module
2
+
3
+ Cross-domain transfer of reliability patterns to human-AI trust management.
4
+ Implements Level 5 (Systems Thinking) capability.
5
+
6
+ Pattern Source: Circuit Breaker (reliability/circuit_breaker.py)
7
+ Transfer: Protect user trust like protecting system stability
8
+ """
9
+
10
+ from .circuit_breaker import (
11
+ TrustCircuitBreaker,
12
+ TrustConfig,
13
+ TrustDamageEvent,
14
+ TrustDamageType,
15
+ TrustRecoveryEvent,
16
+ TrustState,
17
+ create_trust_breaker,
18
+ )
19
+
20
+ __all__ = [
21
+ "TrustCircuitBreaker",
22
+ "TrustConfig",
23
+ "TrustDamageEvent",
24
+ "TrustDamageType",
25
+ "TrustRecoveryEvent",
26
+ "TrustState",
27
+ "create_trust_breaker",
28
+ ]