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)

View file

@ -14,7 +14,7 @@ apis:
- tool_runtime
- vector_io
providers:
inference:
inference:
- provider_id: ${env.CEREBRAS_API_KEY:+cerebras}
provider_type: remote::cerebras
config:
@ -95,29 +95,29 @@ providers:
provider_type: inline::faiss
config:
kvstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/faiss_store.db
backend: kvstore
namespace: faiss
- provider_id: sqlite-vec
provider_type: inline::sqlite-vec
config:
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/sqlite_vec.db
kvstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/sqlite_vec_registry.db
backend: kvstore
namespace: sqlite_vec
- provider_id: ${env.MILVUS_URL:+milvus}
provider_type: inline::milvus
config:
db_path: ${env.MILVUS_DB_PATH:=~/.llama/distributions/ci-tests}/milvus.db
kvstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/milvus_registry.db
backend: kvstore
namespace: milvus
- provider_id: ${env.CHROMADB_URL:+chromadb}
provider_type: remote::chromadb
config:
url: ${env.CHROMADB_URL:=}
kvstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests/}/chroma_remote_registry.db
backend: kvstore
namespace: chromadb
- provider_id: ${env.PGVECTOR_DB:+pgvector}
provider_type: remote::pgvector
config:
@ -127,16 +127,16 @@ providers:
user: ${env.PGVECTOR_USER:=}
password: ${env.PGVECTOR_PASSWORD:=}
kvstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/pgvector_registry.db
backend: kvstore
namespace: pgvector
files:
- provider_id: meta-reference-files
provider_type: inline::localfs
config:
storage_dir: ${env.FILES_STORAGE_DIR:=~/.llama/distributions/ci-tests/files}
metadata_store:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/files_metadata.db
backend: kvstore
namespace: files
safety:
- provider_id: llama-guard
provider_type: inline::llama-guard
@ -149,11 +149,11 @@ providers:
provider_type: inline::meta-reference
config:
persistence_store:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/agents_store.db
backend: sqlstore
namespace: agents
responses_store:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/responses_store.db
backend: sqlstore
namespace: responses
telemetry:
- provider_id: meta-reference
provider_type: inline::meta-reference
@ -172,21 +172,21 @@ providers:
provider_type: inline::meta-reference
config:
kvstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/meta_reference_eval.db
backend: kvstore
namespace: eval
datasetio:
- provider_id: huggingface
provider_type: remote::huggingface
config:
kvstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/huggingface_datasetio.db
backend: kvstore
namespace: huggingface
- provider_id: localfs
provider_type: inline::localfs
config:
kvstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/localfs_datasetio.db
backend: kvstore
namespace: localfs_datasetio
scoring:
- provider_id: basic
provider_type: inline::basic
@ -216,18 +216,21 @@ providers:
provider_type: inline::reference
config:
kvstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/batches.db
backend: kvstore
namespace: batches
persistence:
backends:
default:
kvstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/registry.db
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/kvstore.db
sqlstore:
type: sqlite
db_path: ${env.SQLITE_STORE_DIR:=~/.llama/distributions/ci-tests}/sqlstore.db
stores:
metadata:
backend: default
backend: kvstore
inference:
backend: default
backend: sqlstore
models: []
shields:
- shield_id: llama-guard