abstractcore 2.19.0__tar.gz → 2.19.2__tar.gz
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.
- {abstractcore-2.19.0 → abstractcore-2.19.2}/PKG-INFO +10 -10
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/apps/extractor.py +2 -2
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/apps/judge.py +2 -2
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/model_downloads_catalog.json +25 -5
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/capabilities/registry.py +6 -3
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/pil_text_renderer.py +1 -1
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/capability_defaults.py +191 -32
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/engines.py +59 -34
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/main.py +14 -18
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/manager.py +94 -2
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/model_catalog.py +2 -2
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/model_materializer.py +26 -8
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/recommendations.py +20 -2
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/route_engines.py +54 -7
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/vision_config.py +3 -1
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/generate_contract.py +47 -1
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/download.py +2 -2
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/embeddings/manager.py +3 -4
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/auto_handler.py +4 -1
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/processors/pdf_processor.py +2 -2
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/base.py +2 -2
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/huggingface_provider.py +35 -20
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/mlx_provider.py +4 -3
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/openai_provider.py +3 -3
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/registry.py +31 -21
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/app.py +5 -1
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/camera_endpoints.py +4 -1
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/host_routes.py +2 -2
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/vision_endpoints.py +8 -8
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/browser_tools.py +13 -6
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/common_tools.py +4 -4
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/comms_tools.py +93 -24
- abstractcore-2.19.2/abstractcore/utils/install_settings.py +140 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/version.py +1 -1
- abstractcore-2.19.2/abstractcore/utils/windows_dll.py +159 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore.egg-info/PKG-INFO +10 -10
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore.egg-info/SOURCES.txt +2 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore.egg-info/requires.txt +13 -9
- {abstractcore-2.19.0 → abstractcore-2.19.2}/pyproject.toml +15 -10
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_generate_contract.py +30 -0
- abstractcore-2.19.2/tests/test_install_hints_no_bare_packages.py +200 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_install_settings.py +18 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_multimodal_generate_output.py +42 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_packaging_extras.py +1 -1
- abstractcore-2.19.0/abstractcore/utils/install_settings.py +0 -43
- {abstractcore-2.19.0 → abstractcore-2.19.2}/LICENSE +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/README.md +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/apps/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/apps/__main__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/apps/app_config_utils.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/apps/deepsearch.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/apps/intent.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/apps/summarizer.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/architectures/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/architectures/detection.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/architectures/enums.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/architectures/response_postprocessing.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/architectures/thinking_controls.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/OCRA.ttf +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/OCRB.ttf +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/OCRBL.ttf +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/README.md +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/abstractframework_identity.json +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/architecture_formats.json +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/bloc-schema.jsonld +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/model_capabilities.json +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/model_capabilities.schema.json +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/model_downloads_catalog.schema.json +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/semantic_models.md +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/session_schema.json +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/capabilities/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/capabilities/errors.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/capabilities/host.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/capabilities/music_selectors.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/capabilities/scene3d_selectors.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/capabilities/types.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/capabilities/vision_catalog.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/analytics.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/cache.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/config.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/exceptions.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/glyph_processor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/optimizer.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/orchestrator.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/quality.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/text_formatter.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/compression/vision_compressor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/host_jobs.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/model_verify.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/models_engines_cli.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/config/provider_profiles.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/console/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/console/theme_sync.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/console/themes.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/console/web.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/bloc_kv.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/bloc_metadata.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/cached_session.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/degeneration.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/endpoint_damping.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/enums.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/factory.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/file_blocs.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/file_boxes.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/interface.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/multimodal_generation.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/output_specs.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/retry.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/session.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/core/types.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/embeddings/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/embeddings/models.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/endpoint/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/endpoint/app.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/events/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/exceptions/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/mcp/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/mcp/client.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/mcp/factory.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/mcp/naming.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/mcp/stdio_client.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/mcp/tool_source.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/base.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/capabilities.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/delivery.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/enrichment.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/handlers/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/handlers/anthropic_handler.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/handlers/local_handler.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/handlers/openai_handler.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/openai_parts.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/pdf_routing.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/processors/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/processors/audio_processor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/processors/direct_pdf_processor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/processors/glyph_pdf_processor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/processors/image_processor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/processors/office_processor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/processors/text_processor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/processors/video_processor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/types.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/utils/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/utils/image_scaler.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/utils/video_frames.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/media/vision_fallback.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/processing/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/processing/basic_deepsearch.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/processing/basic_extractor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/processing/basic_intent.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/processing/basic_judge.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/processing/basic_summarizer.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/_http.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/anthropic_provider.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/endpoint_context.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/generation_cancel.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/generation_progress.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/hf_residency.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/lmstudio_provider.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/mlx_model_rules.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/mlx_native_cache.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/mlx_native_session.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/mlx_prefill_observer.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/mlx_qwen4.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/mlx_residency.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/mlx_runtime.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/mlx_vision_addon.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/model_capabilities.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/model_config_fingerprint.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/ollama_provider.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/openai_compatible_provider.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/openrouter_provider.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/portkey_provider.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/process_residency.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/speculation.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/streaming.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/tokenizer_fingerprint.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/vllm_provider.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/providers/weights_fingerprint.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/py.typed +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/__main__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/audio_endpoints.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/capability_generation.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/console_routes.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/credentials.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/first_run.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/scene3d_endpoints.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/server/session_routes.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/structured/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/structured/handler.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/structured/retry.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/structured/schema_compat.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/abstractignore.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/arg_canonicalizer.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/arg_coercion.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/code_analysis.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/core.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/email_digests.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/fetch_url_ssrf.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/handler.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/inventory.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/parser.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/process_tree.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/registry.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/risk_facts.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/shell_session.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/shell_tools.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/syntax_rewriter.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/tag_rewriter.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/telegram_tdlib.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/telegram_tools.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/tools/wire_naming.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/__init__.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/async_stream.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/cli.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/context_calibration.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/context_estimate.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/data_registry.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/display.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/file_filters.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/host_profile.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/hostinfo.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/identity.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/jsonish.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/memory.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/message_preprocessor.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/model_cache.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/model_fit.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/residency.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/self_fixes.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/structured_logging.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/token_utils.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/trace_export.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/truncation.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/vlm_token_calculator.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/utils/workspace_paths.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore.egg-info/dependency_links.txt +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore.egg-info/entry_points.txt +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore.egg-info/top_level.txt +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/setup.cfg +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_abstractendpoint_singleton_provider.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_agentic_cli_compatibility.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_basic_session.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_bloc_kv.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_bloc_kv_cache_dtype.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_bloc_kv_endpoint.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_bloc_kv_engine_fingerprint.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_bloc_kv_model_config_fingerprint.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_bloc_kv_tokenizer_fingerprint.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_bloc_kv_weights_fingerprint.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_bloc_metadata_json_extract.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_cached_session_kv_mode.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_cached_session_kv_thinking_prefix.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_capabilities_registry.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_capabilities_registry_preferred_backends_from_config.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_complete_integration.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_comprehensive_events.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_console_web.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_core_components.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_display_rule.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_email_digests.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_embedding_model_token_warnings.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_enhanced_prompt.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_environment_variable_tool_call_tags.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_factory.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_file_bloc_store_unit.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_file_boxes_cached_session.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_final_accuracy.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_final_comprehensive.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_final_graceful_errors.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_generate_response_reasoning_property_unit.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_generate_with_outputs.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_graceful_fallback.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_import_debug.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_import_safety.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_incremental_thinking_tag_stripper.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_integrated_functionality.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_llms_sources.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_mcp_integration.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_mcp_stdio_client.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_openai_prompt_cache_key_passthrough.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_output_specs.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_packaging_assets.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_prompt_cache_api.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_prompt_cache_bloc_composition.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_prompt_cache_bloc_e2e_gate.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_prompt_cache_control_plane.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_prompt_cache_prepare_modules_thinking_http.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_retry_observability.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_retry_strategy.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_seed_determinism.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_seed_temperature_basic.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_sensory_prompting.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_server_prompt_cache_control_plane_proxy.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_server_prompt_cache_key_passthrough.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_session_reasoning_persistence_unit.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_structured_output_truncation_retry.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_text_only_model_experience.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_unload_memory.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_user_scenario_validation.py +0 -0
- {abstractcore-2.19.0 → abstractcore-2.19.2}/tests/test_voice_host_credentials.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: abstractcore
|
|
3
|
-
Version: 2.19.
|
|
3
|
+
Version: 2.19.2
|
|
4
4
|
Summary: Unified interface to all LLM providers with essential infrastructure for tool calling, streaming, and model management
|
|
5
5
|
Author-email: Laurent-Philippe Albou <contact@abstractcore.ai>
|
|
6
6
|
Maintainer-email: Laurent-Philippe Albou <contact@abstractcore.ai>
|
|
@@ -31,7 +31,7 @@ Description-Content-Type: text/markdown
|
|
|
31
31
|
License-File: LICENSE
|
|
32
32
|
Requires-Dist: pydantic<3.0.0,>=2.0.0
|
|
33
33
|
Requires-Dist: httpx<1.0.0,>=0.24.0
|
|
34
|
-
Requires-Dist: openai<
|
|
34
|
+
Requires-Dist: openai<3.0.0,>=1.0.0
|
|
35
35
|
Requires-Dist: anthropic<1.0.0,>=0.25.0
|
|
36
36
|
Requires-Dist: tiktoken<1.0.0,>=0.5.0
|
|
37
37
|
Requires-Dist: requests<3.0.0,>=2.25.0
|
|
@@ -48,8 +48,8 @@ Requires-Dist: fastapi<1.0.0,>=0.100.0
|
|
|
48
48
|
Requires-Dist: uvicorn[standard]<1.0.0,>=0.23.0
|
|
49
49
|
Requires-Dist: python-multipart<1.0.0,>=0.0.6
|
|
50
50
|
Requires-Dist: sse-starlette<2.0.0,>=1.6.0
|
|
51
|
-
Requires-Dist: abstractvoice>=0.13.
|
|
52
|
-
Requires-Dist: abstractvision>=0.3.
|
|
51
|
+
Requires-Dist: abstractvoice>=0.13.2
|
|
52
|
+
Requires-Dist: abstractvision>=0.3.33
|
|
53
53
|
Requires-Dist: abstractmusic>=0.1.15; python_version >= "3.10"
|
|
54
54
|
Requires-Dist: abstract3d>=0.1.0; python_version >= "3.10"
|
|
55
55
|
Provides-Extra: apple
|
|
@@ -67,26 +67,26 @@ Requires-Dist: accelerate>=1.0.0; extra == "apple"
|
|
|
67
67
|
Requires-Dist: sentence-transformers<6.0.0,>=5.1.0; extra == "apple"
|
|
68
68
|
Requires-Dist: numpy<3.0.0,>=2.1.0; extra == "apple"
|
|
69
69
|
Requires-Dist: Pillow<13.0.0,>=12.1.1; extra == "apple"
|
|
70
|
-
Requires-Dist: abstractvoice[all-apple]>=0.13.
|
|
70
|
+
Requires-Dist: abstractvoice[all-apple]>=0.13.2; extra == "apple"
|
|
71
71
|
Requires-Dist: omnivoice>=0.1.5; extra == "apple"
|
|
72
|
-
Requires-Dist: abstractvision[all-apple]>=0.3.
|
|
72
|
+
Requires-Dist: abstractvision[all-apple]>=0.3.33; extra == "apple"
|
|
73
73
|
Requires-Dist: abstractmusic[all-apple]>=0.1.15; extra == "apple"
|
|
74
74
|
Requires-Dist: playwright<2.0.0,>=1.49.0; extra == "apple"
|
|
75
75
|
Provides-Extra: gpu
|
|
76
|
-
Requires-Dist: vllm<1.0.0,>=0.6.0; extra == "gpu"
|
|
76
|
+
Requires-Dist: vllm<1.0.0,>=0.6.0; sys_platform == "linux" and extra == "gpu"
|
|
77
77
|
Requires-Dist: outlines>=0.1.0; extra == "gpu"
|
|
78
78
|
Requires-Dist: transformers<6.0.0,>=4.57.1; extra == "gpu"
|
|
79
79
|
Requires-Dist: torch<3.0.0,>=2.6.0; extra == "gpu"
|
|
80
80
|
Requires-Dist: torchvision>=0.17.0; extra == "gpu"
|
|
81
81
|
Requires-Dist: torchaudio>=2.1.0; extra == "gpu"
|
|
82
82
|
Requires-Dist: sentencepiece<1.0.0,>=0.1.99; extra == "gpu"
|
|
83
|
-
Requires-Dist: llama-cpp-python<1.0.0,>=0.3.23; extra == "gpu"
|
|
83
|
+
Requires-Dist: llama-cpp-python<1.0.0,>=0.3.23; sys_platform != "win32" and extra == "gpu"
|
|
84
84
|
Requires-Dist: sentence-transformers<6.0.0,>=5.1.0; extra == "gpu"
|
|
85
85
|
Requires-Dist: numpy<3.0.0,>=1.20.0; python_version < "3.13" and extra == "gpu"
|
|
86
86
|
Requires-Dist: numpy<3.0.0,>=2.1.0; python_version >= "3.13" and extra == "gpu"
|
|
87
|
-
Requires-Dist: abstractvoice[all-gpu]>=0.13.
|
|
87
|
+
Requires-Dist: abstractvoice[all-gpu]>=0.13.2; extra == "gpu"
|
|
88
88
|
Requires-Dist: omnivoice>=0.1.5; extra == "gpu"
|
|
89
|
-
Requires-Dist: abstractvision[all-gpu]>=0.3.
|
|
89
|
+
Requires-Dist: abstractvision[all-gpu]>=0.3.33; extra == "gpu"
|
|
90
90
|
Requires-Dist: abstractmusic[all-gpu]>=0.1.15; extra == "gpu"
|
|
91
91
|
Requires-Dist: playwright<2.0.0,>=1.49.0; extra == "gpu"
|
|
92
92
|
Provides-Extra: remote
|
|
@@ -225,7 +225,7 @@ Default model setup:
|
|
|
225
225
|
'--format',
|
|
226
226
|
choices=format_choices,
|
|
227
227
|
default='json-ld',
|
|
228
|
-
help='Output format: json-ld (JSON-LD graph), triples (RDF SUBJECT PREDICATE OBJECT), json (simple JSON)' + (', yaml' if YAML_AVAILABLE else ' -
|
|
228
|
+
help='Output format: json-ld (JSON-LD graph), triples (RDF SUBJECT PREDICATE OBJECT), json (simple JSON)' + (', yaml' if YAML_AVAILABLE else ' - yaml needs PyYAML (part of the light install; repair with: pip install -U abstractcore)')
|
|
229
229
|
)
|
|
230
230
|
|
|
231
231
|
parser.add_argument(
|
|
@@ -513,7 +513,7 @@ Default model setup:
|
|
|
513
513
|
)
|
|
514
514
|
else: # yaml
|
|
515
515
|
if not YAML_AVAILABLE:
|
|
516
|
-
print("Error: PyYAML is required for YAML output format.
|
|
516
|
+
print("Error: PyYAML is required for YAML output format; it is part of the light install. Repair with: pip install -U abstractcore")
|
|
517
517
|
sys.exit(1)
|
|
518
518
|
formatted_output = yaml.dump(result, default_flow_style=False, indent=2, sort_keys=False)
|
|
519
519
|
|
|
@@ -352,7 +352,7 @@ Default model setup:
|
|
|
352
352
|
'--format',
|
|
353
353
|
choices=format_choices,
|
|
354
354
|
default='json',
|
|
355
|
-
help='Output format: json (structured), plain (human-readable)' + (', yaml' if YAML_AVAILABLE else ' -
|
|
355
|
+
help='Output format: json (structured), plain (human-readable)' + (', yaml' if YAML_AVAILABLE else ' - yaml needs PyYAML (part of the light install; repair with: pip install -U abstractcore)')
|
|
356
356
|
)
|
|
357
357
|
|
|
358
358
|
parser.add_argument(
|
|
@@ -623,7 +623,7 @@ Default model setup:
|
|
|
623
623
|
formatted_output = format_assessment_plain(assessment)
|
|
624
624
|
elif args.format == 'yaml':
|
|
625
625
|
if not YAML_AVAILABLE:
|
|
626
|
-
print("Error: PyYAML is required for YAML output format.
|
|
626
|
+
print("Error: PyYAML is required for YAML output format; it is part of the light install. Repair with: pip install -U abstractcore")
|
|
627
627
|
sys.exit(1)
|
|
628
628
|
formatted_output = yaml.dump(assessment, default_flow_style=False, indent=2, sort_keys=False)
|
|
629
629
|
else:
|
{abstractcore-2.19.0 → abstractcore-2.19.2}/abstractcore/assets/model_downloads_catalog.json
RENAMED
|
@@ -1089,8 +1089,8 @@
|
|
|
1089
1089
|
"artifacts": [
|
|
1090
1090
|
{
|
|
1091
1091
|
"provider": "lmstudio",
|
|
1092
|
-
"artifact": "qwen/qwen3.5-9b@
|
|
1093
|
-
"quant": "
|
|
1092
|
+
"artifact": "qwen/qwen3.5-9b@q4_k_m",
|
|
1093
|
+
"quant": "q4_k_m",
|
|
1094
1094
|
"download_bytes": null,
|
|
1095
1095
|
"size_source": "unknown",
|
|
1096
1096
|
"verified": true,
|
|
@@ -4078,7 +4078,7 @@
|
|
|
4078
4078
|
{
|
|
4079
4079
|
"id": "flux.2-klein-4b",
|
|
4080
4080
|
"family": "flux.2",
|
|
4081
|
-
"display_name": "FLUX.2 [klein] 4B
|
|
4081
|
+
"display_name": "FLUX.2 [klein] 4B",
|
|
4082
4082
|
"vendor": "Black Forest Labs",
|
|
4083
4083
|
"params_total": 4000000000,
|
|
4084
4084
|
"params_active": null,
|
|
@@ -4098,6 +4098,26 @@
|
|
|
4098
4098
|
"size_source": "catalog",
|
|
4099
4099
|
"verified": true,
|
|
4100
4100
|
"recommended": true
|
|
4101
|
+
},
|
|
4102
|
+
{
|
|
4103
|
+
"provider": "diffusers",
|
|
4104
|
+
"artifact": "black-forest-labs/FLUX.2-klein-4B",
|
|
4105
|
+
"quant": "bf16",
|
|
4106
|
+
"download_bytes": 23740007447,
|
|
4107
|
+
"size_source": "catalog",
|
|
4108
|
+
"verified": true,
|
|
4109
|
+
"recommended": true,
|
|
4110
|
+
"upstream": {
|
|
4111
|
+
"method": "hf_api",
|
|
4112
|
+
"checked": "2026-09-29",
|
|
4113
|
+
"revision": "e7b7dc27f91deacad38e78976d1f2b499d76a294"
|
|
4114
|
+
},
|
|
4115
|
+
"note": "23,740,007,447 bytes: the whole repo (25 files) at revision e7b7dc27, read with the Hugging Face model API on 2026-09-29; `models download diffusers` fetches it whole, including the 7.75 GB single-file checkpoint (flux-2-klein-4b.safetensors) the Diffusers pipeline does not load. The pipeline's weights are 14.9 GiB in float16 (text encoder 7.49 GiB, transformer 7.22 GiB, VAE 0.16 GiB).",
|
|
4116
|
+
"resident": {
|
|
4117
|
+
"bytes": 8912896000,
|
|
4118
|
+
"source": "nvidia-smi GPU memory peak 7.8-8.3 GiB (the largest, 8.3 GiB, is the figure) of real AbstractVision Diffusers text-to-image generations at 768x768, 4 steps, float16, about 17 s each, with the model CPU offload AbstractVision turns on by itself when the 14.9 GiB of float16 weights do not fit the GPU's free memory (moved whole, the pipeline runs out of CUDA memory on this card); system RAM holds the idle weights, about 15 GiB: Linux, NVIDIA Quadro RTX 5000 16 GB (Turing, sm_75), driver 595, abstractvision 0.3.32 source (commit 281756f), 2026-09-29 (framework backlog 0989)",
|
|
4119
|
+
"measured_with": "AbstractVision/diffusers on CUDA in float16 at 768x768 with model CPU offload, about 15 GiB of idle weights waiting in system RAM"
|
|
4120
|
+
}
|
|
4101
4121
|
}
|
|
4102
4122
|
],
|
|
4103
4123
|
"capabilities_override": {
|
|
@@ -4105,7 +4125,7 @@
|
|
|
4105
4125
|
"vision": false,
|
|
4106
4126
|
"image_generation": true
|
|
4107
4127
|
},
|
|
4108
|
-
"notes": "The AbstractFramework
|
|
4128
|
+
"notes": "The AbstractFramework image-generation recommendation (output.image): the 8-bit MLX-Gen build on Apple silicon, the Diffusers repo on an NVIDIA GPU (CUDA)."
|
|
4109
4129
|
},
|
|
4110
4130
|
{
|
|
4111
4131
|
"id": "supertonic-3",
|
|
@@ -4316,7 +4336,7 @@
|
|
|
4316
4336
|
"voice",
|
|
4317
4337
|
"speech-to-text"
|
|
4318
4338
|
],
|
|
4319
|
-
"starter":
|
|
4339
|
+
"starter": true,
|
|
4320
4340
|
"artifacts": [
|
|
4321
4341
|
{
|
|
4322
4342
|
"provider": "huggingface",
|
|
@@ -647,9 +647,12 @@ class CapabilityRegistry:
|
|
|
647
647
|
if cap in {"voice", "audio", "vision", "music", "scene3d", "3d"}:
|
|
648
648
|
return "pip install -U abstractcore"
|
|
649
649
|
if cap == "camera":
|
|
650
|
-
# camera (seat: camera): no
|
|
651
|
-
#
|
|
652
|
-
return
|
|
650
|
+
# camera (seat: camera): no install setting ships the camera plugin, and a
|
|
651
|
+
# bare-package install is never advised (operator ruling 2026-09-29).
|
|
652
|
+
return (
|
|
653
|
+
"Camera is not available with AbstractCore's install settings (light, apple, gpu): "
|
|
654
|
+
"the camera plugin (abstractcamera) is not part of them"
|
|
655
|
+
)
|
|
653
656
|
return None
|
|
654
657
|
|
|
655
658
|
def _select_backend_id(self, capability: str) -> str:
|
|
@@ -57,7 +57,7 @@ class PILTextRenderer:
|
|
|
57
57
|
from PIL import Image, ImageDraw, ImageFont
|
|
58
58
|
except ImportError as e:
|
|
59
59
|
raise RenderingError(
|
|
60
|
-
f"PIL/Pillow not available: {e}.
|
|
60
|
+
f"PIL/Pillow not available: {e}. Pillow is part of the light install; repair with: pip install -U abstractcore"
|
|
61
61
|
)
|
|
62
62
|
|
|
63
63
|
def _estimate_text_capacity(self, config: RenderingConfig, fonts: dict) -> int:
|
|
@@ -290,7 +290,15 @@ def clean_capability_route_default(value: Any) -> CapabilityRouteDefault:
|
|
|
290
290
|
)
|
|
291
291
|
|
|
292
292
|
|
|
293
|
-
RECOMMENDED_SEED_VERSION = "recommended-
|
|
293
|
+
RECOMMENDED_SEED_VERSION = "recommended-v2"
|
|
294
|
+
|
|
295
|
+
# What each seed version added to the one before it, applied once to a store
|
|
296
|
+
# an earlier seed wrote (`upgrade_recommended_seed`). v2 (AbstractCore 2.19.2):
|
|
297
|
+
# speech input, so a fresh install transcribes locally instead of falling
|
|
298
|
+
# through to OpenAI without a key.
|
|
299
|
+
RECOMMENDED_SEED_ADDITIONS: Tuple[Tuple[str, Tuple[str, ...]], ...] = (
|
|
300
|
+
("recommended-v2", ("input.voice",)),
|
|
301
|
+
)
|
|
294
302
|
|
|
295
303
|
# THE RECOMMENDED MODEL PER CAPABILITY: one table, every surface.
|
|
296
304
|
#
|
|
@@ -317,11 +325,27 @@ RECOMMENDED_SEED_VERSION = "recommended-v1"
|
|
|
317
325
|
# them ONLY when the config file does not exist yet -- never merged into an
|
|
318
326
|
# existing store (an operator who cleared a route meant it), and never on the
|
|
319
327
|
# corrupt-file fallback. `apply-recommended` and `models download
|
|
320
|
-
# --recommended` act on the same starter set
|
|
321
|
-
#
|
|
322
|
-
# writer applies on its own: the operator sets them (`abstractcore config
|
|
328
|
+
# --recommended` act on the same starter set: text, voice output, speech
|
|
329
|
+
# input, image and video. Rows with `starter=False` (music) are
|
|
330
|
+
# recommendations every listing shows, which no writer applies on its own: the operator sets them (`abstractcore config
|
|
323
331
|
# set-default`). Text stores at input.text (the canonical storage key;
|
|
324
332
|
# output.text derives).
|
|
333
|
+
#
|
|
334
|
+
# PER-ACCELERATOR PICKS (`by_accelerator`): a row whose best engine differs by
|
|
335
|
+
# the host's accelerator carries the other pick IN THE ROW, keyed by the host
|
|
336
|
+
# probe's `accelerator` (`cuda`, `metal`, ...). `route`/`download` stay the
|
|
337
|
+
# portable pick every other host starts from; `_full_recommendation` swaps in
|
|
338
|
+
# the accelerator's pick BEFORE the engine-support filter and the memory gate,
|
|
339
|
+
# so the pick is judged by the same rules as every other row. The row stays
|
|
340
|
+
# the one place its recommendation lives.
|
|
341
|
+
@dataclass(frozen=True)
|
|
342
|
+
class AcceleratorPick:
|
|
343
|
+
"""The route and download that replace a row's portable pick on one accelerator."""
|
|
344
|
+
|
|
345
|
+
route: CapabilityRouteDefault
|
|
346
|
+
download: Mapping[str, str]
|
|
347
|
+
|
|
348
|
+
|
|
325
349
|
@dataclass(frozen=True)
|
|
326
350
|
class RecommendedModel:
|
|
327
351
|
"""One capability's recommendation: the route, its download, starter or not."""
|
|
@@ -329,20 +353,31 @@ class RecommendedModel:
|
|
|
329
353
|
route: CapabilityRouteDefault
|
|
330
354
|
download: Mapping[str, str]
|
|
331
355
|
starter: bool
|
|
356
|
+
by_accelerator: Mapping[str, AcceleratorPick] = field(default_factory=dict)
|
|
357
|
+
|
|
358
|
+
def pick_for(self, host: Mapping[str, Any]) -> Tuple[CapabilityRouteDefault, Mapping[str, str]]:
|
|
359
|
+
"""`(route, download)` for `host`: its accelerator's pick, else the portable one."""
|
|
360
|
+
|
|
361
|
+
pick = self.by_accelerator.get(str(host.get("accelerator") or ""))
|
|
362
|
+
return (pick.route, pick.download) if pick is not None else (self.route, self.download)
|
|
332
363
|
|
|
333
364
|
|
|
334
365
|
RECOMMENDED_MODELS: Dict[str, RecommendedModel] = {
|
|
335
366
|
# Text: the 4-BIT quantized build (operator ruling 2026-08-01). The ROUTE
|
|
336
367
|
# stores the bare LM Studio id because that is what the server serves when
|
|
337
368
|
# a single quant is installed; the 4-bit choice is pinned by the download
|
|
338
|
-
# artifact reference, which is what actually fetches the weights.
|
|
369
|
+
# artifact reference, which is what actually fetches the weights. The
|
|
370
|
+
# variant is LM Studio's GGUF Q4_K_M: LM Studio is recommended only off
|
|
371
|
+
# Apple silicon (Linux, Windows), where its catalog has no `4bit` (MLX)
|
|
372
|
+
# variant -- `lms get qwen/qwen3.5-9b@4bit` fails there with "Cannot find
|
|
373
|
+
# variant 4bit" (measured on Linux + NVIDIA, framework backlog 0989).
|
|
339
374
|
"input.text": RecommendedModel(
|
|
340
375
|
route=CapabilityRouteDefault(
|
|
341
376
|
provider="lmstudio", model="qwen/qwen3.5-9b",
|
|
342
377
|
options={"speculation": {"mode": "native_mtp", "num_draft_tokens": 2,
|
|
343
378
|
"require_acceleration": False}},
|
|
344
379
|
),
|
|
345
|
-
download={"provider": "lmstudio", "artifact": "qwen/qwen3.5-9b@
|
|
380
|
+
download={"provider": "lmstudio", "artifact": "qwen/qwen3.5-9b@q4_k_m"},
|
|
346
381
|
starter=True,
|
|
347
382
|
),
|
|
348
383
|
"output.voice": RecommendedModel(
|
|
@@ -350,10 +385,26 @@ RECOMMENDED_MODELS: Dict[str, RecommendedModel] = {
|
|
|
350
385
|
download={"provider": "supertonic", "artifact": "supertonic-3"},
|
|
351
386
|
starter=True,
|
|
352
387
|
),
|
|
388
|
+
# Image: FLUX.2 [klein] 4B. Apple silicon (and the portable pick): the
|
|
389
|
+
# 8-bit MLX-Gen build. An NVIDIA GPU (`cuda`): the same model's Diffusers
|
|
390
|
+
# repo on AbstractVision's `diffusers` backend (the route provider the
|
|
391
|
+
# image lane maps to that backend; device `auto` resolves to CUDA, float16).
|
|
392
|
+
# Its 14.9 GiB of float16 weights do not fit a 16 GB card whole, so
|
|
393
|
+
# AbstractVision (>= 0.3.32, `cpu_offload="auto"`) loads it with model CPU
|
|
394
|
+
# offload there: measured 768x768 in ~17 s with an 8.3 GiB GPU peak on a
|
|
395
|
+
# Quadro RTX 5000 16 GB (framework backlog 0989; the catalog artifact's
|
|
396
|
+
# `resident` is that figure, so the memory gate judges it). Processor-only
|
|
397
|
+
# hosts keep the portable pick and report it unavailable.
|
|
353
398
|
"output.image": RecommendedModel(
|
|
354
399
|
route=CapabilityRouteDefault(provider="mlx-gen", model="AbstractFramework/flux.2-klein-4b-8bit"),
|
|
355
400
|
download={"provider": "mlx-gen", "artifact": "AbstractFramework/flux.2-klein-4b-8bit"},
|
|
356
401
|
starter=True,
|
|
402
|
+
by_accelerator={
|
|
403
|
+
"cuda": AcceleratorPick(
|
|
404
|
+
route=CapabilityRouteDefault(provider="diffusers", model="black-forest-labs/FLUX.2-klein-4B"),
|
|
405
|
+
download={"provider": "diffusers", "artifact": "black-forest-labs/FLUX.2-klein-4B"},
|
|
406
|
+
),
|
|
407
|
+
},
|
|
357
408
|
),
|
|
358
409
|
# Video: Wan2.2 TI2V-5B, ONE checkpoint for text-to-video AND
|
|
359
410
|
# image-to-video, so the modality cell answers both tasks. It is the only
|
|
@@ -371,11 +422,14 @@ RECOMMENDED_MODELS: Dict[str, RecommendedModel] = {
|
|
|
371
422
|
# an NVIDIA GPU, the processor elsewhere -- it has no Metal backend) with
|
|
372
423
|
# AbstractVoice's own default model, `base`. faster-whisper resolves
|
|
373
424
|
# `base` to the Hugging Face repo below in the standard Hugging Face cache,
|
|
374
|
-
# which is where `models download huggingface <repo>` puts it.
|
|
425
|
+
# which is where `models download huggingface <repo>` puts it. A STARTER
|
|
426
|
+
# row (2.19.2, framework rehearsal 0.6.3): without it a fresh install's
|
|
427
|
+
# speech-to-text fell through to OpenAI and failed for want of an API key,
|
|
428
|
+
# although the installer ships faster-whisper (`abstractvoice[stt]`).
|
|
375
429
|
"input.voice": RecommendedModel(
|
|
376
430
|
route=CapabilityRouteDefault(provider="faster-whisper", model="base"),
|
|
377
431
|
download={"provider": "huggingface", "artifact": "Systran/faster-whisper-base"},
|
|
378
|
-
starter=
|
|
432
|
+
starter=True,
|
|
379
433
|
),
|
|
380
434
|
# Music: AbstractMusic's `acestep` backend (Diffusers AceStepPipeline on
|
|
381
435
|
# PyTorch: CUDA, Apple MPS in bfloat16, or the processor in float32) with
|
|
@@ -393,7 +447,7 @@ RECOMMENDED_MODELS: Dict[str, RecommendedModel] = {
|
|
|
393
447
|
# `apply-recommended` and `models download --recommended` act on. Derived,
|
|
394
448
|
# never edited: `RECOMMENDED_MODELS` is the one place a recommendation lives.
|
|
395
449
|
# Like the table, never read directly for a host answer: use the host-aware
|
|
396
|
-
# functions below.
|
|
450
|
+
# functions below. They hold the PORTABLE picks (no `by_accelerator` swap).
|
|
397
451
|
RECOMMENDED_CAPABILITY_DEFAULT_ROUTES: Dict[str, CapabilityRouteDefault] = {
|
|
398
452
|
key: rec.route for key, rec in RECOMMENDED_MODELS.items() if rec.starter
|
|
399
453
|
}
|
|
@@ -408,6 +462,8 @@ RECOMMENDED_MODEL_DOWNLOADS: Dict[str, Dict[str, str]] = {
|
|
|
408
462
|
# ONE owner): the unified-memory tier on Apple silicon (operator ruling
|
|
409
463
|
# 2026-09-24), the portable LM Studio build elsewhere, and the same model's
|
|
410
464
|
# Ollama build where LM Studio has no build (Intel Macs);
|
|
465
|
+
# - a row with a pick for the host's accelerator (`by_accelerator`) uses it:
|
|
466
|
+
# image generation on an NVIDIA GPU is Diffusers, not MLX-Gen;
|
|
411
467
|
# - every row whose engine cannot run on the host is DROPPED, never written
|
|
412
468
|
# as a route that fails at first use. It is reported instead, with the
|
|
413
469
|
# reason, by `recommended_unavailable_routes()` -- the grid then shows the
|
|
@@ -443,6 +499,10 @@ RECOMMENDED_MODEL_DOWNLOADS: Dict[str, Dict[str, str]] = {
|
|
|
443
499
|
# acestep abstractmusic's ACE-Step backend is a Diffusers pipeline on
|
|
444
500
|
# PyTorch (abstractmusic/backends/acestep.py): Apple-silicon
|
|
445
501
|
# macOS, x86_64/arm64 Linux, x86_64 Windows.
|
|
502
|
+
# diffusers abstractvision's Diffusers backend is PyTorch
|
|
503
|
+
# (abstractvision/backends/huggingface_diffusers.py), the same
|
|
504
|
+
# builds as acestep. Recommended on `cuda` hosts only
|
|
505
|
+
# (`RECOMMENDED_MODELS["output.image"].by_accelerator`).
|
|
446
506
|
_RECOMMENDED_PROVIDER_ENGINE = {
|
|
447
507
|
"mlx": "mlx",
|
|
448
508
|
"mlx-gen": "mlx",
|
|
@@ -451,12 +511,14 @@ _RECOMMENDED_PROVIDER_ENGINE = {
|
|
|
451
511
|
"supertonic": "onnxruntime",
|
|
452
512
|
"faster-whisper": "ctranslate2",
|
|
453
513
|
"acestep": "torch",
|
|
514
|
+
"diffusers": "torch",
|
|
454
515
|
}
|
|
455
516
|
# How a provider that runs ON another engine words the engine's refusal.
|
|
456
517
|
_ENGINE_VIA = {
|
|
457
518
|
"supertonic": "Supertonic voice runs on ONNX Runtime (CPU), and ",
|
|
458
519
|
"faster-whisper": "faster-whisper speech input runs on CTranslate2, and ",
|
|
459
520
|
"acestep": "ACE-Step music generation runs on PyTorch, and ",
|
|
521
|
+
"diffusers": "Diffusers image generation runs on PyTorch, and ",
|
|
460
522
|
}
|
|
461
523
|
|
|
462
524
|
# CONFIGURED routes whose engine runs INSIDE this process (AbstractCore's MLX
|
|
@@ -470,8 +532,9 @@ _ENGINE_VIA = {
|
|
|
470
532
|
_IN_PROCESS_PROVIDERS = frozenset({"mlx", "mlx-gen", "supertonic"})
|
|
471
533
|
|
|
472
534
|
# What an operator can do instead, per route, appended to the reason. Provider
|
|
473
|
-
# ids are abstractvision's own (`diffusers`, `sdcpp`)
|
|
474
|
-
#
|
|
535
|
+
# ids are abstractvision's own (`diffusers`, `sdcpp`). An NVIDIA GPU gets the
|
|
536
|
+
# Diffusers image pick itself (`by_accelerator`); a processor-only host does not
|
|
537
|
+
# (no measured processor run vouches for it), so the sentence names the engines.
|
|
475
538
|
# Video has NO local alternative off Apple silicon today: abstractvision's
|
|
476
539
|
# Diffusers text-to-video is disabled for its only model (CogVideoX-2b,
|
|
477
540
|
# `_TEMPORARILY_DISABLED_LOCAL_DIFFUSERS_TASKS`) and has no image-to-video,
|
|
@@ -494,11 +557,6 @@ _UNAVAILABLE_NEXT_STEP = {
|
|
|
494
557
|
"input.text to a cloud provider or to a text server on another machine (lmstudio, ollama or "
|
|
495
558
|
"openai-compatible, with its base_url)"
|
|
496
559
|
),
|
|
497
|
-
"output.image": (
|
|
498
|
-
"set output.image to an image engine this host runs: diffusers (included with abstractcore[gpu]), "
|
|
499
|
-
"sdcpp (stable-diffusion.cpp, included with abstractcore[apple] and abstractcore[gpu]) or a cloud "
|
|
500
|
-
"image provider"
|
|
501
|
-
),
|
|
502
560
|
"output.video": _VIDEO_NO_LOCAL_ENGINE,
|
|
503
561
|
# Engine ids are abstractvoice's (`transformers-asr`, `openai`).
|
|
504
562
|
"input.voice": (
|
|
@@ -508,6 +566,27 @@ _UNAVAILABLE_NEXT_STEP = {
|
|
|
508
566
|
# Backend ids are abstractmusic's (`acemusic`, `elevenlabs-music`).
|
|
509
567
|
"output.music": "set output.music to a cloud music backend (acemusic or elevenlabs-music, with its API key)",
|
|
510
568
|
}
|
|
569
|
+
# output.image names only the three settings (operator ruling 2026-09-29). Apple
|
|
570
|
+
# silicon never reaches this (MLX-Gen runs there), nor does an NVIDIA GPU (its
|
|
571
|
+
# pick is Diffusers, which runs there). Linux: abstractcore[gpu] ships
|
|
572
|
+
# both local image engines; Windows x86_64: abstractcore[gpu] ships diffusers
|
|
573
|
+
# (stable-diffusion.cpp is a source build there, marked out; backlog 0988). An Intel
|
|
574
|
+
# Mac or Windows on ARM has no setting that installs them (`uv pip compile` of
|
|
575
|
+
# abstractcore[gpu] for x86_64-apple-darwin fails on torch). One sentence covers every
|
|
576
|
+
# non-Apple host so a machine-class row ("Linux or Windows ...") stays exact.
|
|
577
|
+
_UNAVAILABLE_NEXT_STEP["output.image"] = (
|
|
578
|
+
"set output.image to a local image engine: diffusers, included with abstractcore[gpu] on Linux and "
|
|
579
|
+
"Windows, or sdcpp (stable-diffusion.cpp), included with abstractcore[gpu] on Linux (on an Intel Mac or "
|
|
580
|
+
"Windows on ARM they are not available with AbstractCore's install settings), or to a cloud image provider"
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
def _unavailable_next_step(key: Optional[str], host: Mapping[str, Any]) -> Optional[str]:
|
|
585
|
+
"""What an operator can do instead of an unavailable recommended row."""
|
|
586
|
+
|
|
587
|
+
return _UNAVAILABLE_NEXT_STEP.get(key or "")
|
|
588
|
+
|
|
589
|
+
|
|
511
590
|
# Next step when the engine runs but the model does not fit (fit-gated rows).
|
|
512
591
|
_TOO_LARGE_NEXT_STEP = {
|
|
513
592
|
"output.image": "use a Mac with more unified memory, or a cloud image provider",
|
|
@@ -520,6 +599,12 @@ _TOO_LARGE_NEXT_STEP = {
|
|
|
520
599
|
"with its API key)"
|
|
521
600
|
),
|
|
522
601
|
}
|
|
602
|
+
# The same, where the host's accelerator words it differently (the key is
|
|
603
|
+
# `(accelerator, route)`): an NVIDIA GPU's image pick is judged against GPU
|
|
604
|
+
# memory, not a Mac's unified memory.
|
|
605
|
+
_TOO_LARGE_NEXT_STEP_BY_ACCELERATOR = {
|
|
606
|
+
("cuda", "output.image"): "use an NVIDIA GPU with more memory, or a cloud image provider",
|
|
607
|
+
}
|
|
523
608
|
# Recommended rows written only where the catalog's fit estimate (the same one
|
|
524
609
|
# the model browser's "fits this computer" filter uses: `fits` or `tight`)
|
|
525
610
|
# says the model fits this host's memory.
|
|
@@ -606,7 +691,8 @@ def _fit_gate_sentence(
|
|
|
606
691
|
if verdict in ("fits", "tight"):
|
|
607
692
|
return None
|
|
608
693
|
name = got["row"].get("display_name") or got["row"].get("id")
|
|
609
|
-
|
|
694
|
+
step = _TOO_LARGE_NEXT_STEP_BY_ACCELERATOR.get((str(host.get("accelerator") or ""), key)) or _TOO_LARGE_NEXT_STEP.get(key)
|
|
695
|
+
next_step = f"; {step}" if step else ""
|
|
610
696
|
if verdict == "unknown" or not isinstance(fit.get("need_bytes"), int) or not isinstance(fit.get("usable_bytes"), int):
|
|
611
697
|
return f"{name} needs a lot of memory and this computer's memory could not be measured{next_step}"
|
|
612
698
|
# "measured" only where the seed carries a measured run-time peak
|
|
@@ -666,8 +752,9 @@ def _unavailable_reasons(
|
|
|
666
752
|
for key, route in routes.items():
|
|
667
753
|
reason = recommended_route_unavailable_reason(route.provider, host, key)
|
|
668
754
|
if reason:
|
|
669
|
-
|
|
670
|
-
|
|
755
|
+
next_step = _unavailable_next_step(key, host)
|
|
756
|
+
if next_step:
|
|
757
|
+
reason = f"{reason}; {next_step}"
|
|
671
758
|
out[key] = reason
|
|
672
759
|
continue
|
|
673
760
|
if key in _FIT_GATED_ROUTES:
|
|
@@ -682,9 +769,19 @@ def _host_or_probe(host: Optional[Mapping[str, Any]]) -> Dict[str, Any]:
|
|
|
682
769
|
return dict(host)
|
|
683
770
|
from ..utils.host_profile import host_profile
|
|
684
771
|
|
|
685
|
-
# The LIGHT reading: os / arch / Apple silicon / RAM, no GPU tool,
|
|
686
|
-
# torch, no mlx
|
|
687
|
-
|
|
772
|
+
# The LIGHT reading first: os / arch / Apple silicon / RAM, no GPU tool,
|
|
773
|
+
# no torch, no mlx. It answers Apple silicon whole. Off Apple silicon it
|
|
774
|
+
# reads every GPU as `none`, and there the accelerator decides a
|
|
775
|
+
# recommendation (an NVIDIA GPU's image pick, `by_accelerator`), so the
|
|
776
|
+
# FULL probe answers (cached for a few seconds; nvidia-smi). On the light
|
|
777
|
+
# reading alone apply-recommended, the grid and `models download
|
|
778
|
+
# --recommended` would treat a CUDA host as processor-only and never
|
|
779
|
+
# offer its image pick (framework backlog 0989). The import-time seed never comes here: it passes the light reading
|
|
780
|
+
# itself (`seed_recommended_capability_defaults`).
|
|
781
|
+
light = host_profile(light=True)
|
|
782
|
+
if light.get("accelerator") == "metal":
|
|
783
|
+
return light
|
|
784
|
+
return host_profile()
|
|
688
785
|
|
|
689
786
|
|
|
690
787
|
def _full_recommendation(
|
|
@@ -698,15 +795,15 @@ def _full_recommendation(
|
|
|
698
795
|
|
|
699
796
|
from .model_catalog import recommended_text_model
|
|
700
797
|
|
|
701
|
-
table = {key: rec for key, rec in RECOMMENDED_MODELS.items() if rec.starter or not starter_only}
|
|
798
|
+
table = {key: rec.pick_for(host) for key, rec in RECOMMENDED_MODELS.items() if rec.starter or not starter_only}
|
|
702
799
|
routes = {
|
|
703
800
|
key: CapabilityRouteDefault(
|
|
704
|
-
provider=
|
|
705
|
-
reasoning=
|
|
801
|
+
provider=route.provider, model=route.model, base_url=route.base_url,
|
|
802
|
+
reasoning=route.reasoning, options=dict(route.options),
|
|
706
803
|
)
|
|
707
|
-
for key,
|
|
804
|
+
for key, (route, _download) in table.items()
|
|
708
805
|
}
|
|
709
|
-
downloads = {key: dict(
|
|
806
|
+
downloads = {key: dict(download) for key, (_route, download) in table.items()}
|
|
710
807
|
pick = recommended_text_model(host, fit=False)
|
|
711
808
|
routes["input.text"] = CapabilityRouteDefault(
|
|
712
809
|
provider=pick["provider"], model=pick["model"], options=dict(pick.get("options") or {})
|
|
@@ -743,9 +840,11 @@ def image_input_unavailable_reason(
|
|
|
743
840
|
def recommended_unavailable_routes(host: Optional[Mapping[str, Any]] = None) -> Dict[str, Dict[str, str]]:
|
|
744
841
|
"""Recommended rows this host cannot run: `{key: {provider, model, reason}}`.
|
|
745
842
|
|
|
746
|
-
On every host that is not Apple silicon `output.
|
|
747
|
-
|
|
748
|
-
|
|
843
|
+
On every host that is not Apple silicon `output.video` is here (its only
|
|
844
|
+
recommended engine, MLX-Gen, is Apple silicon only), and so is
|
|
845
|
+
`output.image` except on an NVIDIA GPU, whose image pick is Diffusers
|
|
846
|
+
(`by_accelerator`; there it is here only where the catalog says it does
|
|
847
|
+
not fit the GPU's memory). On Apple
|
|
749
848
|
silicon the memory-gated rows (`_FIT_GATED_ROUTES`: image, video) are here
|
|
750
849
|
where the catalog says their model does not fit: `output.image` on an 8 GB
|
|
751
850
|
Mac (FLUX.2 klein 4B needs ~8.5 GiB), `output.video` below 32 GiB of
|
|
@@ -837,8 +936,8 @@ def configured_routes_unavailable(
|
|
|
837
936
|
pick = recommended.get(rec_key) if rec_key else None
|
|
838
937
|
if pick is not None:
|
|
839
938
|
reason = f"{reason}; this computer's recommended route is {pick.provider}/{pick.model}"
|
|
840
|
-
elif rec_key
|
|
841
|
-
reason = f"{reason}; {
|
|
939
|
+
elif _unavailable_next_step(rec_key, profile):
|
|
940
|
+
reason = f"{reason}; {_unavailable_next_step(rec_key, profile)}"
|
|
842
941
|
out[key] = {"provider": provider, "model": model, "reason": reason}
|
|
843
942
|
return out
|
|
844
943
|
|
|
@@ -904,6 +1003,7 @@ def recommended_model_downloads(host: Optional[Mapping[str, Any]] = None) -> Dic
|
|
|
904
1003
|
RECOMMENDED_SELECTORS: Dict[str, str] = {
|
|
905
1004
|
"text": "input.text",
|
|
906
1005
|
"voice": "output.voice",
|
|
1006
|
+
"stt": "input.voice",
|
|
907
1007
|
"image": "output.image",
|
|
908
1008
|
"video": "output.video",
|
|
909
1009
|
}
|
|
@@ -1073,7 +1173,16 @@ def seed_recommended_capability_defaults(
|
|
|
1073
1173
|
provenance marker so surfaces can label the values as recommended. The
|
|
1074
1174
|
recommendation is this host's (Apple silicon: the unified-memory tier); a
|
|
1075
1175
|
route this host cannot run is left unset (`recommended_unavailable_routes`).
|
|
1176
|
+
|
|
1177
|
+
With no `host` it reads the LIGHT host profile only: it runs when the
|
|
1178
|
+
config store is first created, on import, where no GPU tool or engine may
|
|
1179
|
+
load. The light reading sees no CUDA, so a fresh NVIDIA install gets no
|
|
1180
|
+
image route here; `apply-recommended` (full probe) writes it.
|
|
1076
1181
|
"""
|
|
1182
|
+
if host is None:
|
|
1183
|
+
from ..utils.host_profile import host_profile
|
|
1184
|
+
|
|
1185
|
+
host = host_profile(light=True)
|
|
1077
1186
|
for key, route in recommended_capability_default_routes(host).items():
|
|
1078
1187
|
existing = config.routes.get(key)
|
|
1079
1188
|
if existing is None or not existing.configured():
|
|
@@ -1086,6 +1195,56 @@ def seed_recommended_capability_defaults(
|
|
|
1086
1195
|
return config
|
|
1087
1196
|
|
|
1088
1197
|
|
|
1198
|
+
def upgrade_recommended_seed(
|
|
1199
|
+
config: CapabilityDefaultsConfig, *, host: Optional[Mapping[str, Any]] = None
|
|
1200
|
+
) -> bool:
|
|
1201
|
+
"""Add the rows later seed versions introduced to a store an earlier seed wrote.
|
|
1202
|
+
|
|
1203
|
+
Only a store stamped by an earlier seed (`seeded` is an older
|
|
1204
|
+
`recommended-v*`) is touched, and only the rows the newer versions added
|
|
1205
|
+
(`RECOMMENDED_SEED_ADDITIONS`) that are EMPTY in it: a route the operator
|
|
1206
|
+
set is never replaced, and a store that was never seeded is never
|
|
1207
|
+
changed. The recommendation is this host's (a row this host cannot run is
|
|
1208
|
+
left unset), read from the light host profile like the seed itself. The
|
|
1209
|
+
result lives in memory, stamped with the current version, exactly like a
|
|
1210
|
+
fresh seed: the next save of the store persists it. Returns whether the
|
|
1211
|
+
config changed.
|
|
1212
|
+
"""
|
|
1213
|
+
|
|
1214
|
+
seeded = str(config.seeded or "")
|
|
1215
|
+
if not seeded.startswith("recommended-v") or seeded == RECOMMENDED_SEED_VERSION:
|
|
1216
|
+
return False
|
|
1217
|
+
try:
|
|
1218
|
+
current = int(seeded[len("recommended-v"):])
|
|
1219
|
+
except ValueError:
|
|
1220
|
+
return False
|
|
1221
|
+
keys = [
|
|
1222
|
+
key
|
|
1223
|
+
for version, added in RECOMMENDED_SEED_ADDITIONS
|
|
1224
|
+
if int(version[len("recommended-v"):]) > current
|
|
1225
|
+
for key in added
|
|
1226
|
+
]
|
|
1227
|
+
if not keys:
|
|
1228
|
+
return False
|
|
1229
|
+
if host is None:
|
|
1230
|
+
from ..utils.host_profile import host_profile
|
|
1231
|
+
|
|
1232
|
+
host = host_profile(light=True)
|
|
1233
|
+
runnable = recommended_capability_default_routes(host)
|
|
1234
|
+
for key in keys:
|
|
1235
|
+
route = runnable.get(key)
|
|
1236
|
+
existing = config.routes.get(key)
|
|
1237
|
+
if route is None or (existing is not None and existing.configured()):
|
|
1238
|
+
continue
|
|
1239
|
+
config.routes[key] = CapabilityRouteDefault(
|
|
1240
|
+
provider=route.provider, model=route.model,
|
|
1241
|
+
base_url=route.base_url, reasoning=route.reasoning,
|
|
1242
|
+
options=dict(route.options),
|
|
1243
|
+
)
|
|
1244
|
+
config.seeded = RECOMMENDED_SEED_VERSION
|
|
1245
|
+
return True
|
|
1246
|
+
|
|
1247
|
+
|
|
1089
1248
|
def capability_defaults_from_dict(value: Any) -> CapabilityDefaultsConfig:
|
|
1090
1249
|
if isinstance(value, CapabilityDefaultsConfig):
|
|
1091
1250
|
return value
|