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.
- attune/__init__.py +358 -0
- attune/adaptive/__init__.py +13 -0
- attune/adaptive/task_complexity.py +127 -0
- attune/agent_monitoring.py +414 -0
- attune/cache/__init__.py +117 -0
- attune/cache/base.py +166 -0
- attune/cache/dependency_manager.py +256 -0
- attune/cache/hash_only.py +251 -0
- attune/cache/hybrid.py +457 -0
- attune/cache/storage.py +285 -0
- attune/cache_monitor.py +356 -0
- attune/cache_stats.py +298 -0
- attune/cli/__init__.py +152 -0
- attune/cli/__main__.py +12 -0
- attune/cli/commands/__init__.py +1 -0
- attune/cli/commands/batch.py +264 -0
- attune/cli/commands/cache.py +248 -0
- attune/cli/commands/help.py +331 -0
- attune/cli/commands/info.py +140 -0
- attune/cli/commands/inspect.py +436 -0
- attune/cli/commands/inspection.py +57 -0
- attune/cli/commands/memory.py +48 -0
- attune/cli/commands/metrics.py +92 -0
- attune/cli/commands/orchestrate.py +184 -0
- attune/cli/commands/patterns.py +207 -0
- attune/cli/commands/profiling.py +202 -0
- attune/cli/commands/provider.py +98 -0
- attune/cli/commands/routing.py +285 -0
- attune/cli/commands/setup.py +96 -0
- attune/cli/commands/status.py +235 -0
- attune/cli/commands/sync.py +166 -0
- attune/cli/commands/tier.py +121 -0
- attune/cli/commands/utilities.py +114 -0
- attune/cli/commands/workflow.py +579 -0
- attune/cli/core.py +32 -0
- attune/cli/parsers/__init__.py +68 -0
- attune/cli/parsers/batch.py +118 -0
- attune/cli/parsers/cache.py +65 -0
- attune/cli/parsers/help.py +41 -0
- attune/cli/parsers/info.py +26 -0
- attune/cli/parsers/inspect.py +66 -0
- attune/cli/parsers/metrics.py +42 -0
- attune/cli/parsers/orchestrate.py +61 -0
- attune/cli/parsers/patterns.py +54 -0
- attune/cli/parsers/provider.py +40 -0
- attune/cli/parsers/routing.py +110 -0
- attune/cli/parsers/setup.py +42 -0
- attune/cli/parsers/status.py +47 -0
- attune/cli/parsers/sync.py +31 -0
- attune/cli/parsers/tier.py +33 -0
- attune/cli/parsers/workflow.py +77 -0
- attune/cli/utils/__init__.py +1 -0
- attune/cli/utils/data.py +242 -0
- attune/cli/utils/helpers.py +68 -0
- attune/cli_legacy.py +3957 -0
- attune/cli_minimal.py +1159 -0
- attune/cli_router.py +437 -0
- attune/cli_unified.py +814 -0
- attune/config/__init__.py +66 -0
- attune/config/xml_config.py +286 -0
- attune/config.py +545 -0
- attune/coordination.py +870 -0
- attune/core.py +1511 -0
- attune/core_modules/__init__.py +15 -0
- attune/cost_tracker.py +626 -0
- attune/dashboard/__init__.py +41 -0
- attune/dashboard/app.py +512 -0
- attune/dashboard/simple_server.py +435 -0
- attune/dashboard/standalone_server.py +547 -0
- attune/discovery.py +306 -0
- attune/emergence.py +306 -0
- attune/exceptions.py +123 -0
- attune/feedback_loops.py +373 -0
- attune/hot_reload/README.md +473 -0
- attune/hot_reload/__init__.py +62 -0
- attune/hot_reload/config.py +83 -0
- attune/hot_reload/integration.py +229 -0
- attune/hot_reload/reloader.py +298 -0
- attune/hot_reload/watcher.py +183 -0
- attune/hot_reload/websocket.py +177 -0
- attune/levels.py +577 -0
- attune/leverage_points.py +441 -0
- attune/logging_config.py +261 -0
- attune/mcp/__init__.py +10 -0
- attune/mcp/server.py +506 -0
- attune/memory/__init__.py +237 -0
- attune/memory/claude_memory.py +469 -0
- attune/memory/config.py +224 -0
- attune/memory/control_panel.py +1290 -0
- attune/memory/control_panel_support.py +145 -0
- attune/memory/cross_session.py +845 -0
- attune/memory/edges.py +179 -0
- attune/memory/encryption.py +159 -0
- attune/memory/file_session.py +770 -0
- attune/memory/graph.py +570 -0
- attune/memory/long_term.py +913 -0
- attune/memory/long_term_types.py +99 -0
- attune/memory/mixins/__init__.py +25 -0
- attune/memory/mixins/backend_init_mixin.py +249 -0
- attune/memory/mixins/capabilities_mixin.py +208 -0
- attune/memory/mixins/handoff_mixin.py +208 -0
- attune/memory/mixins/lifecycle_mixin.py +49 -0
- attune/memory/mixins/long_term_mixin.py +352 -0
- attune/memory/mixins/promotion_mixin.py +109 -0
- attune/memory/mixins/short_term_mixin.py +182 -0
- attune/memory/nodes.py +179 -0
- attune/memory/redis_bootstrap.py +540 -0
- attune/memory/security/__init__.py +31 -0
- attune/memory/security/audit_logger.py +932 -0
- attune/memory/security/pii_scrubber.py +640 -0
- attune/memory/security/secrets_detector.py +678 -0
- attune/memory/short_term.py +2192 -0
- attune/memory/simple_storage.py +302 -0
- attune/memory/storage/__init__.py +15 -0
- attune/memory/storage_backend.py +167 -0
- attune/memory/summary_index.py +583 -0
- attune/memory/types.py +446 -0
- attune/memory/unified.py +182 -0
- attune/meta_workflows/__init__.py +74 -0
- attune/meta_workflows/agent_creator.py +248 -0
- attune/meta_workflows/builtin_templates.py +567 -0
- attune/meta_workflows/cli_commands/__init__.py +56 -0
- attune/meta_workflows/cli_commands/agent_commands.py +321 -0
- attune/meta_workflows/cli_commands/analytics_commands.py +442 -0
- attune/meta_workflows/cli_commands/config_commands.py +232 -0
- attune/meta_workflows/cli_commands/memory_commands.py +182 -0
- attune/meta_workflows/cli_commands/template_commands.py +354 -0
- attune/meta_workflows/cli_commands/workflow_commands.py +382 -0
- attune/meta_workflows/cli_meta_workflows.py +59 -0
- attune/meta_workflows/form_engine.py +292 -0
- attune/meta_workflows/intent_detector.py +409 -0
- attune/meta_workflows/models.py +569 -0
- attune/meta_workflows/pattern_learner.py +738 -0
- attune/meta_workflows/plan_generator.py +384 -0
- attune/meta_workflows/session_context.py +397 -0
- attune/meta_workflows/template_registry.py +229 -0
- attune/meta_workflows/workflow.py +984 -0
- attune/metrics/__init__.py +12 -0
- attune/metrics/collector.py +31 -0
- attune/metrics/prompt_metrics.py +194 -0
- attune/models/__init__.py +172 -0
- attune/models/__main__.py +13 -0
- attune/models/adaptive_routing.py +437 -0
- attune/models/auth_cli.py +444 -0
- attune/models/auth_strategy.py +450 -0
- attune/models/cli.py +655 -0
- attune/models/empathy_executor.py +354 -0
- attune/models/executor.py +257 -0
- attune/models/fallback.py +762 -0
- attune/models/provider_config.py +282 -0
- attune/models/registry.py +472 -0
- attune/models/tasks.py +359 -0
- attune/models/telemetry/__init__.py +71 -0
- attune/models/telemetry/analytics.py +594 -0
- attune/models/telemetry/backend.py +196 -0
- attune/models/telemetry/data_models.py +431 -0
- attune/models/telemetry/storage.py +489 -0
- attune/models/token_estimator.py +420 -0
- attune/models/validation.py +280 -0
- attune/monitoring/__init__.py +52 -0
- attune/monitoring/alerts.py +946 -0
- attune/monitoring/alerts_cli.py +448 -0
- attune/monitoring/multi_backend.py +271 -0
- attune/monitoring/otel_backend.py +362 -0
- attune/optimization/__init__.py +19 -0
- attune/optimization/context_optimizer.py +272 -0
- attune/orchestration/__init__.py +67 -0
- attune/orchestration/agent_templates.py +707 -0
- attune/orchestration/config_store.py +499 -0
- attune/orchestration/execution_strategies.py +2111 -0
- attune/orchestration/meta_orchestrator.py +1168 -0
- attune/orchestration/pattern_learner.py +696 -0
- attune/orchestration/real_tools.py +931 -0
- attune/pattern_cache.py +187 -0
- attune/pattern_library.py +542 -0
- attune/patterns/debugging/all_patterns.json +81 -0
- attune/patterns/debugging/workflow_20260107_1770825e.json +77 -0
- attune/patterns/refactoring_memory.json +89 -0
- attune/persistence.py +564 -0
- attune/platform_utils.py +265 -0
- attune/plugins/__init__.py +28 -0
- attune/plugins/base.py +361 -0
- attune/plugins/registry.py +268 -0
- attune/project_index/__init__.py +32 -0
- attune/project_index/cli.py +335 -0
- attune/project_index/index.py +667 -0
- attune/project_index/models.py +504 -0
- attune/project_index/reports.py +474 -0
- attune/project_index/scanner.py +777 -0
- attune/project_index/scanner_parallel.py +291 -0
- attune/prompts/__init__.py +61 -0
- attune/prompts/config.py +77 -0
- attune/prompts/context.py +177 -0
- attune/prompts/parser.py +285 -0
- attune/prompts/registry.py +313 -0
- attune/prompts/templates.py +208 -0
- attune/redis_config.py +302 -0
- attune/redis_memory.py +799 -0
- attune/resilience/__init__.py +56 -0
- attune/resilience/circuit_breaker.py +256 -0
- attune/resilience/fallback.py +179 -0
- attune/resilience/health.py +300 -0
- attune/resilience/retry.py +209 -0
- attune/resilience/timeout.py +135 -0
- attune/routing/__init__.py +43 -0
- attune/routing/chain_executor.py +433 -0
- attune/routing/classifier.py +217 -0
- attune/routing/smart_router.py +234 -0
- attune/routing/workflow_registry.py +343 -0
- attune/scaffolding/README.md +589 -0
- attune/scaffolding/__init__.py +35 -0
- attune/scaffolding/__main__.py +14 -0
- attune/scaffolding/cli.py +240 -0
- attune/scaffolding/templates/base_wizard.py.jinja2 +121 -0
- attune/scaffolding/templates/coach_wizard.py.jinja2 +321 -0
- attune/scaffolding/templates/domain_wizard.py.jinja2 +408 -0
- attune/scaffolding/templates/linear_flow_wizard.py.jinja2 +203 -0
- attune/socratic/__init__.py +256 -0
- attune/socratic/ab_testing.py +958 -0
- attune/socratic/blueprint.py +533 -0
- attune/socratic/cli.py +703 -0
- attune/socratic/collaboration.py +1114 -0
- attune/socratic/domain_templates.py +924 -0
- attune/socratic/embeddings.py +738 -0
- attune/socratic/engine.py +794 -0
- attune/socratic/explainer.py +682 -0
- attune/socratic/feedback.py +772 -0
- attune/socratic/forms.py +629 -0
- attune/socratic/generator.py +732 -0
- attune/socratic/llm_analyzer.py +637 -0
- attune/socratic/mcp_server.py +702 -0
- attune/socratic/session.py +312 -0
- attune/socratic/storage.py +667 -0
- attune/socratic/success.py +730 -0
- attune/socratic/visual_editor.py +860 -0
- attune/socratic/web_ui.py +958 -0
- attune/telemetry/__init__.py +39 -0
- attune/telemetry/agent_coordination.py +475 -0
- attune/telemetry/agent_tracking.py +367 -0
- attune/telemetry/approval_gates.py +545 -0
- attune/telemetry/cli.py +1231 -0
- attune/telemetry/commands/__init__.py +14 -0
- attune/telemetry/commands/dashboard_commands.py +696 -0
- attune/telemetry/event_streaming.py +409 -0
- attune/telemetry/feedback_loop.py +567 -0
- attune/telemetry/usage_tracker.py +591 -0
- attune/templates.py +754 -0
- attune/test_generator/__init__.py +38 -0
- attune/test_generator/__main__.py +14 -0
- attune/test_generator/cli.py +234 -0
- attune/test_generator/generator.py +355 -0
- attune/test_generator/risk_analyzer.py +216 -0
- attune/test_generator/templates/unit_test.py.jinja2 +272 -0
- attune/tier_recommender.py +384 -0
- attune/tools.py +183 -0
- attune/trust/__init__.py +28 -0
- attune/trust/circuit_breaker.py +579 -0
- attune/trust_building.py +527 -0
- attune/validation/__init__.py +19 -0
- attune/validation/xml_validator.py +281 -0
- attune/vscode_bridge.py +173 -0
- attune/workflow_commands.py +780 -0
- attune/workflow_patterns/__init__.py +33 -0
- attune/workflow_patterns/behavior.py +249 -0
- attune/workflow_patterns/core.py +76 -0
- attune/workflow_patterns/output.py +99 -0
- attune/workflow_patterns/registry.py +255 -0
- attune/workflow_patterns/structural.py +288 -0
- attune/workflows/__init__.py +539 -0
- attune/workflows/autonomous_test_gen.py +1268 -0
- attune/workflows/base.py +2667 -0
- attune/workflows/batch_processing.py +342 -0
- attune/workflows/bug_predict.py +1084 -0
- attune/workflows/builder.py +273 -0
- attune/workflows/caching.py +253 -0
- attune/workflows/code_review.py +1048 -0
- attune/workflows/code_review_adapters.py +312 -0
- attune/workflows/code_review_pipeline.py +722 -0
- attune/workflows/config.py +645 -0
- attune/workflows/dependency_check.py +644 -0
- attune/workflows/document_gen/__init__.py +25 -0
- attune/workflows/document_gen/config.py +30 -0
- attune/workflows/document_gen/report_formatter.py +162 -0
- attune/workflows/document_gen/workflow.py +1426 -0
- attune/workflows/document_manager.py +216 -0
- attune/workflows/document_manager_README.md +134 -0
- attune/workflows/documentation_orchestrator.py +1205 -0
- attune/workflows/history.py +510 -0
- attune/workflows/keyboard_shortcuts/__init__.py +39 -0
- attune/workflows/keyboard_shortcuts/generators.py +391 -0
- attune/workflows/keyboard_shortcuts/parsers.py +416 -0
- attune/workflows/keyboard_shortcuts/prompts.py +295 -0
- attune/workflows/keyboard_shortcuts/schema.py +193 -0
- attune/workflows/keyboard_shortcuts/workflow.py +509 -0
- attune/workflows/llm_base.py +363 -0
- attune/workflows/manage_docs.py +87 -0
- attune/workflows/manage_docs_README.md +134 -0
- attune/workflows/manage_documentation.py +821 -0
- attune/workflows/new_sample_workflow1.py +149 -0
- attune/workflows/new_sample_workflow1_README.md +150 -0
- attune/workflows/orchestrated_health_check.py +849 -0
- attune/workflows/orchestrated_release_prep.py +600 -0
- attune/workflows/output.py +413 -0
- attune/workflows/perf_audit.py +863 -0
- attune/workflows/pr_review.py +762 -0
- attune/workflows/progress.py +785 -0
- attune/workflows/progress_server.py +322 -0
- attune/workflows/progressive/README 2.md +454 -0
- attune/workflows/progressive/README.md +454 -0
- attune/workflows/progressive/__init__.py +82 -0
- attune/workflows/progressive/cli.py +219 -0
- attune/workflows/progressive/core.py +488 -0
- attune/workflows/progressive/orchestrator.py +723 -0
- attune/workflows/progressive/reports.py +520 -0
- attune/workflows/progressive/telemetry.py +274 -0
- attune/workflows/progressive/test_gen.py +495 -0
- attune/workflows/progressive/workflow.py +589 -0
- attune/workflows/refactor_plan.py +694 -0
- attune/workflows/release_prep.py +895 -0
- attune/workflows/release_prep_crew.py +969 -0
- attune/workflows/research_synthesis.py +404 -0
- attune/workflows/routing.py +168 -0
- attune/workflows/secure_release.py +593 -0
- attune/workflows/security_adapters.py +297 -0
- attune/workflows/security_audit.py +1329 -0
- attune/workflows/security_audit_phase3.py +355 -0
- attune/workflows/seo_optimization.py +633 -0
- attune/workflows/step_config.py +234 -0
- attune/workflows/telemetry_mixin.py +269 -0
- attune/workflows/test5.py +125 -0
- attune/workflows/test5_README.md +158 -0
- attune/workflows/test_coverage_boost_crew.py +849 -0
- attune/workflows/test_gen/__init__.py +52 -0
- attune/workflows/test_gen/ast_analyzer.py +249 -0
- attune/workflows/test_gen/config.py +88 -0
- attune/workflows/test_gen/data_models.py +38 -0
- attune/workflows/test_gen/report_formatter.py +289 -0
- attune/workflows/test_gen/test_templates.py +381 -0
- attune/workflows/test_gen/workflow.py +655 -0
- attune/workflows/test_gen.py +54 -0
- attune/workflows/test_gen_behavioral.py +477 -0
- attune/workflows/test_gen_parallel.py +341 -0
- attune/workflows/test_lifecycle.py +526 -0
- attune/workflows/test_maintenance.py +627 -0
- attune/workflows/test_maintenance_cli.py +590 -0
- attune/workflows/test_maintenance_crew.py +840 -0
- attune/workflows/test_runner.py +622 -0
- attune/workflows/tier_tracking.py +531 -0
- attune/workflows/xml_enhanced_crew.py +285 -0
- attune_ai-2.0.0.dist-info/METADATA +1026 -0
- attune_ai-2.0.0.dist-info/RECORD +457 -0
- attune_ai-2.0.0.dist-info/WHEEL +5 -0
- attune_ai-2.0.0.dist-info/entry_points.txt +26 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE +201 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE_CHANGE_ANNOUNCEMENT.md +101 -0
- attune_ai-2.0.0.dist-info/top_level.txt +5 -0
- attune_healthcare/__init__.py +13 -0
- attune_healthcare/monitors/__init__.py +9 -0
- attune_healthcare/monitors/clinical_protocol_monitor.py +315 -0
- attune_healthcare/monitors/monitoring/__init__.py +44 -0
- attune_healthcare/monitors/monitoring/protocol_checker.py +300 -0
- attune_healthcare/monitors/monitoring/protocol_loader.py +214 -0
- attune_healthcare/monitors/monitoring/sensor_parsers.py +306 -0
- attune_healthcare/monitors/monitoring/trajectory_analyzer.py +389 -0
- attune_llm/README.md +553 -0
- attune_llm/__init__.py +28 -0
- attune_llm/agent_factory/__init__.py +53 -0
- attune_llm/agent_factory/adapters/__init__.py +85 -0
- attune_llm/agent_factory/adapters/autogen_adapter.py +312 -0
- attune_llm/agent_factory/adapters/crewai_adapter.py +483 -0
- attune_llm/agent_factory/adapters/haystack_adapter.py +298 -0
- attune_llm/agent_factory/adapters/langchain_adapter.py +362 -0
- attune_llm/agent_factory/adapters/langgraph_adapter.py +333 -0
- attune_llm/agent_factory/adapters/native.py +228 -0
- attune_llm/agent_factory/adapters/wizard_adapter.py +423 -0
- attune_llm/agent_factory/base.py +305 -0
- attune_llm/agent_factory/crews/__init__.py +67 -0
- attune_llm/agent_factory/crews/code_review.py +1113 -0
- attune_llm/agent_factory/crews/health_check.py +1262 -0
- attune_llm/agent_factory/crews/refactoring.py +1128 -0
- attune_llm/agent_factory/crews/security_audit.py +1018 -0
- attune_llm/agent_factory/decorators.py +287 -0
- attune_llm/agent_factory/factory.py +558 -0
- attune_llm/agent_factory/framework.py +193 -0
- attune_llm/agent_factory/memory_integration.py +328 -0
- attune_llm/agent_factory/resilient.py +320 -0
- attune_llm/agents_md/__init__.py +22 -0
- attune_llm/agents_md/loader.py +218 -0
- attune_llm/agents_md/parser.py +271 -0
- attune_llm/agents_md/registry.py +307 -0
- attune_llm/claude_memory.py +466 -0
- attune_llm/cli/__init__.py +8 -0
- attune_llm/cli/sync_claude.py +487 -0
- attune_llm/code_health.py +1313 -0
- attune_llm/commands/__init__.py +51 -0
- attune_llm/commands/context.py +375 -0
- attune_llm/commands/loader.py +301 -0
- attune_llm/commands/models.py +231 -0
- attune_llm/commands/parser.py +371 -0
- attune_llm/commands/registry.py +429 -0
- attune_llm/config/__init__.py +29 -0
- attune_llm/config/unified.py +291 -0
- attune_llm/context/__init__.py +22 -0
- attune_llm/context/compaction.py +455 -0
- attune_llm/context/manager.py +434 -0
- attune_llm/contextual_patterns.py +361 -0
- attune_llm/core.py +907 -0
- attune_llm/git_pattern_extractor.py +435 -0
- attune_llm/hooks/__init__.py +24 -0
- attune_llm/hooks/config.py +306 -0
- attune_llm/hooks/executor.py +289 -0
- attune_llm/hooks/registry.py +302 -0
- attune_llm/hooks/scripts/__init__.py +39 -0
- attune_llm/hooks/scripts/evaluate_session.py +201 -0
- attune_llm/hooks/scripts/first_time_init.py +285 -0
- attune_llm/hooks/scripts/pre_compact.py +207 -0
- attune_llm/hooks/scripts/session_end.py +183 -0
- attune_llm/hooks/scripts/session_start.py +163 -0
- attune_llm/hooks/scripts/suggest_compact.py +225 -0
- attune_llm/learning/__init__.py +30 -0
- attune_llm/learning/evaluator.py +438 -0
- attune_llm/learning/extractor.py +514 -0
- attune_llm/learning/storage.py +560 -0
- attune_llm/levels.py +227 -0
- attune_llm/pattern_confidence.py +414 -0
- attune_llm/pattern_resolver.py +272 -0
- attune_llm/pattern_summary.py +350 -0
- attune_llm/providers.py +967 -0
- attune_llm/routing/__init__.py +32 -0
- attune_llm/routing/model_router.py +362 -0
- attune_llm/security/IMPLEMENTATION_SUMMARY.md +413 -0
- attune_llm/security/PHASE2_COMPLETE.md +384 -0
- attune_llm/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
- attune_llm/security/QUICK_REFERENCE.md +316 -0
- attune_llm/security/README.md +262 -0
- attune_llm/security/__init__.py +62 -0
- attune_llm/security/audit_logger.py +929 -0
- attune_llm/security/audit_logger_example.py +152 -0
- attune_llm/security/pii_scrubber.py +640 -0
- attune_llm/security/secrets_detector.py +678 -0
- attune_llm/security/secrets_detector_example.py +304 -0
- attune_llm/security/secure_memdocs.py +1192 -0
- attune_llm/security/secure_memdocs_example.py +278 -0
- attune_llm/session_status.py +745 -0
- attune_llm/state.py +246 -0
- attune_llm/utils/__init__.py +5 -0
- attune_llm/utils/tokens.py +349 -0
- attune_software/SOFTWARE_PLUGIN_README.md +57 -0
- attune_software/__init__.py +13 -0
- attune_software/cli/__init__.py +120 -0
- attune_software/cli/inspect.py +362 -0
- attune_software/cli.py +574 -0
- attune_software/plugin.py +188 -0
- workflow_scaffolding/__init__.py +11 -0
- workflow_scaffolding/__main__.py +12 -0
- workflow_scaffolding/cli.py +206 -0
- workflow_scaffolding/generator.py +265 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
"""Parallel Behavioral Test Generation & Completion Workflow.
|
|
2
|
+
|
|
3
|
+
Uses multi-tier LLM orchestration to generate AND complete tests in parallel.
|
|
4
|
+
This dramatically accelerates achieving 99.9% test coverage.
|
|
5
|
+
|
|
6
|
+
Key Features:
|
|
7
|
+
- Parallel template generation (cheap tier - fast)
|
|
8
|
+
- Parallel test completion (capable tier - quality)
|
|
9
|
+
- Batch processing of 10-50 modules simultaneously
|
|
10
|
+
- Automatic validation and fixing
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
empathy workflow run test-gen-parallel --top 200 --parallel 10
|
|
14
|
+
|
|
15
|
+
Copyright 2026 Smart-AI-Memory
|
|
16
|
+
Licensed under Apache 2.0
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import ast
|
|
20
|
+
import asyncio
|
|
21
|
+
import json
|
|
22
|
+
from dataclasses import dataclass
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Any
|
|
25
|
+
|
|
26
|
+
from ..workflows.base import BaseWorkflow, ModelTier, WorkflowResult, WorkflowStage
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class TestGenerationTask:
|
|
31
|
+
"""A test generation task."""
|
|
32
|
+
|
|
33
|
+
module_path: str
|
|
34
|
+
coverage: float
|
|
35
|
+
output_path: str
|
|
36
|
+
status: str = "pending" # pending, generated, completed, validated
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ParallelTestGenerationWorkflow(BaseWorkflow):
|
|
40
|
+
"""Generate and complete behavioral tests in parallel using multi-tier LLMs."""
|
|
41
|
+
|
|
42
|
+
def __init__(self):
|
|
43
|
+
super().__init__(
|
|
44
|
+
name="parallel-test-generation",
|
|
45
|
+
description="Generate behavioral tests in parallel with AI completion",
|
|
46
|
+
stages={
|
|
47
|
+
"discover": WorkflowStage(
|
|
48
|
+
name="discover",
|
|
49
|
+
description="Find modules needing tests",
|
|
50
|
+
tier_hint=ModelTier.CHEAP,
|
|
51
|
+
system_prompt="Analyze coverage and prioritize modules for testing",
|
|
52
|
+
task_type="analysis",
|
|
53
|
+
),
|
|
54
|
+
"generate_templates": WorkflowStage(
|
|
55
|
+
name="generate_templates",
|
|
56
|
+
description="Generate test templates in parallel",
|
|
57
|
+
tier_hint=ModelTier.CHEAP,
|
|
58
|
+
system_prompt="Generate behavioral test template structure",
|
|
59
|
+
task_type="code_generation",
|
|
60
|
+
),
|
|
61
|
+
"complete_tests": WorkflowStage(
|
|
62
|
+
name="complete_tests",
|
|
63
|
+
description="Complete test implementation with AI",
|
|
64
|
+
tier_hint=ModelTier.CAPABLE,
|
|
65
|
+
system_prompt="""Complete the behavioral test implementation.
|
|
66
|
+
|
|
67
|
+
You are given a test template with TODO markers. Your task:
|
|
68
|
+
|
|
69
|
+
1. Analyze the module being tested
|
|
70
|
+
2. Create realistic test data
|
|
71
|
+
3. Add proper assertions
|
|
72
|
+
4. Test both success AND error paths
|
|
73
|
+
5. Use mocks/patches where needed
|
|
74
|
+
6. Follow pytest best practices
|
|
75
|
+
|
|
76
|
+
Generate complete, runnable tests that will increase coverage.""",
|
|
77
|
+
task_type="code_generation",
|
|
78
|
+
),
|
|
79
|
+
"validate": WorkflowStage(
|
|
80
|
+
name="validate",
|
|
81
|
+
description="Validate generated tests run correctly",
|
|
82
|
+
tier_hint=ModelTier.CHEAP,
|
|
83
|
+
system_prompt="Check if tests are valid Python and follow pytest conventions",
|
|
84
|
+
task_type="validation",
|
|
85
|
+
),
|
|
86
|
+
},
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
def discover_low_coverage_modules(self, top_n: int = 200) -> list[tuple[str, float]]:
|
|
90
|
+
"""Find modules with lowest coverage."""
|
|
91
|
+
try:
|
|
92
|
+
# Get coverage data
|
|
93
|
+
import subprocess
|
|
94
|
+
|
|
95
|
+
subprocess.run(
|
|
96
|
+
["coverage", "json", "-o", "/tmp/coverage_batch.json"],
|
|
97
|
+
capture_output=True,
|
|
98
|
+
check=True,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
with open("/tmp/coverage_batch.json") as f:
|
|
102
|
+
data = json.load(f)
|
|
103
|
+
|
|
104
|
+
coverage_by_file = []
|
|
105
|
+
for file_path, info in data.get("files", {}).items():
|
|
106
|
+
if file_path.startswith("src/"):
|
|
107
|
+
coverage_pct = info["summary"]["percent_covered"]
|
|
108
|
+
total_lines = info["summary"]["num_statements"]
|
|
109
|
+
|
|
110
|
+
# Skip very small files
|
|
111
|
+
if total_lines > 30:
|
|
112
|
+
coverage_by_file.append((file_path, coverage_pct, total_lines))
|
|
113
|
+
|
|
114
|
+
# Sort by coverage (lowest first), then by size (largest first)
|
|
115
|
+
sorted_modules = sorted(coverage_by_file, key=lambda x: (x[1], -x[2]))
|
|
116
|
+
|
|
117
|
+
return [(path, cov) for path, cov, _ in sorted_modules[:top_n]]
|
|
118
|
+
|
|
119
|
+
except Exception as e:
|
|
120
|
+
self.logger.warning(f"Could not get coverage data: {e}")
|
|
121
|
+
return []
|
|
122
|
+
|
|
123
|
+
def analyze_module_structure(self, file_path: str) -> dict[str, Any]:
|
|
124
|
+
"""Analyze module to extract structure (fast, synchronous)."""
|
|
125
|
+
try:
|
|
126
|
+
source = Path(file_path).read_text()
|
|
127
|
+
tree = ast.parse(source)
|
|
128
|
+
|
|
129
|
+
classes = []
|
|
130
|
+
functions = []
|
|
131
|
+
|
|
132
|
+
for node in ast.walk(tree):
|
|
133
|
+
if isinstance(node, ast.ClassDef):
|
|
134
|
+
methods = [
|
|
135
|
+
n.name
|
|
136
|
+
for n in node.body
|
|
137
|
+
if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))
|
|
138
|
+
]
|
|
139
|
+
classes.append(
|
|
140
|
+
{"name": node.name, "methods": methods, "line": node.lineno}
|
|
141
|
+
)
|
|
142
|
+
elif isinstance(node, ast.FunctionDef) and node.col_offset == 0:
|
|
143
|
+
functions.append({"name": node.name, "line": node.lineno})
|
|
144
|
+
|
|
145
|
+
return {"file": file_path, "classes": classes, "functions": functions}
|
|
146
|
+
|
|
147
|
+
except Exception as e:
|
|
148
|
+
return {"file": file_path, "error": str(e)}
|
|
149
|
+
|
|
150
|
+
async def generate_test_template_with_ai(
|
|
151
|
+
self, module_path: str, structure: dict[str, Any]
|
|
152
|
+
) -> str:
|
|
153
|
+
"""Generate test template using cheap tier AI."""
|
|
154
|
+
prompt = f"""Generate a behavioral test template for this module:
|
|
155
|
+
|
|
156
|
+
File: {module_path}
|
|
157
|
+
Structure: {json.dumps(structure, indent=2)}
|
|
158
|
+
|
|
159
|
+
Generate a pytest test file with:
|
|
160
|
+
1. Proper imports
|
|
161
|
+
2. Test classes for each class in the module
|
|
162
|
+
3. Test methods for key functionality
|
|
163
|
+
4. TODO markers where test logic is needed
|
|
164
|
+
5. Proper async/await for async methods
|
|
165
|
+
|
|
166
|
+
Output ONLY the Python code, no explanations."""
|
|
167
|
+
|
|
168
|
+
result = await self._call_llm(
|
|
169
|
+
tier=ModelTier.CHEAP,
|
|
170
|
+
user_prompt=prompt,
|
|
171
|
+
context={"module": module_path, "structure": structure},
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
return result.get("content", "")
|
|
175
|
+
|
|
176
|
+
async def complete_test_with_ai(self, template: str, module_path: str) -> str:
|
|
177
|
+
"""Complete test implementation using capable tier AI."""
|
|
178
|
+
source_code = Path(module_path).read_text()
|
|
179
|
+
|
|
180
|
+
prompt = f"""Complete this behavioral test implementation.
|
|
181
|
+
|
|
182
|
+
MODULE SOURCE CODE:
|
|
183
|
+
```python
|
|
184
|
+
{source_code[:5000]} # First 5000 chars
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
TEST TEMPLATE:
|
|
188
|
+
```python
|
|
189
|
+
{template}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Complete ALL TODOs with:
|
|
193
|
+
1. Realistic test data
|
|
194
|
+
2. Proper mocking where needed
|
|
195
|
+
3. Comprehensive assertions
|
|
196
|
+
4. Both success and error cases
|
|
197
|
+
|
|
198
|
+
Output the COMPLETE test file, no TODOs remaining."""
|
|
199
|
+
|
|
200
|
+
result = await self._call_llm(
|
|
201
|
+
tier=ModelTier.CAPABLE,
|
|
202
|
+
user_prompt=prompt,
|
|
203
|
+
context={"template": template, "module": module_path},
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
return result.get("content", "")
|
|
207
|
+
|
|
208
|
+
async def process_module_batch(
|
|
209
|
+
self, modules: list[tuple[str, float]], output_dir: Path, batch_size: int = 10
|
|
210
|
+
) -> list[TestGenerationTask]:
|
|
211
|
+
"""Process modules in parallel batches."""
|
|
212
|
+
tasks = []
|
|
213
|
+
|
|
214
|
+
# Create tasks
|
|
215
|
+
for module_path, coverage in modules:
|
|
216
|
+
test_filename = f"test_{Path(module_path).stem}_behavioral.py"
|
|
217
|
+
output_path = output_dir / test_filename
|
|
218
|
+
|
|
219
|
+
tasks.append(
|
|
220
|
+
TestGenerationTask(
|
|
221
|
+
module_path=module_path,
|
|
222
|
+
coverage=coverage,
|
|
223
|
+
output_path=str(output_path),
|
|
224
|
+
)
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Process in batches
|
|
228
|
+
for i in range(0, len(tasks), batch_size):
|
|
229
|
+
batch = tasks[i : i + batch_size]
|
|
230
|
+
|
|
231
|
+
# Generate templates in parallel
|
|
232
|
+
template_coros = []
|
|
233
|
+
for task in batch:
|
|
234
|
+
structure = self.analyze_module_structure(task.module_path)
|
|
235
|
+
coro = self.generate_test_template_with_ai(task.module_path, structure)
|
|
236
|
+
template_coros.append(coro)
|
|
237
|
+
|
|
238
|
+
templates = await asyncio.gather(*template_coros, return_exceptions=True)
|
|
239
|
+
|
|
240
|
+
# Complete tests in parallel
|
|
241
|
+
completion_coros = []
|
|
242
|
+
for task, template in zip(batch, templates, strict=False):
|
|
243
|
+
if isinstance(template, Exception):
|
|
244
|
+
task.status = "error"
|
|
245
|
+
continue
|
|
246
|
+
|
|
247
|
+
coro = self.complete_test_with_ai(template, task.module_path)
|
|
248
|
+
completion_coros.append(coro)
|
|
249
|
+
|
|
250
|
+
completed = await asyncio.gather(*completion_coros, return_exceptions=True)
|
|
251
|
+
|
|
252
|
+
# Save results
|
|
253
|
+
for task, completed_test in zip(batch, completed, strict=False):
|
|
254
|
+
if isinstance(completed_test, Exception):
|
|
255
|
+
task.status = "error"
|
|
256
|
+
continue
|
|
257
|
+
|
|
258
|
+
# Extract code from markdown if needed
|
|
259
|
+
code = self._extract_code(completed_test)
|
|
260
|
+
|
|
261
|
+
# Save to file
|
|
262
|
+
Path(task.output_path).write_text(code)
|
|
263
|
+
task.status = "completed"
|
|
264
|
+
|
|
265
|
+
self.logger.info(f"✅ Generated: {task.output_path}")
|
|
266
|
+
|
|
267
|
+
return tasks
|
|
268
|
+
|
|
269
|
+
def _extract_code(self, content: str) -> str:
|
|
270
|
+
"""Extract Python code from markdown code blocks if present."""
|
|
271
|
+
if "```python" in content:
|
|
272
|
+
parts = content.split("```python")
|
|
273
|
+
if len(parts) > 1:
|
|
274
|
+
code = parts[1].split("```")[0]
|
|
275
|
+
return code.strip()
|
|
276
|
+
|
|
277
|
+
# If no markdown, assume it's already code
|
|
278
|
+
return content
|
|
279
|
+
|
|
280
|
+
async def execute(
|
|
281
|
+
self, top: int = 200, batch_size: int = 10, output_dir: str = "tests/behavioral/generated", **kwargs
|
|
282
|
+
) -> WorkflowResult:
|
|
283
|
+
"""Execute parallel test generation workflow.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
top: Number of modules to process
|
|
287
|
+
batch_size: Number of modules to process in parallel (10-50 recommended)
|
|
288
|
+
output_dir: Where to save generated tests
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
WorkflowResult with generated file paths and statistics
|
|
292
|
+
"""
|
|
293
|
+
output_path = Path(output_dir)
|
|
294
|
+
output_path.mkdir(exist_ok=True, parents=True)
|
|
295
|
+
|
|
296
|
+
# Stage 1: Discover modules
|
|
297
|
+
self.logger.info(f"🔍 Discovering top {top} modules with lowest coverage...")
|
|
298
|
+
modules = self.discover_low_coverage_modules(top_n=top)
|
|
299
|
+
|
|
300
|
+
if not modules:
|
|
301
|
+
return WorkflowResult(
|
|
302
|
+
workflow_name=self.name,
|
|
303
|
+
stages_executed=["discover"],
|
|
304
|
+
final_output={"error": "No coverage data found. Run pytest with coverage first."},
|
|
305
|
+
cost_report=self._generate_cost_report(),
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
self.logger.info(f"📋 Found {len(modules)} modules to process")
|
|
309
|
+
|
|
310
|
+
# Stage 2 & 3: Generate and complete in parallel batches
|
|
311
|
+
self.logger.info(f"⚡ Processing in batches of {batch_size}...")
|
|
312
|
+
tasks = await self.process_module_batch(modules, output_path, batch_size=batch_size)
|
|
313
|
+
|
|
314
|
+
# Statistics
|
|
315
|
+
completed = [t for t in tasks if t.status == "completed"]
|
|
316
|
+
errors = [t for t in tasks if t.status == "error"]
|
|
317
|
+
|
|
318
|
+
result_data = {
|
|
319
|
+
"total_modules": len(modules),
|
|
320
|
+
"completed": len(completed),
|
|
321
|
+
"errors": len(errors),
|
|
322
|
+
"output_dir": str(output_path),
|
|
323
|
+
"generated_files": [t.output_path for t in completed],
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
self.logger.info(f"\n{'='*80}")
|
|
327
|
+
self.logger.info(f"✅ COMPLETED: {len(completed)} test files")
|
|
328
|
+
self.logger.info(f"❌ ERRORS: {len(errors)} modules")
|
|
329
|
+
self.logger.info(f"📁 Location: {output_path}")
|
|
330
|
+
self.logger.info(f"{'='*80}\n")
|
|
331
|
+
|
|
332
|
+
return WorkflowResult(
|
|
333
|
+
workflow_name=self.name,
|
|
334
|
+
stages_executed=["discover", "generate_templates", "complete_tests"],
|
|
335
|
+
final_output=result_data,
|
|
336
|
+
cost_report=self._generate_cost_report(),
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
# Export
|
|
341
|
+
__all__ = ["ParallelTestGenerationWorkflow"]
|