feat: providers use centralized persistence backends

- Add provider_config_resolver to resolve backend references in provider configs
- Providers can now reference persistence.backends instead of duplicating kvstore configs
- Supports kvstore, metadata_store, persistence_store, responses_store references
- Updated ci-tests to use backend references with namespaces
- Eliminates massive config duplication across providers
This commit is contained in:
Ashwin Bharambe 2025-10-05 18:59:54 -07:00
parent 6be4cf7d18
commit d15fa60c1b
3 changed files with 124 additions and 29 deletions

View file

@ -650,6 +650,30 @@ reference them from multiple stores. If not specified, default SQLite stores wil
return Path(v)
return v
@model_validator(mode="after")
def resolve_provider_backend_references(self) -> Self:
"""Resolve backend references in provider kvstore configs."""
if not self.persistence or not self.persistence.backends:
return self
from llama_stack.core.provider_config_resolver import resolve_provider_kvstore_references
# Convert providers to dict format for resolution
providers_dict = {}
for api, provider_list in self.providers.items():
providers_dict[api] = [p.model_dump() for p in provider_list]
# Resolve backend references
resolved_providers = resolve_provider_kvstore_references(
providers_dict, self.persistence.backends
)
# Convert back to Provider objects
for api, provider_list in resolved_providers.items():
self.providers[api] = [Provider(**p) for p in provider_list]
return self
class BuildConfig(BaseModel):
version: int = LLAMA_STACK_BUILD_CONFIG_VERSION

View file

@ -0,0 +1,68 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.
from typing import Any
def resolve_provider_kvstore_references(
providers: dict[str, list[dict[str, Any]]],
persistence_backends: dict[str, Any],
) -> dict[str, list[dict[str, Any]]]:
"""
Resolve backend references in provider kvstore configs to actual backend configs.
This allows providers to reference centralized persistence backends instead of
duplicating kvstore configs.
Example:
# Provider config with backend reference
kvstore:
backend: kvstore
namespace: faiss
# Gets resolved to actual backend config
kvstore:
type: sqlite
db_path: /path/to/kvstore.db
namespace: faiss
"""
for api, provider_list in providers.items():
for provider in provider_list:
config = provider.get("config", {})
_resolve_kvstore_in_dict(config, persistence_backends)
return providers
def _resolve_kvstore_in_dict(config: dict[str, Any], backends: dict[str, Any]) -> None:
"""Recursively find and resolve backend references in config dict."""
# Store keys that typically contain backend references
store_keys = {"kvstore", "metadata_store", "persistence_store", "responses_store"}
for key, value in list(config.items()):
if key in store_keys and isinstance(value, dict):
# Check if it's a backend reference
if "backend" in value:
backend_name = value["backend"]
namespace = value.get("namespace")
if backend_name not in backends:
raise ValueError(
f"Provider references backend '{backend_name}' which is not defined in persistence.backends"
)
# Clone the backend config and apply namespace
backend_config = backends[backend_name]
resolved_config = backend_config.model_dump() if hasattr(backend_config, "model_dump") else dict(backend_config)
if namespace:
resolved_config["namespace"] = namespace
config[key] = resolved_config
elif isinstance(value, dict):
# Recursively process nested dicts
_resolve_kvstore_in_dict(value, backends)