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,32 @@
|
|
|
1
|
+
"""Empathy Framework Model Routing
|
|
2
|
+
|
|
3
|
+
Smart routing of tasks to appropriate model tiers for cost optimization:
|
|
4
|
+
- CHEAP tier: Triage, summarization, classification (Haiku/GPT-4o-mini)
|
|
5
|
+
- CAPABLE tier: Code generation, analysis, sub-agent work (Sonnet/GPT-4o)
|
|
6
|
+
- PREMIUM tier: Coordination, synthesis, critical decisions (Opus/o1)
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
>>> from attune_llm.routing import ModelRouter
|
|
10
|
+
>>>
|
|
11
|
+
>>> router = ModelRouter()
|
|
12
|
+
>>> model = router.route("summarize", provider="anthropic")
|
|
13
|
+
>>> print(model) # claude-3-5-haiku-20241022
|
|
14
|
+
>>>
|
|
15
|
+
>>> model = router.route("coordinate", provider="anthropic")
|
|
16
|
+
>>> print(model) # claude-opus-4-20250514
|
|
17
|
+
>>>
|
|
18
|
+
>>> cost = router.estimate_cost("fix_bug", input_tokens=5000, output_tokens=1000)
|
|
19
|
+
>>> print(f"Estimated cost: ${cost:.4f}")
|
|
20
|
+
|
|
21
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
22
|
+
Licensed under Fair Source 0.9
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from .model_router import ModelRouter, ModelTier, TaskRouting
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"ModelRouter",
|
|
30
|
+
"ModelTier",
|
|
31
|
+
"TaskRouting",
|
|
32
|
+
]
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
"""Smart Model Router for Empathy Framework
|
|
2
|
+
|
|
3
|
+
Routes tasks to appropriate model tiers for optimal cost/quality tradeoff:
|
|
4
|
+
|
|
5
|
+
TIER 1 - CHEAP (Haiku / GPT-4o-mini / Local Ollama):
|
|
6
|
+
Cost: ~$0.25/M input, $1.25/M output
|
|
7
|
+
Use for: Triage, classification, summarization, simple analysis
|
|
8
|
+
|
|
9
|
+
TIER 2 - CAPABLE (Sonnet / GPT-4o):
|
|
10
|
+
Cost: ~$3/M input, $15/M output
|
|
11
|
+
Use for: Code generation, bug fixes, security review, sub-agent work
|
|
12
|
+
|
|
13
|
+
TIER 3 - PREMIUM (Opus / o1):
|
|
14
|
+
Cost: ~$15/M input, $75/M output
|
|
15
|
+
Use for: Coordination, synthesis, architectural decisions, critical work
|
|
16
|
+
|
|
17
|
+
Cost Savings Example:
|
|
18
|
+
WITHOUT routing (all Opus): $4.05 per complex task
|
|
19
|
+
WITH routing (tiered): $0.83 per complex task
|
|
20
|
+
SAVINGS: 80% reduction, ~$9,660/month at 100 tasks/day
|
|
21
|
+
|
|
22
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
23
|
+
Licensed under Fair Source 0.9
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from dataclasses import dataclass
|
|
27
|
+
from enum import Enum
|
|
28
|
+
from typing import Any
|
|
29
|
+
|
|
30
|
+
# Import from unified registry
|
|
31
|
+
from attune.models import MODEL_REGISTRY, ModelInfo
|
|
32
|
+
from attune.models.tasks import CAPABLE_TASKS, CHEAP_TASKS, PREMIUM_TASKS, get_tier_for_task
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ModelTier(Enum):
|
|
36
|
+
"""Model tier classification for routing.
|
|
37
|
+
|
|
38
|
+
CHEAP: Fast, low-cost models for simple tasks
|
|
39
|
+
CAPABLE: Balanced models for most development work
|
|
40
|
+
PREMIUM: Highest capability for complex reasoning
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
CHEAP = "cheap"
|
|
44
|
+
CAPABLE = "capable"
|
|
45
|
+
PREMIUM = "premium"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class ModelConfig:
|
|
50
|
+
"""Configuration for a model in a tier.
|
|
51
|
+
|
|
52
|
+
Note: This class is kept for backward compatibility. New code should
|
|
53
|
+
use attune.models.ModelInfo from the unified registry.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
model_id: str
|
|
57
|
+
cost_per_1k_input: float
|
|
58
|
+
cost_per_1k_output: float
|
|
59
|
+
max_tokens: int = 4096
|
|
60
|
+
supports_tools: bool = True
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def from_model_info(cls, info: ModelInfo) -> "ModelConfig":
|
|
64
|
+
"""Create ModelConfig from unified ModelInfo."""
|
|
65
|
+
return cls(
|
|
66
|
+
model_id=info.id,
|
|
67
|
+
cost_per_1k_input=info.cost_per_1k_input,
|
|
68
|
+
cost_per_1k_output=info.cost_per_1k_output,
|
|
69
|
+
max_tokens=info.max_tokens,
|
|
70
|
+
supports_tools=info.supports_tools,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class TaskRouting:
|
|
75
|
+
"""Task type to model tier mappings.
|
|
76
|
+
|
|
77
|
+
Maps task types to appropriate model tiers based on:
|
|
78
|
+
- Complexity requirements
|
|
79
|
+
- Cost sensitivity
|
|
80
|
+
- Quality needs
|
|
81
|
+
|
|
82
|
+
Note: Task definitions are sourced from attune.models.tasks
|
|
83
|
+
for consistency across the framework.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
# Tasks imported from shared module
|
|
87
|
+
CHEAP_TASKS = CHEAP_TASKS
|
|
88
|
+
CAPABLE_TASKS = CAPABLE_TASKS
|
|
89
|
+
PREMIUM_TASKS = PREMIUM_TASKS
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def get_tier(cls, task_type: str) -> ModelTier:
|
|
93
|
+
"""Get the appropriate tier for a task type.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
task_type: Type of task to route
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
ModelTier for the task
|
|
100
|
+
|
|
101
|
+
"""
|
|
102
|
+
# Delegate to shared module
|
|
103
|
+
tier = get_tier_for_task(task_type)
|
|
104
|
+
# Convert from registry ModelTier to local ModelTier
|
|
105
|
+
return ModelTier(tier.value)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class ModelRouter:
|
|
109
|
+
"""Smart model router for cost-optimized task execution.
|
|
110
|
+
|
|
111
|
+
Routes tasks to appropriate model tiers based on complexity and
|
|
112
|
+
cost requirements. Supports Anthropic, OpenAI, and Ollama providers.
|
|
113
|
+
|
|
114
|
+
Model configurations are sourced from the unified registry at
|
|
115
|
+
attune.models.MODEL_REGISTRY.
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
>>> router = ModelRouter()
|
|
119
|
+
>>>
|
|
120
|
+
>>> # Get model for task
|
|
121
|
+
>>> model = router.route("summarize") # Returns cheap model
|
|
122
|
+
>>> model = router.route("fix_bug") # Returns capable model
|
|
123
|
+
>>> model = router.route("coordinate") # Returns premium model
|
|
124
|
+
>>>
|
|
125
|
+
>>> # Estimate costs
|
|
126
|
+
>>> cost = router.estimate_cost("fix_bug", 5000, 1000)
|
|
127
|
+
>>> print(f"Estimated: ${cost:.4f}")
|
|
128
|
+
>>>
|
|
129
|
+
>>> # Custom routing
|
|
130
|
+
>>> router.add_task_routing("my_task", ModelTier.PREMIUM)
|
|
131
|
+
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
# MODELS is now sourced from the unified registry
|
|
135
|
+
# This is built lazily and cached at the class level for backward compatibility
|
|
136
|
+
MODELS: dict[str, dict[str, ModelConfig]] = {} # Populated in _ensure_models_loaded
|
|
137
|
+
|
|
138
|
+
@classmethod
|
|
139
|
+
def _ensure_models_loaded(cls) -> None:
|
|
140
|
+
"""Ensure MODELS is populated from registry (called lazily)."""
|
|
141
|
+
if not cls.MODELS:
|
|
142
|
+
for provider, tiers in MODEL_REGISTRY.items():
|
|
143
|
+
cls.MODELS[provider] = {}
|
|
144
|
+
for tier, info in tiers.items():
|
|
145
|
+
cls.MODELS[provider][tier] = ModelConfig.from_model_info(info)
|
|
146
|
+
|
|
147
|
+
def __init__(
|
|
148
|
+
self,
|
|
149
|
+
default_provider: str = "anthropic",
|
|
150
|
+
custom_routing: dict[str, ModelTier] | None = None,
|
|
151
|
+
):
|
|
152
|
+
"""Initialize the model router.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
default_provider: Default provider (anthropic, openai, ollama, hybrid)
|
|
156
|
+
custom_routing: Custom task type to tier mappings
|
|
157
|
+
|
|
158
|
+
"""
|
|
159
|
+
# Ensure class-level MODELS is populated from registry
|
|
160
|
+
self._ensure_models_loaded()
|
|
161
|
+
|
|
162
|
+
self._default_provider = default_provider
|
|
163
|
+
self._custom_routing: dict[str, ModelTier] = custom_routing or {}
|
|
164
|
+
|
|
165
|
+
def route(
|
|
166
|
+
self,
|
|
167
|
+
task_type: str,
|
|
168
|
+
provider: str | None = None,
|
|
169
|
+
) -> str:
|
|
170
|
+
"""Route a task to the appropriate model.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
task_type: Type of task (e.g., "summarize", "fix_bug", "coordinate")
|
|
174
|
+
provider: Optional provider override
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Model ID string
|
|
178
|
+
|
|
179
|
+
Example:
|
|
180
|
+
>>> router.route("summarize")
|
|
181
|
+
'claude-3-5-haiku-20241022'
|
|
182
|
+
>>> router.route("fix_bug")
|
|
183
|
+
'claude-sonnet-4-5-20250514'
|
|
184
|
+
>>> router.route("coordinate")
|
|
185
|
+
'claude-opus-4-5-20251101'
|
|
186
|
+
|
|
187
|
+
"""
|
|
188
|
+
provider = provider or self._default_provider
|
|
189
|
+
tier = self._get_tier(task_type)
|
|
190
|
+
|
|
191
|
+
if provider not in self.MODELS:
|
|
192
|
+
raise ValueError(f"Unknown provider: {provider}. Available: {list(self.MODELS.keys())}")
|
|
193
|
+
|
|
194
|
+
config = self.MODELS[provider].get(tier.value)
|
|
195
|
+
if not config:
|
|
196
|
+
# Fallback to capable
|
|
197
|
+
config = self.MODELS[provider]["capable"]
|
|
198
|
+
|
|
199
|
+
return config.model_id
|
|
200
|
+
|
|
201
|
+
def get_config(
|
|
202
|
+
self,
|
|
203
|
+
task_type: str,
|
|
204
|
+
provider: str | None = None,
|
|
205
|
+
) -> ModelConfig:
|
|
206
|
+
"""Get full model configuration for a task.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
task_type: Type of task
|
|
210
|
+
provider: Optional provider override
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
ModelConfig with model_id, costs, and limits
|
|
214
|
+
|
|
215
|
+
"""
|
|
216
|
+
provider = provider or self._default_provider
|
|
217
|
+
tier = self._get_tier(task_type)
|
|
218
|
+
|
|
219
|
+
return self.MODELS[provider][tier.value]
|
|
220
|
+
|
|
221
|
+
def estimate_cost(
|
|
222
|
+
self,
|
|
223
|
+
task_type: str,
|
|
224
|
+
input_tokens: int,
|
|
225
|
+
output_tokens: int,
|
|
226
|
+
provider: str | None = None,
|
|
227
|
+
) -> float:
|
|
228
|
+
"""Estimate cost for a task.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
task_type: Type of task
|
|
232
|
+
input_tokens: Estimated input tokens
|
|
233
|
+
output_tokens: Estimated output tokens
|
|
234
|
+
provider: Optional provider override
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
Estimated cost in dollars
|
|
238
|
+
|
|
239
|
+
Example:
|
|
240
|
+
>>> router.estimate_cost("fix_bug", 5000, 1000)
|
|
241
|
+
0.03 # $0.03 for capable tier
|
|
242
|
+
|
|
243
|
+
"""
|
|
244
|
+
config = self.get_config(task_type, provider)
|
|
245
|
+
|
|
246
|
+
input_cost = (input_tokens / 1000) * config.cost_per_1k_input
|
|
247
|
+
output_cost = (output_tokens / 1000) * config.cost_per_1k_output
|
|
248
|
+
|
|
249
|
+
return input_cost + output_cost
|
|
250
|
+
|
|
251
|
+
def compare_costs(
|
|
252
|
+
self,
|
|
253
|
+
task_type: str,
|
|
254
|
+
input_tokens: int,
|
|
255
|
+
output_tokens: int,
|
|
256
|
+
) -> dict[str, float]:
|
|
257
|
+
"""Compare costs across all tiers for a task.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
task_type: Type of task
|
|
261
|
+
input_tokens: Estimated input tokens
|
|
262
|
+
output_tokens: Estimated output tokens
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
Dict mapping tier to estimated cost
|
|
266
|
+
|
|
267
|
+
"""
|
|
268
|
+
provider = self._default_provider
|
|
269
|
+
costs = {}
|
|
270
|
+
|
|
271
|
+
for tier_name in ["cheap", "capable", "premium"]:
|
|
272
|
+
config = self.MODELS[provider][tier_name]
|
|
273
|
+
input_cost = (input_tokens / 1000) * config.cost_per_1k_input
|
|
274
|
+
output_cost = (output_tokens / 1000) * config.cost_per_1k_output
|
|
275
|
+
costs[tier_name] = input_cost + output_cost
|
|
276
|
+
|
|
277
|
+
return costs
|
|
278
|
+
|
|
279
|
+
def add_task_routing(self, task_type: str, tier: ModelTier) -> None:
|
|
280
|
+
"""Add custom task routing.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
task_type: Task type to route
|
|
284
|
+
tier: Model tier to use
|
|
285
|
+
|
|
286
|
+
"""
|
|
287
|
+
self._custom_routing[task_type.lower()] = tier
|
|
288
|
+
|
|
289
|
+
def get_tier(self, task_type: str) -> ModelTier:
|
|
290
|
+
"""Get the tier for a task type.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
task_type: Task type
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
ModelTier for the task
|
|
297
|
+
|
|
298
|
+
"""
|
|
299
|
+
return self._get_tier(task_type)
|
|
300
|
+
|
|
301
|
+
def _get_tier(self, task_type: str) -> ModelTier:
|
|
302
|
+
"""Internal method to get tier with custom routing support."""
|
|
303
|
+
task_lower = task_type.lower().replace("-", "_").replace(" ", "_")
|
|
304
|
+
|
|
305
|
+
# Check custom routing first
|
|
306
|
+
if task_lower in self._custom_routing:
|
|
307
|
+
return self._custom_routing[task_lower]
|
|
308
|
+
|
|
309
|
+
# Use default routing
|
|
310
|
+
return TaskRouting.get_tier(task_type)
|
|
311
|
+
|
|
312
|
+
@classmethod
|
|
313
|
+
def get_supported_providers(cls) -> list[str]:
|
|
314
|
+
"""Get list of supported providers."""
|
|
315
|
+
cls._ensure_models_loaded()
|
|
316
|
+
return list(cls.MODELS.keys())
|
|
317
|
+
|
|
318
|
+
@classmethod
|
|
319
|
+
def get_all_tasks(cls) -> dict[str, list[str]]:
|
|
320
|
+
"""Get all known task types by tier."""
|
|
321
|
+
return {
|
|
322
|
+
"cheap": list(TaskRouting.CHEAP_TASKS),
|
|
323
|
+
"capable": list(TaskRouting.CAPABLE_TASKS),
|
|
324
|
+
"premium": list(TaskRouting.PREMIUM_TASKS),
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
def calculate_savings(
|
|
328
|
+
self,
|
|
329
|
+
task_type: str,
|
|
330
|
+
input_tokens: int,
|
|
331
|
+
output_tokens: int,
|
|
332
|
+
) -> dict[str, Any]:
|
|
333
|
+
"""Calculate savings from smart routing vs always using premium.
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
task_type: Type of task
|
|
337
|
+
input_tokens: Estimated input tokens
|
|
338
|
+
output_tokens: Estimated output tokens
|
|
339
|
+
|
|
340
|
+
Returns:
|
|
341
|
+
Dict with savings information
|
|
342
|
+
|
|
343
|
+
"""
|
|
344
|
+
routed_cost = self.estimate_cost(task_type, input_tokens, output_tokens)
|
|
345
|
+
|
|
346
|
+
# Calculate what premium would cost
|
|
347
|
+
premium_config = self.MODELS[self._default_provider]["premium"]
|
|
348
|
+
premium_cost = (input_tokens / 1000) * premium_config.cost_per_1k_input + (
|
|
349
|
+
output_tokens / 1000
|
|
350
|
+
) * premium_config.cost_per_1k_output
|
|
351
|
+
|
|
352
|
+
savings = premium_cost - routed_cost
|
|
353
|
+
savings_percent = (savings / premium_cost * 100) if premium_cost > 0 else 0
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
"task_type": task_type,
|
|
357
|
+
"routed_tier": self._get_tier(task_type).value,
|
|
358
|
+
"routed_cost": routed_cost,
|
|
359
|
+
"premium_cost": premium_cost,
|
|
360
|
+
"savings": savings,
|
|
361
|
+
"savings_percent": savings_percent,
|
|
362
|
+
}
|