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,184 @@
1
+ """Orchestration commands for meta-workflows.
2
+
3
+ Copyright 2025 Smart-AI-Memory
4
+ Licensed under Fair Source License 0.9
5
+ """
6
+
7
+ import asyncio
8
+ import json
9
+
10
+ from attune.logging_config import get_logger
11
+
12
+ logger = get_logger(__name__)
13
+
14
+
15
+ def cmd_orchestrate(args):
16
+ """Run meta-orchestration workflows.
17
+
18
+ Orchestrates teams of agents to accomplish complex tasks through
19
+ intelligent composition patterns.
20
+
21
+ Args:
22
+ args: Namespace object from argparse with attributes:
23
+ - workflow (str): Orchestration workflow name.
24
+ - path (str): Target path for orchestration.
25
+ - mode (str | None): Execution mode (e.g., 'daily', 'weekly', 'release').
26
+ - json (bool): If True, output as JSON format.
27
+ - dry_run (bool): If True, show plan without executing.
28
+ - verbose (bool): If True, show detailed output.
29
+
30
+ Returns:
31
+ int: 0 on success, 1 on failure.
32
+ """
33
+ from attune.workflows.orchestrated_health_check import OrchestratedHealthCheckWorkflow
34
+ from attune.workflows.orchestrated_release_prep import OrchestratedReleasePrepWorkflow
35
+
36
+ # Get workflow type
37
+ workflow_type = args.workflow
38
+
39
+ # Only print header in non-JSON mode
40
+ if not (hasattr(args, "json") and args.json):
41
+ print()
42
+ print("=" * 60)
43
+ print(f" META-ORCHESTRATION: {workflow_type.upper()}")
44
+ print("=" * 60)
45
+ print()
46
+
47
+ if workflow_type == "release-prep":
48
+ # Release Preparation workflow
49
+ path = args.path or "."
50
+ quality_gates = {}
51
+
52
+ # Collect custom quality gates
53
+ if hasattr(args, "min_coverage") and args.min_coverage is not None:
54
+ quality_gates["min_coverage"] = args.min_coverage
55
+ if hasattr(args, "min_quality") and args.min_quality is not None:
56
+ quality_gates["min_quality_score"] = args.min_quality
57
+ if hasattr(args, "max_critical") and args.max_critical is not None:
58
+ quality_gates["max_critical_issues"] = args.max_critical
59
+
60
+ # Only print details in non-JSON mode
61
+ if not (hasattr(args, "json") and args.json):
62
+ print(f" Project Path: {path}")
63
+ if quality_gates:
64
+ print(f" Quality Gates: {quality_gates}")
65
+ print()
66
+ print(" 🔍 Parallel Validation Agents:")
67
+ print(" • Security Auditor (vulnerability scan)")
68
+ print(" • Test Coverage Analyzer (gap analysis)")
69
+ print(" • Code Quality Reviewer (best practices)")
70
+ print(" • Documentation Writer (completeness)")
71
+ print()
72
+
73
+ # Create workflow
74
+ workflow = OrchestratedReleasePrepWorkflow(
75
+ quality_gates=quality_gates if quality_gates else None
76
+ )
77
+
78
+ try:
79
+ # Execute workflow
80
+ report = asyncio.run(workflow.execute(path=path))
81
+
82
+ # Display results
83
+ if hasattr(args, "json") and args.json:
84
+ print(json.dumps(report.to_dict(), indent=2))
85
+ else:
86
+ print(report.format_console_output())
87
+
88
+ # Return appropriate exit code
89
+ return 0 if report.approved else 1
90
+
91
+ except Exception as e:
92
+ print(f" ❌ Error executing release prep workflow: {e}")
93
+ print()
94
+ logger.exception("Release prep workflow failed")
95
+ return 1
96
+
97
+ elif workflow_type == "test-coverage":
98
+ # Test Coverage Boost workflow - DISABLED in v4.0.0
99
+ print(" ⚠️ FEATURE DISABLED")
100
+ print(" " + "-" * 56)
101
+ print()
102
+ print(" The test-coverage workflow has been disabled in v4.0.0")
103
+ print(" due to poor quality (0% test pass rate).")
104
+ print()
105
+ print(" This feature is being redesigned and will return in a")
106
+ print(" future release with improved test generation quality.")
107
+ print()
108
+ print(" Available v4.0 workflows:")
109
+ print(" • health-check - Real-time codebase health analysis")
110
+ print(" • release-prep - Quality gate validation")
111
+ print()
112
+ return 1
113
+
114
+ elif workflow_type == "health-check":
115
+ # Health Check workflow
116
+ mode = args.mode or "daily"
117
+ project_root = args.project_root or "."
118
+ focus_area = getattr(args, "focus", None)
119
+
120
+ # Only print details in non-JSON mode
121
+ if not (hasattr(args, "json") and args.json):
122
+ print(f" Mode: {mode.upper()}")
123
+ print(f" Project Root: {project_root}")
124
+ if focus_area:
125
+ print(f" Focus Area: {focus_area}")
126
+ print()
127
+
128
+ # Show agents for mode
129
+ mode_agents = {
130
+ "daily": ["Security", "Coverage", "Quality"],
131
+ "weekly": ["Security", "Coverage", "Quality", "Performance", "Documentation"],
132
+ "release": [
133
+ "Security",
134
+ "Coverage",
135
+ "Quality",
136
+ "Performance",
137
+ "Documentation",
138
+ "Architecture",
139
+ ],
140
+ }
141
+
142
+ print(f" 🔍 {mode.capitalize()} Check Agents:")
143
+ for agent in mode_agents.get(mode, []):
144
+ print(f" • {agent}")
145
+ print()
146
+
147
+ # Create workflow
148
+ workflow = OrchestratedHealthCheckWorkflow(mode=mode, project_root=project_root)
149
+
150
+ try:
151
+ # Execute workflow
152
+ report = asyncio.run(workflow.execute())
153
+
154
+ # Display results
155
+ if hasattr(args, "json") and args.json:
156
+ print(json.dumps(report.to_dict(), indent=2))
157
+ else:
158
+ print(report.format_console_output())
159
+
160
+ # Return appropriate exit code (70+ is passing)
161
+ return 0 if report.overall_health_score >= 70 else 1
162
+
163
+ except Exception as e:
164
+ print(f" ❌ Error executing health check workflow: {e}")
165
+ print()
166
+ logger.exception("Health check workflow failed")
167
+ return 1
168
+
169
+ else:
170
+ print(f" ❌ Unknown workflow type: {workflow_type}")
171
+ print()
172
+ print(" Available workflows:")
173
+ print(" - release-prep: Release readiness validation (parallel agents)")
174
+ print(" - health-check: Project health assessment (daily/weekly/release modes)")
175
+ print()
176
+ print(" Note: test-coverage workflow disabled in v4.0.0 (being redesigned)")
177
+ print()
178
+ return 1
179
+
180
+ print()
181
+ print("=" * 60)
182
+ print()
183
+
184
+ return 0
@@ -0,0 +1,207 @@
1
+ """Pattern management commands for the CLI.
2
+
3
+ Copyright 2025 Smart-AI-Memory
4
+ Licensed under Fair Source License 0.9
5
+ """
6
+
7
+ import sys
8
+
9
+ from attune.config import _validate_file_path
10
+ from attune.logging_config import get_logger
11
+ from attune.persistence import PatternPersistence
12
+
13
+ logger = get_logger(__name__)
14
+
15
+
16
+ def cmd_patterns_list(args):
17
+ """List patterns in a pattern library.
18
+
19
+ Args:
20
+ args: Namespace object from argparse with attributes:
21
+ - library (str): Path to pattern library file.
22
+ - format (str): Library format ('json' or 'sqlite').
23
+
24
+ Returns:
25
+ None: Prints pattern list to stdout. Exits with code 1 on failure.
26
+ """
27
+ filepath = args.library
28
+ format_type = args.format
29
+ logger.info(f"Listing patterns from library: {filepath} (format: {format_type})")
30
+
31
+ try:
32
+ if format_type == "json":
33
+ library = PatternPersistence.load_from_json(filepath)
34
+ elif format_type == "sqlite":
35
+ library = PatternPersistence.load_from_sqlite(filepath)
36
+ else:
37
+ logger.error(f"Unknown pattern library format: {format_type}")
38
+ logger.error(f"✗ Unknown format: {format_type}")
39
+ sys.exit(1)
40
+
41
+ logger.info(f"Loaded {len(library.patterns)} patterns from {filepath}")
42
+ logger.info(f"=== Pattern Library: {filepath} ===\n")
43
+ logger.info(f"Total patterns: {len(library.patterns)}")
44
+ logger.info(f"Total agents: {len(library.agent_contributions)}")
45
+
46
+ if library.patterns:
47
+ logger.info("\nPatterns:")
48
+ for pattern_id, pattern in library.patterns.items():
49
+ logger.info(f"\n [{pattern_id}] {pattern.name}")
50
+ logger.info(f" Agent: {pattern.agent_id}")
51
+ logger.info(f" Type: {pattern.pattern_type}")
52
+ logger.info(f" Confidence: {pattern.confidence:.2f}")
53
+ logger.info(f" Usage: {pattern.usage_count}")
54
+ logger.info(f" Success Rate: {pattern.success_rate:.2f}")
55
+ except FileNotFoundError:
56
+ logger.error(f"Pattern library not found: {filepath}")
57
+ logger.error(f"✗ Pattern library not found: {filepath}")
58
+ sys.exit(1)
59
+
60
+
61
+ def cmd_patterns_export(args):
62
+ """Export patterns from one format to another.
63
+
64
+ Args:
65
+ args: Namespace object from argparse with attributes:
66
+ - input (str): Input file path.
67
+ - output (str): Output file path.
68
+ - input_format (str): Input format ('json' or 'sqlite').
69
+ - output_format (str): Output format ('json' or 'sqlite').
70
+
71
+ Returns:
72
+ None: Exports patterns to output file. Exits with code 1 on failure.
73
+
74
+ Raises:
75
+ ValueError: If output path is invalid or unsafe.
76
+ """
77
+ input_file = args.input
78
+ input_format = args.input_format
79
+ output_file = args.output
80
+ output_format = args.output_format
81
+
82
+ logger.info(f"Exporting patterns from {input_format} to {output_format}")
83
+
84
+ # Load from input format
85
+ try:
86
+ if input_format == "json":
87
+ library = PatternPersistence.load_from_json(input_file)
88
+ elif input_format == "sqlite":
89
+ library = PatternPersistence.load_from_sqlite(input_file)
90
+ else:
91
+ logger.error(f"Unknown input format: {input_format}")
92
+ logger.error(f"✗ Unknown input format: {input_format}")
93
+ sys.exit(1)
94
+
95
+ logger.info(f"Loaded {len(library.patterns)} patterns from {input_file}")
96
+ logger.info(f"✓ Loaded {len(library.patterns)} patterns from {input_file}")
97
+ except (OSError, FileNotFoundError) as e:
98
+ # Input file not found or cannot be read
99
+ logger.error(f"Pattern file error: {e}")
100
+ logger.error(f"✗ Cannot read pattern file: {e}")
101
+ sys.exit(1)
102
+ except (ValueError, KeyError) as e:
103
+ # Invalid pattern data format
104
+ logger.error(f"Pattern data error: {e}")
105
+ logger.error(f"✗ Invalid pattern data: {e}")
106
+ sys.exit(1)
107
+ except Exception as e:
108
+ # Unexpected errors loading patterns
109
+ logger.exception(f"Unexpected error loading patterns: {e}")
110
+ logger.error(f"✗ Failed to load patterns: {e}")
111
+ sys.exit(1)
112
+
113
+ # Validate output path
114
+ validated_output = _validate_file_path(output_file)
115
+
116
+ # Save to output format
117
+ try:
118
+ if output_format == "json":
119
+ PatternPersistence.save_to_json(library, str(validated_output))
120
+ elif output_format == "sqlite":
121
+ PatternPersistence.save_to_sqlite(library, str(validated_output))
122
+
123
+ logger.info(f"Saved {len(library.patterns)} patterns to {output_file}")
124
+ logger.info(f"✓ Saved {len(library.patterns)} patterns to {output_file}")
125
+ except (OSError, FileNotFoundError, PermissionError) as e:
126
+ # Cannot write output file
127
+ logger.error(f"Pattern file write error: {e}")
128
+ logger.error(f"✗ Cannot write pattern file: {e}")
129
+ sys.exit(1)
130
+ except Exception as e:
131
+ # Unexpected errors saving patterns
132
+ logger.exception(f"Unexpected error saving patterns: {e}")
133
+ logger.error(f"✗ Failed to save patterns: {e}")
134
+ sys.exit(1)
135
+
136
+
137
+ def cmd_patterns_resolve(args):
138
+ """Resolve investigating bug patterns with root cause and fix.
139
+
140
+ Updates pattern status and adds resolution information.
141
+
142
+ Args:
143
+ args: Namespace object from argparse with attributes:
144
+ - pattern_id (str | None): Pattern ID to resolve.
145
+ - root_cause (str | None): Root cause description.
146
+ - fix (str | None): Fix description.
147
+ - fix_code (str | None): Code snippet of the fix.
148
+ - time (int | None): Resolution time in minutes.
149
+ - status (str): New status ('resolved', 'wont_fix', etc.).
150
+ - patterns_dir (str): Patterns directory path.
151
+ - commit (str | None): Related commit hash.
152
+
153
+ Returns:
154
+ None: Updates pattern and prints result. Exits with code 1 on failure.
155
+ """
156
+ from attune_llm.pattern_resolver import PatternResolver
157
+
158
+ resolver = PatternResolver(args.patterns_dir)
159
+
160
+ # If no bug_id, list investigating bugs
161
+ if not args.bug_id:
162
+ investigating = resolver.list_investigating()
163
+ if not investigating:
164
+ print("No bugs with 'investigating' status found.")
165
+ return
166
+
167
+ print(f"\nBugs needing resolution ({len(investigating)}):\n")
168
+ for bug in investigating:
169
+ print(f" {bug.get('bug_id', 'unknown')}")
170
+ print(f" Type: {bug.get('error_type', 'unknown')}")
171
+ print(f" File: {bug.get('file_path', 'unknown')}")
172
+ msg = bug.get("error_message", "N/A")
173
+ print(f" Message: {msg[:60]}..." if len(msg) > 60 else f" Message: {msg}")
174
+ print()
175
+ return
176
+
177
+ # Validate required args
178
+ if not args.root_cause or not args.fix:
179
+ print("✗ --root-cause and --fix are required when resolving a bug")
180
+ print(
181
+ " Example: empathy patterns resolve bug_123 --root-cause 'Null check' --fix 'Added ?.'",
182
+ )
183
+ sys.exit(1)
184
+
185
+ # Resolve the specified bug
186
+ success = resolver.resolve_bug(
187
+ bug_id=args.bug_id,
188
+ root_cause=args.root_cause,
189
+ fix_applied=args.fix,
190
+ fix_code=args.fix_code,
191
+ resolution_time_minutes=args.time or 0,
192
+ resolved_by=args.resolved_by or "@developer",
193
+ )
194
+
195
+ if success:
196
+ print(f"✓ Resolved: {args.bug_id}")
197
+
198
+ # Regenerate summary if requested
199
+ if not args.no_regenerate:
200
+ if resolver.regenerate_summary():
201
+ print("✓ Regenerated patterns_summary.md")
202
+ else:
203
+ print("⚠ Failed to regenerate summary")
204
+ else:
205
+ print(f"✗ Failed to resolve: {args.bug_id}")
206
+ print(" Use 'empathy patterns resolve' (no args) to list investigating bugs")
207
+ sys.exit(1)
@@ -0,0 +1,202 @@
1
+ """Profiling commands for Empathy Framework CLI.
2
+
3
+ Performance profiling and memory analysis commands.
4
+
5
+ Usage:
6
+ empathy profile memory-scan # Scan for memory leaks
7
+ empathy profile memory-scan --json # JSON output for CI
8
+ empathy profile memory-test # Profile memory module
9
+
10
+ Copyright 2025 Smart-AI-Memory
11
+ Licensed under Fair Source License 0.9
12
+ """
13
+
14
+ import subprocess
15
+ import sys
16
+ from pathlib import Path
17
+
18
+ import typer
19
+ from rich.console import Console
20
+
21
+ console = Console()
22
+
23
+ # Create the profile command group
24
+ profile_app = typer.Typer(
25
+ name="profile",
26
+ help="Performance profiling and memory analysis",
27
+ no_args_is_help=True,
28
+ )
29
+
30
+
31
+ @profile_app.command("memory-scan")
32
+ def memory_scan(
33
+ path: Path = typer.Argument(
34
+ Path("src"),
35
+ help="Directory to scan for memory issues",
36
+ ),
37
+ feature: str = typer.Option(
38
+ None,
39
+ "--feature",
40
+ "-f",
41
+ help="Scan files related to a specific feature",
42
+ ),
43
+ min_severity: str = typer.Option(
44
+ "MEDIUM",
45
+ "--min-severity",
46
+ "-s",
47
+ help="Minimum severity to report (HIGH, MEDIUM, LOW)",
48
+ ),
49
+ top: int = typer.Option(
50
+ 10,
51
+ "--top",
52
+ "-t",
53
+ help="Number of hot files to show",
54
+ ),
55
+ json_output: bool = typer.Option(
56
+ False,
57
+ "--json",
58
+ "-j",
59
+ help="Output in JSON format",
60
+ ),
61
+ run_profile: bool = typer.Option(
62
+ False,
63
+ "--profile",
64
+ "-p",
65
+ help="Run dynamic memory profiling on hot files",
66
+ ),
67
+ ) -> None:
68
+ """Scan codebase for memory leak patterns.
69
+
70
+ Detects common memory issues like:
71
+ - sorted()[:N] patterns (should use heapq)
72
+ - get_all_* methods that load entire datasets
73
+ - Unbounded caches without eviction
74
+ - Large list comprehensions that could be generators
75
+
76
+ Examples:
77
+ empathy profile memory-scan # Scan src/
78
+ empathy profile memory-scan src/attune # Scan specific dir
79
+ empathy profile memory-scan --feature "cache" # Scan cache-related files
80
+ empathy profile memory-scan --json > report.json # CI integration
81
+ """
82
+ scanner_path = (
83
+ Path(__file__).parent.parent.parent.parent.parent / "benchmarks" / "memory_leak_scanner.py"
84
+ )
85
+
86
+ if not scanner_path.exists():
87
+ console.print("[red]Error:[/red] Memory leak scanner not found at expected path")
88
+ console.print(f"Expected: {scanner_path}")
89
+ console.print("\nThe scanner script may have been moved or renamed.")
90
+ console.print("Check the scripts/ directory or reinstall the package.")
91
+ raise typer.Exit(1)
92
+
93
+ args = [sys.executable, str(scanner_path), "--path", str(path)]
94
+
95
+ if feature:
96
+ args.extend(["--feature", feature])
97
+ if min_severity:
98
+ args.extend(["--min-severity", min_severity])
99
+ if top:
100
+ args.extend(["--top", str(top)])
101
+ if json_output:
102
+ args.append("--json")
103
+ if run_profile:
104
+ args.append("--profile")
105
+
106
+ subprocess.run(args, check=False)
107
+
108
+
109
+ @profile_app.command("memory-test")
110
+ def memory_test(
111
+ module: str = typer.Argument(
112
+ "unified",
113
+ help="Memory module to profile (unified, short_term, graph)",
114
+ ),
115
+ ) -> None:
116
+ """Run memory profiling tests on memory modules.
117
+
118
+ Profiles the specified memory module and reports memory usage
119
+ for key operations like search, store, and retrieve.
120
+
121
+ Examples:
122
+ empathy profile memory-test # Profile unified memory
123
+ empathy profile memory-test unified # Same as above
124
+ """
125
+ try:
126
+ import memory_profiler # noqa: F401 - check if installed
127
+ except ImportError:
128
+ console.print("[yellow]Installing memory_profiler...[/yellow]")
129
+ subprocess.run([sys.executable, "-m", "pip", "install", "memory_profiler"], check=True)
130
+
131
+ profile_script = (
132
+ Path(__file__).parent.parent.parent.parent.parent
133
+ / "benchmarks"
134
+ / "profile_unified_memory.py"
135
+ )
136
+
137
+ if not profile_script.exists():
138
+ console.print("[red]Error:[/red] Memory profiling script not found")
139
+ console.print(f"Expected: {profile_script}")
140
+ console.print("\nInstall memory_profiler with: pip install memory-profiler")
141
+ console.print("Or check that the benchmarks directory exists.")
142
+ raise typer.Exit(1)
143
+
144
+ console.print(f"[bold]Profiling memory module: {module}[/bold]\n")
145
+ subprocess.run([sys.executable, "-m", "memory_profiler", str(profile_script)], check=False)
146
+
147
+
148
+ @profile_app.command("hot-files")
149
+ def hot_files(
150
+ path: Path = typer.Argument(
151
+ Path("src"),
152
+ help="Directory to analyze",
153
+ ),
154
+ top: int = typer.Option(
155
+ 15,
156
+ "--top",
157
+ "-t",
158
+ help="Number of files to show",
159
+ ),
160
+ ) -> None:
161
+ """Show files most likely to have memory issues.
162
+
163
+ Quick scan that ranks files by risk score based on
164
+ detected memory leak patterns.
165
+
166
+ Examples:
167
+ empathy profile hot-files # Scan src/
168
+ empathy profile hot-files --top 20 # Show top 20
169
+ """
170
+ scanner_path = (
171
+ Path(__file__).parent.parent.parent.parent.parent / "benchmarks" / "memory_leak_scanner.py"
172
+ )
173
+
174
+ if not scanner_path.exists():
175
+ console.print("[red]Error:[/red] Memory leak scanner not found")
176
+ raise typer.Exit(1)
177
+
178
+ args = [
179
+ sys.executable,
180
+ str(scanner_path),
181
+ "--path",
182
+ str(path),
183
+ "--min-severity",
184
+ "MEDIUM",
185
+ "--top",
186
+ str(top),
187
+ ]
188
+ subprocess.run(args, check=False)
189
+
190
+
191
+ @profile_app.callback()
192
+ def callback() -> None:
193
+ """Performance profiling and memory analysis tools.
194
+
195
+ Use these commands to identify memory leaks, inefficient patterns,
196
+ and performance bottlenecks in your codebase.
197
+
198
+ [bold]Quick Start:[/bold]
199
+ empathy profile memory-scan Scan for memory issues
200
+ empathy profile hot-files Show riskiest files
201
+ empathy profile memory-test Profile memory module
202
+ """
@@ -0,0 +1,98 @@
1
+ """Provider configuration commands.
2
+
3
+ Copyright 2025 Smart-AI-Memory
4
+ Licensed under Fair Source License 0.9
5
+ """
6
+
7
+ from pathlib import Path
8
+
9
+ from attune.config import _validate_file_path
10
+ from attune.logging_config import get_logger
11
+
12
+ logger = get_logger(__name__)
13
+
14
+
15
+ def cmd_provider_show(args):
16
+ """Show current provider configuration (Anthropic-only as of v5.0.0).
17
+
18
+ Args:
19
+ args: Namespace object from argparse (no additional attributes used).
20
+
21
+ Returns:
22
+ None: Prints Anthropic provider configuration and model mappings.
23
+ """
24
+ from attune.models import MODEL_REGISTRY
25
+ from attune.models.provider_config import ProviderConfig
26
+
27
+ print("\n" + "=" * 60)
28
+ print("Provider Configuration (Claude-Native v5.0.0)")
29
+ print("=" * 60)
30
+
31
+ # Check for Anthropic API key
32
+ config = ProviderConfig.auto_detect()
33
+ if config.available_providers:
34
+ print("\n✓ ANTHROPIC_API_KEY detected")
35
+ else:
36
+ print("\n⚠️ ANTHROPIC_API_KEY not detected")
37
+ print(" Set your API key: export ANTHROPIC_API_KEY='your-key-here'")
38
+ print(" Get key at: https://console.anthropic.com/settings/keys")
39
+
40
+ print("\nProvider: anthropic")
41
+
42
+ # Show Anthropic models
43
+ print("\nModel mapping:")
44
+ anthropic_models = MODEL_REGISTRY.get("anthropic", {})
45
+ for tier in ["cheap", "capable", "premium"]:
46
+ model_info = anthropic_models.get(tier)
47
+ if model_info:
48
+ cost = f"${model_info.input_cost_per_million:.2f}/${model_info.output_cost_per_million:.2f} per M tokens"
49
+ print(f" {tier:8} → {model_info.id:40} {cost}")
50
+
51
+ print()
52
+
53
+
54
+ def cmd_provider_set(args):
55
+ """Set default provider (Anthropic-only as of v5.0.0).
56
+
57
+ Args:
58
+ args: Namespace object from argparse with attributes:
59
+ - name (str): Provider name to set as default (must be 'anthropic').
60
+
61
+ Returns:
62
+ None: Saves provider to .attune/workflows.yaml.
63
+
64
+ Raises:
65
+ SystemExit: If provider is not 'anthropic'.
66
+ """
67
+ import sys
68
+
69
+ import yaml
70
+
71
+ provider = args.name
72
+
73
+ # Validate provider is Anthropic
74
+ if provider.lower() != "anthropic":
75
+ print(f"❌ Error: Provider '{provider}' is not supported.")
76
+ print(" Empathy Framework is now Claude-native (v5.0.0).")
77
+ print(" Only 'anthropic' provider is available.")
78
+ print(" See docs/CLAUDE_NATIVE.md for migration guide.")
79
+ sys.exit(1)
80
+
81
+ workflows_path = Path(".attune/workflows.yaml")
82
+
83
+ # Load existing config or create new
84
+ if workflows_path.exists():
85
+ with open(workflows_path) as f:
86
+ config = yaml.safe_load(f) or {}
87
+ else:
88
+ config = {}
89
+ workflows_path.parent.mkdir(parents=True, exist_ok=True)
90
+
91
+ config["default_provider"] = provider
92
+
93
+ validated_workflows_path = _validate_file_path(str(workflows_path))
94
+ with open(validated_workflows_path, "w") as f:
95
+ yaml.dump(config, f, default_flow_style=False, sort_keys=False)
96
+
97
+ print(f"✓ Default provider set to: {provider}")
98
+ print(f" Saved to: {validated_workflows_path}")