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,1113 @@
1
+ """Code Review Crew
2
+
3
+ A multi-agent crew that performs comprehensive code reviews.
4
+ Demonstrates CrewAI's hierarchical collaboration patterns with:
5
+ - 5 specialized agents with distinct roles
6
+ - Hierarchical task delegation from Review Lead
7
+ - Memory Graph integration for cross-review learning
8
+ - Structured output with verdict and recommendations
9
+
10
+ Usage:
11
+ from attune_llm.agent_factory.crews import CodeReviewCrew
12
+
13
+ crew = CodeReviewCrew(api_key="...")
14
+ report = await crew.review(diff="...", files_changed=["src/api.py"])
15
+
16
+ print(f"Verdict: {report.verdict}")
17
+ for finding in report.critical_findings:
18
+ print(f" - {finding.title}: {finding.suggestion}")
19
+
20
+ Copyright 2025 Smart-AI-Memory
21
+ Licensed under Fair Source License 0.9
22
+ """
23
+
24
+ import logging
25
+ from dataclasses import dataclass, field
26
+ from enum import Enum
27
+ from typing import Any
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ class Severity(Enum):
33
+ """Review finding severity levels."""
34
+
35
+ CRITICAL = "critical"
36
+ HIGH = "high"
37
+ MEDIUM = "medium"
38
+ LOW = "low"
39
+ INFO = "info"
40
+
41
+
42
+ class FindingCategory(Enum):
43
+ """Code review finding categories."""
44
+
45
+ SECURITY = "security"
46
+ ARCHITECTURE = "architecture"
47
+ QUALITY = "quality"
48
+ PERFORMANCE = "performance"
49
+ MAINTAINABILITY = "maintainability"
50
+ TESTING = "testing"
51
+ DOCUMENTATION = "documentation"
52
+ STYLE = "style"
53
+ BUG = "bug"
54
+ OTHER = "other"
55
+
56
+
57
+ class Verdict(Enum):
58
+ """Code review verdict."""
59
+
60
+ APPROVE = "approve"
61
+ APPROVE_WITH_SUGGESTIONS = "approve_with_suggestions"
62
+ REQUEST_CHANGES = "request_changes"
63
+ REJECT = "reject"
64
+
65
+
66
+ @dataclass
67
+ class ReviewFinding:
68
+ """A single finding from the code review."""
69
+
70
+ title: str
71
+ description: str
72
+ severity: Severity
73
+ category: FindingCategory
74
+ file_path: str | None = None
75
+ line_number: int | None = None
76
+ code_snippet: str | None = None
77
+ suggestion: str | None = None
78
+ before_code: str | None = None
79
+ after_code: str | None = None
80
+ confidence: float = 1.0
81
+ metadata: dict = field(default_factory=dict)
82
+
83
+ def to_dict(self) -> dict:
84
+ """Convert finding to dictionary."""
85
+ return {
86
+ "title": self.title,
87
+ "description": self.description,
88
+ "severity": self.severity.value,
89
+ "category": self.category.value,
90
+ "file_path": self.file_path,
91
+ "line_number": self.line_number,
92
+ "code_snippet": self.code_snippet,
93
+ "suggestion": self.suggestion,
94
+ "before_code": self.before_code,
95
+ "after_code": self.after_code,
96
+ "confidence": self.confidence,
97
+ "metadata": self.metadata,
98
+ }
99
+
100
+
101
+ @dataclass
102
+ class CodeReviewReport:
103
+ """Complete code review report."""
104
+
105
+ target: str
106
+ findings: list[ReviewFinding]
107
+ verdict: Verdict
108
+ summary: str = ""
109
+ review_duration_seconds: float = 0.0
110
+ agents_used: list[str] = field(default_factory=list)
111
+ memory_graph_hits: int = 0
112
+ metadata: dict = field(default_factory=dict)
113
+
114
+ @property
115
+ def critical_findings(self) -> list[ReviewFinding]:
116
+ """Get critical severity findings."""
117
+ return [f for f in self.findings if f.severity == Severity.CRITICAL]
118
+
119
+ @property
120
+ def high_findings(self) -> list[ReviewFinding]:
121
+ """Get high severity findings."""
122
+ return [f for f in self.findings if f.severity == Severity.HIGH]
123
+
124
+ @property
125
+ def findings_by_category(self) -> dict[str, list[ReviewFinding]]:
126
+ """Group findings by category."""
127
+ result: dict[str, list[ReviewFinding]] = {}
128
+ for finding in self.findings:
129
+ cat = finding.category.value
130
+ if cat not in result:
131
+ result[cat] = []
132
+ result[cat].append(finding)
133
+ return result
134
+
135
+ @property
136
+ def quality_score(self) -> float:
137
+ """Calculate overall quality score (0-100, higher is better)."""
138
+ if not self.findings:
139
+ return 100.0
140
+
141
+ # Start with 100 and deduct based on severity
142
+ deductions = {
143
+ Severity.CRITICAL: 25,
144
+ Severity.HIGH: 15,
145
+ Severity.MEDIUM: 5,
146
+ Severity.LOW: 2,
147
+ Severity.INFO: 0.5,
148
+ }
149
+
150
+ total_deduction = sum(deductions[f.severity] * f.confidence for f in self.findings)
151
+ return max(0.0, 100.0 - total_deduction)
152
+
153
+ @property
154
+ def has_blocking_issues(self) -> bool:
155
+ """Check if there are issues that should block merge."""
156
+ return len(self.critical_findings) > 0 or len(self.high_findings) > 3
157
+
158
+ def to_dict(self) -> dict:
159
+ """Convert report to dictionary."""
160
+ return {
161
+ "target": self.target,
162
+ "findings": [f.to_dict() for f in self.findings],
163
+ "verdict": self.verdict.value,
164
+ "summary": self.summary,
165
+ "review_duration_seconds": self.review_duration_seconds,
166
+ "agents_used": self.agents_used,
167
+ "memory_graph_hits": self.memory_graph_hits,
168
+ "quality_score": self.quality_score,
169
+ "has_blocking_issues": self.has_blocking_issues,
170
+ "finding_counts": {
171
+ "critical": len(self.critical_findings),
172
+ "high": len(self.high_findings),
173
+ "total": len(self.findings),
174
+ },
175
+ "metadata": self.metadata,
176
+ }
177
+
178
+
179
+ @dataclass
180
+ class CodeReviewConfig:
181
+ """Configuration for code review crew."""
182
+
183
+ # API Configuration
184
+ provider: str = "anthropic"
185
+ api_key: str | None = None
186
+
187
+ # Review Configuration
188
+ review_depth: str = "standard" # "quick", "standard", "thorough"
189
+ focus_areas: list[str] = field(
190
+ default_factory=lambda: ["security", "architecture", "quality", "performance"],
191
+ )
192
+ check_tests: bool = True
193
+ check_docs: bool = False
194
+
195
+ # Memory Graph
196
+ memory_graph_enabled: bool = True
197
+ memory_graph_path: str = "patterns/code_review_memory.json"
198
+
199
+ # Agent Tiers
200
+ lead_tier: str = "premium"
201
+ security_tier: str = "capable"
202
+ architecture_tier: str = "premium"
203
+ quality_tier: str = "capable"
204
+ performance_tier: str = "capable"
205
+
206
+ # Resilience
207
+ resilience_enabled: bool = True
208
+ timeout_seconds: float = 300.0
209
+
210
+ # XML Prompts
211
+ xml_prompts_enabled: bool = True
212
+ xml_schema_version: str = "1.0"
213
+
214
+
215
+ # XML Prompt Templates for Code Review Agents
216
+ XML_PROMPT_TEMPLATES = {
217
+ "review_lead": """<agent role="review_lead" version="{schema_version}">
218
+ <identity>
219
+ <role>Code Review Lead</role>
220
+ <expertise>Code review coordination, technical leadership, quality assessment</expertise>
221
+ </identity>
222
+
223
+ <goal>
224
+ Coordinate the code review team to provide comprehensive, actionable feedback.
225
+ Synthesize findings from all reviewers into a clear verdict and summary.
226
+ </goal>
227
+
228
+ <instructions>
229
+ <step>Coordinate the code review team and delegate to specialists</step>
230
+ <step>Synthesize findings from Security, Architecture, Quality, and Performance reviewers</step>
231
+ <step>Prioritize issues by severity and impact</step>
232
+ <step>Make final verdict (APPROVE, APPROVE_WITH_SUGGESTIONS, REQUEST_CHANGES, REJECT)</step>
233
+ <step>Generate actionable summary with specific next steps</step>
234
+ </instructions>
235
+
236
+ <constraints>
237
+ <rule>Be constructive and specific in all feedback</rule>
238
+ <rule>Prioritize blocking issues over style preferences</rule>
239
+ <rule>Provide code examples for complex suggestions</rule>
240
+ <rule>Consider the reviewer's context and time constraints</rule>
241
+ </constraints>
242
+
243
+ <verdict_criteria>
244
+ <option name="APPROVE">No issues or only minor suggestions that don't require changes</option>
245
+ <option name="APPROVE_WITH_SUGGESTIONS">Good overall, non-blocking improvements</option>
246
+ <option name="REQUEST_CHANGES">Issues that must be addressed before merge</option>
247
+ <option name="REJECT">Fundamental problems requiring significant rework</option>
248
+ </verdict_criteria>
249
+
250
+ <output_format>
251
+ <section name="summary">Executive summary of review findings</section>
252
+ <section name="verdict">Final verdict with confidence level</section>
253
+ <section name="findings">Prioritized list of issues by severity</section>
254
+ <section name="checklist">Action items for the author</section>
255
+ </output_format>
256
+ </agent>""",
257
+ "security_analyst": """<agent role="security_analyst" version="{schema_version}">
258
+ <identity>
259
+ <role>Security Analyst</role>
260
+ <expertise>Application security, OWASP Top 10, secure coding practices</expertise>
261
+ </identity>
262
+
263
+ <goal>
264
+ Identify security vulnerabilities and provide actionable remediation guidance.
265
+ </goal>
266
+
267
+ <instructions>
268
+ <step>Scan for OWASP Top 10 vulnerabilities</step>
269
+ <step>Check for hardcoded secrets, API keys, and credentials</step>
270
+ <step>Review authentication and authorization logic</step>
271
+ <step>Assess input validation and output encoding</step>
272
+ <step>Identify insecure dependencies</step>
273
+ <step>Provide specific remediation with code examples</step>
274
+ </instructions>
275
+
276
+ <constraints>
277
+ <rule>Minimize false positives - focus on exploitable issues</rule>
278
+ <rule>Include file path and line number for each finding</rule>
279
+ <rule>Rate severity as critical/high/medium/low</rule>
280
+ <rule>Provide proof-of-concept or attack scenario where applicable</rule>
281
+ </constraints>
282
+
283
+ <vulnerability_categories>
284
+ <category>SQL Injection</category>
285
+ <category>Cross-Site Scripting (XSS)</category>
286
+ <category>Command Injection</category>
287
+ <category>Path Traversal</category>
288
+ <category>Authentication Bypass</category>
289
+ <category>Insecure Deserialization</category>
290
+ <category>Sensitive Data Exposure</category>
291
+ </vulnerability_categories>
292
+
293
+ <output_format>
294
+ <section name="findings">Vulnerabilities with severity, location, and remediation</section>
295
+ <section name="summary">Overall security posture assessment</section>
296
+ </output_format>
297
+ </agent>""",
298
+ "architecture_reviewer": """<agent role="architecture_reviewer" version="{schema_version}">
299
+ <identity>
300
+ <role>Architecture Reviewer</role>
301
+ <expertise>Software architecture, design patterns, SOLID principles</expertise>
302
+ </identity>
303
+
304
+ <goal>
305
+ Evaluate code architecture and design, ensuring maintainability and scalability.
306
+ </goal>
307
+
308
+ <instructions>
309
+ <step>Evaluate adherence to SOLID principles</step>
310
+ <step>Identify design pattern usage and anti-patterns</step>
311
+ <step>Assess module boundaries and coupling</step>
312
+ <step>Review dependency direction and layering</step>
313
+ <step>Consider scalability and extensibility</step>
314
+ <step>Provide refactoring suggestions with before/after examples</step>
315
+ </instructions>
316
+
317
+ <constraints>
318
+ <rule>Consider the project's architectural context</rule>
319
+ <rule>Balance ideal architecture with pragmatic solutions</rule>
320
+ <rule>Provide concrete refactoring steps</rule>
321
+ <rule>Highlight breaking changes that affect other modules</rule>
322
+ </constraints>
323
+
324
+ <principles>
325
+ <principle name="SRP">Single Responsibility - one reason to change</principle>
326
+ <principle name="OCP">Open/Closed - open for extension, closed for modification</principle>
327
+ <principle name="LSP">Liskov Substitution - subtypes must be substitutable</principle>
328
+ <principle name="ISP">Interface Segregation - prefer small, focused interfaces</principle>
329
+ <principle name="DIP">Dependency Inversion - depend on abstractions</principle>
330
+ </principles>
331
+
332
+ <output_format>
333
+ <section name="findings">Architecture issues with impact and suggestions</section>
334
+ <section name="summary">Overall design assessment</section>
335
+ </output_format>
336
+ </agent>""",
337
+ "quality_analyst": """<agent role="quality_analyst" version="{schema_version}">
338
+ <identity>
339
+ <role>Quality Analyst</role>
340
+ <expertise>Code quality, maintainability, testing, code smells</expertise>
341
+ </identity>
342
+
343
+ <goal>
344
+ Identify code quality issues that affect long-term maintainability.
345
+ </goal>
346
+
347
+ <instructions>
348
+ <step>Identify code smells (long methods, large classes, duplication)</step>
349
+ <step>Assess naming clarity and code readability</step>
350
+ <step>Review error handling and logging</step>
351
+ <step>Check test coverage and test quality</step>
352
+ <step>Evaluate complexity (cyclomatic, cognitive)</step>
353
+ <step>Prioritize issues by maintainability impact</step>
354
+ </instructions>
355
+
356
+ <constraints>
357
+ <rule>Focus on issues that affect long-term maintenance</rule>
358
+ <rule>Distinguish between style preferences and real problems</rule>
359
+ <rule>Consider the team's coding standards</rule>
360
+ <rule>Provide actionable improvement suggestions</rule>
361
+ </constraints>
362
+
363
+ <code_smells>
364
+ <smell>Long Method - methods over 20-30 lines</smell>
365
+ <smell>Large Class - classes with too many responsibilities</smell>
366
+ <smell>Duplicate Code - copy-pasted logic</smell>
367
+ <smell>Dead Code - unused variables, functions, imports</smell>
368
+ <smell>Magic Numbers - unexplained literal values</smell>
369
+ <smell>Deep Nesting - excessive indentation levels</smell>
370
+ </code_smells>
371
+
372
+ <output_format>
373
+ <section name="findings">Quality issues with severity and suggestions</section>
374
+ <section name="summary">Overall code quality assessment</section>
375
+ </output_format>
376
+ </agent>""",
377
+ "performance_reviewer": """<agent role="performance_reviewer" version="{schema_version}">
378
+ <identity>
379
+ <role>Performance Reviewer</role>
380
+ <expertise>Performance optimization, algorithm efficiency, resource management</expertise>
381
+ </identity>
382
+
383
+ <goal>
384
+ Identify performance issues and suggest optimizations with expected impact.
385
+ </goal>
386
+
387
+ <instructions>
388
+ <step>Analyze algorithm time and space complexity</step>
389
+ <step>Identify inefficient data structures or operations</step>
390
+ <step>Check for resource leaks (memory, connections, handles)</step>
391
+ <step>Review database query patterns (N+1, missing indexes)</step>
392
+ <step>Identify blocking operations in async code</step>
393
+ <step>Provide optimization suggestions with expected impact</step>
394
+ </instructions>
395
+
396
+ <constraints>
397
+ <rule>Focus on measurable performance impact</rule>
398
+ <rule>Consider trade-offs (readability vs performance)</rule>
399
+ <rule>Prioritize by frequency of execution</rule>
400
+ <rule>Suggest profiling for uncertain impacts</rule>
401
+ </constraints>
402
+
403
+ <anti_patterns>
404
+ <pattern>N+1 Queries - separate query per item in collection</pattern>
405
+ <pattern>Sync in Async - blocking calls in async code</pattern>
406
+ <pattern>String Concatenation in Loop - O(n²) string building</pattern>
407
+ <pattern>Unoptimized Regex - catastrophic backtracking</pattern>
408
+ <pattern>Memory Leaks - unreleased resources</pattern>
409
+ <pattern>Over-fetching - retrieving more data than needed</pattern>
410
+ </anti_patterns>
411
+
412
+ <output_format>
413
+ <section name="findings">Performance issues with impact and optimizations</section>
414
+ <section name="summary">Overall performance assessment</section>
415
+ </output_format>
416
+ </agent>""",
417
+ }
418
+
419
+
420
+ class CodeReviewCrew:
421
+ """Multi-agent crew for comprehensive code reviews.
422
+
423
+ The crew consists of 5 specialized agents:
424
+
425
+ 1. **Review Lead** (Coordinator)
426
+ - Orchestrates the review team
427
+ - Synthesizes findings from all agents
428
+ - Makes final verdict decision
429
+ - Generates executive summary
430
+ - Model: Premium tier
431
+
432
+ 2. **Security Analyst** (Security Expert)
433
+ - Reviews for security vulnerabilities
434
+ - OWASP Top 10 focus
435
+ - Checks for hardcoded secrets
436
+ - Model: Capable tier
437
+
438
+ 3. **Architecture Reviewer** (Architect)
439
+ - Evaluates design patterns
440
+ - Checks SOLID principles
441
+ - Assesses coupling and cohesion
442
+ - Model: Premium tier
443
+
444
+ 4. **Quality Analyst** (Quality Engineer)
445
+ - Identifies code smells
446
+ - Checks maintainability
447
+ - Reviews test coverage
448
+ - Model: Capable tier
449
+
450
+ 5. **Performance Reviewer** (Performance Engineer)
451
+ - Identifies performance issues
452
+ - Suggests optimizations
453
+ - Checks for anti-patterns
454
+ - Model: Capable tier
455
+
456
+ Example:
457
+ crew = CodeReviewCrew(api_key="...")
458
+ report = await crew.review(
459
+ diff="...",
460
+ files_changed=["src/api.py"],
461
+ )
462
+
463
+ # Access verdict
464
+ if report.verdict == Verdict.APPROVE:
465
+ print("Code is ready to merge!")
466
+
467
+ # Get quality score
468
+ print(f"Quality Score: {report.quality_score}/100")
469
+
470
+ """
471
+
472
+ def __init__(self, config: CodeReviewConfig | None = None, **kwargs: Any):
473
+ """Initialize the Code Review Crew.
474
+
475
+ Args:
476
+ config: CodeReviewConfig or pass individual params as kwargs
477
+ **kwargs: Individual config parameters (api_key, provider, etc.)
478
+
479
+ """
480
+ if config:
481
+ self.config = config
482
+ else:
483
+ self.config = CodeReviewConfig(**kwargs)
484
+
485
+ self._factory: Any = None
486
+ self._agents: dict[str, Any] = {}
487
+ self._workflow: Any = None
488
+ self._graph: Any = None
489
+ self._initialized = False
490
+
491
+ def _render_xml_prompt(self, template_key: str) -> str:
492
+ """Render XML prompt template with config values."""
493
+ template = XML_PROMPT_TEMPLATES.get(template_key, "")
494
+ return template.format(schema_version=self.config.xml_schema_version)
495
+
496
+ def _get_system_prompt(self, agent_key: str, fallback: str) -> str:
497
+ """Get system prompt - XML if enabled, fallback otherwise."""
498
+ if self.config.xml_prompts_enabled:
499
+ return self._render_xml_prompt(agent_key)
500
+ return fallback
501
+
502
+ async def _initialize(self) -> None:
503
+ """Lazy initialization of agents and workflow."""
504
+ if self._initialized:
505
+ return
506
+
507
+ from attune_llm.agent_factory import AgentFactory, Framework
508
+
509
+ # Check if CrewAI is available
510
+ try:
511
+ from attune_llm.agent_factory.adapters.crewai_adapter import _check_crewai
512
+
513
+ use_crewai = _check_crewai()
514
+ except ImportError:
515
+ use_crewai = False
516
+
517
+ # Use CrewAI if available, otherwise fall back to Native
518
+ framework = Framework.CREWAI if use_crewai else Framework.NATIVE
519
+
520
+ self._factory = AgentFactory(
521
+ framework=framework,
522
+ provider=self.config.provider,
523
+ api_key=self.config.api_key,
524
+ )
525
+
526
+ # Initialize Memory Graph if enabled
527
+ if self.config.memory_graph_enabled:
528
+ try:
529
+ from attune.memory import MemoryGraph
530
+
531
+ self._graph = MemoryGraph(path=self.config.memory_graph_path)
532
+ except ImportError:
533
+ logger.warning("Memory Graph not available, continuing without it")
534
+
535
+ # Create the 5 specialized agents
536
+ await self._create_agents()
537
+
538
+ # Create hierarchical workflow
539
+ await self._create_workflow()
540
+
541
+ self._initialized = True
542
+
543
+ async def _create_agents(self) -> None:
544
+ """Create the 5 specialized code review agents with XML-enhanced prompts."""
545
+ # Fallback prompts for when XML is disabled
546
+ lead_fallback = """You are the Review Lead, a senior engineer with 15+ years.
547
+
548
+ Your responsibilities:
549
+ 1. Coordinate the code review team
550
+ 2. Synthesize findings from all reviewers
551
+ 3. Prioritize issues by impact
552
+ 4. Make final verdict decision (approve, request_changes, reject)
553
+ 5. Generate actionable summary
554
+
555
+ You delegate to your team:
556
+ - Security Analyst: Security vulnerabilities and risks
557
+ - Architecture Reviewer: Design patterns and structure
558
+ - Quality Analyst: Code quality and maintainability
559
+ - Performance Reviewer: Performance issues and optimizations
560
+
561
+ For verdict decisions:
562
+ - APPROVE: No issues or only minor suggestions
563
+ - APPROVE_WITH_SUGGESTIONS: Good overall, some improvements recommended
564
+ - REQUEST_CHANGES: Issues that must be addressed before merge
565
+ - REJECT: Fundamental problems requiring significant rework
566
+
567
+ Be constructive and specific in feedback."""
568
+
569
+ # 1. Review Lead (Coordinator)
570
+ self._agents["lead"] = self._factory.create_agent(
571
+ name="review_lead",
572
+ role="coordinator",
573
+ description="Senior engineer who orchestrates the code review team",
574
+ system_prompt=self._get_system_prompt("review_lead", lead_fallback),
575
+ model_tier=self.config.lead_tier,
576
+ memory_graph_enabled=self.config.memory_graph_enabled,
577
+ memory_graph_path=self.config.memory_graph_path,
578
+ resilience_enabled=self.config.resilience_enabled,
579
+ )
580
+
581
+ # Fallback prompts for remaining agents
582
+ security_fallback = """You are the Security Analyst, a security-focused reviewer.
583
+
584
+ Your focus areas:
585
+ 1. OWASP Top 10 vulnerabilities
586
+ 2. SQL Injection, XSS, Command Injection
587
+ 3. Hardcoded secrets, API keys, passwords
588
+ 4. Authentication and authorization flaws
589
+ 5. Input validation issues
590
+ 6. Insecure dependencies
591
+ 7. Cryptographic weaknesses
592
+
593
+ For each finding, provide:
594
+ - Clear description of the security risk
595
+ - File and line number
596
+ - Severity (critical/high/medium/low)
597
+ - Specific remediation with code example
598
+
599
+ Be thorough but minimize false positives. Focus on exploitable issues."""
600
+
601
+ architecture_fallback = """You are the Architecture Reviewer, a software architect.
602
+
603
+ Your evaluation criteria:
604
+ 1. SOLID Principles
605
+ - Single Responsibility
606
+ - Open/Closed
607
+ - Liskov Substitution
608
+ - Interface Segregation
609
+ - Dependency Inversion
610
+
611
+ 2. Design Patterns
612
+ - Appropriate pattern usage
613
+ - Anti-patterns to avoid
614
+ - Missing patterns where beneficial
615
+
616
+ 3. Code Structure
617
+ - Module boundaries
618
+ - Coupling and cohesion
619
+ - Dependency direction
620
+ - Layering violations
621
+
622
+ 4. Scalability
623
+ - Extensibility points
624
+ - Future maintenance burden
625
+ - Breaking changes
626
+
627
+ Provide specific refactoring suggestions with before/after examples."""
628
+
629
+ quality_fallback = """You are the Quality Analyst, a code quality expert.
630
+
631
+ Your focus areas:
632
+ 1. Code Smells
633
+ - Long methods/functions
634
+ - Large classes
635
+ - Duplicate code
636
+ - Dead code
637
+ - Magic numbers/strings
638
+
639
+ 2. Maintainability
640
+ - Clear naming
641
+ - Appropriate comments
642
+ - Consistent formatting
643
+ - Error handling
644
+ - Logging
645
+
646
+ 3. Testing
647
+ - Test coverage gaps
648
+ - Edge cases
649
+ - Error scenarios
650
+ - Integration points
651
+
652
+ 4. Complexity
653
+ - Cyclomatic complexity
654
+ - Nesting depth
655
+ - Parameter counts
656
+ - Cognitive load
657
+
658
+ Prioritize issues that affect long-term maintainability."""
659
+
660
+ # 2. Security Analyst
661
+ self._agents["security"] = self._factory.create_agent(
662
+ name="security_analyst",
663
+ role="security",
664
+ description="Expert at identifying security vulnerabilities",
665
+ system_prompt=self._get_system_prompt("security_analyst", security_fallback),
666
+ model_tier=self.config.security_tier,
667
+ memory_graph_enabled=self.config.memory_graph_enabled,
668
+ memory_graph_path=self.config.memory_graph_path,
669
+ )
670
+
671
+ # 3. Architecture Reviewer
672
+ self._agents["architecture"] = self._factory.create_agent(
673
+ name="architecture_reviewer",
674
+ role="architect",
675
+ description="Evaluates code design and architecture",
676
+ system_prompt=self._get_system_prompt("architecture_reviewer", architecture_fallback),
677
+ model_tier=self.config.architecture_tier,
678
+ memory_graph_enabled=self.config.memory_graph_enabled,
679
+ memory_graph_path=self.config.memory_graph_path,
680
+ )
681
+
682
+ # 4. Quality Analyst
683
+ self._agents["quality"] = self._factory.create_agent(
684
+ name="quality_analyst",
685
+ role="analyst",
686
+ description="Identifies code quality and maintainability issues",
687
+ system_prompt=self._get_system_prompt("quality_analyst", quality_fallback),
688
+ model_tier=self.config.quality_tier,
689
+ memory_graph_enabled=self.config.memory_graph_enabled,
690
+ memory_graph_path=self.config.memory_graph_path,
691
+ )
692
+
693
+ # Performance fallback
694
+ performance_fallback = """You are the Performance Reviewer, a performance engineer.
695
+
696
+ Your focus areas:
697
+ 1. Algorithm Efficiency
698
+ - Time complexity (Big O)
699
+ - Space complexity
700
+ - Unnecessary iterations
701
+ - Inefficient data structures
702
+
703
+ 2. Resource Usage
704
+ - Memory leaks
705
+ - Connection leaks
706
+ - File handle management
707
+ - Cache misuse
708
+
709
+ 3. Common Anti-patterns
710
+ - N+1 queries
711
+ - Sync operations in async code
712
+ - Blocking main thread
713
+ - Unoptimized regex
714
+ - String concatenation in loops
715
+
716
+ 4. Database Performance
717
+ - Missing indexes
718
+ - Expensive queries
719
+ - Over-fetching
720
+ - Transaction scope
721
+
722
+ Provide optimization suggestions with expected impact."""
723
+
724
+ # 5. Performance Reviewer
725
+ self._agents["performance"] = self._factory.create_agent(
726
+ name="performance_reviewer",
727
+ role="analyst",
728
+ description="Identifies performance issues and optimizations",
729
+ system_prompt=self._get_system_prompt("performance_reviewer", performance_fallback),
730
+ model_tier=self.config.performance_tier,
731
+ memory_graph_enabled=self.config.memory_graph_enabled,
732
+ memory_graph_path=self.config.memory_graph_path,
733
+ )
734
+
735
+ async def _create_workflow(self) -> None:
736
+ """Create hierarchical workflow with Review Lead as manager."""
737
+ agents = list(self._agents.values())
738
+
739
+ self._workflow = self._factory.create_workflow(
740
+ name="code_review_workflow",
741
+ agents=agents,
742
+ mode="hierarchical", # Review Lead delegates to others
743
+ description="Comprehensive code review with coordinated analysis",
744
+ )
745
+
746
+ async def review(
747
+ self,
748
+ diff: str = "",
749
+ files_changed: list[str] | None = None,
750
+ target: str = "",
751
+ context: dict | None = None,
752
+ ) -> CodeReviewReport:
753
+ """Perform a comprehensive code review.
754
+
755
+ Args:
756
+ diff: Git diff or code changes to review
757
+ files_changed: List of changed file paths
758
+ target: Description of review target
759
+ context: Optional context (previous findings, focus areas, etc.)
760
+
761
+ Returns:
762
+ CodeReviewReport with findings and verdict
763
+
764
+ """
765
+ import time
766
+
767
+ start_time = time.time()
768
+
769
+ # Initialize if needed
770
+ await self._initialize()
771
+
772
+ context = context or {}
773
+ files_changed = files_changed or []
774
+ findings: list[ReviewFinding] = []
775
+ memory_hits = 0
776
+
777
+ # Build target description
778
+ if not target:
779
+ target = f"Review of {len(files_changed)} files"
780
+
781
+ # Check Memory Graph for similar past reviews
782
+ if self._graph and self.config.memory_graph_enabled:
783
+ try:
784
+ similar = self._graph.find_similar(
785
+ {"name": f"code_review:{target}", "description": target},
786
+ threshold=0.4,
787
+ limit=10,
788
+ )
789
+ if similar:
790
+ memory_hits = len(similar)
791
+ context["similar_reviews"] = [
792
+ {
793
+ "name": node.name,
794
+ "verdict": node.metadata.get("verdict", "unknown"),
795
+ "quality_score": node.metadata.get("quality_score", 0),
796
+ }
797
+ for node, score in similar
798
+ ]
799
+ logger.info(f"Found {memory_hits} similar past reviews")
800
+ except Exception as e:
801
+ logger.warning(f"Error querying Memory Graph: {e}")
802
+
803
+ # Build review task for the crew
804
+ review_task = self._build_review_task(diff, files_changed, context)
805
+
806
+ # Execute the workflow
807
+ verdict = Verdict.APPROVE
808
+ try:
809
+ result = await self._workflow.run(review_task, initial_state=context)
810
+
811
+ # Parse findings from result
812
+ findings = self._parse_findings(result)
813
+
814
+ # Determine verdict
815
+ verdict = self._determine_verdict(findings)
816
+
817
+ except Exception as e:
818
+ logger.error(f"Code review failed: {e}")
819
+ # Return partial report with error
820
+ return CodeReviewReport(
821
+ target=target,
822
+ findings=findings,
823
+ verdict=Verdict.REQUEST_CHANGES,
824
+ summary=f"Review failed with error: {e}",
825
+ review_duration_seconds=time.time() - start_time,
826
+ agents_used=list(self._agents.keys()),
827
+ memory_graph_hits=memory_hits,
828
+ metadata={"error": str(e)},
829
+ )
830
+
831
+ # Build the report
832
+ duration = time.time() - start_time
833
+ report = CodeReviewReport(
834
+ target=target,
835
+ findings=findings,
836
+ verdict=verdict,
837
+ summary=self._generate_summary(findings, verdict),
838
+ review_duration_seconds=duration,
839
+ agents_used=list(self._agents.keys()),
840
+ memory_graph_hits=memory_hits,
841
+ metadata={
842
+ "review_depth": self.config.review_depth,
843
+ "framework": str(self._factory.framework.value),
844
+ "files_changed": files_changed,
845
+ },
846
+ )
847
+
848
+ # Store review in Memory Graph
849
+ if self._graph and self.config.memory_graph_enabled:
850
+ try:
851
+ self._graph.add_finding(
852
+ "code_review_crew",
853
+ {
854
+ "type": "code_review",
855
+ "name": f"review:{target}",
856
+ "description": report.summary,
857
+ "verdict": verdict.value,
858
+ "quality_score": report.quality_score,
859
+ "findings_count": len(findings),
860
+ },
861
+ )
862
+ self._graph._save()
863
+ except Exception as e:
864
+ logger.warning(f"Error storing review in Memory Graph: {e}")
865
+
866
+ return report
867
+
868
+ def _build_review_task(self, diff: str, files_changed: list[str], context: dict) -> str:
869
+ """Build the review task description for the crew."""
870
+ depth_instructions = {
871
+ "quick": "Focus on critical issues only. Skip style and minor issues.",
872
+ "standard": "Cover security, architecture, quality, and performance.",
873
+ "thorough": "Deep review including edge cases, testing, and docs.",
874
+ }
875
+
876
+ focus_list = ", ".join(self.config.focus_areas)
877
+
878
+ task = f"""Perform a comprehensive code review.
879
+
880
+ Review Depth: {self.config.review_depth}
881
+ Instructions: {depth_instructions.get(self.config.review_depth, "standard")}
882
+ Focus Areas: {focus_list}
883
+
884
+ Files Changed ({len(files_changed)}):
885
+ {chr(10).join(f" - {f}" for f in files_changed[:20])}
886
+
887
+ Diff/Code to Review:
888
+ ```
889
+ {diff[:15000]}
890
+ ```
891
+
892
+ Workflow:
893
+ 1. Review Lead coordinates the overall review strategy
894
+ 2. Security Analyst checks for security vulnerabilities
895
+ 3. Architecture Reviewer evaluates design and structure
896
+ 4. Quality Analyst identifies code quality issues
897
+ 5. Performance Reviewer spots performance problems
898
+
899
+ For each finding, provide:
900
+ - Title and description
901
+ - Severity (critical/high/medium/low/info)
902
+ - Category (security/architecture/quality/performance/etc.)
903
+ - File path and line number
904
+ - Specific suggestion with code example if applicable
905
+
906
+ Final Verdict Options:
907
+ - APPROVE: No issues or only minor suggestions
908
+ - APPROVE_WITH_SUGGESTIONS: Good overall, improvements recommended
909
+ - REQUEST_CHANGES: Issues must be addressed before merge
910
+ - REJECT: Fundamental problems requiring rework
911
+
912
+ """
913
+ if context.get("similar_reviews"):
914
+ task += f"""
915
+ Similar Past Reviews Found: {len(context["similar_reviews"])}
916
+ Consider patterns from past reviews.
917
+ """
918
+
919
+ return task
920
+
921
+ def _parse_findings(self, result: dict) -> list[ReviewFinding]:
922
+ """Parse findings from workflow result."""
923
+ findings = []
924
+
925
+ output = result.get("output", "")
926
+ metadata = result.get("metadata", {})
927
+
928
+ # Check for structured findings in metadata
929
+ if "findings" in metadata:
930
+ for f in metadata["findings"]:
931
+ findings.append(self._dict_to_finding(f))
932
+ return findings
933
+
934
+ # Parse from text output (fallback)
935
+ findings = self._parse_text_findings(output)
936
+
937
+ return findings
938
+
939
+ def _dict_to_finding(self, data: dict) -> ReviewFinding:
940
+ """Convert dictionary to ReviewFinding."""
941
+ return ReviewFinding(
942
+ title=data.get("title", "Untitled Finding"),
943
+ description=data.get("description", ""),
944
+ severity=Severity(data.get("severity", "medium")),
945
+ category=FindingCategory(data.get("category", "other")),
946
+ file_path=data.get("file_path"),
947
+ line_number=data.get("line_number"),
948
+ code_snippet=data.get("code_snippet"),
949
+ suggestion=data.get("suggestion"),
950
+ before_code=data.get("before_code"),
951
+ after_code=data.get("after_code"),
952
+ confidence=data.get("confidence", 1.0),
953
+ metadata=data.get("metadata", {}),
954
+ )
955
+
956
+ def _parse_text_findings(self, text: str) -> list[ReviewFinding]:
957
+ """Parse findings from unstructured text output."""
958
+ findings = []
959
+
960
+ severity_keywords = {
961
+ Severity.CRITICAL: ["critical", "security", "vulnerability"],
962
+ Severity.HIGH: ["high", "important", "must fix"],
963
+ Severity.MEDIUM: ["medium", "should", "consider"],
964
+ Severity.LOW: ["low", "minor", "nitpick"],
965
+ Severity.INFO: ["info", "suggestion", "optional"],
966
+ }
967
+
968
+ category_keywords = {
969
+ FindingCategory.SECURITY: ["security", "injection", "xss", "auth"],
970
+ FindingCategory.ARCHITECTURE: ["architecture", "design", "solid"],
971
+ FindingCategory.QUALITY: ["quality", "smell", "duplicate"],
972
+ FindingCategory.PERFORMANCE: ["performance", "slow", "optimize"],
973
+ FindingCategory.TESTING: ["test", "coverage", "assertion"],
974
+ FindingCategory.DOCUMENTATION: ["doc", "comment", "readme"],
975
+ }
976
+
977
+ lines = text.split("\n")
978
+ current_finding = None
979
+
980
+ for line in lines:
981
+ line_lower = line.lower().strip()
982
+
983
+ # Detect severity
984
+ detected_severity = Severity.MEDIUM
985
+ for sev, keywords in severity_keywords.items():
986
+ if any(kw in line_lower for kw in keywords):
987
+ detected_severity = sev
988
+ break
989
+
990
+ # Detect category
991
+ detected_category = FindingCategory.OTHER
992
+ for cat, keywords in category_keywords.items():
993
+ if any(kw in line_lower for kw in keywords):
994
+ detected_category = cat
995
+ break
996
+
997
+ # Simple finding detection
998
+ if any(
999
+ indicator in line_lower
1000
+ for indicator in ["issue", "finding", "problem", "fix", "should"]
1001
+ ):
1002
+ if current_finding:
1003
+ findings.append(current_finding)
1004
+
1005
+ current_finding = ReviewFinding(
1006
+ title=line[:100].strip(),
1007
+ description=line,
1008
+ severity=detected_severity,
1009
+ category=detected_category,
1010
+ )
1011
+
1012
+ if current_finding:
1013
+ findings.append(current_finding)
1014
+
1015
+ return findings
1016
+
1017
+ def _determine_verdict(self, findings: list[ReviewFinding]) -> Verdict:
1018
+ """Determine review verdict based on findings."""
1019
+ if not findings:
1020
+ return Verdict.APPROVE
1021
+
1022
+ critical_count = len([f for f in findings if f.severity == Severity.CRITICAL])
1023
+ high_count = len([f for f in findings if f.severity == Severity.HIGH])
1024
+ medium_count = len([f for f in findings if f.severity == Severity.MEDIUM])
1025
+
1026
+ # Reject if too many critical issues
1027
+ if critical_count >= 3:
1028
+ return Verdict.REJECT
1029
+
1030
+ # Request changes for critical or many high issues
1031
+ if critical_count > 0 or high_count > 3:
1032
+ return Verdict.REQUEST_CHANGES
1033
+
1034
+ # Approve with suggestions for medium/low issues
1035
+ if high_count > 0 or medium_count > 0:
1036
+ return Verdict.APPROVE_WITH_SUGGESTIONS
1037
+
1038
+ return Verdict.APPROVE
1039
+
1040
+ def _generate_summary(self, findings: list[ReviewFinding], verdict: Verdict) -> str:
1041
+ """Generate executive summary of review."""
1042
+ if not findings:
1043
+ return "Code review passed with no issues identified."
1044
+
1045
+ critical = sum(1 for f in findings if f.severity == Severity.CRITICAL)
1046
+ high = sum(1 for f in findings if f.severity == Severity.HIGH)
1047
+ medium = sum(1 for f in findings if f.severity == Severity.MEDIUM)
1048
+ low = sum(1 for f in findings if f.severity == Severity.LOW)
1049
+
1050
+ verdict_text = {
1051
+ Verdict.APPROVE: "Approved - ready to merge",
1052
+ Verdict.APPROVE_WITH_SUGGESTIONS: "Approved with suggestions",
1053
+ Verdict.REQUEST_CHANGES: "Changes requested before merge",
1054
+ Verdict.REJECT: "Rejected - requires significant rework",
1055
+ }
1056
+
1057
+ summary_parts = [
1058
+ f"Code review verdict: {verdict_text.get(verdict, verdict.value)}",
1059
+ f"Total findings: {len(findings)}",
1060
+ ]
1061
+
1062
+ if critical > 0:
1063
+ summary_parts.append(f" - {critical} CRITICAL (blocking)")
1064
+ if high > 0:
1065
+ summary_parts.append(f" - {high} HIGH (should address)")
1066
+ if medium > 0:
1067
+ summary_parts.append(f" - {medium} MEDIUM (recommended)")
1068
+ if low > 0:
1069
+ summary_parts.append(f" - {low} LOW (nice to have)")
1070
+
1071
+ # Add top categories
1072
+ by_category: dict[str, int] = {}
1073
+ for f in findings:
1074
+ cat = f.category.value
1075
+ by_category[cat] = by_category.get(cat, 0) + 1
1076
+
1077
+ if by_category:
1078
+ top_cats = sorted(by_category.items(), key=lambda x: x[1], reverse=True)[:3]
1079
+ summary_parts.append("\nTop issue categories:")
1080
+ for cat, count in top_cats:
1081
+ summary_parts.append(f" - {cat}: {count}")
1082
+
1083
+ return "\n".join(summary_parts)
1084
+
1085
+ @property
1086
+ def agents(self) -> dict[str, Any]:
1087
+ """Get the crew's agents."""
1088
+ return self._agents
1089
+
1090
+ @property
1091
+ def is_initialized(self) -> bool:
1092
+ """Check if crew is initialized."""
1093
+ return self._initialized
1094
+
1095
+ async def get_agent_stats(self) -> dict:
1096
+ """Get statistics about crew agents."""
1097
+ await self._initialize()
1098
+
1099
+ agents_dict: dict = {}
1100
+ stats: dict = {
1101
+ "agent_count": len(self._agents),
1102
+ "agents": agents_dict,
1103
+ "framework": self._factory.framework.value if self._factory else "unknown",
1104
+ "memory_graph_enabled": self.config.memory_graph_enabled,
1105
+ }
1106
+
1107
+ for name, agent in self._agents.items():
1108
+ agents_dict[name] = {
1109
+ "role": agent.config.role if hasattr(agent, "config") else "unknown",
1110
+ "model_tier": getattr(agent.config, "model_tier", "unknown"),
1111
+ }
1112
+
1113
+ return stats