From 0e56e2b83e2c915f73234089d72030df634e2fff Mon Sep 17 00:00:00 2001 From: Jonathan Neufeld Date: Wed, 30 Sep 2026 11:53:28 -0600 Subject: [PATCH 1/4] feat(valkey): identify Valkey connections with lib-name redis-py(litellm) Pass lib_name to every redis-py client the Valkey semantic cache and Valkey vector store build, so CLIENT SETINFO LIB-NAME reports redis-py(litellm). The redis-py base name is kept and LiteLLM appended in the base(tag) form; lib-ver is unchanged. Caller-supplied clients are left as-is. No dependency change: lib_name exists since redis-py 5.0, which redisvl>=0.4.1 already requires. --- litellm/caching/valkey_semantic_cache.py | 12 +++++++++--- litellm/llms/valkey/common_utils.py | 5 +++++ litellm/llms/valkey/vector_stores/transformation.py | 4 +++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/litellm/caching/valkey_semantic_cache.py b/litellm/caching/valkey_semantic_cache.py index 58b76d98d6d..f1ed627b86f 100644 --- a/litellm/caching/valkey_semantic_cache.py +++ b/litellm/caching/valkey_semantic_cache.py @@ -29,7 +29,7 @@ from redis.commands.search.query import Query from litellm._logging import print_verbose from litellm._uuid import uuid -from litellm.llms.valkey.common_utils import build_valkey_url, pack_vector +from litellm.llms.valkey.common_utils import VALKEY_LIB_NAME, build_valkey_url, pack_vector from ._embedding_router import resolve_embedding_timeout from .redis_semantic_cache import RedisSemanticCache @@ -93,8 +93,14 @@ class ValkeySemanticCache(RedisSemanticCache): self.async_client = async_client else: resolved_url: Final = redis_url or self._build_valkey_url(host, port, password, ssl) - self.sync_client = sync_client if sync_client is not None else Redis.from_url(resolved_url) - self.async_client = async_client if async_client is not None else AsyncRedis.from_url(resolved_url) + self.sync_client = ( + sync_client if sync_client is not None else Redis.from_url(resolved_url, lib_name=VALKEY_LIB_NAME) + ) + self.async_client = ( + async_client + if async_client is not None + else AsyncRedis.from_url(resolved_url, lib_name=VALKEY_LIB_NAME) + ) print_verbose(f"Valkey semantic-cache initializing index - {self.index_name}") diff --git a/litellm/llms/valkey/common_utils.py b/litellm/llms/valkey/common_utils.py index 9691450f3e0..703509904be 100644 --- a/litellm/llms/valkey/common_utils.py +++ b/litellm/llms/valkey/common_utils.py @@ -5,6 +5,11 @@ from collections.abc import Sequence from typing import Final from urllib.parse import quote +# Sent via CLIENT SETINFO LIB-NAME so server-side client listings can attribute +# connections to LiteLLM. redis-py's lib_name replaces its default "redis-py", +# so the base name is kept and the tag appended in the conventional base(tag) form. +VALKEY_LIB_NAME: Final = "redis-py(litellm)" + def build_valkey_url(host: str, port: str, password: str | None = None, ssl: bool = False) -> str: """Deliberately reads no environment: callers of the vector store control the diff --git a/litellm/llms/valkey/vector_stores/transformation.py b/litellm/llms/valkey/vector_stores/transformation.py index b250f71cf3f..76c92500ea4 100644 --- a/litellm/llms/valkey/vector_stores/transformation.py +++ b/litellm/llms/valkey/vector_stores/transformation.py @@ -19,7 +19,7 @@ from litellm.llms.base_llm.vector_store.transformation import ( BaseDirectVectorStoreConfig, VectorStoreEmbeddingExecutor, ) -from litellm.llms.valkey.common_utils import build_valkey_url, pack_vector +from litellm.llms.valkey.common_utils import VALKEY_LIB_NAME, build_valkey_url, pack_vector from litellm.types.utils import EmbeddingResponse from litellm.types.vector_stores import ( VectorStoreCreateOptionalRequestParams, @@ -250,6 +250,7 @@ class ValkeyVectorStoreConfig(BaseDirectVectorStoreConfig): params.connection_url(), socket_connect_timeout=connect_timeout, socket_timeout=op_timeout, + lib_name=VALKEY_LIB_NAME, ) try: raw_result: Final = client.ft(vector_store_id).search(knn, query_params=vec_params) @@ -300,6 +301,7 @@ class ValkeyVectorStoreConfig(BaseDirectVectorStoreConfig): params.connection_url(), socket_connect_timeout=connect_timeout, socket_timeout=op_timeout, + lib_name=VALKEY_LIB_NAME, ) try: raw_result: Final = await client.ft(vector_store_id).search( # pyright: ignore[reportGeneralTypeIssues] # types-redis 4.6 stubs shadow redis 5.3.1 and type the async client's ft() as the sync Search, so search() returns a non-awaitable Result; it is a coroutine at runtime From b950e40f5a08c10493e1fc635b5540f2f4c714b4 Mon Sep 17 00:00:00 2001 From: Jonathan Neufeld Date: Wed, 30 Sep 2026 12:45:10 -0600 Subject: [PATCH 2/4] test(valkey): cover lib-name connection identity; scope stub-gap type ignores Assert lib_name="redis-py(litellm)" on the sync and async redis-py clients built by the semantic cache and by the vector-store search paths. types-redis 4.6 stubs shadow redis 5.3.1 and omit from_url(lib_name=...), which added four reportCallIssue errors and tripped the basedpyright budget. Scope a pyright ignore to each call, matching the existing stub-gap comments. --- litellm/caching/valkey_semantic_cache.py | 4 +- .../valkey/vector_stores/transformation.py | 4 +- .../caching/test_valkey_semantic_cache.py | 9 ++++ .../test_valkey_transformation.py | 49 +++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/litellm/caching/valkey_semantic_cache.py b/litellm/caching/valkey_semantic_cache.py index f1ed627b86f..360c6bb5960 100644 --- a/litellm/caching/valkey_semantic_cache.py +++ b/litellm/caching/valkey_semantic_cache.py @@ -94,12 +94,12 @@ class ValkeySemanticCache(RedisSemanticCache): else: resolved_url: Final = redis_url or self._build_valkey_url(host, port, password, ssl) self.sync_client = ( - sync_client if sync_client is not None else Redis.from_url(resolved_url, lib_name=VALKEY_LIB_NAME) + sync_client if sync_client is not None else Redis.from_url(resolved_url, lib_name=VALKEY_LIB_NAME) # pyright: ignore[reportCallIssue] # types-redis 4.6 stubs shadow redis 5.3.1 and omit from_url(lib_name=...); redis-py accepts it at runtime ) self.async_client = ( async_client if async_client is not None - else AsyncRedis.from_url(resolved_url, lib_name=VALKEY_LIB_NAME) + else AsyncRedis.from_url(resolved_url, lib_name=VALKEY_LIB_NAME) # pyright: ignore[reportCallIssue] # types-redis 4.6 stubs shadow redis 5.3.1 and omit from_url(lib_name=...); redis-py accepts it at runtime ) print_verbose(f"Valkey semantic-cache initializing index - {self.index_name}") diff --git a/litellm/llms/valkey/vector_stores/transformation.py b/litellm/llms/valkey/vector_stores/transformation.py index 76c92500ea4..6b8fb4b03a6 100644 --- a/litellm/llms/valkey/vector_stores/transformation.py +++ b/litellm/llms/valkey/vector_stores/transformation.py @@ -246,7 +246,7 @@ class ValkeyVectorStoreConfig(BaseDirectVectorStoreConfig): return self._to_response(raw, query_text, params.text_field) connect_timeout, op_timeout = self._socket_timeouts(timeout) - client: Final = _import_sync_redis().from_url( + client: Final = _import_sync_redis().from_url( # pyright: ignore[reportCallIssue] # types-redis 4.6 stubs shadow redis 5.3.1 and omit from_url(lib_name=...); redis-py accepts it at runtime params.connection_url(), socket_connect_timeout=connect_timeout, socket_timeout=op_timeout, @@ -297,7 +297,7 @@ class ValkeyVectorStoreConfig(BaseDirectVectorStoreConfig): return self._to_response(raw, query_text, params.text_field) connect_timeout, op_timeout = self._socket_timeouts(timeout) - client: Final = _import_async_redis().from_url( + client: Final = _import_async_redis().from_url( # pyright: ignore[reportCallIssue] # types-redis 4.6 stubs shadow redis 5.3.1 and omit from_url(lib_name=...); redis-py accepts it at runtime params.connection_url(), socket_connect_timeout=connect_timeout, socket_timeout=op_timeout, diff --git a/tests/unit/caching/test_valkey_semantic_cache.py b/tests/unit/caching/test_valkey_semantic_cache.py index 749658784ac..935fe72f3f6 100644 --- a/tests/unit/caching/test_valkey_semantic_cache.py +++ b/tests/unit/caching/test_valkey_semantic_cache.py @@ -534,3 +534,12 @@ def test_importing_caching_does_not_require_redis(): ) assert result.returncode == 0, result.stderr assert "ok" in result.stdout + + +def test_self_built_clients_identify_as_litellm_via_lib_name(): + # from_url builds a pool without connecting, so the kwargs redis-py will send + # on CLIENT SETINFO LIB-NAME can be read straight off the real clients. + cache = ValkeySemanticCache(similarity_threshold=0.8, redis_url="redis://valkey-host:6379") + + assert cache.sync_client.connection_pool.connection_kwargs["lib_name"] == "redis-py(litellm)" + assert cache.async_client.connection_pool.connection_kwargs["lib_name"] == "redis-py(litellm)" diff --git a/tests/unit/llms/valkey/vector_stores/test_valkey_transformation.py b/tests/unit/llms/valkey/vector_stores/test_valkey_transformation.py index 64e15008536..0f723f365cd 100644 --- a/tests/unit/llms/valkey/vector_stores/test_valkey_transformation.py +++ b/tests/unit/llms/valkey/vector_stores/test_valkey_transformation.py @@ -398,3 +398,52 @@ def test_provider_config_manager_returns_valkey_config(): config = ProviderConfigManager.get_provider_vector_stores_config(provider=LlmProviders.VALKEY, api_type=None) assert isinstance(config, ValkeyVectorStoreConfig) + + +class _RecordingRedisFactory: + """Stands in for the redis-py client class so the search path's from_url kwargs can be asserted.""" + + def __init__(self, client): + self.client = client + self.from_url_kwargs = None + + def from_url(self, url, **kwargs): + self.from_url_kwargs = kwargs + return self.client + + +class _ClosableFakeRedis(FakeRedis): + def close(self): + pass + + +class _ClosableFakeAsyncRedis(FakeAsyncRedis): + async def aclose(self): + pass + + +def test_sync_search_identifies_connection_as_litellm_via_lib_name(monkeypatch): + factory = _RecordingRedisFactory(_ClosableFakeRedis()) + monkeypatch.setattr("litellm.llms.valkey.vector_stores.transformation._import_sync_redis", lambda: factory) + config = ValkeyVectorStoreConfig(embedding_fn=FakeEmbeddingFn([1.0])) + + _search(config, litellm_params={"valkey_host": "valkey-host"}) + + assert factory.from_url_kwargs["lib_name"] == "redis-py(litellm)" + + +@pytest.mark.asyncio +async def test_async_search_identifies_connection_as_litellm_via_lib_name(monkeypatch): + factory = _RecordingRedisFactory(_ClosableFakeAsyncRedis()) + monkeypatch.setattr("litellm.llms.valkey.vector_stores.transformation._import_async_redis", lambda: factory) + config = ValkeyVectorStoreConfig(aembedding_fn=FakeAsyncEmbeddingFn([1.0])) + + await config.aexecute_search_vector_store_request( + vector_store_id="my_index", + query="q", + vector_store_search_optional_params={}, + litellm_logging_obj=MagicMock(), + litellm_params={"litellm_embedding_model": "openai/text-embedding-3-small", "valkey_host": "valkey-host"}, + ) + + assert factory.from_url_kwargs["lib_name"] == "redis-py(litellm)" From 4e4ff11bcafb3019b7bd75da97f643f47f77b548 Mon Sep 17 00:00:00 2001 From: Jonathan Neufeld Date: Thu, 1 Oct 2026 12:41:30 -0600 Subject: [PATCH 3/4] fix(valkey): keep basedpyright arg-type budget green after main merge The from_url client's return type is unknown under the types-redis 4.6 stubs, so raw_result reaches _to_response as an unknown-typed argument. Suppress reportUnknownArgumentType on those two returns, matching the existing stub-gap ignores on the same calls. No runtime change. Signed-off-by: Jonathan Neufeld --- litellm/llms/valkey/vector_stores/transformation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litellm/llms/valkey/vector_stores/transformation.py b/litellm/llms/valkey/vector_stores/transformation.py index 6b8fb4b03a6..d36228eb50c 100644 --- a/litellm/llms/valkey/vector_stores/transformation.py +++ b/litellm/llms/valkey/vector_stores/transformation.py @@ -254,7 +254,7 @@ class ValkeyVectorStoreConfig(BaseDirectVectorStoreConfig): ) try: raw_result: Final = client.ft(vector_store_id).search(knn, query_params=vec_params) - return self._to_response(raw_result, query_text, params.text_field) + return self._to_response(raw_result, query_text, params.text_field) # pyright: ignore[reportUnknownArgumentType] # raw_result flows from the from_url client whose return type the types-redis 4.6 stubs leave unknown; the shape is validated inside _to_response finally: client.close() @@ -307,7 +307,7 @@ class ValkeyVectorStoreConfig(BaseDirectVectorStoreConfig): raw_result: Final = await client.ft(vector_store_id).search( # pyright: ignore[reportGeneralTypeIssues] # types-redis 4.6 stubs shadow redis 5.3.1 and type the async client's ft() as the sync Search, so search() returns a non-awaitable Result; it is a coroutine at runtime knn, query_params=vec_params ) - return self._to_response(raw_result, query_text, params.text_field) + return self._to_response(raw_result, query_text, params.text_field) # pyright: ignore[reportUnknownArgumentType] # raw_result flows from the from_url client whose return type the types-redis 4.6 stubs leave unknown; the shape is validated inside _to_response finally: await client.aclose() From 1feb1aa37d0875137b538c7dbd5ccb9fcb1cf70d Mon Sep 17 00:00:00 2001 From: Jonathan Neufeld Date: Thu, 8 Oct 2026 09:33:42 -0600 Subject: [PATCH 4/4] fix(valkey): scope basedpyright ignores to the lib_name stub gap The merge of main into this branch (b9e2b36f) made the basedpyright budget gate's reportUnknownMemberType/reportUnknownVariableType ceilings breach by 22: our 3 from_url(..., lib_name=VALKEY_LIB_NAME) call sites don't match either types-redis 4.6 stub overload (neither declares lib_name), so basedpyright can't resolve a sound return type for the client, and every downstream member access and variable inherits Unknown. Add targeted # pyright: ignore[] comments on the exact affected lines in litellm/caching/valkey_semantic_cache.py and litellm/llms/valkey/vector_stores/transformation.py, matching the existing stub-gap-ignore style already used for reportCallIssue and reportUnknownArgumentType in these files (see 4e4ff11b). No behavior change. --- litellm/caching/valkey_semantic_cache.py | 22 +++++++++---------- .../valkey/vector_stores/transformation.py | 12 +++++----- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/litellm/caching/valkey_semantic_cache.py b/litellm/caching/valkey_semantic_cache.py index 959a0427bfa..e1d18a098de 100644 --- a/litellm/caching/valkey_semantic_cache.py +++ b/litellm/caching/valkey_semantic_cache.py @@ -175,26 +175,26 @@ class ValkeySemanticCache(RedisSemanticCache): if self._index_dim == dim: return try: - self.sync_client.ft(self.index_name).create_index( + self.sync_client.ft(self.index_name).create_index( # pyright: ignore[reportUnknownMemberType] # the from_url(lib_name=...) overload mismatch leaves sync_client's type unknown; .ft/.create_index inherit that self._index_schema(dim), definition=self._index_definition() ) except Exception as exc: if not self._is_index_exists_error(exc): raise - self._assert_dim_matches(self.sync_client.ft(self.index_name).info(), dim) + self._assert_dim_matches(self.sync_client.ft(self.index_name).info(), dim) # pyright: ignore[reportUnknownMemberType] # the from_url(lib_name=...) overload mismatch leaves sync_client's type unknown; .ft/.info inherit that self._index_dim = dim async def _ensure_index_async(self, dim: int) -> None: if self._index_dim == dim: return try: - await self.async_client.ft(self.index_name).create_index( + await self.async_client.ft(self.index_name).create_index( # pyright: ignore[reportUnknownMemberType] # the from_url(lib_name=...) overload mismatch leaves async_client's type unknown; .ft/.create_index inherit that self._index_schema(dim), definition=self._index_definition() ) except Exception as exc: if not self._is_index_exists_error(exc): raise - info: Final = await self.async_client.ft(self.index_name).info() + info: Final = await self.async_client.ft(self.index_name).info() # pyright: ignore[reportUnknownMemberType] # the from_url(lib_name=...) overload mismatch leaves async_client's type unknown; .ft/.info inherit that self._assert_dim_matches(info, dim) self._index_dim = dim @@ -221,7 +221,7 @@ class ValkeySemanticCache(RedisSemanticCache): async def _async_search(self, key: str, embedding: Sequence[float]) -> object: """Run the KNN query on the async client, stopping the untyped search surface here.""" - return await self.async_client.ft(self.index_name).search( + return await self.async_client.ft(self.index_name).search( # pyright: ignore[reportUnknownMemberType] # the from_url(lib_name=...) overload mismatch leaves async_client's type unknown; .ft/.search inherit that self._knn_query(key), query_params={"vec": self._embedding_to_bytes(embedding)}, # pyright: ignore[reportArgumentType] # redis stubs omit bytes; KNN vectors are raw bytes at runtime ) @@ -273,10 +273,10 @@ class ValkeySemanticCache(RedisSemanticCache): self._ensure_index_sync(len(embedding)) doc_key: Final = self._doc_key(key) - self.sync_client.hset(doc_key, mapping=self._doc_mapping(key, prompt, str(value), embedding)) + self.sync_client.hset(doc_key, mapping=self._doc_mapping(key, prompt, str(value), embedding)) # pyright: ignore[reportUnknownMemberType] # the from_url(lib_name=...) overload mismatch leaves sync_client's type unknown; .hset inherits that ttl: Final = self._get_ttl(**kwargs) if ttl is not None: - self.sync_client.expire(doc_key, ttl) + self.sync_client.expire(doc_key, ttl) # pyright: ignore[reportUnknownMemberType] # the from_url(lib_name=...) overload mismatch leaves sync_client's type unknown; .expire inherits that except Exception as e: print_verbose(f"Error in Valkey semantic-cache set_cache: {e}") @@ -291,7 +291,7 @@ class ValkeySemanticCache(RedisSemanticCache): embedding: Final = self._get_embedding(prompt) self._ensure_index_sync(len(embedding)) - search_result: Final = self.sync_client.ft(self.index_name).search( + search_result: Final = self.sync_client.ft(self.index_name).search( # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType] # the from_url(lib_name=...) overload mismatch leaves sync_client's type unknown; .ft/.search and their result inherit that self._knn_query(key), query_params={"vec": self._embedding_to_bytes(embedding)}, # pyright: ignore[reportArgumentType] # redis stubs omit bytes; KNN vectors are raw bytes at runtime ) @@ -312,10 +312,10 @@ class ValkeySemanticCache(RedisSemanticCache): await self._ensure_index_async(len(embedding)) doc_key: Final = self._doc_key(key) - await self.async_client.hset(doc_key, mapping=self._doc_mapping(key, prompt, str(value), embedding)) + await self.async_client.hset(doc_key, mapping=self._doc_mapping(key, prompt, str(value), embedding)) # pyright: ignore[reportUnknownMemberType] # the from_url(lib_name=...) overload mismatch leaves async_client's type unknown; .hset inherits that ttl: Final = self._get_ttl(**kwargs) if ttl is not None: - await self.async_client.expire(doc_key, ttl) + await self.async_client.expire(doc_key, ttl) # pyright: ignore[reportUnknownMemberType] # the from_url(lib_name=...) overload mismatch leaves async_client's type unknown; .expire inherits that except Exception as e: print_verbose(f"Error in async Valkey semantic-cache set_cache: {e}") @@ -343,4 +343,4 @@ class ValkeySemanticCache(RedisSemanticCache): print_verbose(f"Error in Valkey semantic-cache async_set_cache_pipeline: {e}") async def _index_info(self) -> Mapping[str, object]: - return await self.async_client.ft(self.index_name).info() + return await self.async_client.ft(self.index_name).info() # pyright: ignore[reportUnknownMemberType] # the from_url(lib_name=...) overload mismatch leaves async_client's type unknown; .ft/.info inherit that diff --git a/litellm/llms/valkey/vector_stores/transformation.py b/litellm/llms/valkey/vector_stores/transformation.py index 90ce4db153d..c40133d0764 100644 --- a/litellm/llms/valkey/vector_stores/transformation.py +++ b/litellm/llms/valkey/vector_stores/transformation.py @@ -245,17 +245,17 @@ class ValkeyVectorStoreConfig(BaseDirectVectorStoreConfig): return self._to_response(raw, query_text, params.text_field) connect_timeout, op_timeout = self._socket_timeouts(timeout) - client: Final = _import_sync_redis().from_url( # pyright: ignore[reportCallIssue] # types-redis 4.6 stubs shadow redis 5.3.1 and omit from_url(lib_name=...); redis-py accepts it at runtime + client: Final = _import_sync_redis().from_url( # pyright: ignore[reportCallIssue, reportUnknownVariableType] # types-redis 4.6 stubs shadow redis 5.3.1 and omit from_url(lib_name=...); redis-py accepts it at runtime, but the overload mismatch leaves the return type unknown params.connection_url(), socket_connect_timeout=connect_timeout, socket_timeout=op_timeout, lib_name=VALKEY_LIB_NAME, ) try: - raw_result: Final = client.ft(vector_store_id).search(knn, query_params=vec_params) + raw_result: Final = client.ft(vector_store_id).search(knn, query_params=vec_params) # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType] # client's type is unknown (see from_url above), so .ft/.search and their result inherit that return self._to_response(raw_result, query_text, params.text_field) # pyright: ignore[reportUnknownArgumentType] # raw_result flows from the from_url client whose return type the types-redis 4.6 stubs leave unknown; the shape is validated inside _to_response finally: - client.close() + client.close() # pyright: ignore[reportUnknownMemberType] # client's type is unknown (see from_url above) async def aexecute_search_vector_store_request( self, @@ -296,19 +296,19 @@ class ValkeyVectorStoreConfig(BaseDirectVectorStoreConfig): return self._to_response(raw, query_text, params.text_field) connect_timeout, op_timeout = self._socket_timeouts(timeout) - client: Final = _import_async_redis().from_url( # pyright: ignore[reportCallIssue] # types-redis 4.6 stubs shadow redis 5.3.1 and omit from_url(lib_name=...); redis-py accepts it at runtime + client: Final = _import_async_redis().from_url( # pyright: ignore[reportCallIssue, reportUnknownVariableType] # types-redis 4.6 stubs shadow redis 5.3.1 and omit from_url(lib_name=...); redis-py accepts it at runtime, but the overload mismatch leaves the return type unknown params.connection_url(), socket_connect_timeout=connect_timeout, socket_timeout=op_timeout, lib_name=VALKEY_LIB_NAME, ) try: - raw_result: Final = await client.ft(vector_store_id).search( # pyright: ignore[reportGeneralTypeIssues] # types-redis 4.6 stubs shadow redis 5.3.1 and type the async client's ft() as the sync Search, so search() returns a non-awaitable Result; it is a coroutine at runtime + raw_result: Final = await client.ft(vector_store_id).search( # pyright: ignore[reportGeneralTypeIssues, reportUnknownMemberType, reportUnknownVariableType] # types-redis 4.6 stubs shadow redis 5.3.1 and type the async client's ft() as the sync Search, so search() returns a non-awaitable Result; it is a coroutine at runtime. client's type is unknown (see from_url above), so .ft/.search and their result inherit that knn, query_params=vec_params ) return self._to_response(raw_result, query_text, params.text_field) # pyright: ignore[reportUnknownArgumentType] # raw_result flows from the from_url client whose return type the types-redis 4.6 stubs leave unknown; the shape is validated inside _to_response finally: - await client.aclose() + await client.aclose() # pyright: ignore[reportUnknownMemberType] # client's type is unknown (see from_url above) def transform_create_vector_store_request( self,