@nhtio/adk 1.20260604.0 → 1.20260607.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +261 -0
- package/adk-mcp.mjs +1 -1
- package/batteries/embeddings/openai/adapter.cjs +1 -1
- package/batteries/embeddings/openai/adapter.mjs +1 -1
- package/batteries/embeddings/webllm/adapter.cjs +1 -1
- package/batteries/embeddings/webllm/adapter.mjs +1 -1
- package/batteries/index.d.ts +1 -0
- package/batteries/llm/openai_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/openai_chat_completions/helpers.cjs +2 -2
- package/batteries/llm/openai_chat_completions/helpers.mjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.cjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/validation.mjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/validation.cjs +2 -2
- package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/validation.mjs +2 -2
- package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -1
- package/batteries/storage/flydrive.cjs +1 -1
- package/batteries/storage/flydrive.mjs +2 -2
- package/batteries/storage/in_memory.cjs +1 -1
- package/batteries/storage/in_memory.mjs +1 -1
- package/batteries/storage/opfs.cjs +1 -1
- package/batteries/storage/opfs.mjs +1 -1
- package/batteries/tools/color.cjs +2 -2
- package/batteries/tools/color.mjs +2 -2
- package/batteries/tools/comparison.cjs +3 -3
- package/batteries/tools/comparison.mjs +3 -3
- package/batteries/tools/data_structure.cjs +3 -3
- package/batteries/tools/data_structure.mjs +3 -3
- package/batteries/tools/datetime_extended.cjs +2 -2
- package/batteries/tools/datetime_extended.mjs +2 -2
- package/batteries/tools/datetime_math.cjs +2 -2
- package/batteries/tools/datetime_math.mjs +2 -2
- package/batteries/tools/encoding.cjs +3 -3
- package/batteries/tools/encoding.mjs +3 -3
- package/batteries/tools/formatting.cjs +3 -3
- package/batteries/tools/formatting.mjs +3 -3
- package/batteries/tools/geo_basics.cjs +2 -2
- package/batteries/tools/geo_basics.mjs +2 -2
- package/batteries/tools/math/index.d.ts +16 -5
- package/batteries/tools/math.cjs +340 -22
- package/batteries/tools/math.cjs.map +1 -1
- package/batteries/tools/math.mjs +338 -21
- package/batteries/tools/math.mjs.map +1 -1
- package/batteries/tools/memory.cjs +5 -5
- package/batteries/tools/memory.mjs +5 -5
- package/batteries/tools/parsing.cjs +4 -4
- package/batteries/tools/parsing.mjs +4 -4
- package/batteries/tools/retrievables.cjs +4 -4
- package/batteries/tools/retrievables.mjs +4 -4
- package/batteries/tools/standing_instructions.cjs +4 -4
- package/batteries/tools/standing_instructions.mjs +4 -4
- package/batteries/tools/statistics.cjs +4 -4
- package/batteries/tools/statistics.mjs +4 -4
- package/batteries/tools/string_processing.cjs +3 -3
- package/batteries/tools/string_processing.mjs +3 -3
- package/batteries/tools/structured_data.cjs +3 -3
- package/batteries/tools/structured_data.mjs +3 -3
- package/batteries/tools/text_analysis.cjs +3 -3
- package/batteries/tools/text_analysis.mjs +3 -3
- package/batteries/tools/text_comparison.cjs +2 -2
- package/batteries/tools/text_comparison.mjs +2 -2
- package/batteries/tools/time.cjs +2 -2
- package/batteries/tools/time.mjs +2 -2
- package/batteries/tools/unit_conversion.cjs +2 -2
- package/batteries/tools/unit_conversion.mjs +2 -2
- package/batteries/vector/arangodb/index.d.ts +38 -0
- package/batteries/vector/arangodb.cjs +257 -0
- package/batteries/vector/arangodb.cjs.map +1 -0
- package/batteries/vector/arangodb.mjs +255 -0
- package/batteries/vector/arangodb.mjs.map +1 -0
- package/batteries/vector/builder.cjs +297 -0
- package/batteries/vector/builder.cjs.map +1 -0
- package/batteries/vector/builder.d.ts +87 -0
- package/batteries/vector/builder.mjs +294 -0
- package/batteries/vector/builder.mjs.map +1 -0
- package/batteries/vector/chroma/index.d.ts +32 -0
- package/batteries/vector/chroma.cjs +305 -0
- package/batteries/vector/chroma.cjs.map +1 -0
- package/batteries/vector/chroma.mjs +302 -0
- package/batteries/vector/chroma.mjs.map +1 -0
- package/batteries/vector/clickhouse/index.d.ts +39 -0
- package/batteries/vector/clickhouse.cjs +246 -0
- package/batteries/vector/clickhouse.cjs.map +1 -0
- package/batteries/vector/clickhouse.mjs +244 -0
- package/batteries/vector/clickhouse.mjs.map +1 -0
- package/batteries/vector/cloudflare/index.d.ts +43 -0
- package/batteries/vector/cloudflare.cjs +397 -0
- package/batteries/vector/cloudflare.cjs.map +1 -0
- package/batteries/vector/cloudflare.mjs +395 -0
- package/batteries/vector/cloudflare.mjs.map +1 -0
- package/batteries/vector/conformance/index.d.ts +15 -0
- package/batteries/vector/conformance.cjs +209 -0
- package/batteries/vector/conformance.cjs.map +1 -0
- package/batteries/vector/conformance.mjs +205 -0
- package/batteries/vector/conformance.mjs.map +1 -0
- package/batteries/vector/contract.cjs +42 -0
- package/batteries/vector/contract.cjs.map +1 -0
- package/batteries/vector/contract.d.ts +39 -0
- package/batteries/vector/contract.mjs +40 -0
- package/batteries/vector/contract.mjs.map +1 -0
- package/batteries/vector/couchbase/index.d.ts +49 -0
- package/batteries/vector/couchbase.cjs +401 -0
- package/batteries/vector/couchbase.cjs.map +1 -0
- package/batteries/vector/couchbase.mjs +399 -0
- package/batteries/vector/couchbase.mjs.map +1 -0
- package/batteries/vector/duckdb/index.d.ts +33 -0
- package/batteries/vector/duckdb.cjs +218 -0
- package/batteries/vector/duckdb.cjs.map +1 -0
- package/batteries/vector/duckdb.mjs +216 -0
- package/batteries/vector/duckdb.mjs.map +1 -0
- package/batteries/vector/elasticsearch/index.d.ts +43 -0
- package/batteries/vector/elasticsearch.cjs +306 -0
- package/batteries/vector/elasticsearch.cjs.map +1 -0
- package/batteries/vector/elasticsearch.mjs +303 -0
- package/batteries/vector/elasticsearch.mjs.map +1 -0
- package/batteries/vector/exceptions.cjs +126 -0
- package/batteries/vector/exceptions.cjs.map +1 -0
- package/batteries/vector/exceptions.d.ts +142 -0
- package/batteries/vector/exceptions.mjs +107 -0
- package/batteries/vector/exceptions.mjs.map +1 -0
- package/batteries/vector/factory.cjs +28 -0
- package/batteries/vector/factory.cjs.map +1 -0
- package/batteries/vector/factory.d.ts +38 -0
- package/batteries/vector/factory.mjs +25 -0
- package/batteries/vector/factory.mjs.map +1 -0
- package/batteries/vector/filters.cjs +107 -0
- package/batteries/vector/filters.cjs.map +1 -0
- package/batteries/vector/filters.d.ts +34 -0
- package/batteries/vector/filters.mjs +99 -0
- package/batteries/vector/filters.mjs.map +1 -0
- package/batteries/vector/helpers.cjs +23 -0
- package/batteries/vector/helpers.cjs.map +1 -0
- package/batteries/vector/helpers.d.ts +12 -0
- package/batteries/vector/helpers.mjs +17 -0
- package/batteries/vector/helpers.mjs.map +1 -0
- package/batteries/vector/hnswlib/index.d.ts +35 -0
- package/batteries/vector/hnswlib.cjs +237 -0
- package/batteries/vector/hnswlib.cjs.map +1 -0
- package/batteries/vector/hnswlib.mjs +235 -0
- package/batteries/vector/hnswlib.mjs.map +1 -0
- package/batteries/vector/in_memory/index.d.ts +23 -0
- package/batteries/vector/in_memory.cjs +178 -0
- package/batteries/vector/in_memory.cjs.map +1 -0
- package/batteries/vector/in_memory.mjs +176 -0
- package/batteries/vector/in_memory.mjs.map +1 -0
- package/batteries/vector/index.d.ts +18 -0
- package/batteries/vector/lancedb/index.d.ts +34 -0
- package/batteries/vector/lancedb.cjs +224 -0
- package/batteries/vector/lancedb.cjs.map +1 -0
- package/batteries/vector/lancedb.mjs +222 -0
- package/batteries/vector/lancedb.mjs.map +1 -0
- package/batteries/vector/mariadb/index.d.ts +39 -0
- package/batteries/vector/mariadb.cjs +228 -0
- package/batteries/vector/mariadb.cjs.map +1 -0
- package/batteries/vector/mariadb.mjs +226 -0
- package/batteries/vector/mariadb.mjs.map +1 -0
- package/batteries/vector/meilisearch/index.d.ts +36 -0
- package/batteries/vector/meilisearch.cjs +242 -0
- package/batteries/vector/meilisearch.cjs.map +1 -0
- package/batteries/vector/meilisearch.mjs +240 -0
- package/batteries/vector/meilisearch.mjs.map +1 -0
- package/batteries/vector/migrate.cjs +54 -0
- package/batteries/vector/migrate.cjs.map +1 -0
- package/batteries/vector/migrate.d.ts +30 -0
- package/batteries/vector/migrate.mjs +52 -0
- package/batteries/vector/migrate.mjs.map +1 -0
- package/batteries/vector/milvus/index.d.ts +35 -0
- package/batteries/vector/milvus.cjs +357 -0
- package/batteries/vector/milvus.cjs.map +1 -0
- package/batteries/vector/milvus.mjs +354 -0
- package/batteries/vector/milvus.mjs.map +1 -0
- package/batteries/vector/mongodb/index.d.ts +46 -0
- package/batteries/vector/mongodb.cjs +270 -0
- package/batteries/vector/mongodb.cjs.map +1 -0
- package/batteries/vector/mongodb.mjs +268 -0
- package/batteries/vector/mongodb.mjs.map +1 -0
- package/batteries/vector/neo4j/index.d.ts +38 -0
- package/batteries/vector/neo4j.cjs +231 -0
- package/batteries/vector/neo4j.cjs.map +1 -0
- package/batteries/vector/neo4j.mjs +229 -0
- package/batteries/vector/neo4j.mjs.map +1 -0
- package/batteries/vector/opensearch/index.d.ts +46 -0
- package/batteries/vector/opensearch.cjs +316 -0
- package/batteries/vector/opensearch.cjs.map +1 -0
- package/batteries/vector/opensearch.mjs +313 -0
- package/batteries/vector/opensearch.mjs.map +1 -0
- package/batteries/vector/oracle23ai/index.d.ts +45 -0
- package/batteries/vector/oracle23ai.cjs +340 -0
- package/batteries/vector/oracle23ai.cjs.map +1 -0
- package/batteries/vector/oracle23ai.mjs +338 -0
- package/batteries/vector/oracle23ai.mjs.map +1 -0
- package/batteries/vector/orama/index.d.ts +23 -0
- package/batteries/vector/orama.cjs +272 -0
- package/batteries/vector/orama.cjs.map +1 -0
- package/batteries/vector/orama.mjs +270 -0
- package/batteries/vector/orama.mjs.map +1 -0
- package/batteries/vector/pgvector/index.d.ts +43 -0
- package/batteries/vector/pgvector.cjs +411 -0
- package/batteries/vector/pgvector.cjs.map +1 -0
- package/batteries/vector/pgvector.mjs +408 -0
- package/batteries/vector/pgvector.mjs.map +1 -0
- package/batteries/vector/pinecone/index.d.ts +38 -0
- package/batteries/vector/pinecone.cjs +415 -0
- package/batteries/vector/pinecone.cjs.map +1 -0
- package/batteries/vector/pinecone.mjs +412 -0
- package/batteries/vector/pinecone.mjs.map +1 -0
- package/batteries/vector/plan.cjs +2 -0
- package/batteries/vector/plan.d.ts +65 -0
- package/batteries/vector/plan.mjs +0 -0
- package/batteries/vector/qdrant/index.d.ts +34 -0
- package/batteries/vector/qdrant.cjs +286 -0
- package/batteries/vector/qdrant.cjs.map +1 -0
- package/batteries/vector/qdrant.mjs +284 -0
- package/batteries/vector/qdrant.mjs.map +1 -0
- package/batteries/vector/redis/index.d.ts +44 -0
- package/batteries/vector/redis.cjs +391 -0
- package/batteries/vector/redis.cjs.map +1 -0
- package/batteries/vector/redis.mjs +388 -0
- package/batteries/vector/redis.mjs.map +1 -0
- package/batteries/vector/retrievable.cjs +69 -0
- package/batteries/vector/retrievable.cjs.map +1 -0
- package/batteries/vector/retrievable.mjs +67 -0
- package/batteries/vector/retrievable.mjs.map +1 -0
- package/batteries/vector/retrievable_glue.d.ts +24 -0
- package/batteries/vector/s3vectors/index.d.ts +52 -0
- package/batteries/vector/s3vectors.cjs +438 -0
- package/batteries/vector/s3vectors.cjs.map +1 -0
- package/batteries/vector/s3vectors.mjs +436 -0
- package/batteries/vector/s3vectors.mjs.map +1 -0
- package/batteries/vector/schema.cjs +96 -0
- package/batteries/vector/schema.cjs.map +1 -0
- package/batteries/vector/schema.d.ts +40 -0
- package/batteries/vector/schema.mjs +93 -0
- package/batteries/vector/schema.mjs.map +1 -0
- package/batteries/vector/solr/index.d.ts +36 -0
- package/batteries/vector/solr.cjs +230 -0
- package/batteries/vector/solr.cjs.map +1 -0
- package/batteries/vector/solr.mjs +228 -0
- package/batteries/vector/solr.mjs.map +1 -0
- package/batteries/vector/sqlite_vec/index.d.ts +30 -0
- package/batteries/vector/sqlite_vec.cjs +318 -0
- package/batteries/vector/sqlite_vec.cjs.map +1 -0
- package/batteries/vector/sqlite_vec.mjs +316 -0
- package/batteries/vector/sqlite_vec.mjs.map +1 -0
- package/batteries/vector/surrealdb/index.d.ts +37 -0
- package/batteries/vector/surrealdb.cjs +230 -0
- package/batteries/vector/surrealdb.cjs.map +1 -0
- package/batteries/vector/surrealdb.mjs +228 -0
- package/batteries/vector/surrealdb.mjs.map +1 -0
- package/batteries/vector/types.cjs +2 -0
- package/batteries/vector/types.d.ts +100 -0
- package/batteries/vector/types.mjs +0 -0
- package/batteries/vector/typesense/index.d.ts +38 -0
- package/batteries/vector/typesense.cjs +272 -0
- package/batteries/vector/typesense.cjs.map +1 -0
- package/batteries/vector/typesense.mjs +270 -0
- package/batteries/vector/typesense.mjs.map +1 -0
- package/batteries/vector/validation.cjs +90 -0
- package/batteries/vector/validation.cjs.map +1 -0
- package/batteries/vector/validation.d.ts +18 -0
- package/batteries/vector/validation.mjs +83 -0
- package/batteries/vector/validation.mjs.map +1 -0
- package/batteries/vector/vector_store_constructor.cjs +56 -0
- package/batteries/vector/vector_store_constructor.cjs.map +1 -0
- package/batteries/vector/vector_store_constructor.d.ts +30 -0
- package/batteries/vector/vector_store_constructor.mjs +53 -0
- package/batteries/vector/vector_store_constructor.mjs.map +1 -0
- package/batteries/vector/vespa/index.d.ts +39 -0
- package/batteries/vector/vespa.cjs +423 -0
- package/batteries/vector/vespa.cjs.map +1 -0
- package/batteries/vector/vespa.mjs +421 -0
- package/batteries/vector/vespa.mjs.map +1 -0
- package/batteries/vector/weaviate/index.d.ts +57 -0
- package/batteries/vector/weaviate.cjs +325 -0
- package/batteries/vector/weaviate.cjs.map +1 -0
- package/batteries/vector/weaviate.mjs +322 -0
- package/batteries/vector/weaviate.mjs.map +1 -0
- package/batteries/vector.cjs +63 -0
- package/batteries/vector.mjs +14 -0
- package/batteries.cjs +62 -0
- package/batteries.mjs +15 -1
- package/{chunk-kRvK8_k2.mjs → chunk-Bpcn9VDT.mjs} +5 -1
- package/{common-lMrnzoyn.mjs → common-BT0nfCi9.mjs} +8 -8
- package/{common-lMrnzoyn.mjs.map → common-BT0nfCi9.mjs.map} +1 -1
- package/{common-D_e5zYsG.js → common-Cj8TaQ9U.js} +8 -8
- package/{common-D_e5zYsG.js.map → common-Cj8TaQ9U.js.map} +1 -1
- package/common.cjs +7 -7
- package/common.mjs +7 -7
- package/{dispatch_runner-CpuyATj1.js → dispatch_runner-BHBNupqp.js} +2 -2
- package/dispatch_runner-BHBNupqp.js.map +1 -0
- package/{dispatch_runner-CDF3X0nv.mjs → dispatch_runner-DPcS7Y_M.mjs} +2 -2
- package/dispatch_runner-DPcS7Y_M.mjs.map +1 -0
- package/dispatch_runner.cjs +1 -1
- package/dispatch_runner.mjs +1 -1
- package/forge.cjs +4 -4
- package/forge.mjs +4 -4
- package/guards.cjs +8 -8
- package/guards.mjs +8 -8
- package/index.cjs +12 -12
- package/index.mjs +12 -12
- package/lib/classes/tool_registry.d.ts +70 -4
- package/mcp/adk-docs-corpus.json +1 -1
- package/package.json +424 -88
- package/skills/adk-assembly/SKILL.md +2 -2
- package/{spooled_artifact-B8gIIn9h.js → spooled_artifact-BTq6Nzfy.js} +4 -4
- package/spooled_artifact-BTq6Nzfy.js.map +1 -0
- package/{spooled_artifact-CWoKUDEm.mjs → spooled_artifact-CHoZgWwI.mjs} +4 -4
- package/spooled_artifact-CHoZgWwI.mjs.map +1 -0
- package/spooled_artifact.cjs +2 -2
- package/spooled_artifact.mjs +2 -2
- package/{spooled_markdown_artifact-DQX0RCdI.js → spooled_markdown_artifact-CALSDxIx.js} +3 -3
- package/{spooled_markdown_artifact-DQX0RCdI.js.map → spooled_markdown_artifact-CALSDxIx.js.map} +1 -1
- package/{spooled_markdown_artifact-CNle4jXN.mjs → spooled_markdown_artifact-Ci5UL7l4.mjs} +3 -3
- package/{spooled_markdown_artifact-CNle4jXN.mjs.map → spooled_markdown_artifact-Ci5UL7l4.mjs.map} +1 -1
- package/src/types/evaluatex.d.ts +31 -0
- package/{thought-BD6AkkOr.js → thought-BbwhJ1wb.js} +4 -4
- package/thought-BbwhJ1wb.js.map +1 -0
- package/{thought-B_P8LiB6.mjs → thought-D34QQZZ9.mjs} +4 -4
- package/thought-D34QQZZ9.mjs.map +1 -0
- package/{tool-CRZSUcdP.mjs → tool-CMhaDRNd.mjs} +3 -3
- package/tool-CMhaDRNd.mjs.map +1 -0
- package/{tool-CX9vNHAw.js → tool-CVyZkFC7.js} +3 -3
- package/tool-CVyZkFC7.js.map +1 -0
- package/{tool_call-BUeMuCc6.mjs → tool_call-CV5qVNlb.mjs} +3 -3
- package/{tool_call-BUeMuCc6.mjs.map → tool_call-CV5qVNlb.mjs.map} +1 -1
- package/{tool_call--7ti-frB.js → tool_call-Db68hB7y.js} +3 -3
- package/{tool_call--7ti-frB.js.map → tool_call-Db68hB7y.js.map} +1 -1
- package/{tool_registry-BGHg6KTq.mjs → tool_registry-D1pSSlsd.mjs} +109 -22
- package/tool_registry-D1pSSlsd.mjs.map +1 -0
- package/{tool_registry-CtCQ4Xoz.js → tool_registry-DYUYqXvo.js} +109 -22
- package/tool_registry-DYUYqXvo.js.map +1 -0
- package/{turn_runner-BJTtAORU.js → turn_runner-DqWHNP80.js} +5 -5
- package/turn_runner-DqWHNP80.js.map +1 -0
- package/{turn_runner-C02LZHjt.mjs → turn_runner-fg1Wc3dK.mjs} +5 -5
- package/turn_runner-fg1Wc3dK.mjs.map +1 -0
- package/turn_runner.cjs +1 -1
- package/turn_runner.mjs +1 -1
- package/dispatch_runner-CDF3X0nv.mjs.map +0 -1
- package/dispatch_runner-CpuyATj1.js.map +0 -1
- package/spooled_artifact-B8gIIn9h.js.map +0 -1
- package/spooled_artifact-CWoKUDEm.mjs.map +0 -1
- package/thought-BD6AkkOr.js.map +0 -1
- package/thought-B_P8LiB6.mjs.map +0 -1
- package/tool-CRZSUcdP.mjs.map +0 -1
- package/tool-CX9vNHAw.js.map +0 -1
- package/tool_registry-BGHg6KTq.mjs.map +0 -1
- package/tool_registry-CtCQ4Xoz.js.map +0 -1
- package/turn_runner-BJTtAORU.js.map +0 -1
- package/turn_runner-C02LZHjt.mjs.map +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @nhtio/adk/batteries/vector/redis
|
|
3
|
+
*
|
|
4
|
+
* One adapter for the whole Redis/Valkey family. The vector engine is RediSearch
|
|
5
|
+
* (`FT.CREATE` / `FT.SEARCH` with a `VECTOR` field over a HASH keyspace); records are
|
|
6
|
+
* stored as Redis hashes keyed `${collection}:${id}`, with the vector packed as a
|
|
7
|
+
* little-endian Float32 buffer. Metadata scalars are stored as TAG/NUMERIC fields so the
|
|
8
|
+
* neutral filter tree compiles to RediSearch query syntax.
|
|
9
|
+
*
|
|
10
|
+
* Works against `redis/redis-stack-server` (bundles RediSearch) and any Redis/Valkey with
|
|
11
|
+
* the RediSearch module loaded.
|
|
12
|
+
*/
|
|
13
|
+
import { BaseVectorStore } from "../contract";
|
|
14
|
+
import type { VectorFilter } from "../filters";
|
|
15
|
+
import type { SearchPlan, UpsertPlan, DeletePlan, CollectionSpec } from "../plan";
|
|
16
|
+
import type { VectorMatch, VectorStoreCapabilities, BaseVectorStoreOptions } from "../types";
|
|
17
|
+
export interface RedisVectorStoreOptions extends BaseVectorStoreOptions {
|
|
18
|
+
connection?: {
|
|
19
|
+
url?: string;
|
|
20
|
+
username?: string;
|
|
21
|
+
password?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Compile the neutral filter tree to a RediSearch query fragment. TAG fields hold string /
|
|
26
|
+
* boolean metadata; NUMERIC fields hold numbers. Returns a fragment to AND with the KNN
|
|
27
|
+
* clause (or to use alone for a filter-scan). Throws on operators RediSearch can't express.
|
|
28
|
+
*/
|
|
29
|
+
export declare const translateRedisFilter: (filter?: VectorFilter) => string;
|
|
30
|
+
export declare class RedisVectorStore extends BaseVectorStore {
|
|
31
|
+
#private;
|
|
32
|
+
readonly capabilities: VectorStoreCapabilities;
|
|
33
|
+
static isAvailable(): boolean;
|
|
34
|
+
isAvailable(): boolean;
|
|
35
|
+
connect(): Promise<void>;
|
|
36
|
+
close(): Promise<void>;
|
|
37
|
+
createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void>;
|
|
38
|
+
dropCollection(collection: string, ifExists: boolean): Promise<void>;
|
|
39
|
+
hasCollection(collection: string): Promise<boolean>;
|
|
40
|
+
renameCollection(_from: string, _to: string): Promise<void>;
|
|
41
|
+
executeUpsert(plan: UpsertPlan): Promise<void>;
|
|
42
|
+
executeSearch(plan: SearchPlan): Promise<VectorMatch[]>;
|
|
43
|
+
executeDelete(plan: DeletePlan): Promise<void>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
require("../../chunk-Ble4zEEl.js");
|
|
3
|
+
const require_tool_registry = require("../../tool_registry-DYUYqXvo.js");
|
|
4
|
+
require("../../guards.cjs");
|
|
5
|
+
const require_batteries_vector_filters = require("./filters.cjs");
|
|
6
|
+
const require_batteries_vector_helpers = require("./helpers.cjs");
|
|
7
|
+
const require_batteries_vector_exceptions = require("./exceptions.cjs");
|
|
8
|
+
const require_batteries_vector_contract = require("./contract.cjs");
|
|
9
|
+
const require_batteries_vector_validation = require("./validation.cjs");
|
|
10
|
+
//#region src/batteries/vector/redis/index.ts
|
|
11
|
+
/**
|
|
12
|
+
* @module @nhtio/adk/batteries/vector/redis
|
|
13
|
+
*
|
|
14
|
+
* One adapter for the whole Redis/Valkey family. The vector engine is RediSearch
|
|
15
|
+
* (`FT.CREATE` / `FT.SEARCH` with a `VECTOR` field over a HASH keyspace); records are
|
|
16
|
+
* stored as Redis hashes keyed `${collection}:${id}`, with the vector packed as a
|
|
17
|
+
* little-endian Float32 buffer. Metadata scalars are stored as TAG/NUMERIC fields so the
|
|
18
|
+
* neutral filter tree compiles to RediSearch query syntax.
|
|
19
|
+
*
|
|
20
|
+
* Works against `redis/redis-stack-server` (bundles RediSearch) and any Redis/Valkey with
|
|
21
|
+
* the RediSearch module loaded.
|
|
22
|
+
*/
|
|
23
|
+
var getRedisClient = async () => {
|
|
24
|
+
try {
|
|
25
|
+
return (await import("redis")).createClient;
|
|
26
|
+
} catch {
|
|
27
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_DRIVER_UNAVAILABLE(["redis"]);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var indexName = (collection) => `idx:${collection}`;
|
|
31
|
+
var keyPrefix = (collection) => `${collection}:`;
|
|
32
|
+
var keyFor = (collection, id) => `${collection}:${id}`;
|
|
33
|
+
var packVector = (vector) => {
|
|
34
|
+
const buf = Buffer.allocUnsafe(vector.length * 4);
|
|
35
|
+
for (let i = 0; i < vector.length; i++) buf.writeFloatLE(vector[i], i * 4);
|
|
36
|
+
return buf;
|
|
37
|
+
};
|
|
38
|
+
var unpackVector = (buf) => {
|
|
39
|
+
const out = [];
|
|
40
|
+
for (let i = 0; i < buf.length; i += 4) out.push(buf.readFloatLE(i));
|
|
41
|
+
return out;
|
|
42
|
+
};
|
|
43
|
+
var metricToRedis = (metric) => metric === "euclidean" ? "L2" : metric === "dot" ? "IP" : "COSINE";
|
|
44
|
+
var escapeTag = (value) => value.replace(/[,.<>{}[\]"':;!@#$%^&*()\-+=~|/\\ ]/g, "\\$&");
|
|
45
|
+
/**
|
|
46
|
+
* Compile the neutral filter tree to a RediSearch query fragment. TAG fields hold string /
|
|
47
|
+
* boolean metadata; NUMERIC fields hold numbers. Returns a fragment to AND with the KNN
|
|
48
|
+
* clause (or to use alone for a filter-scan). Throws on operators RediSearch can't express.
|
|
49
|
+
*/
|
|
50
|
+
var translateRedisFilter = (filter) => {
|
|
51
|
+
if (!filter) return "*";
|
|
52
|
+
if (require_batteries_vector_filters.isRawFilter(filter)) {
|
|
53
|
+
if (filter.$dialect === "redis" && typeof filter.$raw === "string") return filter.$raw;
|
|
54
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(["redis", String(filter.$dialect)]);
|
|
55
|
+
}
|
|
56
|
+
if (require_batteries_vector_filters.isFilterCondition(filter)) {
|
|
57
|
+
const { field, op, value } = filter;
|
|
58
|
+
const tag = (v) => `@${field}:{${escapeTag(String(v))}}`;
|
|
59
|
+
const num = (lo, hi) => `@${field}:[${lo} ${hi}]`;
|
|
60
|
+
switch (op) {
|
|
61
|
+
case "eq": return typeof value === "number" ? num(String(value), String(value)) : tag(value);
|
|
62
|
+
case "ne": return typeof value === "number" ? `-${num(String(value), String(value))}` : `-${tag(value)}`;
|
|
63
|
+
case "gt": return num(`(${String(value)}`, "+inf");
|
|
64
|
+
case "gte": return num(String(value), "+inf");
|
|
65
|
+
case "lt": return num("-inf", `(${String(value)}`);
|
|
66
|
+
case "lte": return num("-inf", String(value));
|
|
67
|
+
case "in":
|
|
68
|
+
if (!Array.isArray(value) || value.length === 0) return "@__never:{__never}";
|
|
69
|
+
return `@${field}:{${value.map((v) => escapeTag(String(v))).join("|")}}`;
|
|
70
|
+
case "nin":
|
|
71
|
+
if (!Array.isArray(value) || value.length === 0) return "*";
|
|
72
|
+
return `-@${field}:{${value.map((v) => escapeTag(String(v))).join("|")}}`;
|
|
73
|
+
case "exists": return `@${field}:*`;
|
|
74
|
+
default: throw new require_batteries_vector_exceptions.E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(["redis", op]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (require_batteries_vector_filters.isFilterGroup(filter)) {
|
|
78
|
+
const { and, or, not } = filter;
|
|
79
|
+
if (and) {
|
|
80
|
+
const parts = and.map(translateRedisFilter).filter((p) => p !== "*");
|
|
81
|
+
return parts.length === 0 ? "*" : `(${parts.join(" ")})`;
|
|
82
|
+
}
|
|
83
|
+
if (or) {
|
|
84
|
+
const parts = or.map(translateRedisFilter).filter((p) => p !== "*");
|
|
85
|
+
return parts.length === 0 ? "*" : `(${parts.join(" | ")})`;
|
|
86
|
+
}
|
|
87
|
+
if (not) {
|
|
88
|
+
const inner = translateRedisFilter(not);
|
|
89
|
+
return inner === "*" ? "*" : `-${inner}`;
|
|
90
|
+
}
|
|
91
|
+
return "*";
|
|
92
|
+
}
|
|
93
|
+
return "*";
|
|
94
|
+
};
|
|
95
|
+
var RedisVectorStore = class extends require_batteries_vector_contract.BaseVectorStore {
|
|
96
|
+
capabilities = {
|
|
97
|
+
transactions: false,
|
|
98
|
+
namedVectors: false,
|
|
99
|
+
rename: false,
|
|
100
|
+
rawSql: false,
|
|
101
|
+
builtInEncoding: false,
|
|
102
|
+
consistency: {
|
|
103
|
+
configurable: false,
|
|
104
|
+
default: "strong",
|
|
105
|
+
modes: ["strong"]
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
#client = null;
|
|
109
|
+
#fields = /* @__PURE__ */ new Map();
|
|
110
|
+
get #opts() {
|
|
111
|
+
return this.options;
|
|
112
|
+
}
|
|
113
|
+
static isAvailable() {
|
|
114
|
+
return typeof process !== "undefined";
|
|
115
|
+
}
|
|
116
|
+
isAvailable() {
|
|
117
|
+
return typeof process !== "undefined";
|
|
118
|
+
}
|
|
119
|
+
async connect() {
|
|
120
|
+
if (this.#client) return;
|
|
121
|
+
const createClient = await getRedisClient();
|
|
122
|
+
const c = this.#opts.connection || {};
|
|
123
|
+
try {
|
|
124
|
+
this.#client = createClient({
|
|
125
|
+
url: c.url ?? "redis://localhost:6379",
|
|
126
|
+
username: c.username,
|
|
127
|
+
password: c.password
|
|
128
|
+
});
|
|
129
|
+
await this.#client.connect();
|
|
130
|
+
} catch (err) {
|
|
131
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_CONNECTION_FAILED([String(err)]);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async close() {
|
|
135
|
+
if (this.#client) {
|
|
136
|
+
try {
|
|
137
|
+
await this.#client.quit();
|
|
138
|
+
} catch {}
|
|
139
|
+
this.#client = null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async #ensure() {
|
|
143
|
+
if (!this.#client) await this.connect();
|
|
144
|
+
return this.#client;
|
|
145
|
+
}
|
|
146
|
+
async createCollection(spec, ifNotExists) {
|
|
147
|
+
const client = await this.#ensure();
|
|
148
|
+
this.#fields.set(spec.collection, spec.fields);
|
|
149
|
+
if (ifNotExists && await this.hasCollection(spec.collection)) return;
|
|
150
|
+
const dim = spec.vector.dimensions;
|
|
151
|
+
const distance = metricToRedis(spec.vector.metric);
|
|
152
|
+
const schema = [
|
|
153
|
+
"__vector",
|
|
154
|
+
"VECTOR",
|
|
155
|
+
"FLAT",
|
|
156
|
+
"6",
|
|
157
|
+
"TYPE",
|
|
158
|
+
"FLOAT32",
|
|
159
|
+
"DIM",
|
|
160
|
+
String(dim),
|
|
161
|
+
"DISTANCE_METRIC",
|
|
162
|
+
distance
|
|
163
|
+
];
|
|
164
|
+
for (const f of spec.fields) {
|
|
165
|
+
schema.push(f.name);
|
|
166
|
+
schema.push(f.type === "integer" || f.type === "number" ? "NUMERIC" : "TAG");
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
await client.sendCommand([
|
|
170
|
+
"FT.CREATE",
|
|
171
|
+
indexName(spec.collection),
|
|
172
|
+
"ON",
|
|
173
|
+
"HASH",
|
|
174
|
+
"PREFIX",
|
|
175
|
+
"1",
|
|
176
|
+
keyPrefix(spec.collection),
|
|
177
|
+
"SCHEMA",
|
|
178
|
+
...schema
|
|
179
|
+
]);
|
|
180
|
+
} catch (err) {
|
|
181
|
+
const msg = String(err);
|
|
182
|
+
if (msg.includes("Index already exists")) return;
|
|
183
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_COLLECTION_FAILED(["createCollection", msg]);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async dropCollection(collection, ifExists) {
|
|
187
|
+
const client = await this.#ensure();
|
|
188
|
+
if (ifExists && !await this.hasCollection(collection)) return;
|
|
189
|
+
try {
|
|
190
|
+
await client.sendCommand([
|
|
191
|
+
"FT.DROPINDEX",
|
|
192
|
+
indexName(collection),
|
|
193
|
+
"DD"
|
|
194
|
+
]);
|
|
195
|
+
} catch (err) {
|
|
196
|
+
const msg = String(err);
|
|
197
|
+
if (ifExists && msg.includes("Unknown")) return;
|
|
198
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_COLLECTION_FAILED(["dropCollection", msg]);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async hasCollection(collection) {
|
|
202
|
+
const client = await this.#ensure();
|
|
203
|
+
try {
|
|
204
|
+
await client.sendCommand(["FT.INFO", indexName(collection)]);
|
|
205
|
+
return true;
|
|
206
|
+
} catch {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async renameCollection(_from, _to) {
|
|
211
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_UNSUPPORTED_OPERATION(["renameCollection", "redis"]);
|
|
212
|
+
}
|
|
213
|
+
async executeUpsert(plan) {
|
|
214
|
+
if (plan.records.length === 0) return;
|
|
215
|
+
require_batteries_vector_validation.validateRecords(plan.records);
|
|
216
|
+
const client = await this.#ensure();
|
|
217
|
+
const expected = this.#opts.dimensions;
|
|
218
|
+
try {
|
|
219
|
+
for (const r of plan.records) {
|
|
220
|
+
let vector = r.vector;
|
|
221
|
+
if (!vector && r.document) {
|
|
222
|
+
const [v] = await this.encode([r.document], "document");
|
|
223
|
+
vector = v;
|
|
224
|
+
}
|
|
225
|
+
if (!vector) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_UPSERT_FAILED(["Record missing vector and document"]);
|
|
226
|
+
if (expected !== void 0 && vector.length !== expected) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_DIMENSION_MISMATCH([expected, vector.length]);
|
|
227
|
+
const blob = packVector(vector);
|
|
228
|
+
const entries = {
|
|
229
|
+
__vector: blob,
|
|
230
|
+
__vecb64: blob.toString("base64"),
|
|
231
|
+
__id: r.id
|
|
232
|
+
};
|
|
233
|
+
if (r.document !== void 0) entries.__document = r.document;
|
|
234
|
+
if (r.metadata) for (const [k, v] of Object.entries(r.metadata)) {
|
|
235
|
+
if (v === null || v === void 0) continue;
|
|
236
|
+
entries[k] = typeof v === "object" ? JSON.stringify(v) : String(v);
|
|
237
|
+
}
|
|
238
|
+
await client.hSet(keyFor(plan.collection, r.id), entries);
|
|
239
|
+
}
|
|
240
|
+
} catch (err) {
|
|
241
|
+
if (require_tool_registry.isInstanceOf(err, "E_VECTOR_STORE_DIMENSION_MISMATCH", require_batteries_vector_exceptions.E_VECTOR_STORE_DIMENSION_MISMATCH) || require_tool_registry.isInstanceOf(err, "E_VECTOR_STORE_UPSERT_FAILED", require_batteries_vector_exceptions.E_VECTOR_STORE_UPSERT_FAILED)) throw err;
|
|
242
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_UPSERT_FAILED([String(err)]);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async executeSearch(plan) {
|
|
246
|
+
const client = await this.#ensure();
|
|
247
|
+
const metric = this.#opts.metric ?? "cosine";
|
|
248
|
+
let queryVector;
|
|
249
|
+
if (plan.near) {
|
|
250
|
+
if ("vector" in plan.near) queryVector = plan.near.vector;
|
|
251
|
+
else if ("serverText" in plan.near) {
|
|
252
|
+
const [v] = await this.encode([plan.near.serverText], "query");
|
|
253
|
+
queryVector = v;
|
|
254
|
+
} else if ("id" in plan.near) {
|
|
255
|
+
const b64 = (await client.hGetAll(keyFor(plan.collection, plan.near.id)))?.__vecb64;
|
|
256
|
+
if (!b64) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_SEARCH_FAILED(["Referenced id not found: " + plan.near.id]);
|
|
257
|
+
queryVector = unpackVector(Buffer.from(String(b64), "base64"));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
try {
|
|
261
|
+
if (queryVector) {
|
|
262
|
+
const query = `(${translateRedisFilter(plan.filter)})=>[KNN ${plan.topK + (plan.offset ?? 0)} @__vector $BLOB AS __score]`;
|
|
263
|
+
const reply = await client.sendCommand([
|
|
264
|
+
"FT.SEARCH",
|
|
265
|
+
indexName(plan.collection),
|
|
266
|
+
query,
|
|
267
|
+
"PARAMS",
|
|
268
|
+
"2",
|
|
269
|
+
"BLOB",
|
|
270
|
+
packVector(queryVector),
|
|
271
|
+
"SORTBY",
|
|
272
|
+
"__score",
|
|
273
|
+
"DIALECT",
|
|
274
|
+
"2",
|
|
275
|
+
"LIMIT",
|
|
276
|
+
String(plan.offset ?? 0),
|
|
277
|
+
String(plan.topK),
|
|
278
|
+
"RETURN",
|
|
279
|
+
"1",
|
|
280
|
+
"__score"
|
|
281
|
+
]);
|
|
282
|
+
return await this.#materialize(client, reply, plan, metric, true);
|
|
283
|
+
} else {
|
|
284
|
+
const filterFrag = translateRedisFilter(plan.filter);
|
|
285
|
+
const reply = await client.sendCommand([
|
|
286
|
+
"FT.SEARCH",
|
|
287
|
+
indexName(plan.collection),
|
|
288
|
+
filterFrag,
|
|
289
|
+
"DIALECT",
|
|
290
|
+
"2",
|
|
291
|
+
"LIMIT",
|
|
292
|
+
String(plan.offset ?? 0),
|
|
293
|
+
String(plan.topK),
|
|
294
|
+
"NOCONTENT"
|
|
295
|
+
]);
|
|
296
|
+
return await this.#materialize(client, reply, plan, metric, false);
|
|
297
|
+
}
|
|
298
|
+
} catch (err) {
|
|
299
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_SEARCH_FAILED([String(err)]);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
#parseSearchReply(reply) {
|
|
303
|
+
if (reply && typeof reply === "object" && Array.isArray(reply.results)) return reply.results.map((r) => ({
|
|
304
|
+
key: String(r.id),
|
|
305
|
+
score: r.extra_attributes && r.extra_attributes.__score !== void 0 ? Number(r.extra_attributes.__score) : void 0
|
|
306
|
+
}));
|
|
307
|
+
if (Array.isArray(reply)) return reply.filter((_, i) => i > 0).map((k) => ({ key: String(k) }));
|
|
308
|
+
return [];
|
|
309
|
+
}
|
|
310
|
+
async #materialize(client, reply, plan, metric, isKnn) {
|
|
311
|
+
const hits = this.#parseSearchReply(reply);
|
|
312
|
+
const out = [];
|
|
313
|
+
for (const hit of hits) {
|
|
314
|
+
const raw = await client.hGetAll(hit.key);
|
|
315
|
+
if (!raw) continue;
|
|
316
|
+
out.push(this.#project(raw, plan, metric, isKnn, hit.score));
|
|
317
|
+
}
|
|
318
|
+
return out;
|
|
319
|
+
}
|
|
320
|
+
#decode(buf) {
|
|
321
|
+
if (buf === void 0 || buf === null) return void 0;
|
|
322
|
+
return Buffer.isBuffer(buf) ? buf.toString("utf8") : String(buf);
|
|
323
|
+
}
|
|
324
|
+
#project(raw, plan, metric, isKnn, rawScore) {
|
|
325
|
+
const proj = plan.projection;
|
|
326
|
+
const out = {};
|
|
327
|
+
if (proj.id) out.id = this.#decode(raw.__id);
|
|
328
|
+
if (proj.vector && raw.__vecb64) out.vector = unpackVector(Buffer.from(String(this.#decode(raw.__vecb64)), "base64"));
|
|
329
|
+
if (proj.document) out.document = this.#decode(raw.__document);
|
|
330
|
+
if (proj.metadata) {
|
|
331
|
+
const meta = {};
|
|
332
|
+
const reserved = new Set([
|
|
333
|
+
"__vector",
|
|
334
|
+
"__vecb64",
|
|
335
|
+
"__id",
|
|
336
|
+
"__document",
|
|
337
|
+
"__score"
|
|
338
|
+
]);
|
|
339
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
340
|
+
if (reserved.has(k)) continue;
|
|
341
|
+
meta[k] = this.#decode(v);
|
|
342
|
+
}
|
|
343
|
+
out.metadata = meta;
|
|
344
|
+
}
|
|
345
|
+
if (isKnn && rawScore !== void 0) out.score = require_batteries_vector_helpers.normalizeScore(rawScore, metric, "distance");
|
|
346
|
+
return out;
|
|
347
|
+
}
|
|
348
|
+
async executeDelete(plan) {
|
|
349
|
+
const client = await this.#ensure();
|
|
350
|
+
try {
|
|
351
|
+
if (plan.ids && plan.ids.length > 0) await client.del(plan.ids.map((id) => keyFor(plan.collection, id)));
|
|
352
|
+
else if (plan.filter) {
|
|
353
|
+
const filterFrag = translateRedisFilter(plan.filter);
|
|
354
|
+
const reply = await client.sendCommand([
|
|
355
|
+
"FT.SEARCH",
|
|
356
|
+
indexName(plan.collection),
|
|
357
|
+
filterFrag,
|
|
358
|
+
"DIALECT",
|
|
359
|
+
"2",
|
|
360
|
+
"LIMIT",
|
|
361
|
+
"0",
|
|
362
|
+
"10000",
|
|
363
|
+
"NOCONTENT"
|
|
364
|
+
]);
|
|
365
|
+
const keys = this.#parseSearchReply(reply).map((h) => h.key);
|
|
366
|
+
if (keys.length > 0) await client.del(keys);
|
|
367
|
+
} else {
|
|
368
|
+
const reply = await client.sendCommand([
|
|
369
|
+
"FT.SEARCH",
|
|
370
|
+
indexName(plan.collection),
|
|
371
|
+
"*",
|
|
372
|
+
"DIALECT",
|
|
373
|
+
"2",
|
|
374
|
+
"LIMIT",
|
|
375
|
+
"0",
|
|
376
|
+
"10000",
|
|
377
|
+
"NOCONTENT"
|
|
378
|
+
]);
|
|
379
|
+
const keys = this.#parseSearchReply(reply).map((h) => h.key);
|
|
380
|
+
if (keys.length > 0) await client.del(keys);
|
|
381
|
+
}
|
|
382
|
+
} catch (err) {
|
|
383
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_DELETE_FAILED([String(err)]);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
//#endregion
|
|
388
|
+
exports.RedisVectorStore = RedisVectorStore;
|
|
389
|
+
exports.translateRedisFilter = translateRedisFilter;
|
|
390
|
+
|
|
391
|
+
//# sourceMappingURL=redis.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.cjs","names":["#opts","#client","#ensure","#fields","#materialize","#parseSearchReply","#project","#decode"],"sources":["../../../src/batteries/vector/redis/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/redis\n *\n * One adapter for the whole Redis/Valkey family. The vector engine is RediSearch\n * (`FT.CREATE` / `FT.SEARCH` with a `VECTOR` field over a HASH keyspace); records are\n * stored as Redis hashes keyed `${collection}:${id}`, with the vector packed as a\n * little-endian Float32 buffer. Metadata scalars are stored as TAG/NUMERIC fields so the\n * neutral filter tree compiles to RediSearch query syntax.\n *\n * Works against `redis/redis-stack-server` (bundles RediSearch) and any Redis/Valkey with\n * the RediSearch module loaded.\n */\n\nimport { normalizeScore } from '../helpers'\nimport { BaseVectorStore } from '../contract'\nimport { validateRecords } from '../validation'\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport { isFilterCondition, isRawFilter, isFilterGroup } from '../filters'\nimport {\n E_VECTOR_STORE_DRIVER_UNAVAILABLE,\n E_VECTOR_STORE_COLLECTION_FAILED,\n E_VECTOR_STORE_UPSERT_FAILED,\n E_VECTOR_STORE_SEARCH_FAILED,\n E_VECTOR_STORE_DELETE_FAILED,\n E_VECTOR_STORE_DIMENSION_MISMATCH,\n E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR,\n E_VECTOR_STORE_UNSUPPORTED_OPERATION,\n E_VECTOR_STORE_CONNECTION_FAILED,\n} from '../exceptions'\nimport type { VectorFilter } from '../filters'\nimport type { SearchPlan, UpsertPlan, DeletePlan, CollectionSpec } from '../plan'\nimport type {\n VectorMatch,\n VectorStoreCapabilities,\n BaseVectorStoreOptions,\n VectorMetadata,\n DistanceMetric,\n} from '../types'\n\nexport interface RedisVectorStoreOptions extends BaseVectorStoreOptions {\n connection?: { url?: string; username?: string; password?: string }\n}\n\nconst getRedisClient = async () => {\n try {\n const mod = await import('redis')\n return mod.createClient\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['redis'])\n }\n}\n\n// RediSearch index name + key prefix derived from the logical collection.\nconst indexName = (collection: string): string => `idx:${collection}`\nconst keyPrefix = (collection: string): string => `${collection}:`\nconst keyFor = (collection: string, id: string): string => `${collection}:${id}`\n\n// Pack a number[] into a little-endian Float32 Buffer (RediSearch FLOAT32 vector blob).\nconst packVector = (vector: number[]): Buffer => {\n const buf = Buffer.allocUnsafe(vector.length * 4)\n for (let i = 0; i < vector.length; i++) buf.writeFloatLE(vector[i], i * 4)\n return buf\n}\n\nconst unpackVector = (buf: Buffer): number[] => {\n const out: number[] = []\n for (let i = 0; i < buf.length; i += 4) out.push(buf.readFloatLE(i))\n return out\n}\n\n// RediSearch distance metric for the index. Cosine + L2 are native; 'dot' maps to IP.\nconst metricToRedis = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'L2' : metric === 'dot' ? 'IP' : 'COSINE'\n\n// Escape a value for a RediSearch TAG filter (`@field:{value}`). Special chars must be escaped.\nconst escapeTag = (value: string): string =>\n value.replace(/[,.<>{}[\\]\"':;!@#$%^&*()\\-+=~|/\\\\ ]/g, '\\\\$&')\n\n/**\n * Compile the neutral filter tree to a RediSearch query fragment. TAG fields hold string /\n * boolean metadata; NUMERIC fields hold numbers. Returns a fragment to AND with the KNN\n * clause (or to use alone for a filter-scan). Throws on operators RediSearch can't express.\n */\nexport const translateRedisFilter = (filter?: VectorFilter): string => {\n if (!filter) return '*'\n if (isRawFilter(filter)) {\n if (filter.$dialect === 'redis' && typeof filter.$raw === 'string') {\n return filter.$raw\n }\n throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['redis', String(filter.$dialect)])\n }\n if (isFilterCondition(filter)) {\n const { field, op, value } = filter\n const tag = (v: unknown): string => `@${field}:{${escapeTag(String(v))}}`\n const num = (lo: string, hi: string): string => `@${field}:[${lo} ${hi}]`\n switch (op) {\n case 'eq':\n return typeof value === 'number' ? num(String(value), String(value)) : tag(value)\n case 'ne':\n return typeof value === 'number'\n ? `-${num(String(value), String(value))}`\n : `-${tag(value)}`\n case 'gt':\n return num(`(${String(value)}`, '+inf')\n case 'gte':\n return num(String(value), '+inf')\n case 'lt':\n return num('-inf', `(${String(value)}`)\n case 'lte':\n return num('-inf', String(value))\n case 'in': {\n if (!Array.isArray(value) || value.length === 0) return '@__never:{__never}'\n return `@${field}:{${value.map((v) => escapeTag(String(v))).join('|')}}`\n }\n case 'nin': {\n if (!Array.isArray(value) || value.length === 0) return '*'\n return `-@${field}:{${value.map((v) => escapeTag(String(v))).join('|')}}`\n }\n case 'exists':\n return `@${field}:*`\n default:\n throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['redis', op])\n }\n }\n if (isFilterGroup(filter)) {\n const { and, or, not } = filter\n if (and) {\n const parts = and.map(translateRedisFilter).filter((p) => p !== '*')\n return parts.length === 0 ? '*' : `(${parts.join(' ')})`\n }\n if (or) {\n const parts = or.map(translateRedisFilter).filter((p) => p !== '*')\n return parts.length === 0 ? '*' : `(${parts.join(' | ')})`\n }\n if (not) {\n const inner = translateRedisFilter(not)\n return inner === '*' ? '*' : `-${inner}`\n }\n return '*'\n }\n return '*'\n}\n\nexport class RedisVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // RediSearch indexes synchronously on HSET; a write is visible on resolve. No-op option.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n #client: any | null = null\n // Per-collection declared metadata fields, so FT.CREATE can declare TAG/NUMERIC schema.\n #fields: Map<string, CollectionSpec['fields']> = new Map()\n\n get #opts(): RedisVectorStoreOptions {\n return this.options as RedisVectorStoreOptions\n }\n\n static isAvailable(): boolean {\n return typeof process !== 'undefined'\n }\n isAvailable(): boolean {\n return typeof process !== 'undefined'\n }\n\n async connect(): Promise<void> {\n if (this.#client) return\n const createClient = await getRedisClient()\n const c = this.#opts.connection || {}\n try {\n this.#client = createClient({\n url: c.url ?? 'redis://localhost:6379',\n username: c.username,\n password: c.password,\n })\n await this.#client.connect()\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n if (this.#client) {\n try {\n await this.#client.quit()\n } catch {\n // ignore quit errors on teardown\n }\n this.#client = null\n }\n }\n\n async #ensure(): Promise<any> {\n if (!this.#client) await this.connect()\n return this.#client!\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const client = await this.#ensure()\n this.#fields.set(spec.collection, spec.fields)\n if (ifNotExists && (await this.hasCollection(spec.collection))) return\n const dim = spec.vector.dimensions\n const distance = metricToRedis(spec.vector.metric)\n // Build the FT.CREATE schema: the vector field + a TAG/NUMERIC field per declared payload\n // column. Declared fields are advisory; undeclared metadata is still stored on the hash\n // (just not independently filterable).\n const schema: string[] = [\n '__vector',\n 'VECTOR',\n 'FLAT',\n '6',\n 'TYPE',\n 'FLOAT32',\n 'DIM',\n String(dim),\n 'DISTANCE_METRIC',\n distance,\n ]\n for (const f of spec.fields) {\n schema.push(f.name)\n schema.push(f.type === 'integer' || f.type === 'number' ? 'NUMERIC' : 'TAG')\n }\n try {\n await client.sendCommand([\n 'FT.CREATE',\n indexName(spec.collection),\n 'ON',\n 'HASH',\n 'PREFIX',\n '1',\n keyPrefix(spec.collection),\n 'SCHEMA',\n ...schema,\n ])\n } catch (err) {\n const msg = String(err)\n if (msg.includes('Index already exists')) return\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', msg])\n }\n }\n\n async dropCollection(collection: string, ifExists: boolean): Promise<void> {\n const client = await this.#ensure()\n if (ifExists && !(await this.hasCollection(collection))) return\n try {\n // DD drops the indexed documents too.\n await client.sendCommand(['FT.DROPINDEX', indexName(collection), 'DD'])\n } catch (err) {\n const msg = String(err)\n if (ifExists && msg.includes('Unknown')) return\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['dropCollection', msg])\n }\n }\n\n async hasCollection(collection: string): Promise<boolean> {\n const client = await this.#ensure()\n try {\n await client.sendCommand(['FT.INFO', indexName(collection)])\n return true\n } catch {\n return false\n }\n }\n\n async renameCollection(_from: string, _to: string): Promise<void> {\n throw new E_VECTOR_STORE_UNSUPPORTED_OPERATION(['renameCollection', 'redis'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const client = await this.#ensure()\n const expected = this.#opts.dimensions\n try {\n for (const r of plan.records) {\n let vector = r.vector\n if (!vector && r.document) {\n const [v] = await this.encode([r.document], 'document')\n vector = v\n }\n if (!vector) {\n throw new E_VECTOR_STORE_UPSERT_FAILED(['Record missing vector and document'])\n }\n if (expected !== undefined && vector.length !== expected) {\n throw new E_VECTOR_STORE_DIMENSION_MISMATCH([expected, vector.length])\n }\n // Hash fields: the vector blob, the document, and each metadata scalar (stringified\n // for TAG, numeric kept as-is). __id/__document are reserved internal fields.\n const blob = packVector(vector)\n const entries: Record<string, string | Buffer> = {\n // Raw FLOAT32 blob for RediSearch to index on...\n __vector: blob,\n // ...plus a base64 copy so the vector survives a plain (string) hGetAll read-back\n // (node-redis v6's buffer-mode read API is version-fragile; base64 is portable).\n __vecb64: blob.toString('base64'),\n __id: r.id,\n }\n if (r.document !== undefined) entries.__document = r.document\n if (r.metadata) {\n for (const [k, v] of Object.entries(r.metadata)) {\n if (v === null || v === undefined) continue\n entries[k] = typeof v === 'object' ? JSON.stringify(v) : String(v)\n }\n }\n await client.hSet(keyFor(plan.collection, r.id), entries)\n }\n } catch (err) {\n if (\n isInstanceOf(err, 'E_VECTOR_STORE_DIMENSION_MISMATCH', E_VECTOR_STORE_DIMENSION_MISMATCH) ||\n isInstanceOf(err, 'E_VECTOR_STORE_UPSERT_FAILED', E_VECTOR_STORE_UPSERT_FAILED)\n )\n throw err\n throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)])\n }\n }\n\n async executeSearch(plan: SearchPlan): Promise<VectorMatch[]> {\n const client = await this.#ensure()\n const metric = this.#opts.metric ?? 'cosine'\n let queryVector: number[] | undefined\n if (plan.near) {\n if ('vector' in plan.near) {\n queryVector = plan.near.vector\n } else if ('serverText' in plan.near) {\n const [v] = await this.encode([plan.near.serverText], 'query')\n queryVector = v\n } else if ('id' in plan.near) {\n const raw = await client.hGetAll(keyFor(plan.collection, plan.near.id))\n const b64 = raw?.__vecb64\n if (!b64) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = unpackVector(Buffer.from(String(b64), 'base64'))\n }\n }\n\n try {\n if (queryVector) {\n const filterFrag = translateRedisFilter(plan.filter)\n const k = plan.topK + (plan.offset ?? 0)\n const query = `(${filterFrag})=>[KNN ${k} @__vector $BLOB AS __score]`\n const reply: any = await client.sendCommand([\n 'FT.SEARCH',\n indexName(plan.collection),\n query,\n 'PARAMS',\n '2',\n 'BLOB',\n packVector(queryVector),\n 'SORTBY',\n '__score',\n 'DIALECT',\n '2',\n 'LIMIT',\n String(plan.offset ?? 0),\n String(plan.topK),\n 'RETURN',\n '1',\n '__score',\n ])\n return await this.#materialize(client, reply, plan, metric, true)\n } else {\n // Filter-scan: FT.SEARCH with the filter fragment, no KNN.\n const filterFrag = translateRedisFilter(plan.filter)\n const reply: any = await client.sendCommand([\n 'FT.SEARCH',\n indexName(plan.collection),\n filterFrag,\n 'DIALECT',\n '2',\n 'LIMIT',\n String(plan.offset ?? 0),\n String(plan.topK),\n 'NOCONTENT',\n ])\n return await this.#materialize(client, reply, plan, metric, false)\n }\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n // Parse a node-redis v6 FT.SEARCH reply (structured object OR legacy flat array) into\n // [{ key, score? }] pairs. Score is read from extra_attributes.__score on KNN searches.\n #parseSearchReply(reply: any): Array<{ key: string; score?: number }> {\n // node-redis v6 returns { total_results, results: [{ id, extra_attributes }] }\n if (reply && typeof reply === 'object' && Array.isArray(reply.results)) {\n return reply.results.map((r: any) => ({\n key: String(r.id),\n score:\n r.extra_attributes && r.extra_attributes.__score !== undefined\n ? Number(r.extra_attributes.__score)\n : undefined,\n }))\n }\n // Legacy flat array reply: [total, key, key, ...]\n if (Array.isArray(reply)) {\n return reply.filter((_: unknown, i: number) => i > 0).map((k: any) => ({ key: String(k) }))\n }\n return []\n }\n\n // Parse the FT.SEARCH reply for keys (+ KNN score), then re-fetch each hash as buffers to\n // project. Re-fetching keeps the vector blob intact (RediSearch's per-field reply mangles it).\n async #materialize(\n client: any,\n reply: any,\n plan: SearchPlan,\n metric: string,\n isKnn: boolean\n ): Promise<VectorMatch[]> {\n const hits = this.#parseSearchReply(reply)\n const out: VectorMatch[] = []\n for (const hit of hits) {\n const raw = await client.hGetAll(hit.key)\n if (!raw) continue\n out.push(this.#project(raw, plan, metric, isKnn, hit.score))\n }\n return out\n }\n\n #decode(buf: unknown): string | undefined {\n if (buf === undefined || buf === null) return undefined\n return Buffer.isBuffer(buf) ? buf.toString('utf8') : String(buf)\n }\n\n #project(\n raw: Record<string, unknown>,\n plan: SearchPlan,\n metric: string,\n isKnn: boolean,\n rawScore?: number\n ): VectorMatch {\n const proj = plan.projection\n const out: VectorMatch = {}\n if (proj.id) out.id = this.#decode(raw.__id)\n if (proj.vector && raw.__vecb64) {\n out.vector = unpackVector(Buffer.from(String(this.#decode(raw.__vecb64)), 'base64'))\n }\n if (proj.document) out.document = this.#decode(raw.__document)\n if (proj.metadata) {\n const meta: VectorMetadata = {}\n const reserved = new Set(['__vector', '__vecb64', '__id', '__document', '__score'])\n for (const [k, v] of Object.entries(raw)) {\n if (reserved.has(k)) continue\n meta[k] = this.#decode(v) as string\n }\n out.metadata = meta\n }\n if (isKnn && rawScore !== undefined) {\n // RediSearch returns the raw distance for the metric; normalize to [0,1] higher-is-better.\n out.score = normalizeScore(rawScore, metric as DistanceMetric, 'distance')\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const client = await this.#ensure()\n try {\n if (plan.ids && plan.ids.length > 0) {\n await client.del(plan.ids.map((id) => keyFor(plan.collection, id)))\n } else if (plan.filter) {\n // Resolve ids via a filter-scan, then delete the hashes.\n const filterFrag = translateRedisFilter(plan.filter)\n const reply: any = await client.sendCommand([\n 'FT.SEARCH',\n indexName(plan.collection),\n filterFrag,\n 'DIALECT',\n '2',\n 'LIMIT',\n '0',\n '10000',\n 'NOCONTENT',\n ])\n const keys = this.#parseSearchReply(reply).map((h) => h.key)\n if (keys.length > 0) await client.del(keys)\n } else {\n // Delete-all: drop every hash under the prefix via the index.\n const reply: any = await client.sendCommand([\n 'FT.SEARCH',\n indexName(plan.collection),\n '*',\n 'DIALECT',\n '2',\n 'LIMIT',\n '0',\n '10000',\n 'NOCONTENT',\n ])\n const keys = this.#parseSearchReply(reply).map((h) => h.key)\n if (keys.length > 0) await client.del(keys)\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|