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,472 @@
|
|
|
1
|
+
"""Unified Model Registry - Single Source of Truth
|
|
2
|
+
|
|
3
|
+
This module provides a centralized model configuration that is consumed by:
|
|
4
|
+
- attune_llm.routing.ModelRouter (via compatibility properties)
|
|
5
|
+
- src/attune/workflows.config.WorkflowConfig
|
|
6
|
+
- src/attune.cost_tracker
|
|
7
|
+
|
|
8
|
+
Pricing is stored in per-million tokens (industry standard) with computed
|
|
9
|
+
properties for per-1k compatibility with legacy code.
|
|
10
|
+
|
|
11
|
+
Copyright 2025 Smart-AI-Memory
|
|
12
|
+
Licensed under Fair Source License 0.9
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from enum import Enum
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ModelTier(Enum):
|
|
21
|
+
"""Model tier classification for routing.
|
|
22
|
+
|
|
23
|
+
CHEAP: Fast, low-cost models for simple tasks (~$0.15-1.00/M input)
|
|
24
|
+
CAPABLE: Balanced models for most development work (~$2.50-3.00/M input)
|
|
25
|
+
PREMIUM: Highest capability for complex reasoning (~$15.00/M input)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
CHEAP = "cheap"
|
|
29
|
+
CAPABLE = "capable"
|
|
30
|
+
PREMIUM = "premium"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ModelProvider(Enum):
|
|
34
|
+
"""Supported model provider (Claude-native architecture as of v5.0.0)."""
|
|
35
|
+
|
|
36
|
+
ANTHROPIC = "anthropic"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True)
|
|
40
|
+
class ModelInfo:
|
|
41
|
+
"""Unified model information - single source of truth.
|
|
42
|
+
|
|
43
|
+
Pricing is stored in per-million tokens format. Use the cost_per_1k_*
|
|
44
|
+
properties for compatibility with code expecting per-1k pricing.
|
|
45
|
+
|
|
46
|
+
Attributes:
|
|
47
|
+
id: Model identifier (e.g., "claude-3-5-haiku-20241022")
|
|
48
|
+
provider: Provider name (e.g., "anthropic")
|
|
49
|
+
tier: Tier level (e.g., "cheap")
|
|
50
|
+
input_cost_per_million: Input token cost per million tokens
|
|
51
|
+
output_cost_per_million: Output token cost per million tokens
|
|
52
|
+
max_tokens: Maximum output tokens
|
|
53
|
+
supports_vision: Whether model supports vision/images
|
|
54
|
+
supports_tools: Whether model supports tool/function calling
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
id: str
|
|
59
|
+
provider: str
|
|
60
|
+
tier: str
|
|
61
|
+
input_cost_per_million: float
|
|
62
|
+
output_cost_per_million: float
|
|
63
|
+
max_tokens: int = 4096
|
|
64
|
+
supports_vision: bool = False
|
|
65
|
+
supports_tools: bool = True
|
|
66
|
+
|
|
67
|
+
# Compatibility properties for toolkit (per-1k pricing)
|
|
68
|
+
@property
|
|
69
|
+
def model_id(self) -> str:
|
|
70
|
+
"""Alias for id - compatibility with ModelRouter.ModelConfig."""
|
|
71
|
+
return self.id
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def name(self) -> str:
|
|
75
|
+
"""Alias for id - compatibility with WorkflowConfig.ModelConfig."""
|
|
76
|
+
return self.id
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def cost_per_1k_input(self) -> float:
|
|
80
|
+
"""Input cost per 1k tokens - for ModelRouter compatibility."""
|
|
81
|
+
return self.input_cost_per_million / 1000
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def cost_per_1k_output(self) -> float:
|
|
85
|
+
"""Output cost per 1k tokens - for ModelRouter compatibility."""
|
|
86
|
+
return self.output_cost_per_million / 1000
|
|
87
|
+
|
|
88
|
+
def to_router_config(self) -> dict[str, Any]:
|
|
89
|
+
"""Convert to ModelRouter.ModelConfig compatible dict."""
|
|
90
|
+
return {
|
|
91
|
+
"model_id": self.id,
|
|
92
|
+
"cost_per_1k_input": self.cost_per_1k_input,
|
|
93
|
+
"cost_per_1k_output": self.cost_per_1k_output,
|
|
94
|
+
"max_tokens": self.max_tokens,
|
|
95
|
+
"supports_tools": self.supports_tools,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
def to_workflow_config(self) -> dict[str, Any]:
|
|
99
|
+
"""Convert to WorkflowConfig.ModelConfig compatible dict."""
|
|
100
|
+
return {
|
|
101
|
+
"name": self.id,
|
|
102
|
+
"provider": self.provider,
|
|
103
|
+
"tier": self.tier,
|
|
104
|
+
"input_cost_per_million": self.input_cost_per_million,
|
|
105
|
+
"output_cost_per_million": self.output_cost_per_million,
|
|
106
|
+
"max_tokens": self.max_tokens,
|
|
107
|
+
"supports_vision": self.supports_vision,
|
|
108
|
+
"supports_tools": self.supports_tools,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
def to_cost_tracker_pricing(self) -> dict[str, float]:
|
|
112
|
+
"""Convert to cost_tracker MODEL_PRICING format."""
|
|
113
|
+
return {
|
|
114
|
+
"input": self.input_cost_per_million,
|
|
115
|
+
"output": self.output_cost_per_million,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# =============================================================================
|
|
120
|
+
# MODEL REGISTRY - Single Source of Truth
|
|
121
|
+
# =============================================================================
|
|
122
|
+
# All model configurations are defined here. Other modules should import
|
|
123
|
+
# from this registry rather than defining their own model configs.
|
|
124
|
+
|
|
125
|
+
MODEL_REGISTRY: dict[str, dict[str, ModelInfo]] = {
|
|
126
|
+
# -------------------------------------------------------------------------
|
|
127
|
+
# Anthropic Claude Models
|
|
128
|
+
# Intelligent fallback: Sonnet 4.5 → Opus 4.5 (5x cost increase for complex tasks)
|
|
129
|
+
# -------------------------------------------------------------------------
|
|
130
|
+
"anthropic": {
|
|
131
|
+
"cheap": ModelInfo(
|
|
132
|
+
id="claude-3-5-haiku-20241022",
|
|
133
|
+
provider="anthropic",
|
|
134
|
+
tier="cheap",
|
|
135
|
+
input_cost_per_million=0.80,
|
|
136
|
+
output_cost_per_million=4.00,
|
|
137
|
+
max_tokens=8192,
|
|
138
|
+
supports_vision=False,
|
|
139
|
+
supports_tools=True,
|
|
140
|
+
),
|
|
141
|
+
"capable": ModelInfo(
|
|
142
|
+
id="claude-sonnet-4-5", # Updated to Sonnet 4.5 (2026)
|
|
143
|
+
provider="anthropic",
|
|
144
|
+
tier="capable",
|
|
145
|
+
input_cost_per_million=3.00,
|
|
146
|
+
output_cost_per_million=15.00,
|
|
147
|
+
max_tokens=8192,
|
|
148
|
+
supports_vision=True,
|
|
149
|
+
supports_tools=True,
|
|
150
|
+
),
|
|
151
|
+
"premium": ModelInfo(
|
|
152
|
+
id="claude-opus-4-5-20251101",
|
|
153
|
+
provider="anthropic",
|
|
154
|
+
tier="premium",
|
|
155
|
+
input_cost_per_million=15.00,
|
|
156
|
+
output_cost_per_million=75.00,
|
|
157
|
+
max_tokens=8192,
|
|
158
|
+
supports_vision=True,
|
|
159
|
+
supports_tools=True,
|
|
160
|
+
),
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
# =============================================================================
|
|
166
|
+
# MODEL REGISTRY CLASS - OOP Interface
|
|
167
|
+
# =============================================================================
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class ModelRegistry:
|
|
171
|
+
"""Object-oriented interface to the model registry.
|
|
172
|
+
|
|
173
|
+
Provides efficient lookup operations with built-in tier and model ID caching
|
|
174
|
+
for O(1) performance on frequently accessed queries.
|
|
175
|
+
|
|
176
|
+
Example:
|
|
177
|
+
>>> registry = ModelRegistry()
|
|
178
|
+
>>> model = registry.get_model("anthropic", "capable")
|
|
179
|
+
>>> print(model.id)
|
|
180
|
+
claude-sonnet-4-5
|
|
181
|
+
|
|
182
|
+
>>> models = registry.get_models_by_tier("cheap")
|
|
183
|
+
>>> print(len(models))
|
|
184
|
+
5
|
|
185
|
+
|
|
186
|
+
>>> model = registry.get_model_by_id("claude-opus-4-5-20251101")
|
|
187
|
+
>>> print(model.tier)
|
|
188
|
+
premium
|
|
189
|
+
|
|
190
|
+
>>> providers = registry.list_providers()
|
|
191
|
+
>>> print(providers)
|
|
192
|
+
['anthropic', 'openai', 'google', 'ollama', 'hybrid']
|
|
193
|
+
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
def __init__(self, registry: dict[str, dict[str, ModelInfo]] | None = None):
|
|
197
|
+
"""Initialize the model registry.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
registry: Optional custom registry dict. If None, uses MODEL_REGISTRY.
|
|
201
|
+
|
|
202
|
+
"""
|
|
203
|
+
self._registry = registry if registry is not None else MODEL_REGISTRY
|
|
204
|
+
|
|
205
|
+
# Build performance caches
|
|
206
|
+
self._build_caches()
|
|
207
|
+
|
|
208
|
+
def _build_caches(self) -> None:
|
|
209
|
+
"""Build tier and model ID caches for O(1) lookups."""
|
|
210
|
+
# Cache for get_models_by_tier (tier -> list[ModelInfo])
|
|
211
|
+
self._tier_cache: dict[str, list[ModelInfo]] = {}
|
|
212
|
+
for tier in ModelTier:
|
|
213
|
+
self._tier_cache[tier.value] = [
|
|
214
|
+
provider_models[tier.value]
|
|
215
|
+
for provider_models in self._registry.values()
|
|
216
|
+
if tier.value in provider_models
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
# Cache for get_model_by_id (model_id -> ModelInfo)
|
|
220
|
+
self._model_id_cache: dict[str, ModelInfo] = {}
|
|
221
|
+
for provider_models in self._registry.values():
|
|
222
|
+
for model_info in provider_models.values():
|
|
223
|
+
self._model_id_cache[model_info.id] = model_info
|
|
224
|
+
|
|
225
|
+
def get_model(self, provider: str, tier: str) -> ModelInfo | None:
|
|
226
|
+
"""Get model info for a provider/tier combination.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
provider: Provider name (anthropic only as of v5.0.0)
|
|
230
|
+
tier: Tier level (cheap, capable, premium)
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
ModelInfo if found, None otherwise
|
|
234
|
+
|
|
235
|
+
Raises:
|
|
236
|
+
ValueError: If provider is not 'anthropic'
|
|
237
|
+
|
|
238
|
+
Example:
|
|
239
|
+
>>> registry = ModelRegistry()
|
|
240
|
+
>>> model = registry.get_model("anthropic", "capable")
|
|
241
|
+
>>> print(model.id)
|
|
242
|
+
claude-sonnet-4-5
|
|
243
|
+
|
|
244
|
+
"""
|
|
245
|
+
if provider.lower() != "anthropic":
|
|
246
|
+
raise ValueError(
|
|
247
|
+
f"Provider '{provider}' is not supported. "
|
|
248
|
+
f"Empathy Framework is now Claude-native (v5.0.0). "
|
|
249
|
+
f"Only 'anthropic' provider is available. "
|
|
250
|
+
f"See docs/CLAUDE_NATIVE.md for migration guide."
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
provider_models = self._registry.get(provider.lower())
|
|
254
|
+
if provider_models is None:
|
|
255
|
+
return None
|
|
256
|
+
return provider_models.get(tier.lower())
|
|
257
|
+
|
|
258
|
+
def get_model_by_id(self, model_id: str) -> ModelInfo | None:
|
|
259
|
+
"""Get model info by model ID.
|
|
260
|
+
|
|
261
|
+
Uses O(1) cache lookup for fast performance.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
model_id: Model identifier (e.g., "claude-3-5-haiku-20241022")
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
ModelInfo if found, None otherwise
|
|
268
|
+
|
|
269
|
+
Example:
|
|
270
|
+
>>> registry = ModelRegistry()
|
|
271
|
+
>>> model = registry.get_model_by_id("claude-opus-4-5-20251101")
|
|
272
|
+
>>> print(model.provider)
|
|
273
|
+
anthropic
|
|
274
|
+
>>> print(model.tier)
|
|
275
|
+
premium
|
|
276
|
+
|
|
277
|
+
>>> model = registry.get_model_by_id("gpt-4o-mini")
|
|
278
|
+
>>> print(f"{model.provider}/{model.tier}")
|
|
279
|
+
openai/cheap
|
|
280
|
+
|
|
281
|
+
"""
|
|
282
|
+
return self._model_id_cache.get(model_id)
|
|
283
|
+
|
|
284
|
+
def get_models_by_tier(self, tier: str) -> list[ModelInfo]:
|
|
285
|
+
"""Get all models in a specific tier (Anthropic-only as of v5.0.0).
|
|
286
|
+
|
|
287
|
+
Uses O(1) cache lookup for fast performance.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
tier: Tier level (cheap, capable, premium)
|
|
291
|
+
|
|
292
|
+
Returns:
|
|
293
|
+
List of ModelInfo objects in the tier (may be empty)
|
|
294
|
+
|
|
295
|
+
Example:
|
|
296
|
+
>>> registry = ModelRegistry()
|
|
297
|
+
>>> cheap_models = registry.get_models_by_tier("cheap")
|
|
298
|
+
>>> print(len(cheap_models))
|
|
299
|
+
1
|
|
300
|
+
>>> print([m.provider for m in cheap_models])
|
|
301
|
+
['anthropic']
|
|
302
|
+
|
|
303
|
+
>>> premium_models = registry.get_models_by_tier("premium")
|
|
304
|
+
>>> for model in premium_models:
|
|
305
|
+
... print(f"{model.provider}: {model.id}")
|
|
306
|
+
anthropic: claude-opus-4-5-20251101
|
|
307
|
+
|
|
308
|
+
"""
|
|
309
|
+
return self._tier_cache.get(tier.lower(), [])
|
|
310
|
+
|
|
311
|
+
def list_providers(self) -> list[str]:
|
|
312
|
+
"""Get list of all provider names (Anthropic-only as of v5.0.0).
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
List of provider names (['anthropic'])
|
|
316
|
+
|
|
317
|
+
Example:
|
|
318
|
+
>>> registry = ModelRegistry()
|
|
319
|
+
>>> providers = registry.list_providers()
|
|
320
|
+
>>> print(providers)
|
|
321
|
+
['anthropic']
|
|
322
|
+
|
|
323
|
+
"""
|
|
324
|
+
return list(self._registry.keys())
|
|
325
|
+
|
|
326
|
+
def list_tiers(self) -> list[str]:
|
|
327
|
+
"""Get list of all available tiers.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
List of tier names (e.g., ['cheap', 'capable', 'premium'])
|
|
331
|
+
|
|
332
|
+
Example:
|
|
333
|
+
>>> registry = ModelRegistry()
|
|
334
|
+
>>> tiers = registry.list_tiers()
|
|
335
|
+
>>> print(tiers)
|
|
336
|
+
['cheap', 'capable', 'premium']
|
|
337
|
+
|
|
338
|
+
"""
|
|
339
|
+
return [tier.value for tier in ModelTier]
|
|
340
|
+
|
|
341
|
+
def get_all_models(self) -> dict[str, dict[str, ModelInfo]]:
|
|
342
|
+
"""Get the complete model registry (Anthropic-only as of v5.0.0).
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
Full registry dict (provider -> tier -> ModelInfo)
|
|
346
|
+
|
|
347
|
+
Example:
|
|
348
|
+
>>> registry = ModelRegistry()
|
|
349
|
+
>>> all_models = registry.get_all_models()
|
|
350
|
+
>>> print(all_models.keys())
|
|
351
|
+
dict_keys(['anthropic'])
|
|
352
|
+
|
|
353
|
+
"""
|
|
354
|
+
return self._registry
|
|
355
|
+
|
|
356
|
+
def get_pricing_for_model(self, model_id: str) -> dict[str, float] | None:
|
|
357
|
+
"""Get pricing for a model by its ID.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
model_id: Model identifier (e.g., "claude-3-5-haiku-20241022")
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
Dict with 'input' and 'output' keys (per-million pricing), or None
|
|
364
|
+
|
|
365
|
+
Example:
|
|
366
|
+
>>> registry = ModelRegistry()
|
|
367
|
+
>>> pricing = registry.get_pricing_for_model("claude-sonnet-4-5")
|
|
368
|
+
>>> print(pricing)
|
|
369
|
+
{'input': 3.0, 'output': 15.0}
|
|
370
|
+
|
|
371
|
+
>>> pricing = registry.get_pricing_for_model("claude-opus-4-5-20251101")
|
|
372
|
+
>>> print(f"${pricing['input']}/M input, ${pricing['output']}/M output")
|
|
373
|
+
$15.0/M input, $75.0/M output
|
|
374
|
+
|
|
375
|
+
"""
|
|
376
|
+
model = self.get_model_by_id(model_id)
|
|
377
|
+
if model is None:
|
|
378
|
+
return None
|
|
379
|
+
return model.to_cost_tracker_pricing()
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
# =============================================================================
|
|
383
|
+
# DEFAULT REGISTRY INSTANCE
|
|
384
|
+
# =============================================================================
|
|
385
|
+
# Global singleton instance for convenience
|
|
386
|
+
_default_registry = ModelRegistry()
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
# =============================================================================
|
|
390
|
+
# HELPER FUNCTIONS - Backward Compatibility
|
|
391
|
+
# =============================================================================
|
|
392
|
+
# These functions wrap the default registry instance to maintain
|
|
393
|
+
# backward compatibility with existing code.
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def get_model(provider: str, tier: str) -> ModelInfo | None:
|
|
397
|
+
"""Get model info for a provider/tier combination.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
provider: Provider name (anthropic only as of v5.0.0)
|
|
401
|
+
tier: Tier level (cheap, capable, premium)
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
ModelInfo if found, None otherwise
|
|
405
|
+
|
|
406
|
+
Raises:
|
|
407
|
+
ValueError: If provider is not 'anthropic'
|
|
408
|
+
|
|
409
|
+
Note:
|
|
410
|
+
This is a convenience wrapper around the default ModelRegistry instance.
|
|
411
|
+
For more features, consider using ModelRegistry directly.
|
|
412
|
+
|
|
413
|
+
"""
|
|
414
|
+
return _default_registry.get_model(provider, tier)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def get_all_models() -> dict[str, dict[str, ModelInfo]]:
|
|
418
|
+
"""Get the complete model registry.
|
|
419
|
+
|
|
420
|
+
Note:
|
|
421
|
+
This is a convenience wrapper around the default ModelRegistry instance.
|
|
422
|
+
|
|
423
|
+
"""
|
|
424
|
+
return _default_registry.get_all_models()
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def get_pricing_for_model(model_id: str) -> dict[str, float] | None:
|
|
428
|
+
"""Get pricing for a model by its ID.
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
model_id: Model identifier (e.g., "claude-3-5-haiku-20241022")
|
|
432
|
+
|
|
433
|
+
Returns:
|
|
434
|
+
Dict with 'input' and 'output' keys (per-million pricing), or None
|
|
435
|
+
|
|
436
|
+
Note:
|
|
437
|
+
This is a convenience wrapper around the default ModelRegistry instance.
|
|
438
|
+
|
|
439
|
+
"""
|
|
440
|
+
return _default_registry.get_pricing_for_model(model_id)
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def get_supported_providers() -> list[str]:
|
|
444
|
+
"""Get list of supported provider names.
|
|
445
|
+
|
|
446
|
+
Note:
|
|
447
|
+
This is a convenience wrapper around the default ModelRegistry instance.
|
|
448
|
+
|
|
449
|
+
"""
|
|
450
|
+
return _default_registry.list_providers()
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def get_tiers() -> list[str]:
|
|
454
|
+
"""Get list of available tiers.
|
|
455
|
+
|
|
456
|
+
Note:
|
|
457
|
+
This is a convenience wrapper around the default ModelRegistry instance.
|
|
458
|
+
|
|
459
|
+
"""
|
|
460
|
+
return _default_registry.list_tiers()
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
# =============================================================================
|
|
464
|
+
# TIER PRICING (for backward compatibility with cost_tracker)
|
|
465
|
+
# =============================================================================
|
|
466
|
+
# These are tier-level pricing aliases for when specific model isn't known
|
|
467
|
+
|
|
468
|
+
TIER_PRICING: dict[str, dict[str, float]] = {
|
|
469
|
+
"cheap": {"input": 0.80, "output": 4.00}, # Haiku 3.5 pricing
|
|
470
|
+
"capable": {"input": 3.00, "output": 15.00}, # Sonnet 4 pricing
|
|
471
|
+
"premium": {"input": 15.00, "output": 75.00}, # Opus 4.5 pricing
|
|
472
|
+
}
|