@nhtio/adk 1.20260607.2 → 1.20260609.1
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 +230 -0
- package/batteries/embeddings/openai/adapter.cjs +1 -1
- package/batteries/embeddings/openai/adapter.mjs +1 -1
- package/batteries/embeddings/openai/exceptions.cjs +1 -1
- package/batteries/embeddings/openai/exceptions.mjs +1 -1
- package/batteries/embeddings/openai/types.d.ts +7 -0
- package/batteries/embeddings/webllm/adapter.cjs +1 -1
- package/batteries/embeddings/webllm/adapter.mjs +1 -1
- package/batteries/embeddings/webllm/exceptions.cjs +1 -1
- package/batteries/embeddings/webllm/exceptions.mjs +1 -1
- package/batteries/llm/chat_common/helpers.d.ts +165 -0
- package/batteries/llm/chat_common/types.d.ts +309 -0
- package/batteries/llm/index.d.ts +5 -0
- package/batteries/llm/ollama/adapter.cjs +736 -0
- package/batteries/llm/ollama/adapter.cjs.map +1 -0
- package/batteries/llm/ollama/adapter.d.ts +64 -0
- package/batteries/llm/ollama/adapter.mjs +734 -0
- package/batteries/llm/ollama/adapter.mjs.map +1 -0
- package/batteries/llm/ollama/exceptions.cjs +105 -0
- package/batteries/llm/ollama/exceptions.cjs.map +1 -0
- package/batteries/llm/ollama/exceptions.d.ts +112 -0
- package/batteries/llm/ollama/exceptions.mjs +96 -0
- package/batteries/llm/ollama/exceptions.mjs.map +1 -0
- package/batteries/llm/ollama/helpers.cjs +487 -0
- package/batteries/llm/ollama/helpers.cjs.map +1 -0
- package/batteries/llm/ollama/helpers.d.ts +158 -0
- package/batteries/llm/ollama/helpers.mjs +450 -0
- package/batteries/llm/ollama/helpers.mjs.map +1 -0
- package/batteries/llm/ollama/index.d.ts +29 -0
- package/batteries/llm/ollama/types.cjs +2 -0
- package/batteries/llm/ollama/types.d.ts +334 -0
- package/batteries/llm/ollama/types.mjs +0 -0
- package/batteries/llm/ollama/validation.cjs +130 -0
- package/batteries/llm/ollama/validation.cjs.map +1 -0
- package/batteries/llm/ollama/validation.d.ts +31 -0
- package/batteries/llm/ollama/validation.mjs +127 -0
- package/batteries/llm/ollama/validation.mjs.map +1 -0
- package/batteries/llm/ollama.cjs +54 -0
- package/batteries/llm/ollama.mjs +6 -0
- package/batteries/llm/openai_chat_completions/adapter.cjs +36 -19
- package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/adapter.mjs +23 -6
- package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/openai_chat_completions/exceptions.cjs +1 -1
- package/batteries/llm/openai_chat_completions/exceptions.mjs +1 -1
- package/batteries/llm/openai_chat_completions/helpers.cjs +80 -320
- package/batteries/llm/openai_chat_completions/helpers.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/helpers.d.ts +68 -144
- package/batteries/llm/openai_chat_completions/helpers.mjs +40 -280
- package/batteries/llm/openai_chat_completions/helpers.mjs.map +1 -1
- package/batteries/llm/openai_chat_completions/types.d.ts +273 -181
- 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/openai_chat_completions.cjs +29 -28
- package/batteries/llm/openai_chat_completions.mjs +2 -1
- package/batteries/llm/webllm_chat_completions/adapter.cjs +38 -19
- package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.d.ts +18 -0
- package/batteries/llm/webllm_chat_completions/adapter.mjs +25 -6
- package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/exceptions.cjs +1 -1
- package/batteries/llm/webllm_chat_completions/exceptions.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/helpers.cjs +29 -28
- package/batteries/llm/webllm_chat_completions/helpers.mjs +2 -1
- package/batteries/llm/webllm_chat_completions/types.d.ts +21 -0
- package/batteries/llm/webllm_chat_completions/validation.cjs +13 -1
- package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/validation.d.ts +12 -0
- package/batteries/llm/webllm_chat_completions/validation.mjs +13 -1
- package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions.cjs +29 -28
- package/batteries/llm/webllm_chat_completions.mjs +2 -1
- package/batteries/llm.cjs +44 -28
- package/batteries/llm.mjs +9 -4
- package/batteries/storage/flydrive.cjs +1 -1
- package/batteries/storage/flydrive.mjs +1 -1
- package/batteries/storage/in_memory/index.d.ts +1 -1
- package/batteries/storage/in_memory.cjs +2 -2
- package/batteries/storage/in_memory.cjs.map +1 -1
- package/batteries/storage/in_memory.mjs +2 -2
- package/batteries/storage/in_memory.mjs.map +1 -1
- package/batteries/storage/opfs/index.d.ts +19 -0
- package/batteries/storage/opfs.cjs +1 -1
- package/batteries/storage/opfs.cjs.map +1 -1
- package/batteries/storage/opfs.mjs +1 -1
- package/batteries/storage/opfs.mjs.map +1 -1
- package/batteries/tools/_shared/index.d.ts +121 -0
- package/batteries/tools/_shared.cjs +157 -0
- package/batteries/tools/_shared.cjs.map +1 -0
- package/batteries/tools/_shared.mjs +149 -0
- package/batteries/tools/_shared.mjs.map +1 -0
- package/batteries/tools/color.cjs +3 -2
- package/batteries/tools/color.cjs.map +1 -1
- package/batteries/tools/color.mjs +3 -2
- package/batteries/tools/color.mjs.map +1 -1
- package/batteries/tools/comparison.cjs +4 -3
- package/batteries/tools/comparison.cjs.map +1 -1
- package/batteries/tools/comparison.mjs +4 -3
- package/batteries/tools/comparison.mjs.map +1 -1
- package/batteries/tools/data_structure.cjs +30 -10
- package/batteries/tools/data_structure.cjs.map +1 -1
- package/batteries/tools/data_structure.mjs +30 -10
- package/batteries/tools/data_structure.mjs.map +1 -1
- package/batteries/tools/datetime_extended.cjs +5 -10
- package/batteries/tools/datetime_extended.cjs.map +1 -1
- package/batteries/tools/datetime_extended.mjs +5 -10
- package/batteries/tools/datetime_extended.mjs.map +1 -1
- package/batteries/tools/datetime_math.cjs +2 -2
- package/batteries/tools/datetime_math.mjs +2 -2
- package/batteries/tools/encoding.cjs +13 -4
- package/batteries/tools/encoding.cjs.map +1 -1
- package/batteries/tools/encoding.mjs +13 -4
- package/batteries/tools/encoding.mjs.map +1 -1
- package/batteries/tools/formatting.cjs +4 -4
- package/batteries/tools/formatting.cjs.map +1 -1
- package/batteries/tools/formatting.mjs +4 -4
- package/batteries/tools/formatting.mjs.map +1 -1
- package/batteries/tools/geo_basics.cjs +2 -2
- package/batteries/tools/geo_basics.mjs +2 -2
- package/batteries/tools/index.d.ts +3 -0
- package/batteries/tools/math.cjs +10 -8
- package/batteries/tools/math.cjs.map +1 -1
- package/batteries/tools/math.mjs +10 -8
- 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 +9 -5
- package/batteries/tools/parsing.cjs.map +1 -1
- package/batteries/tools/parsing.mjs +9 -5
- package/batteries/tools/parsing.mjs.map +1 -1
- package/batteries/tools/retrievables.cjs +4 -4
- package/batteries/tools/retrievables.mjs +4 -4
- package/batteries/tools/scrapper/exceptions.d.ts +21 -0
- package/batteries/tools/scrapper/index.d.ts +172 -0
- package/batteries/tools/scrapper/shared.d.ts +139 -0
- package/batteries/tools/scrapper.cjs +8 -0
- package/batteries/tools/scrapper.mjs +2 -0
- package/batteries/tools/searxng/exceptions.d.ts +21 -0
- package/batteries/tools/searxng/index.d.ts +177 -0
- package/batteries/tools/searxng.cjs +6 -0
- package/batteries/tools/searxng.mjs +2 -0
- package/batteries/tools/standing_instructions.cjs +4 -4
- package/batteries/tools/standing_instructions.mjs +4 -4
- package/batteries/tools/statistics.cjs +54 -43
- package/batteries/tools/statistics.cjs.map +1 -1
- package/batteries/tools/statistics.mjs +54 -43
- package/batteries/tools/statistics.mjs.map +1 -1
- package/batteries/tools/string_processing.cjs +5 -5
- package/batteries/tools/string_processing.cjs.map +1 -1
- package/batteries/tools/string_processing.mjs +5 -5
- package/batteries/tools/string_processing.mjs.map +1 -1
- package/batteries/tools/structured_data.cjs +8 -13
- package/batteries/tools/structured_data.cjs.map +1 -1
- package/batteries/tools/structured_data.mjs +8 -13
- package/batteries/tools/structured_data.mjs.map +1 -1
- 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 +10 -8
- package/batteries/tools/unit_conversion.cjs.map +1 -1
- package/batteries/tools/unit_conversion.mjs +10 -8
- package/batteries/tools/unit_conversion.mjs.map +1 -1
- package/batteries/tools/web_retrieval/index.d.ts +186 -0
- package/batteries/tools/web_retrieval.cjs +206 -0
- package/batteries/tools/web_retrieval.cjs.map +1 -0
- package/batteries/tools/web_retrieval.mjs +201 -0
- package/batteries/tools/web_retrieval.mjs.map +1 -0
- package/batteries/tools.cjs +15 -0
- package/batteries/tools.mjs +4 -1
- package/batteries/vector/arangodb/index.d.ts +2 -0
- package/batteries/vector/arangodb.cjs +2 -1
- package/batteries/vector/arangodb.cjs.map +1 -1
- package/batteries/vector/arangodb.mjs +2 -1
- package/batteries/vector/arangodb.mjs.map +1 -1
- package/batteries/vector/builder.cjs +31 -0
- package/batteries/vector/builder.cjs.map +1 -1
- package/batteries/vector/builder.d.ts +58 -0
- package/batteries/vector/builder.mjs +31 -0
- package/batteries/vector/builder.mjs.map +1 -1
- package/batteries/vector/chroma/index.d.ts +4 -0
- package/batteries/vector/chroma.cjs +3 -0
- package/batteries/vector/chroma.cjs.map +1 -1
- package/batteries/vector/chroma.mjs +3 -0
- package/batteries/vector/chroma.mjs.map +1 -1
- package/batteries/vector/clickhouse/index.d.ts +2 -0
- package/batteries/vector/clickhouse.cjs +2 -1
- package/batteries/vector/clickhouse.cjs.map +1 -1
- package/batteries/vector/clickhouse.mjs +2 -1
- package/batteries/vector/clickhouse.mjs.map +1 -1
- package/batteries/vector/cloudflare/index.d.ts +2 -0
- package/batteries/vector/cloudflare.cjs +2 -1
- package/batteries/vector/cloudflare.cjs.map +1 -1
- package/batteries/vector/cloudflare.mjs +2 -1
- package/batteries/vector/cloudflare.mjs.map +1 -1
- package/batteries/vector/conformance/index.d.ts +22 -0
- package/batteries/vector/conformance.cjs +22 -0
- package/batteries/vector/conformance.cjs.map +1 -1
- package/batteries/vector/conformance.mjs +22 -0
- package/batteries/vector/conformance.mjs.map +1 -1
- package/batteries/vector/contract.cjs +22 -0
- package/batteries/vector/contract.cjs.map +1 -1
- package/batteries/vector/contract.d.ts +51 -0
- package/batteries/vector/contract.mjs +22 -0
- package/batteries/vector/contract.mjs.map +1 -1
- package/batteries/vector/couchbase/index.d.ts +2 -0
- package/batteries/vector/couchbase.cjs +2 -1
- package/batteries/vector/couchbase.cjs.map +1 -1
- package/batteries/vector/couchbase.mjs +2 -1
- package/batteries/vector/couchbase.mjs.map +1 -1
- package/batteries/vector/duckdb/index.d.ts +2 -0
- package/batteries/vector/duckdb.cjs +2 -1
- package/batteries/vector/duckdb.cjs.map +1 -1
- package/batteries/vector/duckdb.mjs +2 -1
- package/batteries/vector/duckdb.mjs.map +1 -1
- package/batteries/vector/elasticsearch/index.d.ts +2 -0
- package/batteries/vector/elasticsearch.cjs +2 -1
- package/batteries/vector/elasticsearch.cjs.map +1 -1
- package/batteries/vector/elasticsearch.mjs +2 -1
- package/batteries/vector/elasticsearch.mjs.map +1 -1
- package/batteries/vector/exceptions.cjs +1 -1
- package/batteries/vector/exceptions.mjs +1 -1
- package/batteries/vector/factory.cjs +6 -0
- package/batteries/vector/factory.cjs.map +1 -1
- package/batteries/vector/factory.d.ts +14 -0
- package/batteries/vector/factory.mjs +6 -0
- package/batteries/vector/factory.mjs.map +1 -1
- package/batteries/vector/filters.cjs +22 -1
- package/batteries/vector/filters.cjs.map +1 -1
- package/batteries/vector/filters.d.ts +38 -0
- package/batteries/vector/filters.mjs +22 -1
- package/batteries/vector/filters.mjs.map +1 -1
- package/batteries/vector/helpers.cjs +13 -0
- package/batteries/vector/helpers.cjs.map +1 -1
- package/batteries/vector/helpers.d.ts +14 -0
- package/batteries/vector/helpers.mjs +13 -0
- package/batteries/vector/helpers.mjs.map +1 -1
- package/batteries/vector/hnswlib/index.d.ts +2 -0
- package/batteries/vector/hnswlib.cjs +2 -1
- package/batteries/vector/hnswlib.cjs.map +1 -1
- package/batteries/vector/hnswlib.mjs +2 -1
- package/batteries/vector/hnswlib.mjs.map +1 -1
- package/batteries/vector/in_memory/index.d.ts +1 -0
- package/batteries/vector/in_memory.cjs +1 -0
- package/batteries/vector/in_memory.cjs.map +1 -1
- package/batteries/vector/in_memory.mjs +1 -0
- package/batteries/vector/in_memory.mjs.map +1 -1
- package/batteries/vector/lancedb/index.d.ts +2 -0
- package/batteries/vector/lancedb.cjs +2 -1
- package/batteries/vector/lancedb.cjs.map +1 -1
- package/batteries/vector/lancedb.mjs +2 -1
- package/batteries/vector/lancedb.mjs.map +1 -1
- package/batteries/vector/mariadb/index.d.ts +2 -0
- package/batteries/vector/mariadb.cjs +2 -1
- package/batteries/vector/mariadb.cjs.map +1 -1
- package/batteries/vector/mariadb.mjs +2 -1
- package/batteries/vector/mariadb.mjs.map +1 -1
- package/batteries/vector/meilisearch/index.d.ts +2 -0
- package/batteries/vector/meilisearch.cjs +2 -1
- package/batteries/vector/meilisearch.cjs.map +1 -1
- package/batteries/vector/meilisearch.mjs +2 -1
- package/batteries/vector/meilisearch.mjs.map +1 -1
- package/batteries/vector/migrate.cjs +18 -1
- package/batteries/vector/migrate.cjs.map +1 -1
- package/batteries/vector/migrate.d.ts +31 -0
- package/batteries/vector/migrate.mjs +18 -1
- package/batteries/vector/migrate.mjs.map +1 -1
- package/batteries/vector/milvus/index.d.ts +5 -0
- package/batteries/vector/milvus.cjs +4 -0
- package/batteries/vector/milvus.cjs.map +1 -1
- package/batteries/vector/milvus.mjs +4 -0
- package/batteries/vector/milvus.mjs.map +1 -1
- package/batteries/vector/mongodb/index.d.ts +2 -0
- package/batteries/vector/mongodb.cjs +2 -1
- package/batteries/vector/mongodb.cjs.map +1 -1
- package/batteries/vector/mongodb.mjs +2 -1
- package/batteries/vector/mongodb.mjs.map +1 -1
- package/batteries/vector/neo4j/index.d.ts +2 -0
- package/batteries/vector/neo4j.cjs +2 -1
- package/batteries/vector/neo4j.cjs.map +1 -1
- package/batteries/vector/neo4j.mjs +2 -1
- package/batteries/vector/neo4j.mjs.map +1 -1
- package/batteries/vector/opensearch/index.d.ts +2 -0
- package/batteries/vector/opensearch.cjs +2 -1
- package/batteries/vector/opensearch.cjs.map +1 -1
- package/batteries/vector/opensearch.mjs +2 -1
- package/batteries/vector/opensearch.mjs.map +1 -1
- package/batteries/vector/oracle23ai/index.d.ts +2 -0
- package/batteries/vector/oracle23ai.cjs +2 -1
- package/batteries/vector/oracle23ai.cjs.map +1 -1
- package/batteries/vector/oracle23ai.mjs +2 -1
- package/batteries/vector/oracle23ai.mjs.map +1 -1
- package/batteries/vector/orama/index.d.ts +1 -0
- package/batteries/vector/orama.cjs +1 -0
- package/batteries/vector/orama.cjs.map +1 -1
- package/batteries/vector/orama.mjs +1 -0
- package/batteries/vector/orama.mjs.map +1 -1
- package/batteries/vector/pgvector/index.d.ts +9 -2
- package/batteries/vector/pgvector.cjs +4 -0
- package/batteries/vector/pgvector.cjs.map +1 -1
- package/batteries/vector/pgvector.mjs +4 -0
- package/batteries/vector/pgvector.mjs.map +1 -1
- package/batteries/vector/pinecone/index.d.ts +5 -0
- package/batteries/vector/pinecone.cjs +3 -1
- package/batteries/vector/pinecone.cjs.map +1 -1
- package/batteries/vector/pinecone.mjs +3 -1
- package/batteries/vector/pinecone.mjs.map +1 -1
- package/batteries/vector/plan.d.ts +27 -0
- package/batteries/vector/qdrant/index.d.ts +5 -0
- package/batteries/vector/qdrant.cjs +4 -0
- package/batteries/vector/qdrant.cjs.map +1 -1
- package/batteries/vector/qdrant.mjs +4 -0
- package/batteries/vector/qdrant.mjs.map +1 -1
- package/batteries/vector/redis/index.d.ts +2 -0
- package/batteries/vector/redis.cjs +2 -1
- package/batteries/vector/redis.cjs.map +1 -1
- package/batteries/vector/redis.mjs +2 -1
- package/batteries/vector/redis.mjs.map +1 -1
- package/batteries/vector/retrievable.cjs +9 -1
- package/batteries/vector/retrievable.cjs.map +1 -1
- package/batteries/vector/retrievable.mjs +9 -1
- package/batteries/vector/retrievable.mjs.map +1 -1
- package/batteries/vector/retrievable_glue.d.ts +21 -0
- package/batteries/vector/s3vectors/index.d.ts +2 -0
- package/batteries/vector/s3vectors.cjs +2 -1
- package/batteries/vector/s3vectors.cjs.map +1 -1
- package/batteries/vector/s3vectors.mjs +2 -1
- package/batteries/vector/s3vectors.mjs.map +1 -1
- package/batteries/vector/schema.cjs +28 -0
- package/batteries/vector/schema.cjs.map +1 -1
- package/batteries/vector/schema.d.ts +39 -0
- package/batteries/vector/schema.mjs +28 -0
- package/batteries/vector/schema.mjs.map +1 -1
- package/batteries/vector/solr/index.d.ts +2 -0
- package/batteries/vector/solr.cjs +2 -1
- package/batteries/vector/solr.cjs.map +1 -1
- package/batteries/vector/solr.mjs +2 -1
- package/batteries/vector/solr.mjs.map +1 -1
- package/batteries/vector/sqlite_vec/index.d.ts +6 -3
- package/batteries/vector/sqlite_vec.cjs +2 -0
- package/batteries/vector/sqlite_vec.cjs.map +1 -1
- package/batteries/vector/sqlite_vec.mjs +2 -0
- package/batteries/vector/sqlite_vec.mjs.map +1 -1
- package/batteries/vector/surrealdb/index.d.ts +2 -0
- package/batteries/vector/surrealdb.cjs +2 -1
- package/batteries/vector/surrealdb.cjs.map +1 -1
- package/batteries/vector/surrealdb.mjs +2 -1
- package/batteries/vector/surrealdb.mjs.map +1 -1
- package/batteries/vector/types.d.ts +27 -0
- package/batteries/vector/typesense/index.d.ts +2 -0
- package/batteries/vector/typesense.cjs +2 -1
- package/batteries/vector/typesense.cjs.map +1 -1
- package/batteries/vector/typesense.mjs +2 -1
- package/batteries/vector/typesense.mjs.map +1 -1
- package/batteries/vector/validation.cjs +14 -0
- package/batteries/vector/validation.cjs.map +1 -1
- package/batteries/vector/validation.d.ts +14 -0
- package/batteries/vector/validation.mjs +14 -0
- package/batteries/vector/validation.mjs.map +1 -1
- package/batteries/vector/vector_store_constructor.cjs +1 -1
- package/batteries/vector/vector_store_constructor.cjs.map +1 -1
- package/batteries/vector/vector_store_constructor.d.ts +1 -1
- package/batteries/vector/vector_store_constructor.mjs +1 -1
- package/batteries/vector/vector_store_constructor.mjs.map +1 -1
- package/batteries/vector/vespa/index.d.ts +2 -0
- package/batteries/vector/vespa.cjs +2 -1
- package/batteries/vector/vespa.cjs.map +1 -1
- package/batteries/vector/vespa.mjs +2 -1
- package/batteries/vector/vespa.mjs.map +1 -1
- package/batteries/vector/weaviate/index.d.ts +2 -0
- package/batteries/vector/weaviate.cjs +2 -1
- package/batteries/vector/weaviate.cjs.map +1 -1
- package/batteries/vector/weaviate.mjs +2 -1
- package/batteries/vector/weaviate.mjs.map +1 -1
- package/batteries.cjs +58 -28
- package/batteries.mjs +12 -5
- package/{common-BT0nfCi9.mjs → common-DYDUi99O.mjs} +9 -9
- package/common-DYDUi99O.mjs.map +1 -0
- package/{common-Cj8TaQ9U.js → common-DZl3ADJs.js} +9 -9
- package/common-DZl3ADJs.js.map +1 -0
- package/common.cjs +7 -7
- package/common.mjs +7 -7
- package/{dispatch_runner-DPcS7Y_M.mjs → dispatch_runner--ZhdDWRZ.mjs} +27 -5
- package/{dispatch_runner-DPcS7Y_M.mjs.map → dispatch_runner--ZhdDWRZ.mjs.map} +1 -1
- package/{dispatch_runner-BHBNupqp.js → dispatch_runner-nHDKkxye.js} +27 -5
- package/{dispatch_runner-BHBNupqp.js.map → dispatch_runner-nHDKkxye.js.map} +1 -1
- package/dispatch_runner.cjs +1 -1
- package/dispatch_runner.d.ts +1 -1
- package/dispatch_runner.mjs +1 -1
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs +1 -0
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs.map +1 -1
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.d.ts +1 -0
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.mjs +1 -0
- package/eslint/rules/artifact_tool_forbids_artifact_constructor.mjs.map +1 -1
- package/eslint/rules/no_model_in_tool_handler.cjs +1 -0
- package/eslint/rules/no_model_in_tool_handler.cjs.map +1 -1
- package/eslint/rules/no_model_in_tool_handler.d.ts +1 -0
- package/eslint/rules/no_model_in_tool_handler.mjs +1 -0
- package/eslint/rules/no_model_in_tool_handler.mjs.map +1 -1
- package/eslint/rules/require_validator_any_required.cjs +1 -0
- package/eslint/rules/require_validator_any_required.cjs.map +1 -1
- package/eslint/rules/require_validator_any_required.d.ts +1 -0
- package/eslint/rules/require_validator_any_required.mjs +1 -0
- package/eslint/rules/require_validator_any_required.mjs.map +1 -1
- package/eslint/rules/thought_payload_requires_replay_tag.cjs +1 -0
- package/eslint/rules/thought_payload_requires_replay_tag.cjs.map +1 -1
- package/eslint/rules/thought_payload_requires_replay_tag.d.ts +1 -0
- package/eslint/rules/thought_payload_requires_replay_tag.mjs +1 -0
- package/eslint/rules/thought_payload_requires_replay_tag.mjs.map +1 -1
- package/eslint/rules/token_encoding_requires_context_window.cjs +1 -0
- package/eslint/rules/token_encoding_requires_context_window.cjs.map +1 -1
- package/eslint/rules/token_encoding_requires_context_window.d.ts +1 -0
- package/eslint/rules/token_encoding_requires_context_window.mjs +1 -0
- package/eslint/rules/token_encoding_requires_context_window.mjs.map +1 -1
- package/eslint/rules.cjs +1 -1
- package/eslint/rules.mjs +1 -1
- package/eslint.cjs +2 -2
- package/eslint.mjs +2 -2
- package/{exceptions-BeWH2FwP.mjs → exceptions-BDhN0Xzr.mjs} +3 -2
- package/exceptions-BDhN0Xzr.mjs.map +1 -0
- package/{exceptions-CitH5wZI.js → exceptions-BRXrUKiW.js} +3 -2
- package/exceptions-BRXrUKiW.js.map +1 -0
- package/exceptions.cjs +2 -2
- package/exceptions.mjs +2 -2
- package/factories.cjs +1 -1
- package/factories.mjs +1 -1
- package/forge.cjs +4 -4
- package/forge.d.ts +1 -1
- package/forge.mjs +4 -4
- package/guards.cjs +9 -9
- package/guards.mjs +9 -9
- package/helpers-DSTFxTiC.js +497 -0
- package/helpers-DSTFxTiC.js.map +1 -0
- package/helpers-xhrQbMAG.mjs +306 -0
- package/helpers-xhrQbMAG.mjs.map +1 -0
- package/index.cjs +12 -12
- package/index.mjs +12 -12
- package/lib/classes/base_exception.d.ts +1 -0
- package/lib/classes/media.d.ts +10 -0
- package/lib/classes/retrievable.d.ts +1 -1
- package/lib/classes/spooled_json_artifact.d.ts +1 -1
- package/lib/classes/spooled_markdown_artifact.d.ts +1 -0
- package/lib/classes/tokenizable.d.ts +3 -0
- package/lib/classes/tool.d.ts +8 -0
- package/lib/classes/turn_gate.d.ts +6 -0
- package/lib/dispatch_runner.d.ts +4 -32
- package/lib/helpers/bignum.cjs +82 -0
- package/lib/helpers/bignum.cjs.map +1 -0
- package/lib/helpers/bignum.d.ts +52 -0
- package/lib/helpers/bignum.mjs +74 -0
- package/lib/helpers/bignum.mjs.map +1 -0
- package/lib/turn_runner.d.ts +1 -1
- package/lib/types/dispatch_runner.d.ts +83 -0
- package/lib/utils/exceptions.d.ts +1 -1
- package/lib/utils/retry.cjs.map +1 -1
- package/lib/utils/retry.d.ts +2 -0
- package/lib/utils/retry.mjs.map +1 -1
- package/mcp/adk-docs-corpus.json +1 -1
- package/package.json +259 -204
- package/{runtime-j92CNi5z.mjs → runtime-Bz5zA8wc.mjs} +2 -2
- package/{runtime-j92CNi5z.mjs.map → runtime-Bz5zA8wc.mjs.map} +1 -1
- package/{runtime-MFFcJrRv.js → runtime-DslE1aBw.js} +2 -2
- package/{runtime-MFFcJrRv.js.map → runtime-DslE1aBw.js.map} +1 -1
- package/scrapper-BHM1mCde.mjs +432 -0
- package/scrapper-BHM1mCde.mjs.map +1 -0
- package/scrapper-BeweWurk.js +462 -0
- package/scrapper-BeweWurk.js.map +1 -0
- package/searxng-BJFulNcK.mjs +247 -0
- package/searxng-BJFulNcK.mjs.map +1 -0
- package/searxng-B_D--V5q.js +265 -0
- package/searxng-B_D--V5q.js.map +1 -0
- package/skills/adk-assembly/SKILL.md +2 -2
- package/{spooled_artifact-CHoZgWwI.mjs → spooled_artifact-7eePq7JA.mjs} +5 -5
- package/{spooled_artifact-CHoZgWwI.mjs.map → spooled_artifact-7eePq7JA.mjs.map} +1 -1
- package/{spooled_artifact-BTq6Nzfy.js → spooled_artifact-DX8LLyUX.js} +5 -5
- package/{spooled_artifact-BTq6Nzfy.js.map → spooled_artifact-DX8LLyUX.js.map} +1 -1
- package/spooled_artifact.cjs +2 -2
- package/spooled_artifact.mjs +2 -2
- package/{spooled_markdown_artifact-CALSDxIx.js → spooled_markdown_artifact-ClX72lek.js} +4 -4
- package/spooled_markdown_artifact-ClX72lek.js.map +1 -0
- package/{spooled_markdown_artifact-Ci5UL7l4.mjs → spooled_markdown_artifact-wkrBF3oX.mjs} +4 -4
- package/spooled_markdown_artifact-wkrBF3oX.mjs.map +1 -0
- package/{thought-D34QQZZ9.mjs → thought-B_vxAiKU.mjs} +5 -5
- package/{thought-D34QQZZ9.mjs.map → thought-B_vxAiKU.mjs.map} +1 -1
- package/{thought-BbwhJ1wb.js → thought-DLwpF7MI.js} +5 -5
- package/{thought-BbwhJ1wb.js.map → thought-DLwpF7MI.js.map} +1 -1
- package/{tool-CVyZkFC7.js → tool-D5WGVIcI.js} +4 -4
- package/{tool-CVyZkFC7.js.map → tool-D5WGVIcI.js.map} +1 -1
- package/{tool-CMhaDRNd.mjs → tool-wMYMVl60.mjs} +4 -4
- package/{tool-CMhaDRNd.mjs.map → tool-wMYMVl60.mjs.map} +1 -1
- package/{tool_call-CV5qVNlb.mjs → tool_call-B4-_-vjG.mjs} +5 -5
- package/tool_call-B4-_-vjG.mjs.map +1 -0
- package/{tool_call-Db68hB7y.js → tool_call-DixVlW40.js} +5 -5
- package/tool_call-DixVlW40.js.map +1 -0
- package/{tool_registry-D1pSSlsd.mjs → tool_registry-791Vrjtf.mjs} +4 -3
- package/tool_registry-791Vrjtf.mjs.map +1 -0
- package/{tool_registry-DYUYqXvo.js → tool_registry-CKJPze3j.js} +4 -3
- package/tool_registry-CKJPze3j.js.map +1 -0
- package/{turn_runner-DqWHNP80.js → turn_runner-HXImLGIn.js} +7 -7
- package/turn_runner-HXImLGIn.js.map +1 -0
- package/{turn_runner-fg1Wc3dK.mjs → turn_runner-ZyYO-Kti.mjs} +7 -7
- package/turn_runner-ZyYO-Kti.mjs.map +1 -0
- package/turn_runner.cjs +1 -1
- package/turn_runner.mjs +1 -1
- package/types.d.ts +1 -1
- package/common-BT0nfCi9.mjs.map +0 -1
- package/common-Cj8TaQ9U.js.map +0 -1
- package/exceptions-BeWH2FwP.mjs.map +0 -1
- package/exceptions-CitH5wZI.js.map +0 -1
- package/spooled_markdown_artifact-CALSDxIx.js.map +0 -1
- package/spooled_markdown_artifact-Ci5UL7l4.mjs.map +0 -1
- package/tool_call-CV5qVNlb.mjs.map +0 -1
- package/tool_call-Db68hB7y.js.map +0 -1
- package/tool_registry-D1pSSlsd.mjs.map +0 -1
- package/tool_registry-DYUYqXvo.js.map +0 -1
- package/turn_runner-DqWHNP80.js.map +0 -1
- package/turn_runner-fg1Wc3dK.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mongodb.mjs","names":["#opts","#client","#db","#col","#name","#sleep","#dims","#settlePresent","#parseMeta","#project"],"sources":["../../../src/batteries/vector/mongodb/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/mongodb\n *\n * MongoDB Atlas Vector Search adapter. Each collection is a MongoDB collection with an Atlas\n * `vectorSearch` index on `vec`; KNN uses the `$vectorSearch` aggregation stage (cosine\n * `vectorSearchScore`, [0,1]). Metadata is a JSON string field filtered with the neutral filter\n * tree's JS reference evaluator for cross-adapter parity.\n *\n * Consistency note: the *document* collection is strongly consistent, but the Atlas vector\n * *index* updates asynchronously after a write (~1s). So filter-scans, fetch-by-id and the\n * delete read-back use a plain `find()` (immediate), and only KNN goes through `$vectorSearch` —\n * after which the adapter polls until the just-inserted ids are index-visible (strong mode).\n *\n * Driver: `mongodb`. Works against `mongodb/mongodb-atlas-local` or a real Atlas cluster.\n */\n\nimport { evaluateFilter } from '../filters'\nimport { BaseVectorStore } from '../contract'\nimport { validateRecords } from '../validation'\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport {\n E_VECTOR_STORE_DRIVER_UNAVAILABLE,\n E_VECTOR_STORE_CONNECTION_FAILED,\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_OPERATION,\n} from '../exceptions'\nimport type { SearchPlan, UpsertPlan, DeletePlan, CollectionSpec } from '../plan'\nimport type {\n VectorMatch,\n VectorStoreCapabilities,\n BaseVectorStoreOptions,\n VectorMetadata,\n DistanceMetric,\n} from '../types'\n\nconst INDEX = 'vec_idx'\n\nexport interface MongoDBVectorStoreOptions extends BaseVectorStoreOptions {\n connection: {\n url: string\n database?: string\n /**\n * When set, the physical MongoDB collection becomes `${collectionPrefix}${collection}`. The\n * logical collection the builder/base see is unchanged. Lets callers (and the test suite)\n * isolate otherwise identically-named collections — useful because the Atlas vectorSearch\n * index builds asynchronously, so a fresh collection per use avoids drop+rebuild churn.\n */\n collectionPrefix?: string\n }\n}\n\nconst getMongo = async () => {\n try {\n const mod = await import('mongodb')\n return mod.MongoClient\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['mongodb'])\n }\n}\n\nconst similarity = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'euclidean' : metric === 'dot' ? 'dotProduct' : 'cosine'\n\nexport class MongoDBVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // The document store is strongly consistent; KNN settles on the async index after writes.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #client: any | null = null\n #db: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): MongoDBVectorStoreOptions {\n return this.options as MongoDBVectorStoreOptions\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 MongoClient = await getMongo()\n const c = this.#opts.connection\n try {\n this.#client = new MongoClient(c.url)\n await this.#client.connect()\n this.#db = this.#client.db(c.database ?? 'vector')\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 await this.#client.close()\n this.#client = null\n this.#db = null\n }\n }\n\n // Map a logical collection name to its physical MongoDB collection (optional prefix).\n #name(collection: string): string {\n const prefix = this.#opts.connection?.collectionPrefix\n return prefix ? `${prefix}${collection}` : collection\n }\n\n async #col(collection: string): Promise<any> {\n if (!this.#db) await this.connect()\n return this.#db.collection(this.#name(collection))\n }\n\n async #sleep(ms: number): Promise<void> {\n await new Promise((r) => setTimeout(r, ms))\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n if (!this.#db) await this.connect()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n const physical = this.#name(spec.collection)\n try {\n const names = await this.#db.listCollections({ name: physical }).toArray()\n if (names.length > 0) {\n if (ifNotExists) {\n // Clear any residual documents so each store starts empty.\n await this.#db.collection(physical).deleteMany({})\n return\n }\n await this.#db\n .collection(physical)\n .drop()\n .catch(() => undefined)\n }\n await this.#db.createCollection(physical).catch(() => undefined)\n const col = this.#db.collection(physical)\n // Create the Atlas vectorSearch index if absent, then wait until it's queryable.\n const existing = await col\n .listSearchIndexes()\n .toArray()\n .catch(() => [])\n if (!existing.find((i: any) => i.name === INDEX)) {\n await col.createSearchIndex({\n name: INDEX,\n type: 'vectorSearch',\n definition: {\n fields: [\n {\n type: 'vector',\n path: 'vec',\n numDimensions: spec.vector.dimensions,\n similarity: similarity(spec.vector.metric),\n },\n ],\n },\n })\n }\n for (let i = 0; i < 60; i++) {\n const list = await col.listSearchIndexes().toArray()\n const idx = list.find((x: any) => x.name === INDEX)\n if (idx?.queryable) break\n await this.#sleep(1000)\n }\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\n }\n }\n\n async dropCollection(collection: string, ifExists: boolean): Promise<void> {\n if (!this.#db) await this.connect()\n const physical = this.#name(collection)\n try {\n const names = await this.#db.listCollections({ name: physical }).toArray()\n if (names.length === 0) {\n if (ifExists) return\n throw new Error('collection not found: ' + collection)\n }\n // Clear documents (fast/immediate) and drop the collection; the search index goes with it.\n await this.#db\n .collection(physical)\n .drop()\n .catch(() => undefined)\n this.#dims.delete(collection)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['dropCollection', String(err)])\n }\n }\n\n async hasCollection(collection: string): Promise<boolean> {\n if (!this.#db) await this.connect()\n const names = await this.#db.listCollections({ name: this.#name(collection) }).toArray()\n return names.length > 0\n }\n\n async renameCollection(_from: string, _to: string): Promise<void> {\n throw new E_VECTOR_STORE_UNSUPPORTED_OPERATION(['renameCollection', 'mongodb'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const col = await this.#col(plan.collection)\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\n const ids: string[] = []\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 await col.updateOne(\n { id: r.id },\n {\n $set: {\n id: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n },\n },\n { upsert: true }\n )\n ids.push(r.id)\n }\n // Settle: wait until the just-written ids are visible to $vectorSearch (the index is async).\n await this.#settlePresent(col, ids, expected ?? this.#dims.get(plan.collection) ?? 0)\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 }\n throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)])\n }\n }\n\n // Poll $vectorSearch until every id in `ids` appears (bounded). Best-effort: returns on timeout.\n async #settlePresent(col: any, ids: string[], dims: number): Promise<void> {\n if (ids.length === 0 || dims <= 0) return\n const probe = new Array(dims).fill(0)\n probe[0] = 1\n const deadline = Date.now() + 10_000\n while (Date.now() < deadline) {\n let seen: Set<string>\n try {\n const res = await col\n .aggregate([\n {\n $vectorSearch: {\n index: INDEX,\n path: 'vec',\n queryVector: probe,\n numCandidates: Math.max(ids.length * 10, 50),\n limit: Math.max(ids.length * 5, 50),\n },\n },\n { $project: { id: 1 } },\n ])\n .toArray()\n seen = new Set(res.map((d: any) => d.id))\n } catch {\n seen = new Set()\n }\n if (ids.every((id) => seen.has(id))) return\n await this.#sleep(300)\n }\n }\n\n async executeSearch(plan: SearchPlan): Promise<VectorMatch[]> {\n const col = await this.#col(plan.collection)\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 // Plain find() — strongly consistent, no index lag.\n const doc = await col.findOne({ id: plan.near.id })\n if (!doc) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = doc.vec as number[]\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n if (queryVector) {\n const k = (plan.filter ? 1000 : plan.topK + offset) || 10\n const pipeline: any[] = [\n {\n $vectorSearch: {\n index: INDEX,\n path: 'vec',\n queryVector,\n numCandidates: Math.max(k * 10, 100),\n limit: k,\n },\n },\n {\n $project: {\n id: 1,\n vec: 1,\n document: 1,\n metadata: 1,\n score: { $meta: 'vectorSearchScore' },\n },\n },\n ]\n const docs = await col.aggregate(pipeline).toArray()\n const filtered = plan.filter\n ? docs.filter((d: any) => evaluateFilter(plan.filter!, this.#parseMeta(d.metadata)))\n : docs\n return filtered\n .slice(offset, offset + plan.topK)\n .map((d: any) => this.#project(d, plan, true))\n } else {\n // Filter-scan: plain find() (strongly consistent, no $vectorSearch index lag).\n const docs = await col.find({}).toArray()\n const filtered = plan.filter\n ? docs.filter((d: any) => evaluateFilter(plan.filter!, this.#parseMeta(d.metadata)))\n : docs\n return filtered\n .slice(offset, offset + plan.topK)\n .map((d: any) => this.#project(d, plan, false))\n }\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #parseMeta(val: unknown): VectorMetadata {\n if (typeof val === 'string') {\n try {\n return JSON.parse(val) as VectorMetadata\n } catch {\n return {}\n }\n }\n if (val && typeof val === 'object') return val as VectorMetadata\n return {}\n }\n\n #project(doc: any, plan: SearchPlan, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const out: VectorMatch = {}\n if (proj.id) out.id = doc.id as string\n if (proj.vector && Array.isArray(doc.vec)) out.vector = (doc.vec as number[]).map(Number)\n if (proj.document) out.document = (doc.document ?? undefined) as string | undefined\n if (proj.metadata) out.metadata = this.#parseMeta(doc.metadata)\n if (isKnn && typeof doc.score === 'number') {\n // Atlas vectorSearchScore for cosine is already in [0,1], higher = closer.\n out.score = doc.score\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const col = await this.#col(plan.collection)\n try {\n if (plan.ids && plan.ids.length > 0) {\n await col.deleteMany({ id: { $in: plan.ids } })\n } else if (plan.filter) {\n // Plain find() to resolve target ids (immediate), then delete by id.\n const docs = await col.find({}).toArray()\n const targets = docs\n .filter((d: any) => evaluateFilter(plan.filter!, this.#parseMeta(d.metadata)))\n .map((d: any) => d.id as string)\n if (targets.length > 0) await col.deleteMany({ id: { $in: targets } })\n } else {\n await col.deleteMany({})\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mongodb.mjs","names":["#opts","#client","#db","#col","#name","#sleep","#dims","#settlePresent","#parseMeta","#project"],"sources":["../../../src/batteries/vector/mongodb/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/mongodb\n *\n * MongoDB Atlas Vector Search adapter. Each collection is a MongoDB collection with an Atlas\n * `vectorSearch` index on `vec`; KNN uses the `$vectorSearch` aggregation stage (cosine\n * `vectorSearchScore`, [0,1]). Metadata is a JSON string field filtered with the neutral filter\n * tree's JS reference evaluator for cross-adapter parity.\n *\n * Consistency note: the *document* collection is strongly consistent, but the Atlas vector\n * *index* updates asynchronously after a write (~1s). So filter-scans, fetch-by-id and the\n * delete read-back use a plain `find()` (immediate), and only KNN goes through `$vectorSearch` —\n * after which the adapter polls until the just-inserted ids are index-visible (strong mode).\n *\n * Driver: `mongodb`. Works against `mongodb/mongodb-atlas-local` or a real Atlas cluster.\n */\n\nimport { evaluateFilter } from '../filters'\nimport { BaseVectorStore } from '../contract'\nimport { validateRecords } from '../validation'\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport {\n E_VECTOR_STORE_DRIVER_UNAVAILABLE,\n E_VECTOR_STORE_CONNECTION_FAILED,\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_OPERATION,\n} from '../exceptions'\nimport type { SearchPlan, UpsertPlan, DeletePlan, CollectionSpec } from '../plan'\nimport type {\n VectorMatch,\n VectorStoreCapabilities,\n BaseVectorStoreOptions,\n VectorMetadata,\n DistanceMetric,\n} from '../types'\n\nconst INDEX = 'vec_idx'\n\nexport interface MongoDBVectorStoreOptions extends BaseVectorStoreOptions {\n /** Connection and authentication parameters for the backend. */\n connection: {\n url: string\n database?: string\n /**\n * When set, the physical MongoDB collection becomes `${collectionPrefix}${collection}`. The\n * logical collection the builder/base see is unchanged. Lets callers (and the test suite)\n * isolate otherwise identically-named collections — useful because the Atlas vectorSearch\n * index builds asynchronously, so a fresh collection per use avoids drop+rebuild churn.\n */\n collectionPrefix?: string\n }\n}\n\nconst getMongo = async () => {\n try {\n const mod = await import('mongodb')\n return mod.MongoClient\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['mongodb'])\n }\n}\n\nconst similarity = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'euclidean' : metric === 'dot' ? 'dotProduct' : 'cosine'\n\nexport class MongoDBVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // The document store is strongly consistent; KNN settles on the async index after writes.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #client: any | null = null\n #db: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): MongoDBVectorStoreOptions {\n return this.options as MongoDBVectorStoreOptions\n }\n\n /** Static availability probe: whether this adapter's runtime driver can load in the current environment. */\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 MongoClient = await getMongo()\n const c = this.#opts.connection\n try {\n this.#client = new MongoClient(c.url)\n await this.#client.connect()\n this.#db = this.#client.db(c.database ?? 'vector')\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 await this.#client.close()\n this.#client = null\n this.#db = null\n }\n }\n\n // Map a logical collection name to its physical MongoDB collection (optional prefix).\n #name(collection: string): string {\n const prefix = this.#opts.connection?.collectionPrefix\n return prefix ? `${prefix}${collection}` : collection\n }\n\n async #col(collection: string): Promise<any> {\n if (!this.#db) await this.connect()\n return this.#db.collection(this.#name(collection))\n }\n\n async #sleep(ms: number): Promise<void> {\n await new Promise((r) => setTimeout(r, ms))\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n if (!this.#db) await this.connect()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n const physical = this.#name(spec.collection)\n try {\n const names = await this.#db.listCollections({ name: physical }).toArray()\n if (names.length > 0) {\n if (ifNotExists) {\n // Clear any residual documents so each store starts empty.\n await this.#db.collection(physical).deleteMany({})\n return\n }\n await this.#db\n .collection(physical)\n .drop()\n .catch(() => undefined)\n }\n await this.#db.createCollection(physical).catch(() => undefined)\n const col = this.#db.collection(physical)\n // Create the Atlas vectorSearch index if absent, then wait until it's queryable.\n const existing = await col\n .listSearchIndexes()\n .toArray()\n .catch(() => [])\n if (!existing.find((i: any) => i.name === INDEX)) {\n await col.createSearchIndex({\n name: INDEX,\n type: 'vectorSearch',\n definition: {\n fields: [\n {\n type: 'vector',\n path: 'vec',\n numDimensions: spec.vector.dimensions,\n similarity: similarity(spec.vector.metric),\n },\n ],\n },\n })\n }\n for (let i = 0; i < 60; i++) {\n const list = await col.listSearchIndexes().toArray()\n const idx = list.find((x: any) => x.name === INDEX)\n if (idx?.queryable) break\n await this.#sleep(1000)\n }\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\n }\n }\n\n async dropCollection(collection: string, ifExists: boolean): Promise<void> {\n if (!this.#db) await this.connect()\n const physical = this.#name(collection)\n try {\n const names = await this.#db.listCollections({ name: physical }).toArray()\n if (names.length === 0) {\n if (ifExists) return\n throw new Error('collection not found: ' + collection)\n }\n // Clear documents (fast/immediate) and drop the collection; the search index goes with it.\n await this.#db\n .collection(physical)\n .drop()\n .catch(() => undefined)\n this.#dims.delete(collection)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['dropCollection', String(err)])\n }\n }\n\n async hasCollection(collection: string): Promise<boolean> {\n if (!this.#db) await this.connect()\n const names = await this.#db.listCollections({ name: this.#name(collection) }).toArray()\n return names.length > 0\n }\n\n async renameCollection(_from: string, _to: string): Promise<void> {\n throw new E_VECTOR_STORE_UNSUPPORTED_OPERATION(['renameCollection', 'mongodb'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const col = await this.#col(plan.collection)\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\n const ids: string[] = []\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 await col.updateOne(\n { id: r.id },\n {\n $set: {\n id: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n },\n },\n { upsert: true }\n )\n ids.push(r.id)\n }\n // Settle: wait until the just-written ids are visible to $vectorSearch (the index is async).\n await this.#settlePresent(col, ids, expected ?? this.#dims.get(plan.collection) ?? 0)\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 }\n throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)])\n }\n }\n\n // Poll $vectorSearch until every id in `ids` appears (bounded). Best-effort: returns on timeout.\n async #settlePresent(col: any, ids: string[], dims: number): Promise<void> {\n if (ids.length === 0 || dims <= 0) return\n const probe = new Array(dims).fill(0)\n probe[0] = 1\n const deadline = Date.now() + 10_000\n while (Date.now() < deadline) {\n let seen: Set<string>\n try {\n const res = await col\n .aggregate([\n {\n $vectorSearch: {\n index: INDEX,\n path: 'vec',\n queryVector: probe,\n numCandidates: Math.max(ids.length * 10, 50),\n limit: Math.max(ids.length * 5, 50),\n },\n },\n { $project: { id: 1 } },\n ])\n .toArray()\n seen = new Set(res.map((d: any) => d.id))\n } catch {\n seen = new Set()\n }\n if (ids.every((id) => seen.has(id))) return\n await this.#sleep(300)\n }\n }\n\n async executeSearch(plan: SearchPlan): Promise<VectorMatch[]> {\n const col = await this.#col(plan.collection)\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 // Plain find() — strongly consistent, no index lag.\n const doc = await col.findOne({ id: plan.near.id })\n if (!doc) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = doc.vec as number[]\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n if (queryVector) {\n const k = (plan.filter ? 1000 : plan.topK + offset) || 10\n const pipeline: any[] = [\n {\n $vectorSearch: {\n index: INDEX,\n path: 'vec',\n queryVector,\n numCandidates: Math.max(k * 10, 100),\n limit: k,\n },\n },\n {\n $project: {\n id: 1,\n vec: 1,\n document: 1,\n metadata: 1,\n score: { $meta: 'vectorSearchScore' },\n },\n },\n ]\n const docs = await col.aggregate(pipeline).toArray()\n const filtered = plan.filter\n ? docs.filter((d: any) => evaluateFilter(plan.filter!, this.#parseMeta(d.metadata)))\n : docs\n return filtered\n .slice(offset, offset + plan.topK)\n .map((d: any) => this.#project(d, plan, true))\n } else {\n // Filter-scan: plain find() (strongly consistent, no $vectorSearch index lag).\n const docs = await col.find({}).toArray()\n const filtered = plan.filter\n ? docs.filter((d: any) => evaluateFilter(plan.filter!, this.#parseMeta(d.metadata)))\n : docs\n return filtered\n .slice(offset, offset + plan.topK)\n .map((d: any) => this.#project(d, plan, false))\n }\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #parseMeta(val: unknown): VectorMetadata {\n if (typeof val === 'string') {\n try {\n return JSON.parse(val) as VectorMetadata\n } catch {\n return {}\n }\n }\n if (val && typeof val === 'object') return val as VectorMetadata\n return {}\n }\n\n #project(doc: any, plan: SearchPlan, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const out: VectorMatch = {}\n if (proj.id) out.id = doc.id as string\n if (proj.vector && Array.isArray(doc.vec)) out.vector = (doc.vec as number[]).map(Number)\n if (proj.document) out.document = (doc.document ?? undefined) as string | undefined\n if (proj.metadata) out.metadata = this.#parseMeta(doc.metadata)\n if (isKnn && typeof doc.score === 'number') {\n // Atlas vectorSearchScore for cosine is already in [0,1], higher = closer.\n out.score = doc.score\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const col = await this.#col(plan.collection)\n try {\n if (plan.ids && plan.ids.length > 0) {\n await col.deleteMany({ id: { $in: plan.ids } })\n } else if (plan.filter) {\n // Plain find() to resolve target ids (immediate), then delete by id.\n const docs = await col.find({}).toArray()\n const targets = docs\n .filter((d: any) => evaluateFilter(plan.filter!, this.#parseMeta(d.metadata)))\n .map((d: any) => d.id as string)\n if (targets.length > 0) await col.deleteMany({ id: { $in: targets } })\n } else {\n await col.deleteMany({})\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuCA,IAAM,QAAQ;AAiBd,IAAM,WAAW,YAAY;CAC3B,IAAI;EAEF,QAAO,MADW,OAAO,YACd;CACb,QAAQ;EACN,MAAM,IAAI,kCAAkC,CAAC,SAAS,CAAC;CACzD;AACF;AAEA,IAAM,cAAc,WAClB,WAAW,cAAc,cAAc,WAAW,QAAQ,eAAe;AAE3E,IAAa,qBAAb,cAAwC,gBAAgB;CACtD,eAAiD;EAC/C,cAAc;EACd,cAAc;EACd,QAAQ;EACR,QAAQ;EACR,iBAAiB;EAEjB,aAAa;GAAE,cAAc;GAAO,SAAS;GAAU,OAAO,CAAC,QAAQ;EAAE;CAC3E;CAEA,UAAsB;CACtB,MAAkB;CAClB,wBAA6B,IAAI,IAAI;CAErC,IAAIA,QAAmC;EACrC,OAAO,KAAK;CACd;;CAGA,OAAO,cAAuB;EAC5B,OAAO,OAAO,YAAY;CAC5B;CACA,cAAuB;EACrB,OAAO,OAAO,YAAY;CAC5B;CAEA,MAAM,UAAyB;EAC7B,IAAI,KAAKC,SAAS;EAClB,MAAM,cAAc,MAAM,SAAS;EACnC,MAAM,IAAI,KAAKD,MAAM;EACrB,IAAI;GACF,KAAKC,UAAU,IAAI,YAAY,EAAE,GAAG;GACpC,MAAM,KAAKA,QAAQ,QAAQ;GAC3B,KAAKC,MAAM,KAAKD,QAAQ,GAAG,EAAE,YAAY,QAAQ;EACnD,SAAS,KAAK;GACZ,MAAM,IAAI,iCAAiC,CAAC,OAAO,GAAG,CAAC,CAAC;EAC1D;CACF;CAEA,MAAM,QAAuB;EAC3B,IAAI,KAAKA,SAAS;GAChB,MAAM,KAAKA,QAAQ,MAAM;GACzB,KAAKA,UAAU;GACf,KAAKC,MAAM;EACb;CACF;CAGA,MAAM,YAA4B;EAChC,MAAM,SAAS,KAAKF,MAAM,YAAY;EACtC,OAAO,SAAS,GAAG,SAAS,eAAe;CAC7C;CAEA,MAAMG,KAAK,YAAkC;EAC3C,IAAI,CAAC,KAAKD,KAAK,MAAM,KAAK,QAAQ;EAClC,OAAO,KAAKA,IAAI,WAAW,KAAKE,MAAM,UAAU,CAAC;CACnD;CAEA,MAAMC,OAAO,IAA2B;EACtC,MAAM,IAAI,SAAS,MAAM,WAAW,GAAG,EAAE,CAAC;CAC5C;CAEA,MAAM,iBAAiB,MAAsB,aAAqC;EAChF,IAAI,CAAC,KAAKH,KAAK,MAAM,KAAK,QAAQ;EAClC,KAAKI,MAAM,IAAI,KAAK,YAAY,KAAK,OAAO,UAAU;EACtD,MAAM,WAAW,KAAKF,MAAM,KAAK,UAAU;EAC3C,IAAI;GAEF,KAAI,MADgB,KAAKF,IAAI,gBAAgB,EAAE,MAAM,SAAS,CAAC,EAAE,QAAQ,GAC/D,SAAS,GAAG;IACpB,IAAI,aAAa;KAEf,MAAM,KAAKA,IAAI,WAAW,QAAQ,EAAE,WAAW,CAAC,CAAC;KACjD;IACF;IACA,MAAM,KAAKA,IACR,WAAW,QAAQ,EACnB,KAAK,EACL,YAAY,KAAA,CAAS;GAC1B;GACA,MAAM,KAAKA,IAAI,iBAAiB,QAAQ,EAAE,YAAY,KAAA,CAAS;GAC/D,MAAM,MAAM,KAAKA,IAAI,WAAW,QAAQ;GAMxC,IAAI,EAAC,MAJkB,IACpB,kBAAkB,EAClB,QAAQ,EACR,YAAY,CAAC,CAAC,GACH,MAAM,MAAW,EAAE,SAAS,KAAK,GAC7C,MAAM,IAAI,kBAAkB;IAC1B,MAAM;IACN,MAAM;IACN,YAAY,EACV,QAAQ,CACN;KACE,MAAM;KACN,MAAM;KACN,eAAe,KAAK,OAAO;KAC3B,YAAY,WAAW,KAAK,OAAO,MAAM;IAC3C,CACF,EACF;GACF,CAAC;GAEH,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;IAG3B,KADY,MADO,IAAI,kBAAkB,EAAE,QAAQ,GAClC,MAAM,MAAW,EAAE,SAAS,KACzC,GAAK,WAAW;IACpB,MAAM,KAAKG,OAAO,GAAI;GACxB;EACF,SAAS,KAAK;GACZ,MAAM,IAAI,iCAAiC,CAAC,oBAAoB,OAAO,GAAG,CAAC,CAAC;EAC9E;CACF;CAEA,MAAM,eAAe,YAAoB,UAAkC;EACzE,IAAI,CAAC,KAAKH,KAAK,MAAM,KAAK,QAAQ;EAClC,MAAM,WAAW,KAAKE,MAAM,UAAU;EACtC,IAAI;GAEF,KAAI,MADgB,KAAKF,IAAI,gBAAgB,EAAE,MAAM,SAAS,CAAC,EAAE,QAAQ,GAC/D,WAAW,GAAG;IACtB,IAAI,UAAU;IACd,MAAM,IAAI,MAAM,2BAA2B,UAAU;GACvD;GAEA,MAAM,KAAKA,IACR,WAAW,QAAQ,EACnB,KAAK,EACL,YAAY,KAAA,CAAS;GACxB,KAAKI,MAAM,OAAO,UAAU;EAC9B,SAAS,KAAK;GACZ,MAAM,IAAI,iCAAiC,CAAC,kBAAkB,OAAO,GAAG,CAAC,CAAC;EAC5E;CACF;CAEA,MAAM,cAAc,YAAsC;EACxD,IAAI,CAAC,KAAKJ,KAAK,MAAM,KAAK,QAAQ;EAElC,QAAO,MADa,KAAKA,IAAI,gBAAgB,EAAE,MAAM,KAAKE,MAAM,UAAU,EAAE,CAAC,EAAE,QAAQ,GAC1E,SAAS;CACxB;CAEA,MAAM,iBAAiB,OAAe,KAA4B;EAChE,MAAM,IAAI,qCAAqC,CAAC,oBAAoB,SAAS,CAAC;CAChF;CAEA,MAAM,cAAc,MAAiC;EACnD,IAAI,KAAK,QAAQ,WAAW,GAAG;EAC/B,gBAAgB,KAAK,OAAO;EAC5B,MAAM,MAAM,MAAM,KAAKD,KAAK,KAAK,UAAU;EAC3C,MAAM,WAAW,KAAKH,MAAM,cAAc,KAAKM,MAAM,IAAI,KAAK,UAAU;EACxE,MAAM,MAAgB,CAAC;EACvB,IAAI;GACF,KAAK,MAAM,KAAK,KAAK,SAAS;IAC5B,IAAI,SAAS,EAAE;IACf,IAAI,CAAC,UAAU,EAAE,UAAU;KACzB,MAAM,CAAC,KAAK,MAAM,KAAK,OAAO,CAAC,EAAE,QAAQ,GAAG,UAAU;KACtD,SAAS;IACX;IACA,IAAI,CAAC,QACH,MAAM,IAAI,6BAA6B,CAAC,oCAAoC,CAAC;IAE/E,IAAI,aAAa,KAAA,KAAa,OAAO,WAAW,UAC9C,MAAM,IAAI,kCAAkC,CAAC,UAAU,OAAO,MAAM,CAAC;IAEvE,MAAM,IAAI,UACR,EAAE,IAAI,EAAE,GAAG,GACX,EACE,MAAM;KACJ,IAAI,EAAE;KACN,KAAK;KACL,UAAU,EAAE,YAAY;KACxB,UAAU,EAAE,WAAW,KAAK,UAAU,EAAE,QAAQ,IAAI;IACtD,EACF,GACA,EAAE,QAAQ,KAAK,CACjB;IACA,IAAI,KAAK,EAAE,EAAE;GACf;GAEA,MAAM,KAAKC,eAAe,KAAK,KAAK,YAAY,KAAKD,MAAM,IAAI,KAAK,UAAU,KAAK,CAAC;EACtF,SAAS,KAAK;GACZ,IACE,aAAa,KAAK,qCAAqC,iCAAiC,KACxF,aAAa,KAAK,gCAAgC,4BAA4B,GAE9E,MAAM;GAER,MAAM,IAAI,6BAA6B,CAAC,OAAO,GAAG,CAAC,CAAC;EACtD;CACF;CAGA,MAAMC,eAAe,KAAU,KAAe,MAA6B;EACzE,IAAI,IAAI,WAAW,KAAK,QAAQ,GAAG;EACnC,MAAM,QAAQ,IAAI,MAAM,IAAI,EAAE,KAAK,CAAC;EACpC,MAAM,KAAK;EACX,MAAM,WAAW,KAAK,IAAI,IAAI;EAC9B,OAAO,KAAK,IAAI,IAAI,UAAU;GAC5B,IAAI;GACJ,IAAI;IACF,MAAM,MAAM,MAAM,IACf,UAAU,CACT,EACE,eAAe;KACb,OAAO;KACP,MAAM;KACN,aAAa;KACb,eAAe,KAAK,IAAI,IAAI,SAAS,IAAI,EAAE;KAC3C,OAAO,KAAK,IAAI,IAAI,SAAS,GAAG,EAAE;IACpC,EACF,GACA,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,CACxB,CAAC,EACA,QAAQ;IACX,OAAO,IAAI,IAAI,IAAI,KAAK,MAAW,EAAE,EAAE,CAAC;GAC1C,QAAQ;IACN,uBAAO,IAAI,IAAI;GACjB;GACA,IAAI,IAAI,OAAO,OAAO,KAAK,IAAI,EAAE,CAAC,GAAG;GACrC,MAAM,KAAKF,OAAO,GAAG;EACvB;CACF;CAEA,MAAM,cAAc,MAA0C;EAC5D,MAAM,MAAM,MAAM,KAAKF,KAAK,KAAK,UAAU;EAC3C,IAAI;EACJ,IAAI,KAAK;OACH,YAAY,KAAK,MACnB,cAAc,KAAK,KAAK;QACnB,IAAI,gBAAgB,KAAK,MAAM;IACpC,MAAM,CAAC,KAAK,MAAM,KAAK,OAAO,CAAC,KAAK,KAAK,UAAU,GAAG,OAAO;IAC7D,cAAc;GAChB,OAAO,IAAI,QAAQ,KAAK,MAAM;IAE5B,MAAM,MAAM,MAAM,IAAI,QAAQ,EAAE,IAAI,KAAK,KAAK,GAAG,CAAC;IAClD,IAAI,CAAC,KACH,MAAM,IAAI,6BAA6B,CAAC,8BAA8B,KAAK,KAAK,EAAE,CAAC;IAErF,cAAc,IAAI;GACpB;;EAGF,MAAM,SAAS,KAAK,UAAU;EAC9B,IAAI;GACF,IAAI,aAAa;IACf,MAAM,KAAK,KAAK,SAAS,MAAO,KAAK,OAAO,WAAW;IACvD,MAAM,WAAkB,CACtB,EACE,eAAe;KACb,OAAO;KACP,MAAM;KACN;KACA,eAAe,KAAK,IAAI,IAAI,IAAI,GAAG;KACnC,OAAO;IACT,EACF,GACA,EACE,UAAU;KACR,IAAI;KACJ,KAAK;KACL,UAAU;KACV,UAAU;KACV,OAAO,EAAE,OAAO,oBAAoB;IACtC,EACF,CACF;IACA,MAAM,OAAO,MAAM,IAAI,UAAU,QAAQ,EAAE,QAAQ;IAInD,QAHiB,KAAK,SAClB,KAAK,QAAQ,MAAW,eAAe,KAAK,QAAS,KAAKK,WAAW,EAAE,QAAQ,CAAC,CAAC,IACjF,MAED,MAAM,QAAQ,SAAS,KAAK,IAAI,EAChC,KAAK,MAAW,KAAKC,SAAS,GAAG,MAAM,IAAI,CAAC;GACjD,OAAO;IAEL,MAAM,OAAO,MAAM,IAAI,KAAK,CAAC,CAAC,EAAE,QAAQ;IAIxC,QAHiB,KAAK,SAClB,KAAK,QAAQ,MAAW,eAAe,KAAK,QAAS,KAAKD,WAAW,EAAE,QAAQ,CAAC,CAAC,IACjF,MAED,MAAM,QAAQ,SAAS,KAAK,IAAI,EAChC,KAAK,MAAW,KAAKC,SAAS,GAAG,MAAM,KAAK,CAAC;GAClD;EACF,SAAS,KAAK;GACZ,MAAM,IAAI,6BAA6B,CAAC,OAAO,GAAG,CAAC,CAAC;EACtD;CACF;CAEA,WAAW,KAA8B;EACvC,IAAI,OAAO,QAAQ,UACjB,IAAI;GACF,OAAO,KAAK,MAAM,GAAG;EACvB,QAAQ;GACN,OAAO,CAAC;EACV;EAEF,IAAI,OAAO,OAAO,QAAQ,UAAU,OAAO;EAC3C,OAAO,CAAC;CACV;CAEA,SAAS,KAAU,MAAkB,OAA6B;EAChE,MAAM,OAAO,KAAK;EAClB,MAAM,MAAmB,CAAC;EAC1B,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI;EAC1B,IAAI,KAAK,UAAU,MAAM,QAAQ,IAAI,GAAG,GAAG,IAAI,SAAU,IAAI,IAAiB,IAAI,MAAM;EACxF,IAAI,KAAK,UAAU,IAAI,WAAY,IAAI,YAAY,KAAA;EACnD,IAAI,KAAK,UAAU,IAAI,WAAW,KAAKD,WAAW,IAAI,QAAQ;EAC9D,IAAI,SAAS,OAAO,IAAI,UAAU,UAEhC,IAAI,QAAQ,IAAI;EAElB,OAAO;CACT;CAEA,MAAM,cAAc,MAAiC;EACnD,MAAM,MAAM,MAAM,KAAKL,KAAK,KAAK,UAAU;EAC3C,IAAI;GACF,IAAI,KAAK,OAAO,KAAK,IAAI,SAAS,GAChC,MAAM,IAAI,WAAW,EAAE,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,CAAC;QACzC,IAAI,KAAK,QAAQ;IAGtB,MAAM,WAAU,MADG,IAAI,KAAK,CAAC,CAAC,EAAE,QAAQ,GAErC,QAAQ,MAAW,eAAe,KAAK,QAAS,KAAKK,WAAW,EAAE,QAAQ,CAAC,CAAC,EAC5E,KAAK,MAAW,EAAE,EAAY;IACjC,IAAI,QAAQ,SAAS,GAAG,MAAM,IAAI,WAAW,EAAE,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;GACvE,OACE,MAAM,IAAI,WAAW,CAAC,CAAC;EAE3B,SAAS,KAAK;GACZ,MAAM,IAAI,6BAA6B,CAAC,OAAO,GAAG,CAAC,CAAC;EACtD;CACF;AACF"}
|
|
@@ -14,6 +14,7 @@ import { BaseVectorStore } from "../contract";
|
|
|
14
14
|
import type { SearchPlan, UpsertPlan, DeletePlan, CollectionSpec } from "../plan";
|
|
15
15
|
import type { VectorMatch, VectorStoreCapabilities, BaseVectorStoreOptions } from "../types";
|
|
16
16
|
export interface Neo4jVectorStoreOptions extends BaseVectorStoreOptions {
|
|
17
|
+
/** Connection and authentication parameters for the backend. */
|
|
17
18
|
connection: {
|
|
18
19
|
url: string;
|
|
19
20
|
username?: string;
|
|
@@ -24,6 +25,7 @@ export interface Neo4jVectorStoreOptions extends BaseVectorStoreOptions {
|
|
|
24
25
|
export declare class Neo4jVectorStore extends BaseVectorStore {
|
|
25
26
|
#private;
|
|
26
27
|
readonly capabilities: VectorStoreCapabilities;
|
|
28
|
+
/** Static availability probe: whether this adapter's runtime driver can load in the current environment. */
|
|
27
29
|
static isAvailable(): boolean;
|
|
28
30
|
isAvailable(): boolean;
|
|
29
31
|
connect(): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../chunk-Ble4zEEl.js");
|
|
3
|
-
const require_tool_registry = require("../../tool_registry-
|
|
3
|
+
const require_tool_registry = require("../../tool_registry-CKJPze3j.js");
|
|
4
4
|
require("../../guards.cjs");
|
|
5
5
|
const require_batteries_vector_filters = require("./filters.cjs");
|
|
6
6
|
const require_batteries_vector_exceptions = require("./exceptions.cjs");
|
|
@@ -50,6 +50,7 @@ var Neo4jVectorStore = class extends require_batteries_vector_contract.BaseVecto
|
|
|
50
50
|
get #opts() {
|
|
51
51
|
return this.options;
|
|
52
52
|
}
|
|
53
|
+
/** Static availability probe: whether this adapter's runtime driver can load in the current environment. */
|
|
53
54
|
static isAvailable() {
|
|
54
55
|
return typeof process !== "undefined";
|
|
55
56
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neo4j.cjs","names":["#opts","#driver","#neo4j","#run","#dims","#parseMeta","#project"],"sources":["../../../src/batteries/vector/neo4j/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/neo4j\n *\n * Neo4j adapter (native vector index, 5.13+). Each collection is a node label; records are\n * nodes with `id`/`vec`/`document`/`metadata` properties and a `VECTOR INDEX` on `vec`. KNN\n * uses `db.index.vector.queryNodes(index, k, vector)` (score is the similarity, already [0,1]\n * for cosine). Metadata is a JSON string property filtered with the neutral filter tree's JS\n * reference evaluator for exact cross-adapter parity.\n *\n * Driver: `neo4j-driver` (pure JS). Labels/index names can't be Cypher-parameterized, so they\n * are derived from the (sanitized) collection name; all values are parameterized.\n */\n\nimport { evaluateFilter } from '../filters'\nimport { BaseVectorStore } from '../contract'\nimport { validateRecords } from '../validation'\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport {\n E_VECTOR_STORE_DRIVER_UNAVAILABLE,\n E_VECTOR_STORE_CONNECTION_FAILED,\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_OPERATION,\n} from '../exceptions'\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 Neo4jVectorStoreOptions extends BaseVectorStoreOptions {\n connection: { url: string; username?: string; password?: string; database?: string }\n}\n\nconst getNeo4j = async () => {\n try {\n const mod = await import('neo4j-driver')\n return (mod as any).default ?? mod\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['neo4j-driver'])\n }\n}\n\n// A Cypher-safe label/index token derived from the collection (labels can't be parameterized).\nconst sanitize = (name: string): string => name.replace(/[^A-Za-z0-9_]/g, '_')\nconst labelFor = (collection: string): string => 'Vec_' + sanitize(collection)\nconst indexFor = (collection: string): string => 'vecidx_' + sanitize(collection)\n\nconst similarityFn = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'euclidean' : 'cosine'\n\nexport class Neo4jVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Writes commit synchronously over Bolt and the index awaits; visible on resolve. No-op option.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #driver: any | null = null\n #neo4j: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): Neo4jVectorStoreOptions {\n return this.options as Neo4jVectorStoreOptions\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.#driver) return\n const neo4j = await getNeo4j()\n this.#neo4j = neo4j\n const c = this.#opts.connection\n try {\n this.#driver = neo4j.driver(\n c.url,\n c.username ? neo4j.auth.basic(c.username, c.password ?? '') : undefined\n )\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n if (this.#driver) {\n await this.#driver.close()\n this.#driver = null\n }\n }\n\n async #run(cypher: string, params?: Record<string, unknown>): Promise<any[]> {\n if (!this.#driver) await this.connect()\n const db = this.#opts.connection.database\n const session = this.#driver.session(db ? { database: db } : undefined)\n try {\n const res = await session.run(cypher, params)\n return res.records\n } finally {\n await session.close()\n }\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n this.#dims.set(spec.collection, spec.vector.dimensions)\n const label = labelFor(spec.collection)\n const index = indexFor(spec.collection)\n try {\n if (!ifNotExists) {\n await this.#run(`DROP INDEX ${index} IF EXISTS`)\n }\n await this.#run(\n `CREATE VECTOR INDEX ${index} IF NOT EXISTS FOR (n:${label}) ON (n.vec) ` +\n `OPTIONS {indexConfig: {\\`vector.dimensions\\`: $dim, \\`vector.similarity_function\\`: $sim}}`,\n { dim: this.#neo4j.int(spec.vector.dimensions), sim: similarityFn(spec.vector.metric) }\n )\n await this.#run(`CALL db.awaitIndex($index, $timeout)`, {\n index,\n timeout: this.#neo4j.int(30),\n }).catch(() => undefined)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\n }\n }\n\n async dropCollection(collection: string, _ifExists: boolean): Promise<void> {\n const label = labelFor(collection)\n const index = indexFor(collection)\n try {\n await this.#run(`DROP INDEX ${index} IF EXISTS`)\n await this.#run(`MATCH (n:${label}) DETACH DELETE n`)\n this.#dims.delete(collection)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['dropCollection', String(err)])\n }\n }\n\n async hasCollection(collection: string): Promise<boolean> {\n const index = indexFor(collection)\n try {\n const recs = await this.#run(`SHOW INDEXES YIELD name WHERE name = $index RETURN name`, {\n index,\n })\n return recs.length > 0\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', 'neo4j'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const label = labelFor(plan.collection)\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\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 await this.#run(\n `MERGE (n:${label} {id: $id}) ` +\n `SET n.vec = $vec, n.document = $document, n.metadata = $metadata`,\n {\n id: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n }\n )\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 }\n throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)])\n }\n }\n\n async executeSearch(plan: SearchPlan): Promise<VectorMatch[]> {\n const label = labelFor(plan.collection)\n const index = indexFor(plan.collection)\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 recs = await this.#run(`MATCH (n:${label} {id: $id}) RETURN n.vec AS vec`, {\n id: plan.near.id,\n })\n if (recs.length === 0) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = recs[0].get('vec') as number[]\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n if (queryVector) {\n // Over-fetch when filtering so the JS post-filter still yields topK.\n const k = plan.filter ? 1000 : plan.topK + offset\n const recs = await this.#run(\n `CALL db.index.vector.queryNodes($index, $k, $qv) YIELD node, score ` +\n `RETURN node.id AS id, node.vec AS vec, node.document AS document, ` +\n `node.metadata AS metadata, score ORDER BY score DESC`,\n { index, k: this.#neo4j.int(k), qv: queryVector }\n )\n const mapped = recs.map((rec: any) => ({\n row: {\n id: rec.get('id'),\n vec: rec.get('vec'),\n document: rec.get('document'),\n metadata: rec.get('metadata'),\n score: rec.get('score'),\n },\n }))\n const filtered = plan.filter\n ? mapped.filter((m: any) => evaluateFilter(plan.filter!, this.#parseMeta(m.row.metadata)))\n : mapped\n return filtered\n .slice(offset, offset + plan.topK)\n .map((m: any) => this.#project(m.row, plan, true))\n } else {\n const recs = await this.#run(\n `MATCH (n:${label}) RETURN n.id AS id, n.vec AS vec, n.document AS document, n.metadata AS metadata`\n )\n const rows = recs.map((rec: any) => ({\n id: rec.get('id'),\n vec: rec.get('vec'),\n document: rec.get('document'),\n metadata: rec.get('metadata'),\n }))\n const filtered = plan.filter\n ? rows.filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n : rows\n return filtered\n .slice(offset, offset + plan.topK)\n .map((row: any) => this.#project(row, plan, false))\n }\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #parseMeta(val: unknown): VectorMetadata {\n if (typeof val === 'string') {\n try {\n return JSON.parse(val) as VectorMetadata\n } catch {\n return {}\n }\n }\n if (val && typeof val === 'object') return val as VectorMetadata\n return {}\n }\n\n #project(row: any, plan: SearchPlan, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const out: VectorMatch = {}\n if (proj.id) out.id = row.id as string\n if (proj.vector && Array.isArray(row.vec)) out.vector = (row.vec as number[]).map(Number)\n if (proj.document) out.document = (row.document ?? undefined) as string | undefined\n if (proj.metadata) out.metadata = this.#parseMeta(row.metadata)\n if (isKnn && row.score !== undefined && row.score !== null) {\n // Neo4j cosine similarity score is already in [0,1], higher = closer.\n out.score = Number(row.score)\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const label = labelFor(plan.collection)\n try {\n if (plan.ids && plan.ids.length > 0) {\n await this.#run(`MATCH (n:${label}) WHERE n.id IN $ids DETACH DELETE n`, { ids: plan.ids })\n } else if (plan.filter) {\n const recs = await this.#run(`MATCH (n:${label}) RETURN n.id AS id, n.metadata AS metadata`)\n const targets = recs\n .filter((rec: any) => evaluateFilter(plan.filter!, this.#parseMeta(rec.get('metadata'))))\n .map((rec: any) => rec.get('id') as string)\n if (targets.length > 0) {\n await this.#run(`MATCH (n:${label}) WHERE n.id IN $ids DETACH DELETE n`, { ids: targets })\n }\n } else {\n await this.#run(`MATCH (n:${label}) DETACH DELETE n`)\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"neo4j.cjs","names":["#opts","#driver","#neo4j","#run","#dims","#parseMeta","#project"],"sources":["../../../src/batteries/vector/neo4j/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/neo4j\n *\n * Neo4j adapter (native vector index, 5.13+). Each collection is a node label; records are\n * nodes with `id`/`vec`/`document`/`metadata` properties and a `VECTOR INDEX` on `vec`. KNN\n * uses `db.index.vector.queryNodes(index, k, vector)` (score is the similarity, already [0,1]\n * for cosine). Metadata is a JSON string property filtered with the neutral filter tree's JS\n * reference evaluator for exact cross-adapter parity.\n *\n * Driver: `neo4j-driver` (pure JS). Labels/index names can't be Cypher-parameterized, so they\n * are derived from the (sanitized) collection name; all values are parameterized.\n */\n\nimport { evaluateFilter } from '../filters'\nimport { BaseVectorStore } from '../contract'\nimport { validateRecords } from '../validation'\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport {\n E_VECTOR_STORE_DRIVER_UNAVAILABLE,\n E_VECTOR_STORE_CONNECTION_FAILED,\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_OPERATION,\n} from '../exceptions'\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 Neo4jVectorStoreOptions extends BaseVectorStoreOptions {\n /** Connection and authentication parameters for the backend. */\n connection: { url: string; username?: string; password?: string; database?: string }\n}\n\nconst getNeo4j = async () => {\n try {\n const mod = await import('neo4j-driver')\n return (mod as any).default ?? mod\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['neo4j-driver'])\n }\n}\n\n// A Cypher-safe label/index token derived from the collection (labels can't be parameterized).\nconst sanitize = (name: string): string => name.replace(/[^A-Za-z0-9_]/g, '_')\nconst labelFor = (collection: string): string => 'Vec_' + sanitize(collection)\nconst indexFor = (collection: string): string => 'vecidx_' + sanitize(collection)\n\nconst similarityFn = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'euclidean' : 'cosine'\n\nexport class Neo4jVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Writes commit synchronously over Bolt and the index awaits; visible on resolve. No-op option.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #driver: any | null = null\n #neo4j: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): Neo4jVectorStoreOptions {\n return this.options as Neo4jVectorStoreOptions\n }\n\n /** Static availability probe: whether this adapter's runtime driver can load in the current environment. */\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.#driver) return\n const neo4j = await getNeo4j()\n this.#neo4j = neo4j\n const c = this.#opts.connection\n try {\n this.#driver = neo4j.driver(\n c.url,\n c.username ? neo4j.auth.basic(c.username, c.password ?? '') : undefined\n )\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n if (this.#driver) {\n await this.#driver.close()\n this.#driver = null\n }\n }\n\n async #run(cypher: string, params?: Record<string, unknown>): Promise<any[]> {\n if (!this.#driver) await this.connect()\n const db = this.#opts.connection.database\n const session = this.#driver.session(db ? { database: db } : undefined)\n try {\n const res = await session.run(cypher, params)\n return res.records\n } finally {\n await session.close()\n }\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n this.#dims.set(spec.collection, spec.vector.dimensions)\n const label = labelFor(spec.collection)\n const index = indexFor(spec.collection)\n try {\n if (!ifNotExists) {\n await this.#run(`DROP INDEX ${index} IF EXISTS`)\n }\n await this.#run(\n `CREATE VECTOR INDEX ${index} IF NOT EXISTS FOR (n:${label}) ON (n.vec) ` +\n `OPTIONS {indexConfig: {\\`vector.dimensions\\`: $dim, \\`vector.similarity_function\\`: $sim}}`,\n { dim: this.#neo4j.int(spec.vector.dimensions), sim: similarityFn(spec.vector.metric) }\n )\n await this.#run(`CALL db.awaitIndex($index, $timeout)`, {\n index,\n timeout: this.#neo4j.int(30),\n }).catch(() => undefined)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\n }\n }\n\n async dropCollection(collection: string, _ifExists: boolean): Promise<void> {\n const label = labelFor(collection)\n const index = indexFor(collection)\n try {\n await this.#run(`DROP INDEX ${index} IF EXISTS`)\n await this.#run(`MATCH (n:${label}) DETACH DELETE n`)\n this.#dims.delete(collection)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['dropCollection', String(err)])\n }\n }\n\n async hasCollection(collection: string): Promise<boolean> {\n const index = indexFor(collection)\n try {\n const recs = await this.#run(`SHOW INDEXES YIELD name WHERE name = $index RETURN name`, {\n index,\n })\n return recs.length > 0\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', 'neo4j'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const label = labelFor(plan.collection)\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\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 await this.#run(\n `MERGE (n:${label} {id: $id}) ` +\n `SET n.vec = $vec, n.document = $document, n.metadata = $metadata`,\n {\n id: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n }\n )\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 }\n throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)])\n }\n }\n\n async executeSearch(plan: SearchPlan): Promise<VectorMatch[]> {\n const label = labelFor(plan.collection)\n const index = indexFor(plan.collection)\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 recs = await this.#run(`MATCH (n:${label} {id: $id}) RETURN n.vec AS vec`, {\n id: plan.near.id,\n })\n if (recs.length === 0) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = recs[0].get('vec') as number[]\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n if (queryVector) {\n // Over-fetch when filtering so the JS post-filter still yields topK.\n const k = plan.filter ? 1000 : plan.topK + offset\n const recs = await this.#run(\n `CALL db.index.vector.queryNodes($index, $k, $qv) YIELD node, score ` +\n `RETURN node.id AS id, node.vec AS vec, node.document AS document, ` +\n `node.metadata AS metadata, score ORDER BY score DESC`,\n { index, k: this.#neo4j.int(k), qv: queryVector }\n )\n const mapped = recs.map((rec: any) => ({\n row: {\n id: rec.get('id'),\n vec: rec.get('vec'),\n document: rec.get('document'),\n metadata: rec.get('metadata'),\n score: rec.get('score'),\n },\n }))\n const filtered = plan.filter\n ? mapped.filter((m: any) => evaluateFilter(plan.filter!, this.#parseMeta(m.row.metadata)))\n : mapped\n return filtered\n .slice(offset, offset + plan.topK)\n .map((m: any) => this.#project(m.row, plan, true))\n } else {\n const recs = await this.#run(\n `MATCH (n:${label}) RETURN n.id AS id, n.vec AS vec, n.document AS document, n.metadata AS metadata`\n )\n const rows = recs.map((rec: any) => ({\n id: rec.get('id'),\n vec: rec.get('vec'),\n document: rec.get('document'),\n metadata: rec.get('metadata'),\n }))\n const filtered = plan.filter\n ? rows.filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n : rows\n return filtered\n .slice(offset, offset + plan.topK)\n .map((row: any) => this.#project(row, plan, false))\n }\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #parseMeta(val: unknown): VectorMetadata {\n if (typeof val === 'string') {\n try {\n return JSON.parse(val) as VectorMetadata\n } catch {\n return {}\n }\n }\n if (val && typeof val === 'object') return val as VectorMetadata\n return {}\n }\n\n #project(row: any, plan: SearchPlan, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const out: VectorMatch = {}\n if (proj.id) out.id = row.id as string\n if (proj.vector && Array.isArray(row.vec)) out.vector = (row.vec as number[]).map(Number)\n if (proj.document) out.document = (row.document ?? undefined) as string | undefined\n if (proj.metadata) out.metadata = this.#parseMeta(row.metadata)\n if (isKnn && row.score !== undefined && row.score !== null) {\n // Neo4j cosine similarity score is already in [0,1], higher = closer.\n out.score = Number(row.score)\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const label = labelFor(plan.collection)\n try {\n if (plan.ids && plan.ids.length > 0) {\n await this.#run(`MATCH (n:${label}) WHERE n.id IN $ids DETACH DELETE n`, { ids: plan.ids })\n } else if (plan.filter) {\n const recs = await this.#run(`MATCH (n:${label}) RETURN n.id AS id, n.metadata AS metadata`)\n const targets = recs\n .filter((rec: any) => evaluateFilter(plan.filter!, this.#parseMeta(rec.get('metadata'))))\n .map((rec: any) => rec.get('id') as string)\n if (targets.length > 0) {\n await this.#run(`MATCH (n:${label}) WHERE n.id IN $ids DETACH DELETE n`, { ids: targets })\n }\n } else {\n await this.#run(`MATCH (n:${label}) DETACH DELETE n`)\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as isInstanceOf } from "../../tool_registry-
|
|
1
|
+
import { s as isInstanceOf } from "../../tool_registry-791Vrjtf.mjs";
|
|
2
2
|
import "../../guards.mjs";
|
|
3
3
|
import { evaluateFilter } from "./filters.mjs";
|
|
4
4
|
import { E_VECTOR_STORE_COLLECTION_FAILED, E_VECTOR_STORE_CONNECTION_FAILED, E_VECTOR_STORE_DELETE_FAILED, E_VECTOR_STORE_DIMENSION_MISMATCH, E_VECTOR_STORE_DRIVER_UNAVAILABLE, E_VECTOR_STORE_SEARCH_FAILED, E_VECTOR_STORE_UNSUPPORTED_OPERATION, E_VECTOR_STORE_UPSERT_FAILED } from "./exceptions.mjs";
|
|
@@ -48,6 +48,7 @@ var Neo4jVectorStore = class extends BaseVectorStore {
|
|
|
48
48
|
get #opts() {
|
|
49
49
|
return this.options;
|
|
50
50
|
}
|
|
51
|
+
/** Static availability probe: whether this adapter's runtime driver can load in the current environment. */
|
|
51
52
|
static isAvailable() {
|
|
52
53
|
return typeof process !== "undefined";
|
|
53
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neo4j.mjs","names":["#opts","#driver","#neo4j","#run","#dims","#parseMeta","#project"],"sources":["../../../src/batteries/vector/neo4j/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/neo4j\n *\n * Neo4j adapter (native vector index, 5.13+). Each collection is a node label; records are\n * nodes with `id`/`vec`/`document`/`metadata` properties and a `VECTOR INDEX` on `vec`. KNN\n * uses `db.index.vector.queryNodes(index, k, vector)` (score is the similarity, already [0,1]\n * for cosine). Metadata is a JSON string property filtered with the neutral filter tree's JS\n * reference evaluator for exact cross-adapter parity.\n *\n * Driver: `neo4j-driver` (pure JS). Labels/index names can't be Cypher-parameterized, so they\n * are derived from the (sanitized) collection name; all values are parameterized.\n */\n\nimport { evaluateFilter } from '../filters'\nimport { BaseVectorStore } from '../contract'\nimport { validateRecords } from '../validation'\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport {\n E_VECTOR_STORE_DRIVER_UNAVAILABLE,\n E_VECTOR_STORE_CONNECTION_FAILED,\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_OPERATION,\n} from '../exceptions'\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 Neo4jVectorStoreOptions extends BaseVectorStoreOptions {\n connection: { url: string; username?: string; password?: string; database?: string }\n}\n\nconst getNeo4j = async () => {\n try {\n const mod = await import('neo4j-driver')\n return (mod as any).default ?? mod\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['neo4j-driver'])\n }\n}\n\n// A Cypher-safe label/index token derived from the collection (labels can't be parameterized).\nconst sanitize = (name: string): string => name.replace(/[^A-Za-z0-9_]/g, '_')\nconst labelFor = (collection: string): string => 'Vec_' + sanitize(collection)\nconst indexFor = (collection: string): string => 'vecidx_' + sanitize(collection)\n\nconst similarityFn = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'euclidean' : 'cosine'\n\nexport class Neo4jVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Writes commit synchronously over Bolt and the index awaits; visible on resolve. No-op option.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #driver: any | null = null\n #neo4j: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): Neo4jVectorStoreOptions {\n return this.options as Neo4jVectorStoreOptions\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.#driver) return\n const neo4j = await getNeo4j()\n this.#neo4j = neo4j\n const c = this.#opts.connection\n try {\n this.#driver = neo4j.driver(\n c.url,\n c.username ? neo4j.auth.basic(c.username, c.password ?? '') : undefined\n )\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n if (this.#driver) {\n await this.#driver.close()\n this.#driver = null\n }\n }\n\n async #run(cypher: string, params?: Record<string, unknown>): Promise<any[]> {\n if (!this.#driver) await this.connect()\n const db = this.#opts.connection.database\n const session = this.#driver.session(db ? { database: db } : undefined)\n try {\n const res = await session.run(cypher, params)\n return res.records\n } finally {\n await session.close()\n }\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n this.#dims.set(spec.collection, spec.vector.dimensions)\n const label = labelFor(spec.collection)\n const index = indexFor(spec.collection)\n try {\n if (!ifNotExists) {\n await this.#run(`DROP INDEX ${index} IF EXISTS`)\n }\n await this.#run(\n `CREATE VECTOR INDEX ${index} IF NOT EXISTS FOR (n:${label}) ON (n.vec) ` +\n `OPTIONS {indexConfig: {\\`vector.dimensions\\`: $dim, \\`vector.similarity_function\\`: $sim}}`,\n { dim: this.#neo4j.int(spec.vector.dimensions), sim: similarityFn(spec.vector.metric) }\n )\n await this.#run(`CALL db.awaitIndex($index, $timeout)`, {\n index,\n timeout: this.#neo4j.int(30),\n }).catch(() => undefined)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\n }\n }\n\n async dropCollection(collection: string, _ifExists: boolean): Promise<void> {\n const label = labelFor(collection)\n const index = indexFor(collection)\n try {\n await this.#run(`DROP INDEX ${index} IF EXISTS`)\n await this.#run(`MATCH (n:${label}) DETACH DELETE n`)\n this.#dims.delete(collection)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['dropCollection', String(err)])\n }\n }\n\n async hasCollection(collection: string): Promise<boolean> {\n const index = indexFor(collection)\n try {\n const recs = await this.#run(`SHOW INDEXES YIELD name WHERE name = $index RETURN name`, {\n index,\n })\n return recs.length > 0\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', 'neo4j'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const label = labelFor(plan.collection)\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\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 await this.#run(\n `MERGE (n:${label} {id: $id}) ` +\n `SET n.vec = $vec, n.document = $document, n.metadata = $metadata`,\n {\n id: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n }\n )\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 }\n throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)])\n }\n }\n\n async executeSearch(plan: SearchPlan): Promise<VectorMatch[]> {\n const label = labelFor(plan.collection)\n const index = indexFor(plan.collection)\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 recs = await this.#run(`MATCH (n:${label} {id: $id}) RETURN n.vec AS vec`, {\n id: plan.near.id,\n })\n if (recs.length === 0) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = recs[0].get('vec') as number[]\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n if (queryVector) {\n // Over-fetch when filtering so the JS post-filter still yields topK.\n const k = plan.filter ? 1000 : plan.topK + offset\n const recs = await this.#run(\n `CALL db.index.vector.queryNodes($index, $k, $qv) YIELD node, score ` +\n `RETURN node.id AS id, node.vec AS vec, node.document AS document, ` +\n `node.metadata AS metadata, score ORDER BY score DESC`,\n { index, k: this.#neo4j.int(k), qv: queryVector }\n )\n const mapped = recs.map((rec: any) => ({\n row: {\n id: rec.get('id'),\n vec: rec.get('vec'),\n document: rec.get('document'),\n metadata: rec.get('metadata'),\n score: rec.get('score'),\n },\n }))\n const filtered = plan.filter\n ? mapped.filter((m: any) => evaluateFilter(plan.filter!, this.#parseMeta(m.row.metadata)))\n : mapped\n return filtered\n .slice(offset, offset + plan.topK)\n .map((m: any) => this.#project(m.row, plan, true))\n } else {\n const recs = await this.#run(\n `MATCH (n:${label}) RETURN n.id AS id, n.vec AS vec, n.document AS document, n.metadata AS metadata`\n )\n const rows = recs.map((rec: any) => ({\n id: rec.get('id'),\n vec: rec.get('vec'),\n document: rec.get('document'),\n metadata: rec.get('metadata'),\n }))\n const filtered = plan.filter\n ? rows.filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n : rows\n return filtered\n .slice(offset, offset + plan.topK)\n .map((row: any) => this.#project(row, plan, false))\n }\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #parseMeta(val: unknown): VectorMetadata {\n if (typeof val === 'string') {\n try {\n return JSON.parse(val) as VectorMetadata\n } catch {\n return {}\n }\n }\n if (val && typeof val === 'object') return val as VectorMetadata\n return {}\n }\n\n #project(row: any, plan: SearchPlan, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const out: VectorMatch = {}\n if (proj.id) out.id = row.id as string\n if (proj.vector && Array.isArray(row.vec)) out.vector = (row.vec as number[]).map(Number)\n if (proj.document) out.document = (row.document ?? undefined) as string | undefined\n if (proj.metadata) out.metadata = this.#parseMeta(row.metadata)\n if (isKnn && row.score !== undefined && row.score !== null) {\n // Neo4j cosine similarity score is already in [0,1], higher = closer.\n out.score = Number(row.score)\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const label = labelFor(plan.collection)\n try {\n if (plan.ids && plan.ids.length > 0) {\n await this.#run(`MATCH (n:${label}) WHERE n.id IN $ids DETACH DELETE n`, { ids: plan.ids })\n } else if (plan.filter) {\n const recs = await this.#run(`MATCH (n:${label}) RETURN n.id AS id, n.metadata AS metadata`)\n const targets = recs\n .filter((rec: any) => evaluateFilter(plan.filter!, this.#parseMeta(rec.get('metadata'))))\n .map((rec: any) => rec.get('id') as string)\n if (targets.length > 0) {\n await this.#run(`MATCH (n:${label}) WHERE n.id IN $ids DETACH DELETE n`, { ids: targets })\n }\n } else {\n await this.#run(`MATCH (n:${label}) DETACH DELETE n`)\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"neo4j.mjs","names":["#opts","#driver","#neo4j","#run","#dims","#parseMeta","#project"],"sources":["../../../src/batteries/vector/neo4j/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/neo4j\n *\n * Neo4j adapter (native vector index, 5.13+). Each collection is a node label; records are\n * nodes with `id`/`vec`/`document`/`metadata` properties and a `VECTOR INDEX` on `vec`. KNN\n * uses `db.index.vector.queryNodes(index, k, vector)` (score is the similarity, already [0,1]\n * for cosine). Metadata is a JSON string property filtered with the neutral filter tree's JS\n * reference evaluator for exact cross-adapter parity.\n *\n * Driver: `neo4j-driver` (pure JS). Labels/index names can't be Cypher-parameterized, so they\n * are derived from the (sanitized) collection name; all values are parameterized.\n */\n\nimport { evaluateFilter } from '../filters'\nimport { BaseVectorStore } from '../contract'\nimport { validateRecords } from '../validation'\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport {\n E_VECTOR_STORE_DRIVER_UNAVAILABLE,\n E_VECTOR_STORE_CONNECTION_FAILED,\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_OPERATION,\n} from '../exceptions'\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 Neo4jVectorStoreOptions extends BaseVectorStoreOptions {\n /** Connection and authentication parameters for the backend. */\n connection: { url: string; username?: string; password?: string; database?: string }\n}\n\nconst getNeo4j = async () => {\n try {\n const mod = await import('neo4j-driver')\n return (mod as any).default ?? mod\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['neo4j-driver'])\n }\n}\n\n// A Cypher-safe label/index token derived from the collection (labels can't be parameterized).\nconst sanitize = (name: string): string => name.replace(/[^A-Za-z0-9_]/g, '_')\nconst labelFor = (collection: string): string => 'Vec_' + sanitize(collection)\nconst indexFor = (collection: string): string => 'vecidx_' + sanitize(collection)\n\nconst similarityFn = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'euclidean' : 'cosine'\n\nexport class Neo4jVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Writes commit synchronously over Bolt and the index awaits; visible on resolve. No-op option.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #driver: any | null = null\n #neo4j: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): Neo4jVectorStoreOptions {\n return this.options as Neo4jVectorStoreOptions\n }\n\n /** Static availability probe: whether this adapter's runtime driver can load in the current environment. */\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.#driver) return\n const neo4j = await getNeo4j()\n this.#neo4j = neo4j\n const c = this.#opts.connection\n try {\n this.#driver = neo4j.driver(\n c.url,\n c.username ? neo4j.auth.basic(c.username, c.password ?? '') : undefined\n )\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n if (this.#driver) {\n await this.#driver.close()\n this.#driver = null\n }\n }\n\n async #run(cypher: string, params?: Record<string, unknown>): Promise<any[]> {\n if (!this.#driver) await this.connect()\n const db = this.#opts.connection.database\n const session = this.#driver.session(db ? { database: db } : undefined)\n try {\n const res = await session.run(cypher, params)\n return res.records\n } finally {\n await session.close()\n }\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n this.#dims.set(spec.collection, spec.vector.dimensions)\n const label = labelFor(spec.collection)\n const index = indexFor(spec.collection)\n try {\n if (!ifNotExists) {\n await this.#run(`DROP INDEX ${index} IF EXISTS`)\n }\n await this.#run(\n `CREATE VECTOR INDEX ${index} IF NOT EXISTS FOR (n:${label}) ON (n.vec) ` +\n `OPTIONS {indexConfig: {\\`vector.dimensions\\`: $dim, \\`vector.similarity_function\\`: $sim}}`,\n { dim: this.#neo4j.int(spec.vector.dimensions), sim: similarityFn(spec.vector.metric) }\n )\n await this.#run(`CALL db.awaitIndex($index, $timeout)`, {\n index,\n timeout: this.#neo4j.int(30),\n }).catch(() => undefined)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\n }\n }\n\n async dropCollection(collection: string, _ifExists: boolean): Promise<void> {\n const label = labelFor(collection)\n const index = indexFor(collection)\n try {\n await this.#run(`DROP INDEX ${index} IF EXISTS`)\n await this.#run(`MATCH (n:${label}) DETACH DELETE n`)\n this.#dims.delete(collection)\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['dropCollection', String(err)])\n }\n }\n\n async hasCollection(collection: string): Promise<boolean> {\n const index = indexFor(collection)\n try {\n const recs = await this.#run(`SHOW INDEXES YIELD name WHERE name = $index RETURN name`, {\n index,\n })\n return recs.length > 0\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', 'neo4j'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const label = labelFor(plan.collection)\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\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 await this.#run(\n `MERGE (n:${label} {id: $id}) ` +\n `SET n.vec = $vec, n.document = $document, n.metadata = $metadata`,\n {\n id: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n }\n )\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 }\n throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)])\n }\n }\n\n async executeSearch(plan: SearchPlan): Promise<VectorMatch[]> {\n const label = labelFor(plan.collection)\n const index = indexFor(plan.collection)\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 recs = await this.#run(`MATCH (n:${label} {id: $id}) RETURN n.vec AS vec`, {\n id: plan.near.id,\n })\n if (recs.length === 0) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = recs[0].get('vec') as number[]\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n if (queryVector) {\n // Over-fetch when filtering so the JS post-filter still yields topK.\n const k = plan.filter ? 1000 : plan.topK + offset\n const recs = await this.#run(\n `CALL db.index.vector.queryNodes($index, $k, $qv) YIELD node, score ` +\n `RETURN node.id AS id, node.vec AS vec, node.document AS document, ` +\n `node.metadata AS metadata, score ORDER BY score DESC`,\n { index, k: this.#neo4j.int(k), qv: queryVector }\n )\n const mapped = recs.map((rec: any) => ({\n row: {\n id: rec.get('id'),\n vec: rec.get('vec'),\n document: rec.get('document'),\n metadata: rec.get('metadata'),\n score: rec.get('score'),\n },\n }))\n const filtered = plan.filter\n ? mapped.filter((m: any) => evaluateFilter(plan.filter!, this.#parseMeta(m.row.metadata)))\n : mapped\n return filtered\n .slice(offset, offset + plan.topK)\n .map((m: any) => this.#project(m.row, plan, true))\n } else {\n const recs = await this.#run(\n `MATCH (n:${label}) RETURN n.id AS id, n.vec AS vec, n.document AS document, n.metadata AS metadata`\n )\n const rows = recs.map((rec: any) => ({\n id: rec.get('id'),\n vec: rec.get('vec'),\n document: rec.get('document'),\n metadata: rec.get('metadata'),\n }))\n const filtered = plan.filter\n ? rows.filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n : rows\n return filtered\n .slice(offset, offset + plan.topK)\n .map((row: any) => this.#project(row, plan, false))\n }\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #parseMeta(val: unknown): VectorMetadata {\n if (typeof val === 'string') {\n try {\n return JSON.parse(val) as VectorMetadata\n } catch {\n return {}\n }\n }\n if (val && typeof val === 'object') return val as VectorMetadata\n return {}\n }\n\n #project(row: any, plan: SearchPlan, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const out: VectorMatch = {}\n if (proj.id) out.id = row.id as string\n if (proj.vector && Array.isArray(row.vec)) out.vector = (row.vec as number[]).map(Number)\n if (proj.document) out.document = (row.document ?? undefined) as string | undefined\n if (proj.metadata) out.metadata = this.#parseMeta(row.metadata)\n if (isKnn && row.score !== undefined && row.score !== null) {\n // Neo4j cosine similarity score is already in [0,1], higher = closer.\n out.score = Number(row.score)\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const label = labelFor(plan.collection)\n try {\n if (plan.ids && plan.ids.length > 0) {\n await this.#run(`MATCH (n:${label}) WHERE n.id IN $ids DETACH DELETE n`, { ids: plan.ids })\n } else if (plan.filter) {\n const recs = await this.#run(`MATCH (n:${label}) RETURN n.id AS id, n.metadata AS metadata`)\n const targets = recs\n .filter((rec: any) => evaluateFilter(plan.filter!, this.#parseMeta(rec.get('metadata'))))\n .map((rec: any) => rec.get('id') as string)\n if (targets.length > 0) {\n await this.#run(`MATCH (n:${label}) WHERE n.id IN $ids DETACH DELETE n`, { ids: targets })\n }\n } else {\n await this.#run(`MATCH (n:${label}) DETACH DELETE n`)\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ import type { VectorFilter } from "../filters";
|
|
|
15
15
|
import type { SearchPlan, UpsertPlan, DeletePlan, CollectionSpec } from "../plan";
|
|
16
16
|
import type { VectorMatch, VectorStoreCapabilities, BaseVectorStoreOptions } from "../types";
|
|
17
17
|
export interface OpenSearchVectorStoreOptions extends BaseVectorStoreOptions {
|
|
18
|
+
/** Connection and authentication parameters for the backend. */
|
|
18
19
|
connection?: {
|
|
19
20
|
node?: string;
|
|
20
21
|
auth?: {
|
|
@@ -32,6 +33,7 @@ export declare const translateOpenSearchFilter: (filter?: VectorFilter) => Recor
|
|
|
32
33
|
export declare class OpenSearchVectorStore extends BaseVectorStore {
|
|
33
34
|
#private;
|
|
34
35
|
readonly capabilities: VectorStoreCapabilities;
|
|
36
|
+
/** Static availability probe: whether this adapter's runtime driver can load in the current environment. */
|
|
35
37
|
static isAvailable(): boolean;
|
|
36
38
|
isAvailable(): boolean;
|
|
37
39
|
connect(): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../chunk-Ble4zEEl.js");
|
|
3
|
-
const require_tool_registry = require("../../tool_registry-
|
|
3
|
+
const require_tool_registry = require("../../tool_registry-CKJPze3j.js");
|
|
4
4
|
require("../../guards.cjs");
|
|
5
5
|
const require_batteries_vector_filters = require("./filters.cjs");
|
|
6
6
|
const require_batteries_vector_helpers = require("./helpers.cjs");
|
|
@@ -93,6 +93,7 @@ var OpenSearchVectorStore = class extends require_batteries_vector_contract.Base
|
|
|
93
93
|
get #opts() {
|
|
94
94
|
return this.options;
|
|
95
95
|
}
|
|
96
|
+
/** Static availability probe: whether this adapter's runtime driver can load in the current environment. */
|
|
96
97
|
static isAvailable() {
|
|
97
98
|
return typeof process !== "undefined";
|
|
98
99
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opensearch.cjs","names":["#opts","#client","#ensure","#dims","#body","#project"],"sources":["../../../src/batteries/vector/opensearch/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/opensearch\n *\n * One adapter for the Elasticsearch / OpenSearch family — they share the same kNN `_search`\n * data model. Each collection is an index with a `knn_vector` field; KNN search uses the\n * native `knn` query, and the neutral filter tree compiles to a bool-query `filter` over\n * `metadata.*` keyword/numeric sub-fields. The document and id live in `_source`.\n *\n * Driver: `@opensearch-project/opensearch` by default. To target Elasticsearch instead,\n * pass a compatible client instance via `options.connection.client` (the `@elastic/elasticsearch`\n * Client has the same `.indices`/`.index`/`.search`/`.deleteByQuery` surface used here).\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_CONNECTION_FAILED,\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_OPERATION,\n E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR,\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 OpenSearchVectorStoreOptions extends BaseVectorStoreOptions {\n connection?: {\n node?: string\n auth?: { username: string; password: string }\n // A pre-built ES/OpenSearch-compatible client. Overrides `node` when provided.\n client?: unknown\n }\n}\n\nconst getOpenSearchClient = async () => {\n try {\n const mod = await import('@opensearch-project/opensearch')\n return mod.Client\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['@opensearch-project/opensearch'])\n }\n}\n\n// OpenSearch knn_vector space per metric.\nconst spaceType = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'l2' : metric === 'dot' ? 'innerproduct' : 'cosinesimil'\n\n/**\n * Compile the neutral filter tree to an OpenSearch bool-query clause over `metadata.*`.\n * String values use the `.keyword` sub-field for exact match; numbers use range/term.\n */\nexport const translateOpenSearchFilter = (\n filter?: VectorFilter\n): Record<string, unknown> | undefined => {\n if (!filter) return undefined\n if (isRawFilter(filter)) {\n if (filter.$dialect === 'opensearch' || filter.$dialect === 'elasticsearch') {\n return filter.$raw as Record<string, unknown>\n }\n throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['opensearch', String(filter.$dialect)])\n }\n if (isFilterCondition(filter)) {\n const { field, op, value } = filter\n const f = `metadata.${field}`\n const kw = `metadata.${field}.keyword`\n const term = (v: unknown) =>\n typeof v === 'number' || typeof v === 'boolean' ? { term: { [f]: v } } : { term: { [kw]: v } }\n switch (op) {\n case 'eq':\n return term(value)\n case 'ne':\n return { bool: { must_not: [term(value)] } }\n case 'gt':\n return { range: { [f]: { gt: value } } }\n case 'gte':\n return { range: { [f]: { gte: value } } }\n case 'lt':\n return { range: { [f]: { lt: value } } }\n case 'lte':\n return { range: { [f]: { lte: value } } }\n case 'in': {\n const arr = Array.isArray(value) ? value : [value]\n const allNum = arr.every((v) => typeof v === 'number' || typeof v === 'boolean')\n return { terms: { [allNum ? f : kw]: arr } }\n }\n case 'nin': {\n const arr = Array.isArray(value) ? value : [value]\n const allNum = arr.every((v) => typeof v === 'number' || typeof v === 'boolean')\n return { bool: { must_not: [{ terms: { [allNum ? f : kw]: arr } }] } }\n }\n case 'exists':\n return { exists: { field: f } }\n default:\n throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['opensearch', op])\n }\n }\n if (isFilterGroup(filter)) {\n const { and, or, not } = filter\n if (and) {\n const must = and.map(translateOpenSearchFilter).filter(Boolean)\n return { bool: { must } }\n }\n if (or) {\n const should = or.map(translateOpenSearchFilter).filter(Boolean)\n return { bool: { should, minimum_should_match: 1 } }\n }\n if (not) {\n const inner = translateOpenSearchFilter(not)\n return inner ? { bool: { must_not: [inner] } } : undefined\n }\n }\n return undefined\n}\n\nexport class OpenSearchVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Made strongly consistent by refreshing the index after every write (refresh: true /\n // explicit _refresh), so a write is visible to the next search. The option is a no-op.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #client: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): OpenSearchVectorStoreOptions {\n return this.options as OpenSearchVectorStoreOptions\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 c = this.#opts.connection || {}\n if (c.client) {\n this.#client = c.client\n return\n }\n const Client = await getOpenSearchClient()\n try {\n this.#client = new Client({ node: c.node ?? 'http://localhost:9200', auth: c.auth })\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n if (\n this.#client &&\n typeof this.#client.close === 'function' &&\n !this.#opts.connection?.client\n ) {\n await this.#client.close()\n }\n this.#client = null\n }\n\n async #ensure(): Promise<any> {\n if (!this.#client) await this.connect()\n return this.#client!\n }\n\n // Unwrap the {body}/direct response shape across client versions.\n #body(res: any): any {\n return res && res.body !== undefined ? res.body : res\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const client = await this.#ensure()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n if (ifNotExists && (await this.hasCollection(spec.collection))) return\n try {\n await client.indices.create({\n index: spec.collection,\n body: {\n settings: { index: { knn: true } },\n mappings: {\n properties: {\n vec: {\n type: 'knn_vector',\n dimension: spec.vector.dimensions,\n method: {\n name: 'hnsw',\n space_type: spaceType(spec.vector.metric),\n engine: 'lucene',\n },\n },\n document: { type: 'text' },\n metadata: { type: 'object', enabled: true },\n },\n },\n },\n })\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\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 await client.indices.delete({ index: collection })\n this.#dims.delete(collection)\n } catch (err) {\n const msg = String(err)\n if (ifExists && msg.includes('index_not_found')) 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 const res = await client.indices.exists({ index: collection })\n const body = this.#body(res)\n return body === true || body === 200 || res?.statusCode === 200\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', 'opensearch'])\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 ?? this.#dims.get(plan.collection)\n try {\n const operations: any[] = []\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 operations.push({ index: { _index: plan.collection, _id: r.id } })\n operations.push({ vec: vector, document: r.document ?? '', metadata: r.metadata ?? {} })\n }\n await client.bulk({ body: operations, refresh: true })\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 }\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 try {\n const res = await client.get({ index: plan.collection, id: plan.near.id })\n queryVector = this.#body(res)?._source?.vec as number[]\n } catch {\n queryVector = undefined\n }\n if (!queryVector) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n }\n }\n\n const filter = translateOpenSearchFilter(plan.filter)\n const size = plan.topK\n const from = plan.offset ?? 0\n try {\n let body: any\n if (queryVector) {\n const knn: any = { vec: { vector: queryVector, k: size + from } }\n if (filter) knn.vec.filter = filter\n body = { size, from, query: { knn } }\n } else {\n body = { size, from, query: filter ?? { match_all: {} } }\n }\n const res = await client.search({ index: plan.collection, body })\n const hits = this.#body(res)?.hits?.hits ?? []\n return hits.map((hit: any) => this.#project(hit, plan, metric, !!queryVector))\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #project(hit: any, plan: SearchPlan, metric: string, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const src = hit._source ?? {}\n const out: VectorMatch = {}\n if (proj.id) out.id = hit._id as string\n if (proj.vector && src.vec) out.vector = src.vec as number[]\n if (proj.document) out.document = src.document as string | undefined\n if (proj.metadata) out.metadata = (src.metadata ?? {}) as VectorMetadata\n if (isKnn && typeof hit._score === 'number') {\n // OpenSearch returns a similarity score (higher = closer); normalize defensively to [0,1].\n out.score = normalizeScore(hit._score, metric as DistanceMetric, 'similarity')\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 const operations = plan.ids.map((id) => ({ delete: { _index: plan.collection, _id: id } }))\n await client.bulk({ body: operations, refresh: true })\n } else if (plan.filter) {\n const filter = translateOpenSearchFilter(plan.filter)\n await client.deleteByQuery({\n index: plan.collection,\n refresh: true,\n body: { query: filter ?? { match_all: {} } },\n })\n } else {\n await client.deleteByQuery({\n index: plan.collection,\n refresh: true,\n body: { query: { match_all: {} } },\n })\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"opensearch.cjs","names":["#opts","#client","#ensure","#dims","#body","#project"],"sources":["../../../src/batteries/vector/opensearch/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/opensearch\n *\n * One adapter for the Elasticsearch / OpenSearch family — they share the same kNN `_search`\n * data model. Each collection is an index with a `knn_vector` field; KNN search uses the\n * native `knn` query, and the neutral filter tree compiles to a bool-query `filter` over\n * `metadata.*` keyword/numeric sub-fields. The document and id live in `_source`.\n *\n * Driver: `@opensearch-project/opensearch` by default. To target Elasticsearch instead,\n * pass a compatible client instance via `options.connection.client` (the `@elastic/elasticsearch`\n * Client has the same `.indices`/`.index`/`.search`/`.deleteByQuery` surface used here).\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_CONNECTION_FAILED,\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_OPERATION,\n E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR,\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 OpenSearchVectorStoreOptions extends BaseVectorStoreOptions {\n /** Connection and authentication parameters for the backend. */\n connection?: {\n node?: string\n auth?: { username: string; password: string }\n // A pre-built ES/OpenSearch-compatible client. Overrides `node` when provided.\n client?: unknown\n }\n}\n\nconst getOpenSearchClient = async () => {\n try {\n const mod = await import('@opensearch-project/opensearch')\n return mod.Client\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['@opensearch-project/opensearch'])\n }\n}\n\n// OpenSearch knn_vector space per metric.\nconst spaceType = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'l2' : metric === 'dot' ? 'innerproduct' : 'cosinesimil'\n\n/**\n * Compile the neutral filter tree to an OpenSearch bool-query clause over `metadata.*`.\n * String values use the `.keyword` sub-field for exact match; numbers use range/term.\n */\nexport const translateOpenSearchFilter = (\n filter?: VectorFilter\n): Record<string, unknown> | undefined => {\n if (!filter) return undefined\n if (isRawFilter(filter)) {\n if (filter.$dialect === 'opensearch' || filter.$dialect === 'elasticsearch') {\n return filter.$raw as Record<string, unknown>\n }\n throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['opensearch', String(filter.$dialect)])\n }\n if (isFilterCondition(filter)) {\n const { field, op, value } = filter\n const f = `metadata.${field}`\n const kw = `metadata.${field}.keyword`\n const term = (v: unknown) =>\n typeof v === 'number' || typeof v === 'boolean' ? { term: { [f]: v } } : { term: { [kw]: v } }\n switch (op) {\n case 'eq':\n return term(value)\n case 'ne':\n return { bool: { must_not: [term(value)] } }\n case 'gt':\n return { range: { [f]: { gt: value } } }\n case 'gte':\n return { range: { [f]: { gte: value } } }\n case 'lt':\n return { range: { [f]: { lt: value } } }\n case 'lte':\n return { range: { [f]: { lte: value } } }\n case 'in': {\n const arr = Array.isArray(value) ? value : [value]\n const allNum = arr.every((v) => typeof v === 'number' || typeof v === 'boolean')\n return { terms: { [allNum ? f : kw]: arr } }\n }\n case 'nin': {\n const arr = Array.isArray(value) ? value : [value]\n const allNum = arr.every((v) => typeof v === 'number' || typeof v === 'boolean')\n return { bool: { must_not: [{ terms: { [allNum ? f : kw]: arr } }] } }\n }\n case 'exists':\n return { exists: { field: f } }\n default:\n throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['opensearch', op])\n }\n }\n if (isFilterGroup(filter)) {\n const { and, or, not } = filter\n if (and) {\n const must = and.map(translateOpenSearchFilter).filter(Boolean)\n return { bool: { must } }\n }\n if (or) {\n const should = or.map(translateOpenSearchFilter).filter(Boolean)\n return { bool: { should, minimum_should_match: 1 } }\n }\n if (not) {\n const inner = translateOpenSearchFilter(not)\n return inner ? { bool: { must_not: [inner] } } : undefined\n }\n }\n return undefined\n}\n\nexport class OpenSearchVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Made strongly consistent by refreshing the index after every write (refresh: true /\n // explicit _refresh), so a write is visible to the next search. The option is a no-op.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #client: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): OpenSearchVectorStoreOptions {\n return this.options as OpenSearchVectorStoreOptions\n }\n\n /** Static availability probe: whether this adapter's runtime driver can load in the current environment. */\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 c = this.#opts.connection || {}\n if (c.client) {\n this.#client = c.client\n return\n }\n const Client = await getOpenSearchClient()\n try {\n this.#client = new Client({ node: c.node ?? 'http://localhost:9200', auth: c.auth })\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n if (\n this.#client &&\n typeof this.#client.close === 'function' &&\n !this.#opts.connection?.client\n ) {\n await this.#client.close()\n }\n this.#client = null\n }\n\n async #ensure(): Promise<any> {\n if (!this.#client) await this.connect()\n return this.#client!\n }\n\n // Unwrap the {body}/direct response shape across client versions.\n #body(res: any): any {\n return res && res.body !== undefined ? res.body : res\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const client = await this.#ensure()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n if (ifNotExists && (await this.hasCollection(spec.collection))) return\n try {\n await client.indices.create({\n index: spec.collection,\n body: {\n settings: { index: { knn: true } },\n mappings: {\n properties: {\n vec: {\n type: 'knn_vector',\n dimension: spec.vector.dimensions,\n method: {\n name: 'hnsw',\n space_type: spaceType(spec.vector.metric),\n engine: 'lucene',\n },\n },\n document: { type: 'text' },\n metadata: { type: 'object', enabled: true },\n },\n },\n },\n })\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\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 await client.indices.delete({ index: collection })\n this.#dims.delete(collection)\n } catch (err) {\n const msg = String(err)\n if (ifExists && msg.includes('index_not_found')) 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 const res = await client.indices.exists({ index: collection })\n const body = this.#body(res)\n return body === true || body === 200 || res?.statusCode === 200\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', 'opensearch'])\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 ?? this.#dims.get(plan.collection)\n try {\n const operations: any[] = []\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 operations.push({ index: { _index: plan.collection, _id: r.id } })\n operations.push({ vec: vector, document: r.document ?? '', metadata: r.metadata ?? {} })\n }\n await client.bulk({ body: operations, refresh: true })\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 }\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 try {\n const res = await client.get({ index: plan.collection, id: plan.near.id })\n queryVector = this.#body(res)?._source?.vec as number[]\n } catch {\n queryVector = undefined\n }\n if (!queryVector) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n }\n }\n\n const filter = translateOpenSearchFilter(plan.filter)\n const size = plan.topK\n const from = plan.offset ?? 0\n try {\n let body: any\n if (queryVector) {\n const knn: any = { vec: { vector: queryVector, k: size + from } }\n if (filter) knn.vec.filter = filter\n body = { size, from, query: { knn } }\n } else {\n body = { size, from, query: filter ?? { match_all: {} } }\n }\n const res = await client.search({ index: plan.collection, body })\n const hits = this.#body(res)?.hits?.hits ?? []\n return hits.map((hit: any) => this.#project(hit, plan, metric, !!queryVector))\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #project(hit: any, plan: SearchPlan, metric: string, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const src = hit._source ?? {}\n const out: VectorMatch = {}\n if (proj.id) out.id = hit._id as string\n if (proj.vector && src.vec) out.vector = src.vec as number[]\n if (proj.document) out.document = src.document as string | undefined\n if (proj.metadata) out.metadata = (src.metadata ?? {}) as VectorMetadata\n if (isKnn && typeof hit._score === 'number') {\n // OpenSearch returns a similarity score (higher = closer); normalize defensively to [0,1].\n out.score = normalizeScore(hit._score, metric as DistanceMetric, 'similarity')\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 const operations = plan.ids.map((id) => ({ delete: { _index: plan.collection, _id: id } }))\n await client.bulk({ body: operations, refresh: true })\n } else if (plan.filter) {\n const filter = translateOpenSearchFilter(plan.filter)\n await client.deleteByQuery({\n index: plan.collection,\n refresh: true,\n body: { query: filter ?? { match_all: {} } },\n })\n } else {\n await client.deleteByQuery({\n index: plan.collection,\n refresh: true,\n body: { query: { match_all: {} } },\n })\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as isInstanceOf } from "../../tool_registry-
|
|
1
|
+
import { s as isInstanceOf } from "../../tool_registry-791Vrjtf.mjs";
|
|
2
2
|
import "../../guards.mjs";
|
|
3
3
|
import { isFilterCondition, isFilterGroup, isRawFilter } from "./filters.mjs";
|
|
4
4
|
import { normalizeScore } from "./helpers.mjs";
|
|
@@ -91,6 +91,7 @@ var OpenSearchVectorStore = class extends BaseVectorStore {
|
|
|
91
91
|
get #opts() {
|
|
92
92
|
return this.options;
|
|
93
93
|
}
|
|
94
|
+
/** Static availability probe: whether this adapter's runtime driver can load in the current environment. */
|
|
94
95
|
static isAvailable() {
|
|
95
96
|
return typeof process !== "undefined";
|
|
96
97
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opensearch.mjs","names":["#opts","#client","#ensure","#dims","#body","#project"],"sources":["../../../src/batteries/vector/opensearch/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/opensearch\n *\n * One adapter for the Elasticsearch / OpenSearch family — they share the same kNN `_search`\n * data model. Each collection is an index with a `knn_vector` field; KNN search uses the\n * native `knn` query, and the neutral filter tree compiles to a bool-query `filter` over\n * `metadata.*` keyword/numeric sub-fields. The document and id live in `_source`.\n *\n * Driver: `@opensearch-project/opensearch` by default. To target Elasticsearch instead,\n * pass a compatible client instance via `options.connection.client` (the `@elastic/elasticsearch`\n * Client has the same `.indices`/`.index`/`.search`/`.deleteByQuery` surface used here).\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_CONNECTION_FAILED,\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_OPERATION,\n E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR,\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 OpenSearchVectorStoreOptions extends BaseVectorStoreOptions {\n connection?: {\n node?: string\n auth?: { username: string; password: string }\n // A pre-built ES/OpenSearch-compatible client. Overrides `node` when provided.\n client?: unknown\n }\n}\n\nconst getOpenSearchClient = async () => {\n try {\n const mod = await import('@opensearch-project/opensearch')\n return mod.Client\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['@opensearch-project/opensearch'])\n }\n}\n\n// OpenSearch knn_vector space per metric.\nconst spaceType = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'l2' : metric === 'dot' ? 'innerproduct' : 'cosinesimil'\n\n/**\n * Compile the neutral filter tree to an OpenSearch bool-query clause over `metadata.*`.\n * String values use the `.keyword` sub-field for exact match; numbers use range/term.\n */\nexport const translateOpenSearchFilter = (\n filter?: VectorFilter\n): Record<string, unknown> | undefined => {\n if (!filter) return undefined\n if (isRawFilter(filter)) {\n if (filter.$dialect === 'opensearch' || filter.$dialect === 'elasticsearch') {\n return filter.$raw as Record<string, unknown>\n }\n throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['opensearch', String(filter.$dialect)])\n }\n if (isFilterCondition(filter)) {\n const { field, op, value } = filter\n const f = `metadata.${field}`\n const kw = `metadata.${field}.keyword`\n const term = (v: unknown) =>\n typeof v === 'number' || typeof v === 'boolean' ? { term: { [f]: v } } : { term: { [kw]: v } }\n switch (op) {\n case 'eq':\n return term(value)\n case 'ne':\n return { bool: { must_not: [term(value)] } }\n case 'gt':\n return { range: { [f]: { gt: value } } }\n case 'gte':\n return { range: { [f]: { gte: value } } }\n case 'lt':\n return { range: { [f]: { lt: value } } }\n case 'lte':\n return { range: { [f]: { lte: value } } }\n case 'in': {\n const arr = Array.isArray(value) ? value : [value]\n const allNum = arr.every((v) => typeof v === 'number' || typeof v === 'boolean')\n return { terms: { [allNum ? f : kw]: arr } }\n }\n case 'nin': {\n const arr = Array.isArray(value) ? value : [value]\n const allNum = arr.every((v) => typeof v === 'number' || typeof v === 'boolean')\n return { bool: { must_not: [{ terms: { [allNum ? f : kw]: arr } }] } }\n }\n case 'exists':\n return { exists: { field: f } }\n default:\n throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['opensearch', op])\n }\n }\n if (isFilterGroup(filter)) {\n const { and, or, not } = filter\n if (and) {\n const must = and.map(translateOpenSearchFilter).filter(Boolean)\n return { bool: { must } }\n }\n if (or) {\n const should = or.map(translateOpenSearchFilter).filter(Boolean)\n return { bool: { should, minimum_should_match: 1 } }\n }\n if (not) {\n const inner = translateOpenSearchFilter(not)\n return inner ? { bool: { must_not: [inner] } } : undefined\n }\n }\n return undefined\n}\n\nexport class OpenSearchVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Made strongly consistent by refreshing the index after every write (refresh: true /\n // explicit _refresh), so a write is visible to the next search. The option is a no-op.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #client: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): OpenSearchVectorStoreOptions {\n return this.options as OpenSearchVectorStoreOptions\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 c = this.#opts.connection || {}\n if (c.client) {\n this.#client = c.client\n return\n }\n const Client = await getOpenSearchClient()\n try {\n this.#client = new Client({ node: c.node ?? 'http://localhost:9200', auth: c.auth })\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n if (\n this.#client &&\n typeof this.#client.close === 'function' &&\n !this.#opts.connection?.client\n ) {\n await this.#client.close()\n }\n this.#client = null\n }\n\n async #ensure(): Promise<any> {\n if (!this.#client) await this.connect()\n return this.#client!\n }\n\n // Unwrap the {body}/direct response shape across client versions.\n #body(res: any): any {\n return res && res.body !== undefined ? res.body : res\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const client = await this.#ensure()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n if (ifNotExists && (await this.hasCollection(spec.collection))) return\n try {\n await client.indices.create({\n index: spec.collection,\n body: {\n settings: { index: { knn: true } },\n mappings: {\n properties: {\n vec: {\n type: 'knn_vector',\n dimension: spec.vector.dimensions,\n method: {\n name: 'hnsw',\n space_type: spaceType(spec.vector.metric),\n engine: 'lucene',\n },\n },\n document: { type: 'text' },\n metadata: { type: 'object', enabled: true },\n },\n },\n },\n })\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\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 await client.indices.delete({ index: collection })\n this.#dims.delete(collection)\n } catch (err) {\n const msg = String(err)\n if (ifExists && msg.includes('index_not_found')) 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 const res = await client.indices.exists({ index: collection })\n const body = this.#body(res)\n return body === true || body === 200 || res?.statusCode === 200\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', 'opensearch'])\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 ?? this.#dims.get(plan.collection)\n try {\n const operations: any[] = []\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 operations.push({ index: { _index: plan.collection, _id: r.id } })\n operations.push({ vec: vector, document: r.document ?? '', metadata: r.metadata ?? {} })\n }\n await client.bulk({ body: operations, refresh: true })\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 }\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 try {\n const res = await client.get({ index: plan.collection, id: plan.near.id })\n queryVector = this.#body(res)?._source?.vec as number[]\n } catch {\n queryVector = undefined\n }\n if (!queryVector) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n }\n }\n\n const filter = translateOpenSearchFilter(plan.filter)\n const size = plan.topK\n const from = plan.offset ?? 0\n try {\n let body: any\n if (queryVector) {\n const knn: any = { vec: { vector: queryVector, k: size + from } }\n if (filter) knn.vec.filter = filter\n body = { size, from, query: { knn } }\n } else {\n body = { size, from, query: filter ?? { match_all: {} } }\n }\n const res = await client.search({ index: plan.collection, body })\n const hits = this.#body(res)?.hits?.hits ?? []\n return hits.map((hit: any) => this.#project(hit, plan, metric, !!queryVector))\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #project(hit: any, plan: SearchPlan, metric: string, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const src = hit._source ?? {}\n const out: VectorMatch = {}\n if (proj.id) out.id = hit._id as string\n if (proj.vector && src.vec) out.vector = src.vec as number[]\n if (proj.document) out.document = src.document as string | undefined\n if (proj.metadata) out.metadata = (src.metadata ?? {}) as VectorMetadata\n if (isKnn && typeof hit._score === 'number') {\n // OpenSearch returns a similarity score (higher = closer); normalize defensively to [0,1].\n out.score = normalizeScore(hit._score, metric as DistanceMetric, 'similarity')\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 const operations = plan.ids.map((id) => ({ delete: { _index: plan.collection, _id: id } }))\n await client.bulk({ body: operations, refresh: true })\n } else if (plan.filter) {\n const filter = translateOpenSearchFilter(plan.filter)\n await client.deleteByQuery({\n index: plan.collection,\n refresh: true,\n body: { query: filter ?? { match_all: {} } },\n })\n } else {\n await client.deleteByQuery({\n index: plan.collection,\n refresh: true,\n body: { query: { match_all: {} } },\n })\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"opensearch.mjs","names":["#opts","#client","#ensure","#dims","#body","#project"],"sources":["../../../src/batteries/vector/opensearch/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/opensearch\n *\n * One adapter for the Elasticsearch / OpenSearch family — they share the same kNN `_search`\n * data model. Each collection is an index with a `knn_vector` field; KNN search uses the\n * native `knn` query, and the neutral filter tree compiles to a bool-query `filter` over\n * `metadata.*` keyword/numeric sub-fields. The document and id live in `_source`.\n *\n * Driver: `@opensearch-project/opensearch` by default. To target Elasticsearch instead,\n * pass a compatible client instance via `options.connection.client` (the `@elastic/elasticsearch`\n * Client has the same `.indices`/`.index`/`.search`/`.deleteByQuery` surface used here).\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_CONNECTION_FAILED,\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_OPERATION,\n E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR,\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 OpenSearchVectorStoreOptions extends BaseVectorStoreOptions {\n /** Connection and authentication parameters for the backend. */\n connection?: {\n node?: string\n auth?: { username: string; password: string }\n // A pre-built ES/OpenSearch-compatible client. Overrides `node` when provided.\n client?: unknown\n }\n}\n\nconst getOpenSearchClient = async () => {\n try {\n const mod = await import('@opensearch-project/opensearch')\n return mod.Client\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['@opensearch-project/opensearch'])\n }\n}\n\n// OpenSearch knn_vector space per metric.\nconst spaceType = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'l2' : metric === 'dot' ? 'innerproduct' : 'cosinesimil'\n\n/**\n * Compile the neutral filter tree to an OpenSearch bool-query clause over `metadata.*`.\n * String values use the `.keyword` sub-field for exact match; numbers use range/term.\n */\nexport const translateOpenSearchFilter = (\n filter?: VectorFilter\n): Record<string, unknown> | undefined => {\n if (!filter) return undefined\n if (isRawFilter(filter)) {\n if (filter.$dialect === 'opensearch' || filter.$dialect === 'elasticsearch') {\n return filter.$raw as Record<string, unknown>\n }\n throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['opensearch', String(filter.$dialect)])\n }\n if (isFilterCondition(filter)) {\n const { field, op, value } = filter\n const f = `metadata.${field}`\n const kw = `metadata.${field}.keyword`\n const term = (v: unknown) =>\n typeof v === 'number' || typeof v === 'boolean' ? { term: { [f]: v } } : { term: { [kw]: v } }\n switch (op) {\n case 'eq':\n return term(value)\n case 'ne':\n return { bool: { must_not: [term(value)] } }\n case 'gt':\n return { range: { [f]: { gt: value } } }\n case 'gte':\n return { range: { [f]: { gte: value } } }\n case 'lt':\n return { range: { [f]: { lt: value } } }\n case 'lte':\n return { range: { [f]: { lte: value } } }\n case 'in': {\n const arr = Array.isArray(value) ? value : [value]\n const allNum = arr.every((v) => typeof v === 'number' || typeof v === 'boolean')\n return { terms: { [allNum ? f : kw]: arr } }\n }\n case 'nin': {\n const arr = Array.isArray(value) ? value : [value]\n const allNum = arr.every((v) => typeof v === 'number' || typeof v === 'boolean')\n return { bool: { must_not: [{ terms: { [allNum ? f : kw]: arr } }] } }\n }\n case 'exists':\n return { exists: { field: f } }\n default:\n throw new E_VECTOR_STORE_UNSUPPORTED_FILTER_OPERATOR(['opensearch', op])\n }\n }\n if (isFilterGroup(filter)) {\n const { and, or, not } = filter\n if (and) {\n const must = and.map(translateOpenSearchFilter).filter(Boolean)\n return { bool: { must } }\n }\n if (or) {\n const should = or.map(translateOpenSearchFilter).filter(Boolean)\n return { bool: { should, minimum_should_match: 1 } }\n }\n if (not) {\n const inner = translateOpenSearchFilter(not)\n return inner ? { bool: { must_not: [inner] } } : undefined\n }\n }\n return undefined\n}\n\nexport class OpenSearchVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Made strongly consistent by refreshing the index after every write (refresh: true /\n // explicit _refresh), so a write is visible to the next search. The option is a no-op.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #client: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): OpenSearchVectorStoreOptions {\n return this.options as OpenSearchVectorStoreOptions\n }\n\n /** Static availability probe: whether this adapter's runtime driver can load in the current environment. */\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 c = this.#opts.connection || {}\n if (c.client) {\n this.#client = c.client\n return\n }\n const Client = await getOpenSearchClient()\n try {\n this.#client = new Client({ node: c.node ?? 'http://localhost:9200', auth: c.auth })\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n if (\n this.#client &&\n typeof this.#client.close === 'function' &&\n !this.#opts.connection?.client\n ) {\n await this.#client.close()\n }\n this.#client = null\n }\n\n async #ensure(): Promise<any> {\n if (!this.#client) await this.connect()\n return this.#client!\n }\n\n // Unwrap the {body}/direct response shape across client versions.\n #body(res: any): any {\n return res && res.body !== undefined ? res.body : res\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const client = await this.#ensure()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n if (ifNotExists && (await this.hasCollection(spec.collection))) return\n try {\n await client.indices.create({\n index: spec.collection,\n body: {\n settings: { index: { knn: true } },\n mappings: {\n properties: {\n vec: {\n type: 'knn_vector',\n dimension: spec.vector.dimensions,\n method: {\n name: 'hnsw',\n space_type: spaceType(spec.vector.metric),\n engine: 'lucene',\n },\n },\n document: { type: 'text' },\n metadata: { type: 'object', enabled: true },\n },\n },\n },\n })\n } catch (err) {\n throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\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 await client.indices.delete({ index: collection })\n this.#dims.delete(collection)\n } catch (err) {\n const msg = String(err)\n if (ifExists && msg.includes('index_not_found')) 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 const res = await client.indices.exists({ index: collection })\n const body = this.#body(res)\n return body === true || body === 200 || res?.statusCode === 200\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', 'opensearch'])\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 ?? this.#dims.get(plan.collection)\n try {\n const operations: any[] = []\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 operations.push({ index: { _index: plan.collection, _id: r.id } })\n operations.push({ vec: vector, document: r.document ?? '', metadata: r.metadata ?? {} })\n }\n await client.bulk({ body: operations, refresh: true })\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 }\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 try {\n const res = await client.get({ index: plan.collection, id: plan.near.id })\n queryVector = this.#body(res)?._source?.vec as number[]\n } catch {\n queryVector = undefined\n }\n if (!queryVector) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n }\n }\n\n const filter = translateOpenSearchFilter(plan.filter)\n const size = plan.topK\n const from = plan.offset ?? 0\n try {\n let body: any\n if (queryVector) {\n const knn: any = { vec: { vector: queryVector, k: size + from } }\n if (filter) knn.vec.filter = filter\n body = { size, from, query: { knn } }\n } else {\n body = { size, from, query: filter ?? { match_all: {} } }\n }\n const res = await client.search({ index: plan.collection, body })\n const hits = this.#body(res)?.hits?.hits ?? []\n return hits.map((hit: any) => this.#project(hit, plan, metric, !!queryVector))\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n }\n\n #project(hit: any, plan: SearchPlan, metric: string, isKnn: boolean): VectorMatch {\n const proj = plan.projection\n const src = hit._source ?? {}\n const out: VectorMatch = {}\n if (proj.id) out.id = hit._id as string\n if (proj.vector && src.vec) out.vector = src.vec as number[]\n if (proj.document) out.document = src.document as string | undefined\n if (proj.metadata) out.metadata = (src.metadata ?? {}) as VectorMetadata\n if (isKnn && typeof hit._score === 'number') {\n // OpenSearch returns a similarity score (higher = closer); normalize defensively to [0,1].\n out.score = normalizeScore(hit._score, metric as DistanceMetric, 'similarity')\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 const operations = plan.ids.map((id) => ({ delete: { _index: plan.collection, _id: id } }))\n await client.bulk({ body: operations, refresh: true })\n } else if (plan.filter) {\n const filter = translateOpenSearchFilter(plan.filter)\n await client.deleteByQuery({\n index: plan.collection,\n refresh: true,\n body: { query: filter ?? { match_all: {} } },\n })\n } else {\n await client.deleteByQuery({\n index: plan.collection,\n refresh: true,\n body: { query: { match_all: {} } },\n })\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|