Valkey Search Kit (Python)
betterdb-valkey-search-kit is the Python counterpart to @betterdb/valkey-search-kit: shared low-level helpers for working with Valkey Search (FT.*) from Python.
It has no runtime dependencies and exposes only pure functions, so it stays trivial to vendor and test. It is the shared foundation the betterdb-retrieval and betterdb-agent-memory packages build on.
Prerequisites
- Valkey 8.0+ with the
valkey-searchmodule loaded (for theFT.*commands these helpers target) - Python >= 3.11
Installation
pip install betterdb-valkey-search-kit
Usage
Vector encoding
from betterdb_valkey_search_kit import encode_float32, decode_float32
blob = encode_float32([0.1, 0.2, 0.3]) # little-endian Float32 bytes
vec = decode_float32(blob) # back to list[float]
Use encode_float32 to store embeddings as binary HSET field values and as the PARAMS vector for a KNN FT.SEARCH.
TAG escaping
from betterdb_valkey_search_kit import escape_tag
f"@model:}" # -> "@model:{gpt\\-4o}"
Escapes every character with special meaning in the TAG filter syntax, including spaces (unescaped spaces are treated as OR term separators).
FT.SEARCH reply parsing
from betterdb_valkey_search_kit import parse_ft_search_response
raw = await client.execute_command("FT.SEARCH", index, query)
hits = parse_ft_search_response(raw)
# [{"key": "cache:entry:abc", "fields": {"prompt": "...", "__score": "0.05"}}]
Handles valkey-py’s mixed bytes/str replies, RETURN 0 mode (keys with no field list), and odd-length field lists. Binary field values that are not valid UTF-8 (e.g. raw embedding bytes) are skipped. Never raises - returns [] on any malformed input.
FT.INFO parsing (version-skew tolerant)
from betterdb_valkey_search_kit import (
parse_dimension_from_info,
parse_ft_info_stats,
)
info = await client.execute_command("FT.INFO", index)
dims = parse_dimension_from_info(info) # 1536, or 0 if no vector field
stats = parse_ft_info_stats(info) # FtIndexStats(num_docs=..., indexing_state=...)
parse_dimension_from_info understands both the flat DIM attribute pair and the nested index/dimensions shape introduced in Valkey Search 1.2.
Error classification
from betterdb_valkey_search_kit import is_index_not_found_error
try:
await client.execute_command("FT.INFO", index)
except Exception as err:
if is_index_not_found_error(err):
... # index does not exist yet
else:
raise
Matches the “index does not exist” message variants emitted across Valkey Search / RediSearch versions, case-insensitively.
Interoperability with the TypeScript package
The Python and TypeScript kits implement the same byte encodings and the same reply-parsing rules. An embedding encoded by encode_float32 is byte-identical to one from encodeFloat32, so a Python writer and a TypeScript reader (or vice versa) can share the same Valkey Search index.
See also
- Valkey Search Kit - the TypeScript original.
- Retrieval (Python) and Agent Memory (Python) - higher-level SDKs built on this kit.