mirror of
https://github.com/meta-llama/llama-stack.git
synced 2025-12-03 09:53:45 +00:00
feat: remove BuildConfig and its usage
Signed-off-by: Charlie Doern <cdoern@redhat.com>
This commit is contained in:
parent
3916015755
commit
0424afb7ed
6 changed files with 9 additions and 202 deletions
|
|
@ -4,36 +4,9 @@
|
||||||
# This source code is licensed under the terms described in the LICENSE file in
|
# This source code is licensed under the terms described in the LICENSE file in
|
||||||
# the root directory of this source tree.
|
# the root directory of this source tree.
|
||||||
|
|
||||||
import json
|
|
||||||
import sys
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from functools import lru_cache
|
|
||||||
from pathlib import Path
|
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"
|
TEMPLATES_PATH = Path(__file__).parent.parent.parent / "distributions"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -49,103 +22,3 @@ def print_subcommand_description(parser, subparsers):
|
||||||
description = subcommand.description
|
description = subcommand.description
|
||||||
description_text += f" {name:<21} {description}\n"
|
description_text += f" {name:<21} {description}\n"
|
||||||
parser.epilog = description_text
|
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
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ def get_provider_dependencies(
|
||||||
|
|
||||||
deps = []
|
deps = []
|
||||||
external_provider_deps = []
|
external_provider_deps = []
|
||||||
registry = get_provider_registry(config)
|
registry = get_provider_registry(config, True)
|
||||||
for api_str, provider_or_providers in providers.items():
|
for api_str, provider_or_providers in providers.items():
|
||||||
providers_for_api = registry[Api(api_str)]
|
providers_for_api = registry[Api(api_str)]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.responses, sql_backends, "storage.stores.responses")
|
||||||
_ensure_backend(stores.prompts, kv_backends, "storage.stores.prompts")
|
_ensure_backend(stores.prompts, kv_backends, "storage.stores.prompts")
|
||||||
return self
|
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
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ from typing import Any
|
||||||
import yaml
|
import yaml
|
||||||
from pydantic import BaseModel
|
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.core.external import load_external_apis
|
||||||
from llama_stack.log import get_logger
|
from llama_stack.log import get_logger
|
||||||
from llama_stack_api import (
|
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
|
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.
|
"""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.
|
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 = get_external_providers_from_module(
|
||||||
registry=registry,
|
registry=registry,
|
||||||
config=config,
|
config=config,
|
||||||
building=(isinstance(config, BuildConfig) or isinstance(config, DistributionSpec)),
|
building=building,
|
||||||
)
|
)
|
||||||
|
|
||||||
return registry
|
return registry
|
||||||
|
|
@ -223,10 +225,7 @@ def get_external_providers_from_module(
|
||||||
registry: dict[Api, dict[str, ProviderSpec]], config, building: bool
|
registry: dict[Api, dict[str, ProviderSpec]], config, building: bool
|
||||||
) -> dict[Api, dict[str, ProviderSpec]]:
|
) -> dict[Api, dict[str, ProviderSpec]]:
|
||||||
provider_list = None
|
provider_list = None
|
||||||
if isinstance(config, BuildConfig):
|
provider_list = config.providers.items()
|
||||||
provider_list = config.distribution_spec.providers.items()
|
|
||||||
else:
|
|
||||||
provider_list = config.providers.items()
|
|
||||||
if provider_list is None:
|
if provider_list is None:
|
||||||
logger.warning("Could not get list of providers from config")
|
logger.warning("Could not get list of providers from config")
|
||||||
return registry
|
return registry
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,14 @@
|
||||||
|
|
||||||
import yaml
|
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.log import get_logger
|
||||||
from llama_stack_api import Api, ExternalApiSpec
|
from llama_stack_api import Api, ExternalApiSpec
|
||||||
|
|
||||||
logger = get_logger(name=__name__, category="core")
|
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.
|
"""Load external API specifications from the configured directory.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,8 @@ from llama_stack.core.datatypes import (
|
||||||
LLAMA_STACK_RUN_CONFIG_VERSION,
|
LLAMA_STACK_RUN_CONFIG_VERSION,
|
||||||
Api,
|
Api,
|
||||||
BenchmarkInput,
|
BenchmarkInput,
|
||||||
BuildConfig,
|
|
||||||
BuildProvider,
|
BuildProvider,
|
||||||
DatasetInput,
|
DatasetInput,
|
||||||
DistributionSpec,
|
|
||||||
ModelInput,
|
ModelInput,
|
||||||
Provider,
|
Provider,
|
||||||
SafetyConfig,
|
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.kvstore.config import SqliteKVStoreConfig
|
||||||
from llama_stack.core.storage.sqlstore.sqlstore import SqliteSqlStoreConfig
|
from llama_stack.core.storage.sqlstore.sqlstore import SqliteSqlStoreConfig
|
||||||
from llama_stack.core.utils.dynamic import instantiate_class_type
|
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.providers.utils.inference.model_registry import ProviderModelEntry
|
||||||
from llama_stack_api import DatasetPurpose, ModelType
|
from llama_stack_api import DatasetPurpose, ModelType
|
||||||
|
|
||||||
|
|
@ -320,28 +317,6 @@ class DistributionTemplate(BaseModel):
|
||||||
|
|
||||||
available_models_by_provider: dict[str, list[ProviderModelEntry]] | None = None
|
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:
|
def generate_markdown_docs(self) -> str:
|
||||||
providers_table = "| API | Provider(s) |\n"
|
providers_table = "| API | Provider(s) |\n"
|
||||||
providers_table += "|-----|-------------|\n"
|
providers_table += "|-----|-------------|\n"
|
||||||
|
|
@ -413,14 +388,6 @@ class DistributionTemplate(BaseModel):
|
||||||
for output_dir in [yaml_output_dir, doc_output_dir]:
|
for output_dir in [yaml_output_dir, doc_output_dir]:
|
||||||
output_dir.mkdir(parents=True, exist_ok=True)
|
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():
|
for yaml_pth, settings in self.run_configs.items():
|
||||||
run_config = settings.run_config(self.name, self.providers, self.container_image)
|
run_config = settings.run_config(self.name, self.providers, self.container_image)
|
||||||
with open(yaml_output_dir / yaml_pth, "w") as f:
|
with open(yaml_output_dir / yaml_pth, "w") as f:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue