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,472 @@
1
+ """Unified Model Registry - Single Source of Truth
2
+
3
+ This module provides a centralized model configuration that is consumed by:
4
+ - attune_llm.routing.ModelRouter (via compatibility properties)
5
+ - src/attune/workflows.config.WorkflowConfig
6
+ - src/attune.cost_tracker
7
+
8
+ Pricing is stored in per-million tokens (industry standard) with computed
9
+ properties for per-1k compatibility with legacy code.
10
+
11
+ Copyright 2025 Smart-AI-Memory
12
+ Licensed under Fair Source License 0.9
13
+ """
14
+
15
+ from dataclasses import dataclass
16
+ from enum import Enum
17
+ from typing import Any
18
+
19
+
20
+ class ModelTier(Enum):
21
+ """Model tier classification for routing.
22
+
23
+ CHEAP: Fast, low-cost models for simple tasks (~$0.15-1.00/M input)
24
+ CAPABLE: Balanced models for most development work (~$2.50-3.00/M input)
25
+ PREMIUM: Highest capability for complex reasoning (~$15.00/M input)
26
+ """
27
+
28
+ CHEAP = "cheap"
29
+ CAPABLE = "capable"
30
+ PREMIUM = "premium"
31
+
32
+
33
+ class ModelProvider(Enum):
34
+ """Supported model provider (Claude-native architecture as of v5.0.0)."""
35
+
36
+ ANTHROPIC = "anthropic"
37
+
38
+
39
+ @dataclass(frozen=True)
40
+ class ModelInfo:
41
+ """Unified model information - single source of truth.
42
+
43
+ Pricing is stored in per-million tokens format. Use the cost_per_1k_*
44
+ properties for compatibility with code expecting per-1k pricing.
45
+
46
+ Attributes:
47
+ id: Model identifier (e.g., "claude-3-5-haiku-20241022")
48
+ provider: Provider name (e.g., "anthropic")
49
+ tier: Tier level (e.g., "cheap")
50
+ input_cost_per_million: Input token cost per million tokens
51
+ output_cost_per_million: Output token cost per million tokens
52
+ max_tokens: Maximum output tokens
53
+ supports_vision: Whether model supports vision/images
54
+ supports_tools: Whether model supports tool/function calling
55
+
56
+ """
57
+
58
+ id: str
59
+ provider: str
60
+ tier: str
61
+ input_cost_per_million: float
62
+ output_cost_per_million: float
63
+ max_tokens: int = 4096
64
+ supports_vision: bool = False
65
+ supports_tools: bool = True
66
+
67
+ # Compatibility properties for toolkit (per-1k pricing)
68
+ @property
69
+ def model_id(self) -> str:
70
+ """Alias for id - compatibility with ModelRouter.ModelConfig."""
71
+ return self.id
72
+
73
+ @property
74
+ def name(self) -> str:
75
+ """Alias for id - compatibility with WorkflowConfig.ModelConfig."""
76
+ return self.id
77
+
78
+ @property
79
+ def cost_per_1k_input(self) -> float:
80
+ """Input cost per 1k tokens - for ModelRouter compatibility."""
81
+ return self.input_cost_per_million / 1000
82
+
83
+ @property
84
+ def cost_per_1k_output(self) -> float:
85
+ """Output cost per 1k tokens - for ModelRouter compatibility."""
86
+ return self.output_cost_per_million / 1000
87
+
88
+ def to_router_config(self) -> dict[str, Any]:
89
+ """Convert to ModelRouter.ModelConfig compatible dict."""
90
+ return {
91
+ "model_id": self.id,
92
+ "cost_per_1k_input": self.cost_per_1k_input,
93
+ "cost_per_1k_output": self.cost_per_1k_output,
94
+ "max_tokens": self.max_tokens,
95
+ "supports_tools": self.supports_tools,
96
+ }
97
+
98
+ def to_workflow_config(self) -> dict[str, Any]:
99
+ """Convert to WorkflowConfig.ModelConfig compatible dict."""
100
+ return {
101
+ "name": self.id,
102
+ "provider": self.provider,
103
+ "tier": self.tier,
104
+ "input_cost_per_million": self.input_cost_per_million,
105
+ "output_cost_per_million": self.output_cost_per_million,
106
+ "max_tokens": self.max_tokens,
107
+ "supports_vision": self.supports_vision,
108
+ "supports_tools": self.supports_tools,
109
+ }
110
+
111
+ def to_cost_tracker_pricing(self) -> dict[str, float]:
112
+ """Convert to cost_tracker MODEL_PRICING format."""
113
+ return {
114
+ "input": self.input_cost_per_million,
115
+ "output": self.output_cost_per_million,
116
+ }
117
+
118
+
119
+ # =============================================================================
120
+ # MODEL REGISTRY - Single Source of Truth
121
+ # =============================================================================
122
+ # All model configurations are defined here. Other modules should import
123
+ # from this registry rather than defining their own model configs.
124
+
125
+ MODEL_REGISTRY: dict[str, dict[str, ModelInfo]] = {
126
+ # -------------------------------------------------------------------------
127
+ # Anthropic Claude Models
128
+ # Intelligent fallback: Sonnet 4.5 → Opus 4.5 (5x cost increase for complex tasks)
129
+ # -------------------------------------------------------------------------
130
+ "anthropic": {
131
+ "cheap": ModelInfo(
132
+ id="claude-3-5-haiku-20241022",
133
+ provider="anthropic",
134
+ tier="cheap",
135
+ input_cost_per_million=0.80,
136
+ output_cost_per_million=4.00,
137
+ max_tokens=8192,
138
+ supports_vision=False,
139
+ supports_tools=True,
140
+ ),
141
+ "capable": ModelInfo(
142
+ id="claude-sonnet-4-5", # Updated to Sonnet 4.5 (2026)
143
+ provider="anthropic",
144
+ tier="capable",
145
+ input_cost_per_million=3.00,
146
+ output_cost_per_million=15.00,
147
+ max_tokens=8192,
148
+ supports_vision=True,
149
+ supports_tools=True,
150
+ ),
151
+ "premium": ModelInfo(
152
+ id="claude-opus-4-5-20251101",
153
+ provider="anthropic",
154
+ tier="premium",
155
+ input_cost_per_million=15.00,
156
+ output_cost_per_million=75.00,
157
+ max_tokens=8192,
158
+ supports_vision=True,
159
+ supports_tools=True,
160
+ ),
161
+ },
162
+ }
163
+
164
+
165
+ # =============================================================================
166
+ # MODEL REGISTRY CLASS - OOP Interface
167
+ # =============================================================================
168
+
169
+
170
+ class ModelRegistry:
171
+ """Object-oriented interface to the model registry.
172
+
173
+ Provides efficient lookup operations with built-in tier and model ID caching
174
+ for O(1) performance on frequently accessed queries.
175
+
176
+ Example:
177
+ >>> registry = ModelRegistry()
178
+ >>> model = registry.get_model("anthropic", "capable")
179
+ >>> print(model.id)
180
+ claude-sonnet-4-5
181
+
182
+ >>> models = registry.get_models_by_tier("cheap")
183
+ >>> print(len(models))
184
+ 5
185
+
186
+ >>> model = registry.get_model_by_id("claude-opus-4-5-20251101")
187
+ >>> print(model.tier)
188
+ premium
189
+
190
+ >>> providers = registry.list_providers()
191
+ >>> print(providers)
192
+ ['anthropic', 'openai', 'google', 'ollama', 'hybrid']
193
+
194
+ """
195
+
196
+ def __init__(self, registry: dict[str, dict[str, ModelInfo]] | None = None):
197
+ """Initialize the model registry.
198
+
199
+ Args:
200
+ registry: Optional custom registry dict. If None, uses MODEL_REGISTRY.
201
+
202
+ """
203
+ self._registry = registry if registry is not None else MODEL_REGISTRY
204
+
205
+ # Build performance caches
206
+ self._build_caches()
207
+
208
+ def _build_caches(self) -> None:
209
+ """Build tier and model ID caches for O(1) lookups."""
210
+ # Cache for get_models_by_tier (tier -> list[ModelInfo])
211
+ self._tier_cache: dict[str, list[ModelInfo]] = {}
212
+ for tier in ModelTier:
213
+ self._tier_cache[tier.value] = [
214
+ provider_models[tier.value]
215
+ for provider_models in self._registry.values()
216
+ if tier.value in provider_models
217
+ ]
218
+
219
+ # Cache for get_model_by_id (model_id -> ModelInfo)
220
+ self._model_id_cache: dict[str, ModelInfo] = {}
221
+ for provider_models in self._registry.values():
222
+ for model_info in provider_models.values():
223
+ self._model_id_cache[model_info.id] = model_info
224
+
225
+ def get_model(self, provider: str, tier: str) -> ModelInfo | None:
226
+ """Get model info for a provider/tier combination.
227
+
228
+ Args:
229
+ provider: Provider name (anthropic only as of v5.0.0)
230
+ tier: Tier level (cheap, capable, premium)
231
+
232
+ Returns:
233
+ ModelInfo if found, None otherwise
234
+
235
+ Raises:
236
+ ValueError: If provider is not 'anthropic'
237
+
238
+ Example:
239
+ >>> registry = ModelRegistry()
240
+ >>> model = registry.get_model("anthropic", "capable")
241
+ >>> print(model.id)
242
+ claude-sonnet-4-5
243
+
244
+ """
245
+ if provider.lower() != "anthropic":
246
+ raise ValueError(
247
+ f"Provider '{provider}' is not supported. "
248
+ f"Empathy Framework is now Claude-native (v5.0.0). "
249
+ f"Only 'anthropic' provider is available. "
250
+ f"See docs/CLAUDE_NATIVE.md for migration guide."
251
+ )
252
+
253
+ provider_models = self._registry.get(provider.lower())
254
+ if provider_models is None:
255
+ return None
256
+ return provider_models.get(tier.lower())
257
+
258
+ def get_model_by_id(self, model_id: str) -> ModelInfo | None:
259
+ """Get model info by model ID.
260
+
261
+ Uses O(1) cache lookup for fast performance.
262
+
263
+ Args:
264
+ model_id: Model identifier (e.g., "claude-3-5-haiku-20241022")
265
+
266
+ Returns:
267
+ ModelInfo if found, None otherwise
268
+
269
+ Example:
270
+ >>> registry = ModelRegistry()
271
+ >>> model = registry.get_model_by_id("claude-opus-4-5-20251101")
272
+ >>> print(model.provider)
273
+ anthropic
274
+ >>> print(model.tier)
275
+ premium
276
+
277
+ >>> model = registry.get_model_by_id("gpt-4o-mini")
278
+ >>> print(f"{model.provider}/{model.tier}")
279
+ openai/cheap
280
+
281
+ """
282
+ return self._model_id_cache.get(model_id)
283
+
284
+ def get_models_by_tier(self, tier: str) -> list[ModelInfo]:
285
+ """Get all models in a specific tier (Anthropic-only as of v5.0.0).
286
+
287
+ Uses O(1) cache lookup for fast performance.
288
+
289
+ Args:
290
+ tier: Tier level (cheap, capable, premium)
291
+
292
+ Returns:
293
+ List of ModelInfo objects in the tier (may be empty)
294
+
295
+ Example:
296
+ >>> registry = ModelRegistry()
297
+ >>> cheap_models = registry.get_models_by_tier("cheap")
298
+ >>> print(len(cheap_models))
299
+ 1
300
+ >>> print([m.provider for m in cheap_models])
301
+ ['anthropic']
302
+
303
+ >>> premium_models = registry.get_models_by_tier("premium")
304
+ >>> for model in premium_models:
305
+ ... print(f"{model.provider}: {model.id}")
306
+ anthropic: claude-opus-4-5-20251101
307
+
308
+ """
309
+ return self._tier_cache.get(tier.lower(), [])
310
+
311
+ def list_providers(self) -> list[str]:
312
+ """Get list of all provider names (Anthropic-only as of v5.0.0).
313
+
314
+ Returns:
315
+ List of provider names (['anthropic'])
316
+
317
+ Example:
318
+ >>> registry = ModelRegistry()
319
+ >>> providers = registry.list_providers()
320
+ >>> print(providers)
321
+ ['anthropic']
322
+
323
+ """
324
+ return list(self._registry.keys())
325
+
326
+ def list_tiers(self) -> list[str]:
327
+ """Get list of all available tiers.
328
+
329
+ Returns:
330
+ List of tier names (e.g., ['cheap', 'capable', 'premium'])
331
+
332
+ Example:
333
+ >>> registry = ModelRegistry()
334
+ >>> tiers = registry.list_tiers()
335
+ >>> print(tiers)
336
+ ['cheap', 'capable', 'premium']
337
+
338
+ """
339
+ return [tier.value for tier in ModelTier]
340
+
341
+ def get_all_models(self) -> dict[str, dict[str, ModelInfo]]:
342
+ """Get the complete model registry (Anthropic-only as of v5.0.0).
343
+
344
+ Returns:
345
+ Full registry dict (provider -> tier -> ModelInfo)
346
+
347
+ Example:
348
+ >>> registry = ModelRegistry()
349
+ >>> all_models = registry.get_all_models()
350
+ >>> print(all_models.keys())
351
+ dict_keys(['anthropic'])
352
+
353
+ """
354
+ return self._registry
355
+
356
+ def get_pricing_for_model(self, model_id: str) -> dict[str, float] | None:
357
+ """Get pricing for a model by its ID.
358
+
359
+ Args:
360
+ model_id: Model identifier (e.g., "claude-3-5-haiku-20241022")
361
+
362
+ Returns:
363
+ Dict with 'input' and 'output' keys (per-million pricing), or None
364
+
365
+ Example:
366
+ >>> registry = ModelRegistry()
367
+ >>> pricing = registry.get_pricing_for_model("claude-sonnet-4-5")
368
+ >>> print(pricing)
369
+ {'input': 3.0, 'output': 15.0}
370
+
371
+ >>> pricing = registry.get_pricing_for_model("claude-opus-4-5-20251101")
372
+ >>> print(f"${pricing['input']}/M input, ${pricing['output']}/M output")
373
+ $15.0/M input, $75.0/M output
374
+
375
+ """
376
+ model = self.get_model_by_id(model_id)
377
+ if model is None:
378
+ return None
379
+ return model.to_cost_tracker_pricing()
380
+
381
+
382
+ # =============================================================================
383
+ # DEFAULT REGISTRY INSTANCE
384
+ # =============================================================================
385
+ # Global singleton instance for convenience
386
+ _default_registry = ModelRegistry()
387
+
388
+
389
+ # =============================================================================
390
+ # HELPER FUNCTIONS - Backward Compatibility
391
+ # =============================================================================
392
+ # These functions wrap the default registry instance to maintain
393
+ # backward compatibility with existing code.
394
+
395
+
396
+ def get_model(provider: str, tier: str) -> ModelInfo | None:
397
+ """Get model info for a provider/tier combination.
398
+
399
+ Args:
400
+ provider: Provider name (anthropic only as of v5.0.0)
401
+ tier: Tier level (cheap, capable, premium)
402
+
403
+ Returns:
404
+ ModelInfo if found, None otherwise
405
+
406
+ Raises:
407
+ ValueError: If provider is not 'anthropic'
408
+
409
+ Note:
410
+ This is a convenience wrapper around the default ModelRegistry instance.
411
+ For more features, consider using ModelRegistry directly.
412
+
413
+ """
414
+ return _default_registry.get_model(provider, tier)
415
+
416
+
417
+ def get_all_models() -> dict[str, dict[str, ModelInfo]]:
418
+ """Get the complete model registry.
419
+
420
+ Note:
421
+ This is a convenience wrapper around the default ModelRegistry instance.
422
+
423
+ """
424
+ return _default_registry.get_all_models()
425
+
426
+
427
+ def get_pricing_for_model(model_id: str) -> dict[str, float] | None:
428
+ """Get pricing for a model by its ID.
429
+
430
+ Args:
431
+ model_id: Model identifier (e.g., "claude-3-5-haiku-20241022")
432
+
433
+ Returns:
434
+ Dict with 'input' and 'output' keys (per-million pricing), or None
435
+
436
+ Note:
437
+ This is a convenience wrapper around the default ModelRegistry instance.
438
+
439
+ """
440
+ return _default_registry.get_pricing_for_model(model_id)
441
+
442
+
443
+ def get_supported_providers() -> list[str]:
444
+ """Get list of supported provider names.
445
+
446
+ Note:
447
+ This is a convenience wrapper around the default ModelRegistry instance.
448
+
449
+ """
450
+ return _default_registry.list_providers()
451
+
452
+
453
+ def get_tiers() -> list[str]:
454
+ """Get list of available tiers.
455
+
456
+ Note:
457
+ This is a convenience wrapper around the default ModelRegistry instance.
458
+
459
+ """
460
+ return _default_registry.list_tiers()
461
+
462
+
463
+ # =============================================================================
464
+ # TIER PRICING (for backward compatibility with cost_tracker)
465
+ # =============================================================================
466
+ # These are tier-level pricing aliases for when specific model isn't known
467
+
468
+ TIER_PRICING: dict[str, dict[str, float]] = {
469
+ "cheap": {"input": 0.80, "output": 4.00}, # Haiku 3.5 pricing
470
+ "capable": {"input": 3.00, "output": 15.00}, # Sonnet 4 pricing
471
+ "premium": {"input": 15.00, "output": 75.00}, # Opus 4.5 pricing
472
+ }