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,281 @@
1
+ """XML validation for response verification.
2
+
3
+ Validates XML-structured responses with graceful fallbacks.
4
+
5
+ Copyright 2026 Smart-AI-Memory
6
+ Licensed under Fair Source License 0.9
7
+ """
8
+
9
+ import xml.etree.ElementTree as ET
10
+ from dataclasses import dataclass
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+
15
+ @dataclass
16
+ class ValidationResult:
17
+ """Result of XML validation.
18
+
19
+ Attributes:
20
+ is_valid: Whether XML is valid
21
+ error_message: Error message if invalid
22
+ parsed_data: Parsed data if valid
23
+ fallback_used: Whether fallback parsing was used
24
+ """
25
+
26
+ is_valid: bool
27
+ error_message: str | None = None
28
+ parsed_data: dict[str, Any] | None = None
29
+ fallback_used: bool = False
30
+
31
+
32
+ class XMLValidator:
33
+ """Validates XML responses with graceful fallbacks.
34
+
35
+ Supports:
36
+ - Well-formedness validation
37
+ - XSD schema validation (optional)
38
+ - Graceful fallback on validation errors
39
+ - Schema caching for performance
40
+
41
+ Usage:
42
+ validator = XMLValidator()
43
+ result = validator.validate("<thinking>...</thinking>")
44
+
45
+ if result.is_valid:
46
+ data = result.parsed_data
47
+ else:
48
+ # Use fallback parsing
49
+ data = fallback_parse(response)
50
+ """
51
+
52
+ def __init__(
53
+ self,
54
+ schema_dir: str = ".attune/schemas",
55
+ strict: bool = False,
56
+ enable_xsd: bool = False,
57
+ ):
58
+ """Initialize validator.
59
+
60
+ Args:
61
+ schema_dir: Directory containing XSD schemas
62
+ strict: If True, fail on validation errors. If False, use fallback.
63
+ enable_xsd: Enable XSD schema validation (requires lxml)
64
+ """
65
+ self.schema_dir = Path(schema_dir)
66
+ self.strict = strict
67
+ self.enable_xsd = enable_xsd
68
+ self._schema_cache: dict[str, Any] = {}
69
+
70
+ # Try to import lxml for XSD validation
71
+ self._lxml_available = False
72
+ if enable_xsd:
73
+ try:
74
+ from lxml import etree as lxml_etree # noqa: F401
75
+
76
+ self._lxml_available = True
77
+ except ImportError:
78
+ pass
79
+
80
+ def validate(self, xml_string: str, schema_name: str | None = None) -> ValidationResult:
81
+ """Validate XML string.
82
+
83
+ Args:
84
+ xml_string: XML content to validate
85
+ schema_name: Optional XSD schema name (e.g., "agent_response")
86
+
87
+ Returns:
88
+ ValidationResult with validation status and parsed data
89
+ """
90
+ # Step 1: Well-formedness validation
91
+ try:
92
+ root = ET.fromstring(xml_string) # nosec B314 - parsing trusted LLM responses
93
+ except ET.ParseError as e:
94
+ if self.strict:
95
+ return ValidationResult(
96
+ is_valid=False,
97
+ error_message=f"XML parsing failed: {e}",
98
+ fallback_used=False,
99
+ )
100
+ # Try fallback parsing
101
+ return self._fallback_parse(xml_string, str(e))
102
+
103
+ # Step 2: XSD schema validation (optional)
104
+ if schema_name and self.enable_xsd and self._lxml_available:
105
+ schema_result = self._validate_with_xsd(xml_string, schema_name)
106
+ if not schema_result.is_valid:
107
+ if self.strict:
108
+ return schema_result
109
+ # Continue with parsed data despite schema error
110
+ return ValidationResult(
111
+ is_valid=True,
112
+ parsed_data=self._extract_data(root),
113
+ fallback_used=True,
114
+ error_message=f"Schema validation failed: {schema_result.error_message}",
115
+ )
116
+
117
+ # Step 3: Extract structured data
118
+ parsed_data = self._extract_data(root)
119
+
120
+ return ValidationResult(
121
+ is_valid=True,
122
+ parsed_data=parsed_data,
123
+ fallback_used=False,
124
+ )
125
+
126
+ def _validate_with_xsd(self, xml_string: str, schema_name: str) -> ValidationResult:
127
+ """Validate XML against XSD schema.
128
+
129
+ Args:
130
+ xml_string: XML content
131
+ schema_name: Schema file name (without .xsd extension)
132
+
133
+ Returns:
134
+ ValidationResult
135
+ """
136
+ if not self._lxml_available:
137
+ return ValidationResult(
138
+ is_valid=False,
139
+ error_message="lxml not available for XSD validation",
140
+ )
141
+
142
+ try:
143
+ from lxml import etree as lxml_etree
144
+ except ImportError:
145
+ return ValidationResult(
146
+ is_valid=False,
147
+ error_message="lxml import failed",
148
+ )
149
+
150
+ # Load schema
151
+ schema_path = self.schema_dir / f"{schema_name}.xsd"
152
+ if not schema_path.exists():
153
+ return ValidationResult(
154
+ is_valid=False,
155
+ error_message=f"Schema not found: {schema_path}",
156
+ )
157
+
158
+ # Check cache
159
+ if schema_name not in self._schema_cache:
160
+ try:
161
+ schema_doc = lxml_etree.parse(str(schema_path))
162
+ self._schema_cache[schema_name] = lxml_etree.XMLSchema(schema_doc)
163
+ except Exception as e:
164
+ return ValidationResult(
165
+ is_valid=False,
166
+ error_message=f"Schema loading failed: {e}",
167
+ )
168
+
169
+ schema = self._schema_cache[schema_name]
170
+
171
+ # Validate
172
+ try:
173
+ xml_doc = lxml_etree.fromstring(xml_string.encode("utf-8"))
174
+ is_valid = schema.validate(xml_doc)
175
+
176
+ if not is_valid:
177
+ error_log = schema.error_log
178
+ return ValidationResult(
179
+ is_valid=False,
180
+ error_message=f"Schema validation failed: {error_log}",
181
+ )
182
+
183
+ return ValidationResult(is_valid=True)
184
+
185
+ except Exception as e:
186
+ return ValidationResult(
187
+ is_valid=False,
188
+ error_message=f"Validation error: {e}",
189
+ )
190
+
191
+ def _fallback_parse(self, xml_string: str, error: str) -> ValidationResult:
192
+ """Attempt fallback parsing of malformed XML.
193
+
194
+ Args:
195
+ xml_string: XML string that failed to parse
196
+ error: Parse error message
197
+
198
+ Returns:
199
+ ValidationResult with fallback data
200
+ """
201
+ # Try to extract data using regex patterns
202
+ import re
203
+
204
+ data: dict[str, Any] = {}
205
+
206
+ # Extract thinking content
207
+ thinking_match = re.search(r"<thinking[^>]*>(.*?)</thinking>", xml_string, re.DOTALL)
208
+ if thinking_match:
209
+ data["thinking"] = thinking_match.group(1).strip()
210
+
211
+ # Extract answer content
212
+ answer_match = re.search(r"<answer[^>]*>(.*?)</answer>", xml_string, re.DOTALL)
213
+ if answer_match:
214
+ data["answer"] = answer_match.group(1).strip()
215
+
216
+ # If we extracted something, consider it a partial success
217
+ if data:
218
+ return ValidationResult(
219
+ is_valid=True,
220
+ parsed_data=data,
221
+ fallback_used=True,
222
+ error_message=f"XML parsing failed, used fallback: {error}",
223
+ )
224
+
225
+ # Complete failure
226
+ return ValidationResult(
227
+ is_valid=False,
228
+ error_message=f"XML parsing and fallback failed: {error}",
229
+ fallback_used=True,
230
+ )
231
+
232
+ def _extract_data(self, root: ET.Element) -> dict[str, Any]:
233
+ """Extract structured data from parsed XML.
234
+
235
+ Args:
236
+ root: Parsed XML root element
237
+
238
+ Returns:
239
+ Dictionary with extracted data
240
+ """
241
+ data: dict[str, Any] = {}
242
+
243
+ # Extract all child elements
244
+ for child in root:
245
+ # Handle nested elements
246
+ if len(child):
247
+ data[child.tag] = self._extract_data(child)
248
+ else:
249
+ # Leaf node - get text content
250
+ data[child.tag] = child.text if child.text else ""
251
+
252
+ # Also store root attributes
253
+ if root.attrib:
254
+ data["_attributes"] = dict(root.attrib)
255
+
256
+ return data
257
+
258
+
259
+ def validate_xml_response(
260
+ response: str,
261
+ schema_name: str | None = None,
262
+ strict: bool = False,
263
+ ) -> ValidationResult:
264
+ """Convenience function to validate XML response.
265
+
266
+ Args:
267
+ response: XML response string
268
+ schema_name: Optional XSD schema name
269
+ strict: If True, fail on validation errors
270
+
271
+ Returns:
272
+ ValidationResult
273
+
274
+ Example:
275
+ >>> response = "<thinking>Analysis</thinking><answer>Result</answer>"
276
+ >>> result = validate_xml_response(response)
277
+ >>> if result.is_valid:
278
+ ... print(result.parsed_data)
279
+ """
280
+ validator = XMLValidator(strict=strict)
281
+ return validator.validate(response, schema_name)
@@ -0,0 +1,173 @@
1
+ """VS Code Extension Bridge
2
+
3
+ Provides functions to write data that the VS Code extension can pick up.
4
+ Enables Claude Code CLI output to appear in VS Code webview panels.
5
+
6
+ Copyright 2026 Smart-AI-Memory
7
+ Licensed under Fair Source License 0.9
8
+ """
9
+
10
+ import json
11
+ from dataclasses import asdict, dataclass
12
+ from datetime import datetime
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+
17
+ @dataclass
18
+ class ReviewFinding:
19
+ """A code review finding."""
20
+
21
+ id: str
22
+ file: str
23
+ line: int
24
+ severity: str # 'critical' | 'high' | 'medium' | 'low' | 'info'
25
+ category: str # 'security' | 'performance' | 'maintainability' | 'style' | 'correctness'
26
+ message: str
27
+ column: int = 1
28
+ details: str | None = None
29
+ recommendation: str | None = None
30
+
31
+
32
+ @dataclass
33
+ class CodeReviewResult:
34
+ """Code review results for VS Code bridge."""
35
+
36
+ findings: list[dict[str, Any]]
37
+ summary: dict[str, Any]
38
+ verdict: str # 'approve' | 'approve_with_suggestions' | 'request_changes' | 'reject'
39
+ security_score: int
40
+ formatted_report: str
41
+ model_tier_used: str
42
+ timestamp: str
43
+
44
+
45
+ def get_empathy_dir() -> Path:
46
+ """Get the .empathy directory, creating if needed."""
47
+ empathy_dir = Path(".empathy")
48
+ empathy_dir.mkdir(exist_ok=True)
49
+ return empathy_dir
50
+
51
+
52
+ def write_code_review_results(
53
+ findings: list[dict[str, Any]] | None = None,
54
+ summary: dict[str, Any] | None = None,
55
+ verdict: str = "approve_with_suggestions",
56
+ security_score: int = 85,
57
+ formatted_report: str = "",
58
+ model_tier_used: str = "capable",
59
+ ) -> Path:
60
+ """Write code review results for VS Code extension to pick up.
61
+
62
+ Args:
63
+ findings: List of finding dicts with keys: id, file, line, severity, category, message
64
+ summary: Summary dict with keys: total_findings, by_severity, by_category, files_affected
65
+ verdict: One of 'approve', 'approve_with_suggestions', 'request_changes', 'reject'
66
+ security_score: 0-100 score
67
+ formatted_report: Markdown formatted report
68
+ model_tier_used: 'cheap', 'capable', or 'premium'
69
+
70
+ Returns:
71
+ Path to the written file
72
+ """
73
+ findings = findings or []
74
+
75
+ # Build summary if not provided
76
+ if summary is None:
77
+ by_severity: dict[str, int] = {}
78
+ by_category: dict[str, int] = {}
79
+ files_affected: set[str] = set()
80
+
81
+ for f in findings:
82
+ sev = f.get("severity", "info")
83
+ cat = f.get("category", "correctness")
84
+ by_severity[sev] = by_severity.get(sev, 0) + 1
85
+ by_category[cat] = by_category.get(cat, 0) + 1
86
+ if f.get("file"):
87
+ files_affected.add(f["file"])
88
+
89
+ summary = {
90
+ "total_findings": len(findings),
91
+ "by_severity": by_severity,
92
+ "by_category": by_category,
93
+ "files_affected": list(files_affected),
94
+ }
95
+
96
+ result = CodeReviewResult(
97
+ findings=findings,
98
+ summary=summary,
99
+ verdict=verdict,
100
+ security_score=security_score,
101
+ formatted_report=formatted_report,
102
+ model_tier_used=model_tier_used,
103
+ timestamp=datetime.now().isoformat(),
104
+ )
105
+
106
+ output_path = get_empathy_dir() / "code-review-results.json"
107
+
108
+ with open(output_path, "w") as f:
109
+ json.dump(asdict(result), f, indent=2)
110
+
111
+ return output_path
112
+
113
+
114
+ def write_pr_review_results(
115
+ pr_number: int | str,
116
+ title: str,
117
+ findings: list[dict[str, Any]],
118
+ verdict: str = "approve_with_suggestions",
119
+ summary_text: str = "",
120
+ ) -> Path:
121
+ """Write PR review results for VS Code extension.
122
+
123
+ Convenience wrapper for PR reviews from GitHub.
124
+
125
+ Args:
126
+ pr_number: The PR number
127
+ title: PR title
128
+ findings: List of review findings
129
+ verdict: Review verdict
130
+ summary_text: Summary of the review
131
+
132
+ Returns:
133
+ Path to the written file
134
+ """
135
+ formatted_report = f"""## PR #{pr_number}: {title}
136
+
137
+ {summary_text}
138
+
139
+ ### Findings ({len(findings)})
140
+
141
+ """
142
+ for f in findings:
143
+ formatted_report += f"- **{f.get('severity', 'info').upper()}** [{f.get('file', 'unknown')}:{f.get('line', 0)}]: {f.get('message', '')}\n"
144
+
145
+ return write_code_review_results(
146
+ findings=findings,
147
+ verdict=verdict,
148
+ formatted_report=formatted_report,
149
+ model_tier_used="capable",
150
+ )
151
+
152
+
153
+ # Quick helper for Claude Code to call
154
+ def send_to_vscode(
155
+ message: str,
156
+ findings: list[dict[str, Any]] | None = None,
157
+ verdict: str = "approve_with_suggestions",
158
+ ) -> str:
159
+ """Quick helper to send review results to VS Code.
160
+
161
+ Usage in Claude Code:
162
+ from attune.vscode_bridge import send_to_vscode
163
+ send_to_vscode("Review complete", findings=[...])
164
+
165
+ Returns:
166
+ Confirmation message
167
+ """
168
+ path = write_code_review_results(
169
+ findings=findings or [],
170
+ formatted_report=message,
171
+ verdict=verdict,
172
+ )
173
+ return f"Results written to {path} - VS Code will update automatically"