fix(vector_stores): keep config-defined vector stores when /vector_store/list reconciles with the DB

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Devin AI 2026-09-02 16:55:17 +00:00
parent 55e9e4ce2f
commit f577c7d3a4
3 changed files with 53 additions and 2 deletions

View file

@ -613,6 +613,7 @@ async def list_vector_stores(
# Process in-memory vector stores
if litellm.vector_store_registry is not None:
in_memory_vector_stores: Final = copy.deepcopy(litellm.vector_store_registry.vector_stores)
config_vector_store_ids: Final = litellm.vector_store_registry.config_vector_store_ids
vector_stores_to_delete_from_memory: Final[list[str]] = []
@ -621,8 +622,7 @@ async def list_vector_stores(
if not vector_store_id:
continue
# If vector store is in memory but NOT in database, it was deleted
if vector_store_id not in db_vector_store_ids:
if vector_store_id not in db_vector_store_ids and vector_store_id not in config_vector_store_ids:
verbose_proxy_logger.info(
"Vector store %s exists in memory but not in database - marking for deletion from cache",
vector_store_id,

View file

@ -104,6 +104,7 @@ class VectorStoreRegistry:
def __init__(self, vector_stores: list[LiteLLM_ManagedVectorStore] = []):
self.vector_stores: list[LiteLLM_ManagedVectorStore] = vector_stores
self.vector_store_ids_to_vector_store_map: dict[str, LiteLLM_ManagedVectorStore] = {}
self.config_vector_store_ids: set[str] = set()
def _extract_tool_params(self, tool: dict) -> VectorStoreToolParams:
"""
@ -429,6 +430,7 @@ class VectorStoreRegistry:
updated_at=datetime.now(timezone.utc),
)
self.vector_stores.append(litellm_managed_vector_store)
self.config_vector_store_ids.add(vector_store_id)
verbose_logger.debug(
"all loaded vector stores = %s",
@ -474,6 +476,7 @@ class VectorStoreRegistry:
for vector_store in self.vector_stores
if vector_store.get("vector_store_id") != vector_store_id
]
self.config_vector_store_ids.discard(vector_store_id)
def update_vector_store_in_registry(self, vector_store_id: str, updated_data: LiteLLM_ManagedVectorStore):
"""Update or add a vector store in the registry"""

View file

@ -2002,6 +2002,54 @@ async def test_vector_store_update_and_list_synchronization():
), "List should return updated data from database"
@pytest.mark.asyncio
async def test_list_vector_stores_keeps_config_defined_store_missing_from_db():
"""
Stores from config.yaml `vector_store_registry` are only loaded in memory and never written
to the DB. Listing must not treat that DB miss as a deletion and evict them, while a
DB-sourced store that disappeared from the DB is still evicted.
"""
from litellm.proxy.vector_store_endpoints.management_endpoints import list_vector_stores
from litellm.vector_stores.vector_store_registry import VectorStoreRegistry
registry = VectorStoreRegistry(vector_stores=[])
registry.load_vector_stores_from_config(
[
{
"vector_store_name": "config-search-store",
"litellm_params": {
"vector_store_id": "config-search-store",
"custom_llm_provider": "azure_ai",
"api_key": "fake",
"api_base": "https://example.search.windows.net",
},
}
]
)
stale_db_store: LiteLLM_ManagedVectorStore = {
"vector_store_id": "deleted-elsewhere",
"custom_llm_provider": "bedrock",
"litellm_params": {"vector_store_id": "deleted-elsewhere", "custom_llm_provider": "bedrock"},
}
registry.add_vector_store_to_registry(vector_store=stale_db_store)
admin = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN.value, user_id="admin")
with (
patch.dict("litellm.proxy.proxy_server.general_settings", {}, clear=True),
patch("litellm.proxy.proxy_server.prisma_client", MagicMock()),
patch.object(litellm, "vector_store_registry", registry),
patch(
"litellm.proxy.vector_store_endpoints.management_endpoints.VectorStoreRegistry._get_vector_stores_from_db",
new=AsyncMock(return_value=[]),
),
):
response = await list_vector_stores(user_api_key_dict=admin)
assert [vs.get("vector_store_id") for vs in response["data"]] == ["config-search-store"]
assert registry.get_litellm_managed_vector_store_from_registry_by_name("config-search-store") is not None
assert registry.get_litellm_managed_vector_store_from_registry("deleted-elsewhere") is None
@pytest.mark.asyncio
async def test_resolve_embedding_config_from_db():
"""Test that _resolve_embedding_config_from_db correctly resolves embedding config from database."""