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,423 @@
|
|
|
1
|
+
"""Wizard-to-Agent Bridge Adapter
|
|
2
|
+
|
|
3
|
+
Bridges existing wizards to the Agent Factory interface, allowing
|
|
4
|
+
wizards to be used in Agent Factory workflows and pipelines.
|
|
5
|
+
|
|
6
|
+
This enables:
|
|
7
|
+
- Using existing wizards in Agent Factory workflows
|
|
8
|
+
- Combining wizards with other agents
|
|
9
|
+
- Applying model tier routing to wizard operations
|
|
10
|
+
- Cost tracking for wizard calls
|
|
11
|
+
|
|
12
|
+
Copyright 2025 Smart-AI-Memory
|
|
13
|
+
Licensed under Fair Source License 0.9
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
|
|
18
|
+
from attune_llm.agent_factory.base import (
|
|
19
|
+
AgentConfig,
|
|
20
|
+
AgentRole,
|
|
21
|
+
BaseAdapter,
|
|
22
|
+
BaseAgent,
|
|
23
|
+
BaseWorkflow,
|
|
24
|
+
WorkflowConfig,
|
|
25
|
+
)
|
|
26
|
+
from attune_llm.agent_factory.decorators import log_performance, safe_agent_operation
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class WizardAgent(BaseAgent):
|
|
32
|
+
"""Agent wrapper for existing wizards.
|
|
33
|
+
|
|
34
|
+
Adapts the wizard's analyze() method to the Agent Factory
|
|
35
|
+
invoke() interface.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, wizard, config: AgentConfig):
|
|
39
|
+
"""Initialize wizard agent.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
wizard: Wizard instance (must have analyze() method)
|
|
43
|
+
config: Agent configuration
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
super().__init__(config)
|
|
47
|
+
self._wizard = wizard
|
|
48
|
+
|
|
49
|
+
# Extract wizard properties
|
|
50
|
+
self._wizard_name = getattr(wizard, "name", wizard.__class__.__name__)
|
|
51
|
+
self._wizard_level = getattr(wizard, "level", 4)
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def wizard(self):
|
|
55
|
+
"""Get the underlying wizard."""
|
|
56
|
+
return self._wizard
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def wizard_level(self) -> int:
|
|
60
|
+
"""Get the wizard's empathy level."""
|
|
61
|
+
return self._wizard_level
|
|
62
|
+
|
|
63
|
+
@safe_agent_operation("wizard_invoke")
|
|
64
|
+
@log_performance(threshold_seconds=5.0)
|
|
65
|
+
async def invoke(self, input_data: str | dict, context: dict | None = None) -> dict:
|
|
66
|
+
"""Invoke the wizard.
|
|
67
|
+
|
|
68
|
+
Transforms input to wizard format, calls analyze(),
|
|
69
|
+
and transforms output to Agent Factory format.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
input_data: String query or dict with input
|
|
73
|
+
context: Optional additional context
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Dict with output, metadata, predictions, recommendations
|
|
77
|
+
|
|
78
|
+
"""
|
|
79
|
+
# Build wizard context
|
|
80
|
+
wizard_context = context.copy() if context else {}
|
|
81
|
+
|
|
82
|
+
if isinstance(input_data, str):
|
|
83
|
+
wizard_context["input"] = input_data
|
|
84
|
+
wizard_context["query"] = input_data
|
|
85
|
+
else:
|
|
86
|
+
wizard_context.update(input_data)
|
|
87
|
+
|
|
88
|
+
# Add agent metadata
|
|
89
|
+
wizard_context["agent_name"] = self.name
|
|
90
|
+
wizard_context["agent_role"] = self.role.value
|
|
91
|
+
|
|
92
|
+
# Add conversation history if available
|
|
93
|
+
if self._conversation_history:
|
|
94
|
+
wizard_context["conversation_history"] = self._conversation_history[-10:]
|
|
95
|
+
|
|
96
|
+
# Call wizard analyze
|
|
97
|
+
result = await self._wizard.analyze(wizard_context)
|
|
98
|
+
|
|
99
|
+
# Transform to Agent Factory format
|
|
100
|
+
output = self._extract_output(result)
|
|
101
|
+
|
|
102
|
+
# Track conversation
|
|
103
|
+
user_input = wizard_context.get("input", wizard_context.get("query", str(input_data)))
|
|
104
|
+
self._conversation_history.append({"role": "user", "content": user_input})
|
|
105
|
+
self._conversation_history.append({"role": "assistant", "content": str(output)})
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
"output": output,
|
|
109
|
+
"metadata": {
|
|
110
|
+
"wizard": self._wizard_name,
|
|
111
|
+
"level": self._wizard_level,
|
|
112
|
+
"confidence": result.get("confidence", 0.0),
|
|
113
|
+
"from_cache": result.get("_from_cache", False),
|
|
114
|
+
"model": self.model,
|
|
115
|
+
},
|
|
116
|
+
"predictions": result.get("predictions", []),
|
|
117
|
+
"recommendations": result.get("recommendations", []),
|
|
118
|
+
"patterns": result.get("patterns", []),
|
|
119
|
+
"raw_result": result,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
def _extract_output(self, result: dict) -> str:
|
|
123
|
+
"""Extract the main output from wizard result.
|
|
124
|
+
|
|
125
|
+
Wizards return various formats, so we need to normalize.
|
|
126
|
+
"""
|
|
127
|
+
# Try common output keys
|
|
128
|
+
for key in ["output", "response", "result", "analysis", "summary"]:
|
|
129
|
+
if result.get(key):
|
|
130
|
+
value = result[key]
|
|
131
|
+
if isinstance(value, str):
|
|
132
|
+
return value
|
|
133
|
+
if isinstance(value, list):
|
|
134
|
+
return "\n".join(str(item) for item in value)
|
|
135
|
+
return str(value)
|
|
136
|
+
|
|
137
|
+
# Fall back to recommendations
|
|
138
|
+
if "recommendations" in result:
|
|
139
|
+
recs = result["recommendations"]
|
|
140
|
+
if isinstance(recs, list):
|
|
141
|
+
return "\n".join(f"- {r}" for r in recs)
|
|
142
|
+
|
|
143
|
+
# Last resort: stringify the result
|
|
144
|
+
return str(result)
|
|
145
|
+
|
|
146
|
+
async def stream(self, input_data: str | dict, context: dict | None = None):
|
|
147
|
+
"""Stream wizard response.
|
|
148
|
+
|
|
149
|
+
Most wizards don't support streaming, so we yield the full response.
|
|
150
|
+
"""
|
|
151
|
+
result = await self.invoke(input_data, context)
|
|
152
|
+
yield result
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class WizardWorkflow(BaseWorkflow):
|
|
156
|
+
"""Workflow for chaining multiple wizards.
|
|
157
|
+
|
|
158
|
+
Allows wizards to be composed into pipelines where
|
|
159
|
+
the output of one feeds into the next.
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
async def run(self, input_data: str | dict, initial_state: dict | None = None) -> dict:
|
|
163
|
+
"""Run the wizard workflow.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
input_data: Initial input
|
|
167
|
+
initial_state: Optional starting state
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Combined results from all wizards
|
|
171
|
+
|
|
172
|
+
"""
|
|
173
|
+
self._state = initial_state or {}
|
|
174
|
+
self._state["input"] = input_data
|
|
175
|
+
|
|
176
|
+
results: list[dict] = []
|
|
177
|
+
current_input = input_data
|
|
178
|
+
|
|
179
|
+
for agent in self.agents.values():
|
|
180
|
+
# Build context with previous results
|
|
181
|
+
context = {
|
|
182
|
+
"previous_results": results,
|
|
183
|
+
"state": self._state,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
# Invoke wizard agent
|
|
187
|
+
result = await agent.invoke(current_input, context)
|
|
188
|
+
result["agent"] = agent.name
|
|
189
|
+
results.append(result)
|
|
190
|
+
|
|
191
|
+
# Pass output to next wizard
|
|
192
|
+
current_input = result.get("output", "")
|
|
193
|
+
|
|
194
|
+
# Collect predictions and recommendations
|
|
195
|
+
self._state.setdefault("all_predictions", []).extend(result.get("predictions", []))
|
|
196
|
+
self._state.setdefault("all_recommendations", []).extend(
|
|
197
|
+
result.get("recommendations", []),
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Build final output
|
|
201
|
+
self._state["results"] = results
|
|
202
|
+
self._state["final_output"] = results[-1]["output"] if results else ""
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
"output": self._state["final_output"],
|
|
206
|
+
"results": results,
|
|
207
|
+
"state": self._state,
|
|
208
|
+
"agents_invoked": [r.get("agent") for r in results],
|
|
209
|
+
"all_predictions": self._state.get("all_predictions", []),
|
|
210
|
+
"all_recommendations": self._state.get("all_recommendations", []),
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async def stream(self, input_data: str | dict, initial_state: dict | None = None):
|
|
214
|
+
"""Stream workflow execution."""
|
|
215
|
+
self._state = initial_state or {}
|
|
216
|
+
self._state["input"] = input_data
|
|
217
|
+
|
|
218
|
+
for agent in self.agents.values():
|
|
219
|
+
context = {"state": self._state}
|
|
220
|
+
yield {"event": "wizard_start", "wizard": agent.name}
|
|
221
|
+
|
|
222
|
+
# agent.stream returns an async generator
|
|
223
|
+
stream_gen = agent.stream(input_data, context)
|
|
224
|
+
async for chunk in stream_gen: # type: ignore[attr-defined]
|
|
225
|
+
yield {"event": "wizard_output", "wizard": agent.name, "data": chunk}
|
|
226
|
+
|
|
227
|
+
yield {"event": "wizard_end", "wizard": agent.name}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class WizardAdapter(BaseAdapter):
|
|
231
|
+
"""Adapter for integrating wizards with Agent Factory.
|
|
232
|
+
|
|
233
|
+
Allows existing wizards to be used as agents in the
|
|
234
|
+
Agent Factory ecosystem.
|
|
235
|
+
|
|
236
|
+
Example:
|
|
237
|
+
adapter = WizardAdapter()
|
|
238
|
+
|
|
239
|
+
# Wrap a wizard instance
|
|
240
|
+
wizard = MyCustomWizard()
|
|
241
|
+
agent = adapter.create_agent_from_wizard(
|
|
242
|
+
wizard,
|
|
243
|
+
name="my_wizard",
|
|
244
|
+
model_tier="capable"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
# Use in workflow
|
|
248
|
+
result = await agent.invoke({"input": data})
|
|
249
|
+
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
def __init__(self, provider: str = "anthropic", api_key: str | None = None):
|
|
253
|
+
"""Initialize wizard adapter.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
provider: LLM provider (for model tier resolution)
|
|
257
|
+
api_key: API key (uses env var if not provided)
|
|
258
|
+
|
|
259
|
+
"""
|
|
260
|
+
self.provider = provider
|
|
261
|
+
self.api_key = api_key
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def framework_name(self) -> str:
|
|
265
|
+
return "wizard"
|
|
266
|
+
|
|
267
|
+
def is_available(self) -> bool:
|
|
268
|
+
"""Wizard adapter is always available."""
|
|
269
|
+
return True
|
|
270
|
+
|
|
271
|
+
def create_agent(self, config: AgentConfig) -> WizardAgent:
|
|
272
|
+
"""Create a wizard agent from config.
|
|
273
|
+
|
|
274
|
+
Note: This requires a wizard instance in config.framework_options.
|
|
275
|
+
|
|
276
|
+
Args:
|
|
277
|
+
config: Agent configuration with wizard in framework_options
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
WizardAgent instance
|
|
281
|
+
|
|
282
|
+
"""
|
|
283
|
+
wizard = config.framework_options.get("wizard")
|
|
284
|
+
if wizard is None:
|
|
285
|
+
raise ValueError(
|
|
286
|
+
"Wizard instance required in config.framework_options['wizard']. "
|
|
287
|
+
"Use create_agent_from_wizard() for easier wizard wrapping.",
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
return WizardAgent(wizard, config)
|
|
291
|
+
|
|
292
|
+
def create_agent_from_wizard(
|
|
293
|
+
self,
|
|
294
|
+
wizard,
|
|
295
|
+
name: str | None = None,
|
|
296
|
+
role: AgentRole | str = AgentRole.CUSTOM,
|
|
297
|
+
model_tier: str = "capable",
|
|
298
|
+
**kwargs,
|
|
299
|
+
) -> WizardAgent:
|
|
300
|
+
"""Create an agent from a wizard instance.
|
|
301
|
+
|
|
302
|
+
This is the preferred method for wrapping wizards.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
wizard: Wizard instance
|
|
306
|
+
name: Agent name (defaults to wizard name)
|
|
307
|
+
role: Agent role
|
|
308
|
+
model_tier: Model tier for LLM calls
|
|
309
|
+
**kwargs: Additional AgentConfig options
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
WizardAgent wrapping the wizard
|
|
313
|
+
|
|
314
|
+
"""
|
|
315
|
+
# Get wizard name
|
|
316
|
+
wizard_name = getattr(wizard, "name", wizard.__class__.__name__)
|
|
317
|
+
agent_name = name or wizard_name.lower().replace(" ", "_")
|
|
318
|
+
|
|
319
|
+
# Get wizard empathy level
|
|
320
|
+
wizard_level = getattr(wizard, "level", 4)
|
|
321
|
+
|
|
322
|
+
# Parse role
|
|
323
|
+
if isinstance(role, str):
|
|
324
|
+
try:
|
|
325
|
+
role = AgentRole(role.lower())
|
|
326
|
+
except ValueError:
|
|
327
|
+
role = AgentRole.CUSTOM
|
|
328
|
+
|
|
329
|
+
# Build config
|
|
330
|
+
config = AgentConfig(
|
|
331
|
+
name=agent_name,
|
|
332
|
+
role=role,
|
|
333
|
+
description=f"Agent wrapping {wizard_name}",
|
|
334
|
+
model_tier=model_tier,
|
|
335
|
+
empathy_level=wizard_level,
|
|
336
|
+
framework_options={"wizard": wizard},
|
|
337
|
+
**kwargs,
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
return WizardAgent(wizard, config)
|
|
341
|
+
|
|
342
|
+
def create_agent_from_wizard_class(
|
|
343
|
+
self,
|
|
344
|
+
wizard_class: type,
|
|
345
|
+
name: str | None = None,
|
|
346
|
+
wizard_kwargs: dict | None = None,
|
|
347
|
+
**agent_kwargs,
|
|
348
|
+
) -> WizardAgent:
|
|
349
|
+
"""Create an agent from a wizard class.
|
|
350
|
+
|
|
351
|
+
Instantiates the wizard and wraps it.
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
wizard_class: Wizard class to instantiate
|
|
355
|
+
name: Agent name
|
|
356
|
+
wizard_kwargs: Arguments for wizard constructor
|
|
357
|
+
**agent_kwargs: Arguments for create_agent_from_wizard
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
WizardAgent instance
|
|
361
|
+
|
|
362
|
+
"""
|
|
363
|
+
wizard_kwargs = wizard_kwargs or {}
|
|
364
|
+
wizard = wizard_class(**wizard_kwargs)
|
|
365
|
+
|
|
366
|
+
return self.create_agent_from_wizard(wizard, name=name, **agent_kwargs)
|
|
367
|
+
|
|
368
|
+
def create_workflow(self, config: WorkflowConfig, agents: list[BaseAgent]) -> WizardWorkflow:
|
|
369
|
+
"""Create a workflow from wizard agents.
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
config: Workflow configuration
|
|
373
|
+
agents: List of wizard agents
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
WizardWorkflow instance
|
|
377
|
+
|
|
378
|
+
"""
|
|
379
|
+
return WizardWorkflow(config, agents)
|
|
380
|
+
|
|
381
|
+
def create_tool(
|
|
382
|
+
self,
|
|
383
|
+
name: str,
|
|
384
|
+
description: str,
|
|
385
|
+
func,
|
|
386
|
+
args_schema: dict | None = None,
|
|
387
|
+
) -> dict:
|
|
388
|
+
"""Create a tool dict (wizards don't use tools directly).
|
|
389
|
+
|
|
390
|
+
Returns a tool dict for documentation purposes.
|
|
391
|
+
"""
|
|
392
|
+
return {
|
|
393
|
+
"name": name,
|
|
394
|
+
"description": description,
|
|
395
|
+
"func": func,
|
|
396
|
+
"args_schema": args_schema,
|
|
397
|
+
"note": "Wizards typically don't use external tools",
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
# Convenience function for quick wizard wrapping
|
|
402
|
+
def wrap_wizard(wizard, name: str | None = None, model_tier: str = "capable") -> WizardAgent:
|
|
403
|
+
"""Quick helper to wrap a wizard as an agent.
|
|
404
|
+
|
|
405
|
+
Args:
|
|
406
|
+
wizard: Wizard instance
|
|
407
|
+
name: Optional agent name
|
|
408
|
+
model_tier: Model tier
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
WizardAgent instance
|
|
412
|
+
|
|
413
|
+
Example:
|
|
414
|
+
from attune_llm.agent_factory.adapters.wizard_adapter import wrap_wizard
|
|
415
|
+
|
|
416
|
+
my_wizard = MyCustomWizard()
|
|
417
|
+
agent = wrap_wizard(my_wizard, model_tier="capable")
|
|
418
|
+
|
|
419
|
+
result = await agent.invoke({"input": data})
|
|
420
|
+
|
|
421
|
+
"""
|
|
422
|
+
adapter = WizardAdapter()
|
|
423
|
+
return adapter.create_agent_from_wizard(wizard, name=name, model_tier=model_tier)
|