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,437 @@
1
+ """Adaptive Model Routing based on historical telemetry.
2
+
3
+ This module implements Pattern 3 from AGENT_COORDINATION_ARCHITECTURE.md:
4
+ Using telemetry history to learn which models work best for each workflow/stage.
5
+
6
+ Key Features:
7
+ - Analyzes historical performance per model/workflow/stage
8
+ - Recommends best model based on success rate and cost
9
+ - Auto-detects when tier upgrades are needed (>20% failure rate)
10
+ - Respects cost and latency constraints
11
+
12
+ Copyright 2025 Smart-AI-Memory
13
+ Licensed under Fair Source License 0.9
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import logging
19
+ from dataclasses import dataclass
20
+ from typing import Any
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ # Lazy import to avoid circular dependency
25
+ _model_registry = None
26
+
27
+
28
+ def _get_registry():
29
+ """Get ModelRegistry instance (lazy load to avoid circular import)."""
30
+ global _model_registry
31
+ if _model_registry is None:
32
+ from .registry import MODEL_REGISTRY
33
+ _model_registry = MODEL_REGISTRY
34
+ return _model_registry
35
+
36
+
37
+ @dataclass
38
+ class ModelPerformance:
39
+ """Performance metrics for a model on a specific task.
40
+
41
+ Attributes:
42
+ model_id: Model identifier (e.g., "claude-sonnet-4.5")
43
+ tier: Model tier (CHEAP, CAPABLE, PREMIUM)
44
+ success_rate: Percentage of successful calls (0.0 - 1.0)
45
+ avg_latency_ms: Average response time in milliseconds
46
+ avg_cost: Average cost per call in USD
47
+ sample_size: Number of calls analyzed
48
+ recent_failures: Number of failures in last 20 calls
49
+ """
50
+
51
+ model_id: str
52
+ tier: str
53
+ success_rate: float
54
+ avg_latency_ms: float
55
+ avg_cost: float
56
+ sample_size: int
57
+ recent_failures: int = 0
58
+
59
+ @property
60
+ def quality_score(self) -> float:
61
+ """Calculate quality score for ranking models.
62
+
63
+ Score prioritizes:
64
+ 1. Success rate (most important)
65
+ 2. Cost (secondary)
66
+
67
+ Returns:
68
+ Quality score (higher is better)
69
+ """
70
+ # Success rate contributes 100 points max
71
+ # Lower cost adds bonus points
72
+ return (self.success_rate * 100) - (self.avg_cost * 10)
73
+
74
+
75
+ class AdaptiveModelRouter:
76
+ """Route tasks to models based on historical telemetry performance.
77
+
78
+ Uses telemetry data to learn which models work best for each workflow/stage
79
+ combination. Automatically recommends tier upgrades when failure rates are high.
80
+
81
+ Example:
82
+ >>> from attune.telemetry import UsageTracker
83
+ >>> router = AdaptiveModelRouter(UsageTracker.get_instance())
84
+ >>>
85
+ >>> # Get best model for this workflow stage
86
+ >>> model = router.get_best_model(
87
+ ... workflow="code-review",
88
+ ... stage="analysis",
89
+ ... max_cost=0.01
90
+ ... )
91
+ >>> print(f"Using {model}")
92
+ Using claude-3-5-haiku-20241022
93
+ >>>
94
+ >>> # Check if we should upgrade tier
95
+ >>> should_upgrade, reason = router.recommend_tier_upgrade(
96
+ ... workflow="code-review",
97
+ ... stage="analysis"
98
+ ... )
99
+ >>> if should_upgrade:
100
+ ... print(f"⚠️ {reason}")
101
+ ⚠️ High failure rate: 25.0% in last 20 calls
102
+ """
103
+
104
+ # Minimum sample size for making routing decisions
105
+ MIN_SAMPLE_SIZE = 10
106
+
107
+ # Failure rate threshold for tier upgrade recommendation
108
+ FAILURE_RATE_THRESHOLD = 0.2 # 20%
109
+
110
+ # Recent window size for failure detection
111
+ RECENT_WINDOW_SIZE = 20
112
+
113
+ def __init__(self, telemetry: Any):
114
+ """Initialize adaptive router.
115
+
116
+ Args:
117
+ telemetry: UsageTracker instance for telemetry data access
118
+ """
119
+ self.telemetry = telemetry
120
+
121
+ def _get_default_model(self, tier: str = "CHEAP") -> str:
122
+ """Get default Anthropic model for a tier from registry.
123
+
124
+ This dynamically fetches the current Anthropic model for each tier,
125
+ so when new models are released (e.g., Claude 5), they're automatically used.
126
+
127
+ Args:
128
+ tier: Tier name (CHEAP, CAPABLE, or PREMIUM)
129
+
130
+ Returns:
131
+ Model ID from registry (e.g., "claude-3-5-haiku-20241022")
132
+ """
133
+ registry = _get_registry()
134
+
135
+ # Get Anthropic model for this tier
136
+ tier_lower = tier.lower()
137
+ if tier_lower in registry.get("anthropic", {}):
138
+ return registry["anthropic"][tier_lower].id
139
+
140
+ # Fallback to known models if registry lookup fails
141
+ fallbacks = {
142
+ "cheap": "claude-3-5-haiku-20241022",
143
+ "capable": "claude-sonnet-4-5",
144
+ "premium": "claude-opus-4-5-20251101",
145
+ }
146
+ return fallbacks.get(tier_lower, "claude-3-5-haiku-20241022")
147
+
148
+ def get_best_model(
149
+ self,
150
+ workflow: str,
151
+ stage: str,
152
+ max_cost: float | None = None,
153
+ max_latency_ms: int | None = None,
154
+ min_success_rate: float = 0.8,
155
+ ) -> str:
156
+ """Get best model for workflow/stage based on historical performance.
157
+
158
+ Analyzes recent telemetry to find the model with the best quality score
159
+ (success rate + cost efficiency) that meets the specified constraints.
160
+
161
+ Args:
162
+ workflow: Workflow name (e.g., "code-review", "bug-predict")
163
+ stage: Stage name (e.g., "analysis", "synthesis")
164
+ max_cost: Maximum acceptable cost per call (USD)
165
+ max_latency_ms: Maximum acceptable latency (milliseconds)
166
+ min_success_rate: Minimum acceptable success rate (0.0 - 1.0)
167
+
168
+ Returns:
169
+ Model ID to use (e.g., "claude-3-5-haiku-20241022")
170
+
171
+ Example:
172
+ >>> model = router.get_best_model(
173
+ ... workflow="code-review",
174
+ ... stage="analysis",
175
+ ... max_cost=0.01,
176
+ ... min_success_rate=0.9
177
+ ... )
178
+ >>> print(model)
179
+ claude-3-5-haiku-20241022
180
+ """
181
+ # Get performance data for all models on this workflow/stage
182
+ performances = self._analyze_model_performance(workflow, stage)
183
+
184
+ if not performances:
185
+ # No historical data, use default Anthropic cheap model from registry
186
+ default_model = self._get_default_model("CHEAP")
187
+ logger.info(
188
+ "adaptive_routing_no_history",
189
+ workflow=workflow,
190
+ stage=stage,
191
+ fallback=default_model,
192
+ )
193
+ return default_model
194
+
195
+ # Filter by constraints
196
+ candidates = []
197
+ for perf in performances:
198
+ # Skip if insufficient data
199
+ if perf.sample_size < self.MIN_SAMPLE_SIZE:
200
+ continue
201
+
202
+ # Skip if doesn't meet minimum success rate
203
+ if perf.success_rate < min_success_rate:
204
+ continue
205
+
206
+ # Skip if exceeds cost constraint
207
+ if max_cost is not None and perf.avg_cost > max_cost:
208
+ continue
209
+
210
+ # Skip if exceeds latency constraint
211
+ if max_latency_ms is not None and perf.avg_latency_ms > max_latency_ms:
212
+ continue
213
+
214
+ candidates.append(perf)
215
+
216
+ if not candidates:
217
+ # All models filtered out, fall back to default Anthropic model
218
+ default_model = self._get_default_model("CHEAP")
219
+ logger.warning(
220
+ "adaptive_routing_no_candidates",
221
+ workflow=workflow,
222
+ stage=stage,
223
+ constraints={"max_cost": max_cost, "max_latency_ms": max_latency_ms},
224
+ fallback=default_model,
225
+ )
226
+ return default_model
227
+
228
+ # Sort by quality score (success rate + cost efficiency)
229
+ candidates.sort(key=lambda p: p.quality_score, reverse=True)
230
+ best = candidates[0]
231
+
232
+ logger.info(
233
+ "adaptive_routing_selected",
234
+ workflow=workflow,
235
+ stage=stage,
236
+ model=best.model_id,
237
+ success_rate=f"{best.success_rate:.1%}",
238
+ avg_cost=f"${best.avg_cost:.4f}",
239
+ sample_size=best.sample_size,
240
+ )
241
+
242
+ return best.model_id
243
+
244
+ def recommend_tier_upgrade(
245
+ self, workflow: str, stage: str
246
+ ) -> tuple[bool, str]:
247
+ """Check if tier should be upgraded based on failure rate.
248
+
249
+ Analyzes recent telemetry (last 20 calls) for this workflow/stage.
250
+ If failure rate exceeds threshold (20%), recommends tier upgrade.
251
+
252
+ Args:
253
+ workflow: Workflow name
254
+ stage: Stage name
255
+
256
+ Returns:
257
+ Tuple of (should_upgrade: bool, reason: str)
258
+
259
+ Example:
260
+ >>> should_upgrade, reason = router.recommend_tier_upgrade(
261
+ ... workflow="code-review",
262
+ ... stage="analysis"
263
+ ... )
264
+ >>> if should_upgrade:
265
+ ... print(f"⚠️ Upgrading tier: {reason}")
266
+ ⚠️ Upgrading tier: High failure rate: 25.0% in last 20 calls
267
+ """
268
+ # Get recent entries for this workflow/stage
269
+ entries = self._get_workflow_stage_entries(workflow, stage, days=7)
270
+
271
+ if len(entries) < self.MIN_SAMPLE_SIZE:
272
+ return False, f"Insufficient data ({len(entries)} calls, need {self.MIN_SAMPLE_SIZE})"
273
+
274
+ # Analyze recent window (last 20 calls)
275
+ recent = entries[-self.RECENT_WINDOW_SIZE :]
276
+ failures = sum(1 for e in recent if not e.get("success", True))
277
+ failure_rate = failures / len(recent)
278
+
279
+ if failure_rate > self.FAILURE_RATE_THRESHOLD:
280
+ return (
281
+ True,
282
+ f"High failure rate: {failure_rate:.1%} ({failures}/{len(recent)} failed in recent calls)",
283
+ )
284
+
285
+ return False, f"Performance acceptable: {failure_rate:.1%} failure rate"
286
+
287
+ def get_routing_stats(
288
+ self, workflow: str, stage: str | None = None, days: int = 7
289
+ ) -> dict[str, Any]:
290
+ """Get routing statistics for a workflow (or specific stage).
291
+
292
+ Args:
293
+ workflow: Workflow name
294
+ stage: Optional stage name (None for all stages)
295
+ days: Number of days to analyze
296
+
297
+ Returns:
298
+ Dictionary with routing statistics:
299
+ - models_used: List of models used
300
+ - performance_by_model: Performance metrics per model
301
+ - total_calls: Total number of calls
302
+ - avg_cost: Average cost per call
303
+ - avg_success_rate: Average success rate
304
+
305
+ Example:
306
+ >>> stats = router.get_routing_stats("code-review", days=7)
307
+ >>> print(f"Models used: {stats['models_used']}")
308
+ Models used: ['claude-haiku-3.5', 'claude-sonnet-4.5']
309
+ >>> print(f"Average cost: ${stats['avg_cost']:.4f}")
310
+ Average cost: $0.0023
311
+ """
312
+ entries = self._get_workflow_stage_entries(workflow, stage, days=days)
313
+
314
+ if not entries:
315
+ return {
316
+ "models_used": [],
317
+ "performance_by_model": {},
318
+ "total_calls": 0,
319
+ "avg_cost": 0.0,
320
+ "avg_success_rate": 0.0,
321
+ }
322
+
323
+ # Calculate stats
324
+ models_used = list({e["model"] for e in entries})
325
+ total_calls = len(entries)
326
+ total_cost = sum(e.get("cost", 0.0) for e in entries)
327
+ successes = sum(1 for e in entries if e.get("success", True))
328
+
329
+ # Per-model performance
330
+ performance_by_model = {}
331
+ for model in models_used:
332
+ model_entries = [e for e in entries if e["model"] == model]
333
+ model_successes = sum(1 for e in model_entries if e.get("success", True))
334
+
335
+ performance_by_model[model] = {
336
+ "calls": len(model_entries),
337
+ "success_rate": model_successes / len(model_entries),
338
+ "avg_cost": sum(e.get("cost", 0.0) for e in model_entries)
339
+ / len(model_entries),
340
+ "avg_latency_ms": sum(e.get("duration_ms", 0) for e in model_entries)
341
+ / len(model_entries),
342
+ }
343
+
344
+ return {
345
+ "workflow": workflow,
346
+ "stage": stage or "all",
347
+ "days_analyzed": days,
348
+ "models_used": models_used,
349
+ "performance_by_model": performance_by_model,
350
+ "total_calls": total_calls,
351
+ "avg_cost": total_cost / total_calls if total_calls > 0 else 0.0,
352
+ "avg_success_rate": successes / total_calls if total_calls > 0 else 0.0,
353
+ }
354
+
355
+ def _analyze_model_performance(
356
+ self, workflow: str, stage: str, days: int = 7
357
+ ) -> list[ModelPerformance]:
358
+ """Analyze performance of all models for this workflow/stage.
359
+
360
+ Args:
361
+ workflow: Workflow name
362
+ stage: Stage name
363
+ days: Number of days to analyze
364
+
365
+ Returns:
366
+ List of ModelPerformance objects, one per model
367
+ """
368
+ entries = self._get_workflow_stage_entries(workflow, stage, days=days)
369
+
370
+ if not entries:
371
+ return []
372
+
373
+ # Group by model
374
+ by_model: dict[str, list[dict]] = {}
375
+ for entry in entries:
376
+ model = entry["model"]
377
+ if model not in by_model:
378
+ by_model[model] = []
379
+ by_model[model].append(entry)
380
+
381
+ # Calculate performance metrics per model
382
+ performances = []
383
+ for model, model_entries in by_model.items():
384
+ total = len(model_entries)
385
+ successes = sum(1 for e in model_entries if e.get("success", True))
386
+ success_rate = successes / total
387
+
388
+ avg_latency = (
389
+ sum(e.get("duration_ms", 0) for e in model_entries) / total
390
+ )
391
+ avg_cost = sum(e.get("cost", 0.0) for e in model_entries) / total
392
+
393
+ # Analyze recent failures (last 20 calls)
394
+ recent = model_entries[-self.RECENT_WINDOW_SIZE :]
395
+ recent_failures = sum(1 for e in recent if not e.get("success", True))
396
+
397
+ performances.append(
398
+ ModelPerformance(
399
+ model_id=model,
400
+ tier=model_entries[0].get("tier", "unknown"),
401
+ success_rate=success_rate,
402
+ avg_latency_ms=avg_latency,
403
+ avg_cost=avg_cost,
404
+ sample_size=total,
405
+ recent_failures=recent_failures,
406
+ )
407
+ )
408
+
409
+ return performances
410
+
411
+ def _get_workflow_stage_entries(
412
+ self, workflow: str, stage: str | None, days: int
413
+ ) -> list[dict[str, Any]]:
414
+ """Get telemetry entries for a workflow/stage.
415
+
416
+ Args:
417
+ workflow: Workflow name
418
+ stage: Stage name (None for all stages)
419
+ days: Number of days to retrieve
420
+
421
+ Returns:
422
+ List of telemetry entries
423
+ """
424
+ # Get recent entries from telemetry tracker
425
+ all_entries = self.telemetry.get_recent_entries(limit=10000, days=days)
426
+
427
+ # Filter to this workflow
428
+ workflow_entries = [e for e in all_entries if e.get("workflow") == workflow]
429
+
430
+ # Filter to this stage if specified
431
+ if stage is not None:
432
+ workflow_entries = [e for e in workflow_entries if e.get("stage") == stage]
433
+
434
+ return workflow_entries
435
+
436
+
437
+ __all__ = ["AdaptiveModelRouter", "ModelPerformance"]