diff --git a/src/llama_stack/cli/stack/utils.py b/src/llama_stack/cli/stack/utils.py index e02448e04..51e92f3df 100644 --- a/src/llama_stack/cli/stack/utils.py +++ b/src/llama_stack/cli/stack/utils.py @@ -4,36 +4,9 @@ # This source code is licensed under the terms described in the LICENSE file in # the root directory of this source tree. -import json -import sys from enum import Enum -from functools import lru_cache from pathlib import Path -import yaml -from termcolor import cprint - -from llama_stack.core.datatypes import ( - BuildConfig, - Provider, - StackConfig, - StorageConfig, -) -from llama_stack.core.distribution import get_provider_registry -from llama_stack.core.resolver import InvalidProviderError -from llama_stack.core.storage.datatypes import ( - InferenceStoreReference, - KVStoreReference, - ServerStoresConfig, - SqliteKVStoreConfig, - SqliteSqlStoreConfig, - SqlStoreReference, -) -from llama_stack.core.utils.config_dirs import DISTRIBS_BASE_DIR, EXTERNAL_PROVIDERS_DIR -from llama_stack.core.utils.dynamic import instantiate_class_type -from llama_stack.core.utils.image_types import LlamaStackImageType -from llama_stack_api import Api - TEMPLATES_PATH = Path(__file__).parent.parent.parent / "distributions" @@ -49,103 +22,3 @@ def print_subcommand_description(parser, subparsers): description = subcommand.description description_text += f" {name:<21} {description}\n" parser.epilog = description_text - - -def generate_run_config( - build_config: BuildConfig, - build_dir: Path, - image_name: str, -) -> Path: - """ - Generate a config.yaml template file for user to edit from a build.yaml file - """ - apis = list(build_config.distribution_spec.providers.keys()) - distro_dir = DISTRIBS_BASE_DIR / image_name - run_config = StackConfig( - container_image=(image_name if build_config.image_type == LlamaStackImageType.CONTAINER.value else None), - image_name=image_name, - apis=apis, - providers={}, - storage=StorageConfig( - backends={ - "kv_default": SqliteKVStoreConfig(db_path=str(distro_dir / "kvstore.db")), - "sql_default": SqliteSqlStoreConfig(db_path=str(distro_dir / "sql_store.db")), - }, - stores=ServerStoresConfig( - metadata=KVStoreReference(backend="kv_default", namespace="registry"), - inference=InferenceStoreReference(backend="sql_default", table_name="inference_store"), - conversations=SqlStoreReference(backend="sql_default", table_name="openai_conversations"), - ), - ), - external_providers_dir=build_config.external_providers_dir - if build_config.external_providers_dir - else EXTERNAL_PROVIDERS_DIR, - ) - # build providers dict - provider_registry = get_provider_registry(build_config) - for api in apis: - run_config.providers[api] = [] - providers = build_config.distribution_spec.providers[api] - - for provider in providers: - pid = provider.provider_type.split("::")[-1] - - p = provider_registry[Api(api)][provider.provider_type] - if p.deprecation_error: - raise InvalidProviderError(p.deprecation_error) - - try: - config_type = instantiate_class_type(provider_registry[Api(api)][provider.provider_type].config_class) - except (ModuleNotFoundError, ValueError) as exc: - # HACK ALERT: - # This code executes after building is done, the import cannot work since the - # package is either available in the venv or container - not available on the host. - # TODO: use a "is_external" flag in ProviderSpec to check if the provider is - # external - cprint( - f"Failed to import provider {provider.provider_type} for API {api} - assuming it's external, skipping: {exc}", - color="yellow", - file=sys.stderr, - ) - # Set config_type to None to avoid UnboundLocalError - config_type = None - - if config_type is not None and hasattr(config_type, "sample_run_config"): - config = config_type.sample_run_config(__distro_dir__=f"~/.llama/distributions/{image_name}") - else: - config = {} - - p_spec = Provider( - provider_id=pid, - provider_type=provider.provider_type, - config=config, - module=provider.module, - ) - run_config.providers[api].append(p_spec) - - run_config_file = build_dir / f"{image_name}-config.yaml" - - with open(run_config_file, "w") as f: - to_write = json.loads(run_config.model_dump_json()) - f.write(yaml.dump(to_write, sort_keys=False)) - - # Only print this message for non-container builds since it will be displayed before the - # container is built - # For non-container builds, the config.yaml is generated at the very end of the build process so it - # makes sense to display this message - if build_config.image_type != LlamaStackImageType.CONTAINER.value: - cprint(f"You can now run your stack with `llama stack run {run_config_file}`", color="green", file=sys.stderr) - return run_config_file - - -@lru_cache -def available_templates_specs() -> dict[str, BuildConfig]: - import yaml - - template_specs = {} - for p in TEMPLATES_PATH.rglob("*build.yaml"): - template_name = p.parent.name - with open(p) as f: - build_config = BuildConfig(**yaml.safe_load(f)) - template_specs[template_name] = build_config - return template_specs diff --git a/src/llama_stack/core/build.py b/src/llama_stack/core/build.py index 4e6ccc9f7..6c53e1439 100644 --- a/src/llama_stack/core/build.py +++ b/src/llama_stack/core/build.py @@ -46,7 +46,7 @@ def get_provider_dependencies( deps = [] external_provider_deps = [] - registry = get_provider_registry(config) + registry = get_provider_registry(config, True) for api_str, provider_or_providers in providers.items(): providers_for_api = registry[Api(api_str)] diff --git a/src/llama_stack/core/datatypes.py b/src/llama_stack/core/datatypes.py index 5ab2b43dc..05f1d3690 100644 --- a/src/llama_stack/core/datatypes.py +++ b/src/llama_stack/core/datatypes.py @@ -607,35 +607,3 @@ can be instantiated multiple times (with different configs) if necessary. _ensure_backend(stores.responses, sql_backends, "storage.stores.responses") _ensure_backend(stores.prompts, kv_backends, "storage.stores.prompts") return self - - -class BuildConfig(BaseModel): - version: int = LLAMA_STACK_BUILD_CONFIG_VERSION - - distribution_spec: DistributionSpec = Field(description="The distribution spec to build including API providers. ") - image_type: str = Field( - default="venv", - description="Type of package to build (container | venv)", - ) - image_name: str | None = Field( - default=None, - description="Name of the distribution to build", - ) - external_providers_dir: Path | None = Field( - default=None, - description="Path to directory containing external provider implementations. The providers packages will be resolved from this directory. " - "pip_packages MUST contain the provider package name.", - ) - external_apis_dir: Path | None = Field( - default=None, - description="Path to directory containing external API implementations. The APIs code and dependencies must be installed on the system.", - ) - - @field_validator("external_providers_dir") - @classmethod - def validate_external_providers_dir(cls, v): - if v is None: - return None - if isinstance(v, str): - return Path(v) - return v diff --git a/src/llama_stack/core/distribution.py b/src/llama_stack/core/distribution.py index 658c75ef2..554b99ddb 100644 --- a/src/llama_stack/core/distribution.py +++ b/src/llama_stack/core/distribution.py @@ -12,7 +12,7 @@ from typing import Any import yaml from pydantic import BaseModel -from llama_stack.core.datatypes import BuildConfig, DistributionSpec +from llama_stack.core.datatypes import StackConfig from llama_stack.core.external import load_external_apis from llama_stack.log import get_logger from llama_stack_api import ( @@ -85,7 +85,9 @@ def _load_inline_provider_spec(spec_data: dict[str, Any], api: Api, provider_nam return spec -def get_provider_registry(config=None) -> dict[Api, dict[str, ProviderSpec]]: +def get_provider_registry( + config: StackConfig | None = None, building: bool = False +) -> dict[Api, dict[str, ProviderSpec]]: """Get the provider registry, optionally including external providers. This function loads both built-in providers and external providers from YAML files or from their provided modules. @@ -161,7 +163,7 @@ def get_provider_registry(config=None) -> dict[Api, dict[str, ProviderSpec]]: registry = get_external_providers_from_module( registry=registry, config=config, - building=(isinstance(config, BuildConfig) or isinstance(config, DistributionSpec)), + building=building, ) return registry @@ -223,10 +225,7 @@ def get_external_providers_from_module( registry: dict[Api, dict[str, ProviderSpec]], config, building: bool ) -> dict[Api, dict[str, ProviderSpec]]: provider_list = None - if isinstance(config, BuildConfig): - provider_list = config.distribution_spec.providers.items() - else: - provider_list = config.providers.items() + provider_list = config.providers.items() if provider_list is None: logger.warning("Could not get list of providers from config") return registry diff --git a/src/llama_stack/core/external.py b/src/llama_stack/core/external.py index aa2a0c2c9..94f8d7525 100644 --- a/src/llama_stack/core/external.py +++ b/src/llama_stack/core/external.py @@ -7,14 +7,14 @@ import yaml -from llama_stack.core.datatypes import BuildConfig, StackConfig +from llama_stack.core.datatypes import StackConfig from llama_stack.log import get_logger from llama_stack_api import Api, ExternalApiSpec logger = get_logger(name=__name__, category="core") -def load_external_apis(config: StackConfig | BuildConfig | None) -> dict[Api, ExternalApiSpec]: +def load_external_apis(config: StackConfig | None) -> dict[Api, ExternalApiSpec]: """Load external API specifications from the configured directory. Args: diff --git a/src/llama_stack/distributions/template.py b/src/llama_stack/distributions/template.py index a8e5f2839..afeb8ee92 100644 --- a/src/llama_stack/distributions/template.py +++ b/src/llama_stack/distributions/template.py @@ -16,10 +16,8 @@ from llama_stack.core.datatypes import ( LLAMA_STACK_RUN_CONFIG_VERSION, Api, BenchmarkInput, - BuildConfig, BuildProvider, DatasetInput, - DistributionSpec, ModelInput, Provider, SafetyConfig, @@ -38,7 +36,6 @@ from llama_stack.core.storage.datatypes import ( from llama_stack.core.storage.kvstore.config import SqliteKVStoreConfig from llama_stack.core.storage.sqlstore.sqlstore import SqliteSqlStoreConfig from llama_stack.core.utils.dynamic import instantiate_class_type -from llama_stack.core.utils.image_types import LlamaStackImageType from llama_stack.providers.utils.inference.model_registry import ProviderModelEntry from llama_stack_api import DatasetPurpose, ModelType @@ -320,28 +317,6 @@ class DistributionTemplate(BaseModel): available_models_by_provider: dict[str, list[ProviderModelEntry]] | None = None - def build_config(self) -> BuildConfig: - # Create minimal providers for build config (without runtime configs) - build_providers = {} - for api, providers in self.providers.items(): - build_providers[api] = [] - for provider in providers: - # Create a minimal build provider object with only essential build information - build_provider = BuildProvider( - provider_type=provider.provider_type, - module=provider.module, - ) - build_providers[api].append(build_provider) - - return BuildConfig( - distribution_spec=DistributionSpec( - description=self.description, - container_image=self.container_image, - providers=build_providers, - ), - image_type=LlamaStackImageType.VENV.value, # default to venv - ) - def generate_markdown_docs(self) -> str: providers_table = "| API | Provider(s) |\n" providers_table += "|-----|-------------|\n" @@ -413,14 +388,6 @@ class DistributionTemplate(BaseModel): for output_dir in [yaml_output_dir, doc_output_dir]: output_dir.mkdir(parents=True, exist_ok=True) - build_config = self.build_config() - with open(yaml_output_dir / "build.yaml", "w") as f: - yaml.safe_dump( - filter_empty_values(build_config.model_dump(exclude_none=True)), - f, - sort_keys=False, - ) - for yaml_pth, settings in self.run_configs.items(): run_config = settings.run_config(self.name, self.providers, self.container_image) with open(yaml_output_dir / yaml_pth, "w") as f: