@nhtio/adk 1.20260604.0 → 1.20260607.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +261 -0
- package/adk-mcp.mjs +1 -1
- package/batteries/embeddings/openai/adapter.cjs +1 -1
- package/batteries/embeddings/openai/adapter.mjs +1 -1
- package/batteries/embeddings/webllm/adapter.cjs +1 -1
- package/batteries/embeddings/webllm/adapter.mjs +1 -1
- package/batteries/index.d.ts +1 -0
- package/batteries/llm/openai_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/openai_chat_completions/helpers.cjs +2 -2
- package/batteries/llm/openai_chat_completions/helpers.mjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.cjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/validation.mjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/validation.cjs +2 -2
- package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/validation.mjs +2 -2
- package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -1
- package/batteries/storage/flydrive.cjs +1 -1
- package/batteries/storage/flydrive.mjs +2 -2
- package/batteries/storage/in_memory.cjs +1 -1
- package/batteries/storage/in_memory.mjs +1 -1
- package/batteries/storage/opfs.cjs +1 -1
- package/batteries/storage/opfs.mjs +1 -1
- package/batteries/tools/color.cjs +2 -2
- package/batteries/tools/color.mjs +2 -2
- package/batteries/tools/comparison.cjs +3 -3
- package/batteries/tools/comparison.mjs +3 -3
- package/batteries/tools/data_structure.cjs +3 -3
- package/batteries/tools/data_structure.mjs +3 -3
- package/batteries/tools/datetime_extended.cjs +2 -2
- package/batteries/tools/datetime_extended.mjs +2 -2
- package/batteries/tools/datetime_math.cjs +2 -2
- package/batteries/tools/datetime_math.mjs +2 -2
- package/batteries/tools/encoding.cjs +3 -3
- package/batteries/tools/encoding.mjs +3 -3
- package/batteries/tools/formatting.cjs +3 -3
- package/batteries/tools/formatting.mjs +3 -3
- package/batteries/tools/geo_basics.cjs +2 -2
- package/batteries/tools/geo_basics.mjs +2 -2
- package/batteries/tools/math/index.d.ts +16 -5
- package/batteries/tools/math.cjs +340 -22
- package/batteries/tools/math.cjs.map +1 -1
- package/batteries/tools/math.mjs +338 -21
- package/batteries/tools/math.mjs.map +1 -1
- package/batteries/tools/memory.cjs +5 -5
- package/batteries/tools/memory.mjs +5 -5
- package/batteries/tools/parsing.cjs +4 -4
- package/batteries/tools/parsing.mjs +4 -4
- package/batteries/tools/retrievables.cjs +4 -4
- package/batteries/tools/retrievables.mjs +4 -4
- package/batteries/tools/standing_instructions.cjs +4 -4
- package/batteries/tools/standing_instructions.mjs +4 -4
- package/batteries/tools/statistics.cjs +4 -4
- package/batteries/tools/statistics.mjs +4 -4
- package/batteries/tools/string_processing.cjs +3 -3
- package/batteries/tools/string_processing.mjs +3 -3
- package/batteries/tools/structured_data.cjs +3 -3
- package/batteries/tools/structured_data.mjs +3 -3
- package/batteries/tools/text_analysis.cjs +3 -3
- package/batteries/tools/text_analysis.mjs +3 -3
- package/batteries/tools/text_comparison.cjs +2 -2
- package/batteries/tools/text_comparison.mjs +2 -2
- package/batteries/tools/time.cjs +2 -2
- package/batteries/tools/time.mjs +2 -2
- package/batteries/tools/unit_conversion.cjs +2 -2
- package/batteries/tools/unit_conversion.mjs +2 -2
- package/batteries/vector/arangodb/index.d.ts +38 -0
- package/batteries/vector/arangodb.cjs +257 -0
- package/batteries/vector/arangodb.cjs.map +1 -0
- package/batteries/vector/arangodb.mjs +255 -0
- package/batteries/vector/arangodb.mjs.map +1 -0
- package/batteries/vector/builder.cjs +297 -0
- package/batteries/vector/builder.cjs.map +1 -0
- package/batteries/vector/builder.d.ts +87 -0
- package/batteries/vector/builder.mjs +294 -0
- package/batteries/vector/builder.mjs.map +1 -0
- package/batteries/vector/chroma/index.d.ts +32 -0
- package/batteries/vector/chroma.cjs +305 -0
- package/batteries/vector/chroma.cjs.map +1 -0
- package/batteries/vector/chroma.mjs +302 -0
- package/batteries/vector/chroma.mjs.map +1 -0
- package/batteries/vector/clickhouse/index.d.ts +39 -0
- package/batteries/vector/clickhouse.cjs +246 -0
- package/batteries/vector/clickhouse.cjs.map +1 -0
- package/batteries/vector/clickhouse.mjs +244 -0
- package/batteries/vector/clickhouse.mjs.map +1 -0
- package/batteries/vector/cloudflare/index.d.ts +43 -0
- package/batteries/vector/cloudflare.cjs +397 -0
- package/batteries/vector/cloudflare.cjs.map +1 -0
- package/batteries/vector/cloudflare.mjs +395 -0
- package/batteries/vector/cloudflare.mjs.map +1 -0
- package/batteries/vector/conformance/index.d.ts +15 -0
- package/batteries/vector/conformance.cjs +209 -0
- package/batteries/vector/conformance.cjs.map +1 -0
- package/batteries/vector/conformance.mjs +205 -0
- package/batteries/vector/conformance.mjs.map +1 -0
- package/batteries/vector/contract.cjs +42 -0
- package/batteries/vector/contract.cjs.map +1 -0
- package/batteries/vector/contract.d.ts +39 -0
- package/batteries/vector/contract.mjs +40 -0
- package/batteries/vector/contract.mjs.map +1 -0
- package/batteries/vector/couchbase/index.d.ts +49 -0
- package/batteries/vector/couchbase.cjs +401 -0
- package/batteries/vector/couchbase.cjs.map +1 -0
- package/batteries/vector/couchbase.mjs +399 -0
- package/batteries/vector/couchbase.mjs.map +1 -0
- package/batteries/vector/duckdb/index.d.ts +33 -0
- package/batteries/vector/duckdb.cjs +218 -0
- package/batteries/vector/duckdb.cjs.map +1 -0
- package/batteries/vector/duckdb.mjs +216 -0
- package/batteries/vector/duckdb.mjs.map +1 -0
- package/batteries/vector/elasticsearch/index.d.ts +43 -0
- package/batteries/vector/elasticsearch.cjs +306 -0
- package/batteries/vector/elasticsearch.cjs.map +1 -0
- package/batteries/vector/elasticsearch.mjs +303 -0
- package/batteries/vector/elasticsearch.mjs.map +1 -0
- package/batteries/vector/exceptions.cjs +126 -0
- package/batteries/vector/exceptions.cjs.map +1 -0
- package/batteries/vector/exceptions.d.ts +142 -0
- package/batteries/vector/exceptions.mjs +107 -0
- package/batteries/vector/exceptions.mjs.map +1 -0
- package/batteries/vector/factory.cjs +28 -0
- package/batteries/vector/factory.cjs.map +1 -0
- package/batteries/vector/factory.d.ts +38 -0
- package/batteries/vector/factory.mjs +25 -0
- package/batteries/vector/factory.mjs.map +1 -0
- package/batteries/vector/filters.cjs +107 -0
- package/batteries/vector/filters.cjs.map +1 -0
- package/batteries/vector/filters.d.ts +34 -0
- package/batteries/vector/filters.mjs +99 -0
- package/batteries/vector/filters.mjs.map +1 -0
- package/batteries/vector/helpers.cjs +23 -0
- package/batteries/vector/helpers.cjs.map +1 -0
- package/batteries/vector/helpers.d.ts +12 -0
- package/batteries/vector/helpers.mjs +17 -0
- package/batteries/vector/helpers.mjs.map +1 -0
- package/batteries/vector/hnswlib/index.d.ts +35 -0
- package/batteries/vector/hnswlib.cjs +237 -0
- package/batteries/vector/hnswlib.cjs.map +1 -0
- package/batteries/vector/hnswlib.mjs +235 -0
- package/batteries/vector/hnswlib.mjs.map +1 -0
- package/batteries/vector/in_memory/index.d.ts +23 -0
- package/batteries/vector/in_memory.cjs +178 -0
- package/batteries/vector/in_memory.cjs.map +1 -0
- package/batteries/vector/in_memory.mjs +176 -0
- package/batteries/vector/in_memory.mjs.map +1 -0
- package/batteries/vector/index.d.ts +18 -0
- package/batteries/vector/lancedb/index.d.ts +34 -0
- package/batteries/vector/lancedb.cjs +224 -0
- package/batteries/vector/lancedb.cjs.map +1 -0
- package/batteries/vector/lancedb.mjs +222 -0
- package/batteries/vector/lancedb.mjs.map +1 -0
- package/batteries/vector/mariadb/index.d.ts +39 -0
- package/batteries/vector/mariadb.cjs +228 -0
- package/batteries/vector/mariadb.cjs.map +1 -0
- package/batteries/vector/mariadb.mjs +226 -0
- package/batteries/vector/mariadb.mjs.map +1 -0
- package/batteries/vector/meilisearch/index.d.ts +36 -0
- package/batteries/vector/meilisearch.cjs +242 -0
- package/batteries/vector/meilisearch.cjs.map +1 -0
- package/batteries/vector/meilisearch.mjs +240 -0
- package/batteries/vector/meilisearch.mjs.map +1 -0
- package/batteries/vector/migrate.cjs +54 -0
- package/batteries/vector/migrate.cjs.map +1 -0
- package/batteries/vector/migrate.d.ts +30 -0
- package/batteries/vector/migrate.mjs +52 -0
- package/batteries/vector/migrate.mjs.map +1 -0
- package/batteries/vector/milvus/index.d.ts +35 -0
- package/batteries/vector/milvus.cjs +357 -0
- package/batteries/vector/milvus.cjs.map +1 -0
- package/batteries/vector/milvus.mjs +354 -0
- package/batteries/vector/milvus.mjs.map +1 -0
- package/batteries/vector/mongodb/index.d.ts +46 -0
- package/batteries/vector/mongodb.cjs +270 -0
- package/batteries/vector/mongodb.cjs.map +1 -0
- package/batteries/vector/mongodb.mjs +268 -0
- package/batteries/vector/mongodb.mjs.map +1 -0
- package/batteries/vector/neo4j/index.d.ts +38 -0
- package/batteries/vector/neo4j.cjs +231 -0
- package/batteries/vector/neo4j.cjs.map +1 -0
- package/batteries/vector/neo4j.mjs +229 -0
- package/batteries/vector/neo4j.mjs.map +1 -0
- package/batteries/vector/opensearch/index.d.ts +46 -0
- package/batteries/vector/opensearch.cjs +316 -0
- package/batteries/vector/opensearch.cjs.map +1 -0
- package/batteries/vector/opensearch.mjs +313 -0
- package/batteries/vector/opensearch.mjs.map +1 -0
- package/batteries/vector/oracle23ai/index.d.ts +45 -0
- package/batteries/vector/oracle23ai.cjs +340 -0
- package/batteries/vector/oracle23ai.cjs.map +1 -0
- package/batteries/vector/oracle23ai.mjs +338 -0
- package/batteries/vector/oracle23ai.mjs.map +1 -0
- package/batteries/vector/orama/index.d.ts +23 -0
- package/batteries/vector/orama.cjs +272 -0
- package/batteries/vector/orama.cjs.map +1 -0
- package/batteries/vector/orama.mjs +270 -0
- package/batteries/vector/orama.mjs.map +1 -0
- package/batteries/vector/pgvector/index.d.ts +43 -0
- package/batteries/vector/pgvector.cjs +411 -0
- package/batteries/vector/pgvector.cjs.map +1 -0
- package/batteries/vector/pgvector.mjs +408 -0
- package/batteries/vector/pgvector.mjs.map +1 -0
- package/batteries/vector/pinecone/index.d.ts +38 -0
- package/batteries/vector/pinecone.cjs +415 -0
- package/batteries/vector/pinecone.cjs.map +1 -0
- package/batteries/vector/pinecone.mjs +412 -0
- package/batteries/vector/pinecone.mjs.map +1 -0
- package/batteries/vector/plan.cjs +2 -0
- package/batteries/vector/plan.d.ts +65 -0
- package/batteries/vector/plan.mjs +0 -0
- package/batteries/vector/qdrant/index.d.ts +34 -0
- package/batteries/vector/qdrant.cjs +286 -0
- package/batteries/vector/qdrant.cjs.map +1 -0
- package/batteries/vector/qdrant.mjs +284 -0
- package/batteries/vector/qdrant.mjs.map +1 -0
- package/batteries/vector/redis/index.d.ts +44 -0
- package/batteries/vector/redis.cjs +391 -0
- package/batteries/vector/redis.cjs.map +1 -0
- package/batteries/vector/redis.mjs +388 -0
- package/batteries/vector/redis.mjs.map +1 -0
- package/batteries/vector/retrievable.cjs +69 -0
- package/batteries/vector/retrievable.cjs.map +1 -0
- package/batteries/vector/retrievable.mjs +67 -0
- package/batteries/vector/retrievable.mjs.map +1 -0
- package/batteries/vector/retrievable_glue.d.ts +24 -0
- package/batteries/vector/s3vectors/index.d.ts +52 -0
- package/batteries/vector/s3vectors.cjs +438 -0
- package/batteries/vector/s3vectors.cjs.map +1 -0
- package/batteries/vector/s3vectors.mjs +436 -0
- package/batteries/vector/s3vectors.mjs.map +1 -0
- package/batteries/vector/schema.cjs +96 -0
- package/batteries/vector/schema.cjs.map +1 -0
- package/batteries/vector/schema.d.ts +40 -0
- package/batteries/vector/schema.mjs +93 -0
- package/batteries/vector/schema.mjs.map +1 -0
- package/batteries/vector/solr/index.d.ts +36 -0
- package/batteries/vector/solr.cjs +230 -0
- package/batteries/vector/solr.cjs.map +1 -0
- package/batteries/vector/solr.mjs +228 -0
- package/batteries/vector/solr.mjs.map +1 -0
- package/batteries/vector/sqlite_vec/index.d.ts +30 -0
- package/batteries/vector/sqlite_vec.cjs +318 -0
- package/batteries/vector/sqlite_vec.cjs.map +1 -0
- package/batteries/vector/sqlite_vec.mjs +316 -0
- package/batteries/vector/sqlite_vec.mjs.map +1 -0
- package/batteries/vector/surrealdb/index.d.ts +37 -0
- package/batteries/vector/surrealdb.cjs +230 -0
- package/batteries/vector/surrealdb.cjs.map +1 -0
- package/batteries/vector/surrealdb.mjs +228 -0
- package/batteries/vector/surrealdb.mjs.map +1 -0
- package/batteries/vector/types.cjs +2 -0
- package/batteries/vector/types.d.ts +100 -0
- package/batteries/vector/types.mjs +0 -0
- package/batteries/vector/typesense/index.d.ts +38 -0
- package/batteries/vector/typesense.cjs +272 -0
- package/batteries/vector/typesense.cjs.map +1 -0
- package/batteries/vector/typesense.mjs +270 -0
- package/batteries/vector/typesense.mjs.map +1 -0
- package/batteries/vector/validation.cjs +90 -0
- package/batteries/vector/validation.cjs.map +1 -0
- package/batteries/vector/validation.d.ts +18 -0
- package/batteries/vector/validation.mjs +83 -0
- package/batteries/vector/validation.mjs.map +1 -0
- package/batteries/vector/vector_store_constructor.cjs +56 -0
- package/batteries/vector/vector_store_constructor.cjs.map +1 -0
- package/batteries/vector/vector_store_constructor.d.ts +30 -0
- package/batteries/vector/vector_store_constructor.mjs +53 -0
- package/batteries/vector/vector_store_constructor.mjs.map +1 -0
- package/batteries/vector/vespa/index.d.ts +39 -0
- package/batteries/vector/vespa.cjs +423 -0
- package/batteries/vector/vespa.cjs.map +1 -0
- package/batteries/vector/vespa.mjs +421 -0
- package/batteries/vector/vespa.mjs.map +1 -0
- package/batteries/vector/weaviate/index.d.ts +57 -0
- package/batteries/vector/weaviate.cjs +325 -0
- package/batteries/vector/weaviate.cjs.map +1 -0
- package/batteries/vector/weaviate.mjs +322 -0
- package/batteries/vector/weaviate.mjs.map +1 -0
- package/batteries/vector.cjs +63 -0
- package/batteries/vector.mjs +14 -0
- package/batteries.cjs +62 -0
- package/batteries.mjs +15 -1
- package/{chunk-kRvK8_k2.mjs → chunk-Bpcn9VDT.mjs} +5 -1
- package/{common-lMrnzoyn.mjs → common-BT0nfCi9.mjs} +8 -8
- package/{common-lMrnzoyn.mjs.map → common-BT0nfCi9.mjs.map} +1 -1
- package/{common-D_e5zYsG.js → common-Cj8TaQ9U.js} +8 -8
- package/{common-D_e5zYsG.js.map → common-Cj8TaQ9U.js.map} +1 -1
- package/common.cjs +7 -7
- package/common.mjs +7 -7
- package/{dispatch_runner-CpuyATj1.js → dispatch_runner-BHBNupqp.js} +2 -2
- package/dispatch_runner-BHBNupqp.js.map +1 -0
- package/{dispatch_runner-CDF3X0nv.mjs → dispatch_runner-DPcS7Y_M.mjs} +2 -2
- package/dispatch_runner-DPcS7Y_M.mjs.map +1 -0
- package/dispatch_runner.cjs +1 -1
- package/dispatch_runner.mjs +1 -1
- package/forge.cjs +4 -4
- package/forge.mjs +4 -4
- package/guards.cjs +8 -8
- package/guards.mjs +8 -8
- package/index.cjs +12 -12
- package/index.mjs +12 -12
- package/lib/classes/tool_registry.d.ts +70 -4
- package/mcp/adk-docs-corpus.json +1 -1
- package/package.json +424 -88
- package/skills/adk-assembly/SKILL.md +2 -2
- package/{spooled_artifact-B8gIIn9h.js → spooled_artifact-BTq6Nzfy.js} +4 -4
- package/spooled_artifact-BTq6Nzfy.js.map +1 -0
- package/{spooled_artifact-CWoKUDEm.mjs → spooled_artifact-CHoZgWwI.mjs} +4 -4
- package/spooled_artifact-CHoZgWwI.mjs.map +1 -0
- package/spooled_artifact.cjs +2 -2
- package/spooled_artifact.mjs +2 -2
- package/{spooled_markdown_artifact-DQX0RCdI.js → spooled_markdown_artifact-CALSDxIx.js} +3 -3
- package/{spooled_markdown_artifact-DQX0RCdI.js.map → spooled_markdown_artifact-CALSDxIx.js.map} +1 -1
- package/{spooled_markdown_artifact-CNle4jXN.mjs → spooled_markdown_artifact-Ci5UL7l4.mjs} +3 -3
- package/{spooled_markdown_artifact-CNle4jXN.mjs.map → spooled_markdown_artifact-Ci5UL7l4.mjs.map} +1 -1
- package/src/types/evaluatex.d.ts +31 -0
- package/{thought-BD6AkkOr.js → thought-BbwhJ1wb.js} +4 -4
- package/thought-BbwhJ1wb.js.map +1 -0
- package/{thought-B_P8LiB6.mjs → thought-D34QQZZ9.mjs} +4 -4
- package/thought-D34QQZZ9.mjs.map +1 -0
- package/{tool-CRZSUcdP.mjs → tool-CMhaDRNd.mjs} +3 -3
- package/tool-CMhaDRNd.mjs.map +1 -0
- package/{tool-CX9vNHAw.js → tool-CVyZkFC7.js} +3 -3
- package/tool-CVyZkFC7.js.map +1 -0
- package/{tool_call-BUeMuCc6.mjs → tool_call-CV5qVNlb.mjs} +3 -3
- package/{tool_call-BUeMuCc6.mjs.map → tool_call-CV5qVNlb.mjs.map} +1 -1
- package/{tool_call--7ti-frB.js → tool_call-Db68hB7y.js} +3 -3
- package/{tool_call--7ti-frB.js.map → tool_call-Db68hB7y.js.map} +1 -1
- package/{tool_registry-BGHg6KTq.mjs → tool_registry-D1pSSlsd.mjs} +109 -22
- package/tool_registry-D1pSSlsd.mjs.map +1 -0
- package/{tool_registry-CtCQ4Xoz.js → tool_registry-DYUYqXvo.js} +109 -22
- package/tool_registry-DYUYqXvo.js.map +1 -0
- package/{turn_runner-BJTtAORU.js → turn_runner-DqWHNP80.js} +5 -5
- package/turn_runner-DqWHNP80.js.map +1 -0
- package/{turn_runner-C02LZHjt.mjs → turn_runner-fg1Wc3dK.mjs} +5 -5
- package/turn_runner-fg1Wc3dK.mjs.map +1 -0
- package/turn_runner.cjs +1 -1
- package/turn_runner.mjs +1 -1
- package/dispatch_runner-CDF3X0nv.mjs.map +0 -1
- package/dispatch_runner-CpuyATj1.js.map +0 -1
- package/spooled_artifact-B8gIIn9h.js.map +0 -1
- package/spooled_artifact-CWoKUDEm.mjs.map +0 -1
- package/thought-BD6AkkOr.js.map +0 -1
- package/thought-B_P8LiB6.mjs.map +0 -1
- package/tool-CRZSUcdP.mjs.map +0 -1
- package/tool-CX9vNHAw.js.map +0 -1
- package/tool_registry-BGHg6KTq.mjs.map +0 -1
- package/tool_registry-CtCQ4Xoz.js.map +0 -1
- package/turn_runner-BJTtAORU.js.map +0 -1
- package/turn_runner-C02LZHjt.mjs.map +0 -1
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
require("../../chunk-Ble4zEEl.js");
|
|
3
|
+
const require_tool_registry = require("../../tool_registry-DYUYqXvo.js");
|
|
4
|
+
require("../../guards.cjs");
|
|
5
|
+
const require_batteries_vector_filters = require("./filters.cjs");
|
|
6
|
+
const require_batteries_vector_exceptions = require("./exceptions.cjs");
|
|
7
|
+
const require_batteries_vector_contract = require("./contract.cjs");
|
|
8
|
+
const require_batteries_vector_validation = require("./validation.cjs");
|
|
9
|
+
//#region src/batteries/vector/mongodb/index.ts
|
|
10
|
+
/**
|
|
11
|
+
* @module @nhtio/adk/batteries/vector/mongodb
|
|
12
|
+
*
|
|
13
|
+
* MongoDB Atlas Vector Search adapter. Each collection is a MongoDB collection with an Atlas
|
|
14
|
+
* `vectorSearch` index on `vec`; KNN uses the `$vectorSearch` aggregation stage (cosine
|
|
15
|
+
* `vectorSearchScore`, [0,1]). Metadata is a JSON string field filtered with the neutral filter
|
|
16
|
+
* tree's JS reference evaluator for cross-adapter parity.
|
|
17
|
+
*
|
|
18
|
+
* Consistency note: the *document* collection is strongly consistent, but the Atlas vector
|
|
19
|
+
* *index* updates asynchronously after a write (~1s). So filter-scans, fetch-by-id and the
|
|
20
|
+
* delete read-back use a plain `find()` (immediate), and only KNN goes through `$vectorSearch` —
|
|
21
|
+
* after which the adapter polls until the just-inserted ids are index-visible (strong mode).
|
|
22
|
+
*
|
|
23
|
+
* Driver: `mongodb`. Works against `mongodb/mongodb-atlas-local` or a real Atlas cluster.
|
|
24
|
+
*/
|
|
25
|
+
var INDEX = "vec_idx";
|
|
26
|
+
var getMongo = async () => {
|
|
27
|
+
try {
|
|
28
|
+
return (await import("mongodb")).MongoClient;
|
|
29
|
+
} catch {
|
|
30
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_DRIVER_UNAVAILABLE(["mongodb"]);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var similarity = (metric) => metric === "euclidean" ? "euclidean" : metric === "dot" ? "dotProduct" : "cosine";
|
|
34
|
+
var MongoDBVectorStore = class extends require_batteries_vector_contract.BaseVectorStore {
|
|
35
|
+
capabilities = {
|
|
36
|
+
transactions: false,
|
|
37
|
+
namedVectors: false,
|
|
38
|
+
rename: false,
|
|
39
|
+
rawSql: false,
|
|
40
|
+
builtInEncoding: false,
|
|
41
|
+
consistency: {
|
|
42
|
+
configurable: false,
|
|
43
|
+
default: "strong",
|
|
44
|
+
modes: ["strong"]
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
#client = null;
|
|
48
|
+
#db = null;
|
|
49
|
+
#dims = /* @__PURE__ */ new Map();
|
|
50
|
+
get #opts() {
|
|
51
|
+
return this.options;
|
|
52
|
+
}
|
|
53
|
+
static isAvailable() {
|
|
54
|
+
return typeof process !== "undefined";
|
|
55
|
+
}
|
|
56
|
+
isAvailable() {
|
|
57
|
+
return typeof process !== "undefined";
|
|
58
|
+
}
|
|
59
|
+
async connect() {
|
|
60
|
+
if (this.#client) return;
|
|
61
|
+
const MongoClient = await getMongo();
|
|
62
|
+
const c = this.#opts.connection;
|
|
63
|
+
try {
|
|
64
|
+
this.#client = new MongoClient(c.url);
|
|
65
|
+
await this.#client.connect();
|
|
66
|
+
this.#db = this.#client.db(c.database ?? "vector");
|
|
67
|
+
} catch (err) {
|
|
68
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_CONNECTION_FAILED([String(err)]);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async close() {
|
|
72
|
+
if (this.#client) {
|
|
73
|
+
await this.#client.close();
|
|
74
|
+
this.#client = null;
|
|
75
|
+
this.#db = null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
#name(collection) {
|
|
79
|
+
const prefix = this.#opts.connection?.collectionPrefix;
|
|
80
|
+
return prefix ? `${prefix}${collection}` : collection;
|
|
81
|
+
}
|
|
82
|
+
async #col(collection) {
|
|
83
|
+
if (!this.#db) await this.connect();
|
|
84
|
+
return this.#db.collection(this.#name(collection));
|
|
85
|
+
}
|
|
86
|
+
async #sleep(ms) {
|
|
87
|
+
await new Promise((r) => setTimeout(r, ms));
|
|
88
|
+
}
|
|
89
|
+
async createCollection(spec, ifNotExists) {
|
|
90
|
+
if (!this.#db) await this.connect();
|
|
91
|
+
this.#dims.set(spec.collection, spec.vector.dimensions);
|
|
92
|
+
const physical = this.#name(spec.collection);
|
|
93
|
+
try {
|
|
94
|
+
if ((await this.#db.listCollections({ name: physical }).toArray()).length > 0) {
|
|
95
|
+
if (ifNotExists) {
|
|
96
|
+
await this.#db.collection(physical).deleteMany({});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
await this.#db.collection(physical).drop().catch(() => void 0);
|
|
100
|
+
}
|
|
101
|
+
await this.#db.createCollection(physical).catch(() => void 0);
|
|
102
|
+
const col = this.#db.collection(physical);
|
|
103
|
+
if (!(await col.listSearchIndexes().toArray().catch(() => [])).find((i) => i.name === INDEX)) await col.createSearchIndex({
|
|
104
|
+
name: INDEX,
|
|
105
|
+
type: "vectorSearch",
|
|
106
|
+
definition: { fields: [{
|
|
107
|
+
type: "vector",
|
|
108
|
+
path: "vec",
|
|
109
|
+
numDimensions: spec.vector.dimensions,
|
|
110
|
+
similarity: similarity(spec.vector.metric)
|
|
111
|
+
}] }
|
|
112
|
+
});
|
|
113
|
+
for (let i = 0; i < 60; i++) {
|
|
114
|
+
if ((await col.listSearchIndexes().toArray()).find((x) => x.name === INDEX)?.queryable) break;
|
|
115
|
+
await this.#sleep(1e3);
|
|
116
|
+
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_COLLECTION_FAILED(["createCollection", String(err)]);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async dropCollection(collection, ifExists) {
|
|
122
|
+
if (!this.#db) await this.connect();
|
|
123
|
+
const physical = this.#name(collection);
|
|
124
|
+
try {
|
|
125
|
+
if ((await this.#db.listCollections({ name: physical }).toArray()).length === 0) {
|
|
126
|
+
if (ifExists) return;
|
|
127
|
+
throw new Error("collection not found: " + collection);
|
|
128
|
+
}
|
|
129
|
+
await this.#db.collection(physical).drop().catch(() => void 0);
|
|
130
|
+
this.#dims.delete(collection);
|
|
131
|
+
} catch (err) {
|
|
132
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_COLLECTION_FAILED(["dropCollection", String(err)]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async hasCollection(collection) {
|
|
136
|
+
if (!this.#db) await this.connect();
|
|
137
|
+
return (await this.#db.listCollections({ name: this.#name(collection) }).toArray()).length > 0;
|
|
138
|
+
}
|
|
139
|
+
async renameCollection(_from, _to) {
|
|
140
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_UNSUPPORTED_OPERATION(["renameCollection", "mongodb"]);
|
|
141
|
+
}
|
|
142
|
+
async executeUpsert(plan) {
|
|
143
|
+
if (plan.records.length === 0) return;
|
|
144
|
+
require_batteries_vector_validation.validateRecords(plan.records);
|
|
145
|
+
const col = await this.#col(plan.collection);
|
|
146
|
+
const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection);
|
|
147
|
+
const ids = [];
|
|
148
|
+
try {
|
|
149
|
+
for (const r of plan.records) {
|
|
150
|
+
let vector = r.vector;
|
|
151
|
+
if (!vector && r.document) {
|
|
152
|
+
const [v] = await this.encode([r.document], "document");
|
|
153
|
+
vector = v;
|
|
154
|
+
}
|
|
155
|
+
if (!vector) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_UPSERT_FAILED(["Record missing vector and document"]);
|
|
156
|
+
if (expected !== void 0 && vector.length !== expected) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_DIMENSION_MISMATCH([expected, vector.length]);
|
|
157
|
+
await col.updateOne({ id: r.id }, { $set: {
|
|
158
|
+
id: r.id,
|
|
159
|
+
vec: vector,
|
|
160
|
+
document: r.document ?? "",
|
|
161
|
+
metadata: r.metadata ? JSON.stringify(r.metadata) : "{}"
|
|
162
|
+
} }, { upsert: true });
|
|
163
|
+
ids.push(r.id);
|
|
164
|
+
}
|
|
165
|
+
await this.#settlePresent(col, ids, expected ?? this.#dims.get(plan.collection) ?? 0);
|
|
166
|
+
} catch (err) {
|
|
167
|
+
if (require_tool_registry.isInstanceOf(err, "E_VECTOR_STORE_DIMENSION_MISMATCH", require_batteries_vector_exceptions.E_VECTOR_STORE_DIMENSION_MISMATCH) || require_tool_registry.isInstanceOf(err, "E_VECTOR_STORE_UPSERT_FAILED", require_batteries_vector_exceptions.E_VECTOR_STORE_UPSERT_FAILED)) throw err;
|
|
168
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_UPSERT_FAILED([String(err)]);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async #settlePresent(col, ids, dims) {
|
|
172
|
+
if (ids.length === 0 || dims <= 0) return;
|
|
173
|
+
const probe = new Array(dims).fill(0);
|
|
174
|
+
probe[0] = 1;
|
|
175
|
+
const deadline = Date.now() + 1e4;
|
|
176
|
+
while (Date.now() < deadline) {
|
|
177
|
+
let seen;
|
|
178
|
+
try {
|
|
179
|
+
const res = await col.aggregate([{ $vectorSearch: {
|
|
180
|
+
index: INDEX,
|
|
181
|
+
path: "vec",
|
|
182
|
+
queryVector: probe,
|
|
183
|
+
numCandidates: Math.max(ids.length * 10, 50),
|
|
184
|
+
limit: Math.max(ids.length * 5, 50)
|
|
185
|
+
} }, { $project: { id: 1 } }]).toArray();
|
|
186
|
+
seen = new Set(res.map((d) => d.id));
|
|
187
|
+
} catch {
|
|
188
|
+
seen = /* @__PURE__ */ new Set();
|
|
189
|
+
}
|
|
190
|
+
if (ids.every((id) => seen.has(id))) return;
|
|
191
|
+
await this.#sleep(300);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async executeSearch(plan) {
|
|
195
|
+
const col = await this.#col(plan.collection);
|
|
196
|
+
let queryVector;
|
|
197
|
+
if (plan.near) {
|
|
198
|
+
if ("vector" in plan.near) queryVector = plan.near.vector;
|
|
199
|
+
else if ("serverText" in plan.near) {
|
|
200
|
+
const [v] = await this.encode([plan.near.serverText], "query");
|
|
201
|
+
queryVector = v;
|
|
202
|
+
} else if ("id" in plan.near) {
|
|
203
|
+
const doc = await col.findOne({ id: plan.near.id });
|
|
204
|
+
if (!doc) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_SEARCH_FAILED(["Referenced id not found: " + plan.near.id]);
|
|
205
|
+
queryVector = doc.vec;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const offset = plan.offset ?? 0;
|
|
209
|
+
try {
|
|
210
|
+
if (queryVector) {
|
|
211
|
+
const k = (plan.filter ? 1e3 : plan.topK + offset) || 10;
|
|
212
|
+
const pipeline = [{ $vectorSearch: {
|
|
213
|
+
index: INDEX,
|
|
214
|
+
path: "vec",
|
|
215
|
+
queryVector,
|
|
216
|
+
numCandidates: Math.max(k * 10, 100),
|
|
217
|
+
limit: k
|
|
218
|
+
} }, { $project: {
|
|
219
|
+
id: 1,
|
|
220
|
+
vec: 1,
|
|
221
|
+
document: 1,
|
|
222
|
+
metadata: 1,
|
|
223
|
+
score: { $meta: "vectorSearchScore" }
|
|
224
|
+
} }];
|
|
225
|
+
const docs = await col.aggregate(pipeline).toArray();
|
|
226
|
+
return (plan.filter ? docs.filter((d) => require_batteries_vector_filters.evaluateFilter(plan.filter, this.#parseMeta(d.metadata))) : docs).slice(offset, offset + plan.topK).map((d) => this.#project(d, plan, true));
|
|
227
|
+
} else {
|
|
228
|
+
const docs = await col.find({}).toArray();
|
|
229
|
+
return (plan.filter ? docs.filter((d) => require_batteries_vector_filters.evaluateFilter(plan.filter, this.#parseMeta(d.metadata))) : docs).slice(offset, offset + plan.topK).map((d) => this.#project(d, plan, false));
|
|
230
|
+
}
|
|
231
|
+
} catch (err) {
|
|
232
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_SEARCH_FAILED([String(err)]);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
#parseMeta(val) {
|
|
236
|
+
if (typeof val === "string") try {
|
|
237
|
+
return JSON.parse(val);
|
|
238
|
+
} catch {
|
|
239
|
+
return {};
|
|
240
|
+
}
|
|
241
|
+
if (val && typeof val === "object") return val;
|
|
242
|
+
return {};
|
|
243
|
+
}
|
|
244
|
+
#project(doc, plan, isKnn) {
|
|
245
|
+
const proj = plan.projection;
|
|
246
|
+
const out = {};
|
|
247
|
+
if (proj.id) out.id = doc.id;
|
|
248
|
+
if (proj.vector && Array.isArray(doc.vec)) out.vector = doc.vec.map(Number);
|
|
249
|
+
if (proj.document) out.document = doc.document ?? void 0;
|
|
250
|
+
if (proj.metadata) out.metadata = this.#parseMeta(doc.metadata);
|
|
251
|
+
if (isKnn && typeof doc.score === "number") out.score = doc.score;
|
|
252
|
+
return out;
|
|
253
|
+
}
|
|
254
|
+
async executeDelete(plan) {
|
|
255
|
+
const col = await this.#col(plan.collection);
|
|
256
|
+
try {
|
|
257
|
+
if (plan.ids && plan.ids.length > 0) await col.deleteMany({ id: { $in: plan.ids } });
|
|
258
|
+
else if (plan.filter) {
|
|
259
|
+
const targets = (await col.find({}).toArray()).filter((d) => require_batteries_vector_filters.evaluateFilter(plan.filter, this.#parseMeta(d.metadata))).map((d) => d.id);
|
|
260
|
+
if (targets.length > 0) await col.deleteMany({ id: { $in: targets } });
|
|
261
|
+
} else await col.deleteMany({});
|
|
262
|
+
} catch (err) {
|
|
263
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_DELETE_FAILED([String(err)]);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
//#endregion
|
|
268
|
+
exports.MongoDBVectorStore = MongoDBVectorStore;
|
|
269
|
+
|
|
270
|
+
//# sourceMappingURL=mongodb.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mongodb.cjs","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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"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { s as isInstanceOf } from "../../tool_registry-D1pSSlsd.mjs";
|
|
2
|
+
import "../../guards.mjs";
|
|
3
|
+
import { evaluateFilter } from "./filters.mjs";
|
|
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";
|
|
5
|
+
import { BaseVectorStore } from "./contract.mjs";
|
|
6
|
+
import { validateRecords } from "./validation.mjs";
|
|
7
|
+
//#region src/batteries/vector/mongodb/index.ts
|
|
8
|
+
/**
|
|
9
|
+
* @module @nhtio/adk/batteries/vector/mongodb
|
|
10
|
+
*
|
|
11
|
+
* MongoDB Atlas Vector Search adapter. Each collection is a MongoDB collection with an Atlas
|
|
12
|
+
* `vectorSearch` index on `vec`; KNN uses the `$vectorSearch` aggregation stage (cosine
|
|
13
|
+
* `vectorSearchScore`, [0,1]). Metadata is a JSON string field filtered with the neutral filter
|
|
14
|
+
* tree's JS reference evaluator for cross-adapter parity.
|
|
15
|
+
*
|
|
16
|
+
* Consistency note: the *document* collection is strongly consistent, but the Atlas vector
|
|
17
|
+
* *index* updates asynchronously after a write (~1s). So filter-scans, fetch-by-id and the
|
|
18
|
+
* delete read-back use a plain `find()` (immediate), and only KNN goes through `$vectorSearch` —
|
|
19
|
+
* after which the adapter polls until the just-inserted ids are index-visible (strong mode).
|
|
20
|
+
*
|
|
21
|
+
* Driver: `mongodb`. Works against `mongodb/mongodb-atlas-local` or a real Atlas cluster.
|
|
22
|
+
*/
|
|
23
|
+
var INDEX = "vec_idx";
|
|
24
|
+
var getMongo = async () => {
|
|
25
|
+
try {
|
|
26
|
+
return (await import("mongodb")).MongoClient;
|
|
27
|
+
} catch {
|
|
28
|
+
throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(["mongodb"]);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var similarity = (metric) => metric === "euclidean" ? "euclidean" : metric === "dot" ? "dotProduct" : "cosine";
|
|
32
|
+
var MongoDBVectorStore = class extends BaseVectorStore {
|
|
33
|
+
capabilities = {
|
|
34
|
+
transactions: false,
|
|
35
|
+
namedVectors: false,
|
|
36
|
+
rename: false,
|
|
37
|
+
rawSql: false,
|
|
38
|
+
builtInEncoding: false,
|
|
39
|
+
consistency: {
|
|
40
|
+
configurable: false,
|
|
41
|
+
default: "strong",
|
|
42
|
+
modes: ["strong"]
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
#client = null;
|
|
46
|
+
#db = null;
|
|
47
|
+
#dims = /* @__PURE__ */ new Map();
|
|
48
|
+
get #opts() {
|
|
49
|
+
return this.options;
|
|
50
|
+
}
|
|
51
|
+
static isAvailable() {
|
|
52
|
+
return typeof process !== "undefined";
|
|
53
|
+
}
|
|
54
|
+
isAvailable() {
|
|
55
|
+
return typeof process !== "undefined";
|
|
56
|
+
}
|
|
57
|
+
async connect() {
|
|
58
|
+
if (this.#client) return;
|
|
59
|
+
const MongoClient = await getMongo();
|
|
60
|
+
const c = this.#opts.connection;
|
|
61
|
+
try {
|
|
62
|
+
this.#client = new MongoClient(c.url);
|
|
63
|
+
await this.#client.connect();
|
|
64
|
+
this.#db = this.#client.db(c.database ?? "vector");
|
|
65
|
+
} catch (err) {
|
|
66
|
+
throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)]);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async close() {
|
|
70
|
+
if (this.#client) {
|
|
71
|
+
await this.#client.close();
|
|
72
|
+
this.#client = null;
|
|
73
|
+
this.#db = null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
#name(collection) {
|
|
77
|
+
const prefix = this.#opts.connection?.collectionPrefix;
|
|
78
|
+
return prefix ? `${prefix}${collection}` : collection;
|
|
79
|
+
}
|
|
80
|
+
async #col(collection) {
|
|
81
|
+
if (!this.#db) await this.connect();
|
|
82
|
+
return this.#db.collection(this.#name(collection));
|
|
83
|
+
}
|
|
84
|
+
async #sleep(ms) {
|
|
85
|
+
await new Promise((r) => setTimeout(r, ms));
|
|
86
|
+
}
|
|
87
|
+
async createCollection(spec, ifNotExists) {
|
|
88
|
+
if (!this.#db) await this.connect();
|
|
89
|
+
this.#dims.set(spec.collection, spec.vector.dimensions);
|
|
90
|
+
const physical = this.#name(spec.collection);
|
|
91
|
+
try {
|
|
92
|
+
if ((await this.#db.listCollections({ name: physical }).toArray()).length > 0) {
|
|
93
|
+
if (ifNotExists) {
|
|
94
|
+
await this.#db.collection(physical).deleteMany({});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
await this.#db.collection(physical).drop().catch(() => void 0);
|
|
98
|
+
}
|
|
99
|
+
await this.#db.createCollection(physical).catch(() => void 0);
|
|
100
|
+
const col = this.#db.collection(physical);
|
|
101
|
+
if (!(await col.listSearchIndexes().toArray().catch(() => [])).find((i) => i.name === INDEX)) await col.createSearchIndex({
|
|
102
|
+
name: INDEX,
|
|
103
|
+
type: "vectorSearch",
|
|
104
|
+
definition: { fields: [{
|
|
105
|
+
type: "vector",
|
|
106
|
+
path: "vec",
|
|
107
|
+
numDimensions: spec.vector.dimensions,
|
|
108
|
+
similarity: similarity(spec.vector.metric)
|
|
109
|
+
}] }
|
|
110
|
+
});
|
|
111
|
+
for (let i = 0; i < 60; i++) {
|
|
112
|
+
if ((await col.listSearchIndexes().toArray()).find((x) => x.name === INDEX)?.queryable) break;
|
|
113
|
+
await this.#sleep(1e3);
|
|
114
|
+
}
|
|
115
|
+
} catch (err) {
|
|
116
|
+
throw new E_VECTOR_STORE_COLLECTION_FAILED(["createCollection", String(err)]);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async dropCollection(collection, ifExists) {
|
|
120
|
+
if (!this.#db) await this.connect();
|
|
121
|
+
const physical = this.#name(collection);
|
|
122
|
+
try {
|
|
123
|
+
if ((await this.#db.listCollections({ name: physical }).toArray()).length === 0) {
|
|
124
|
+
if (ifExists) return;
|
|
125
|
+
throw new Error("collection not found: " + collection);
|
|
126
|
+
}
|
|
127
|
+
await this.#db.collection(physical).drop().catch(() => void 0);
|
|
128
|
+
this.#dims.delete(collection);
|
|
129
|
+
} catch (err) {
|
|
130
|
+
throw new E_VECTOR_STORE_COLLECTION_FAILED(["dropCollection", String(err)]);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async hasCollection(collection) {
|
|
134
|
+
if (!this.#db) await this.connect();
|
|
135
|
+
return (await this.#db.listCollections({ name: this.#name(collection) }).toArray()).length > 0;
|
|
136
|
+
}
|
|
137
|
+
async renameCollection(_from, _to) {
|
|
138
|
+
throw new E_VECTOR_STORE_UNSUPPORTED_OPERATION(["renameCollection", "mongodb"]);
|
|
139
|
+
}
|
|
140
|
+
async executeUpsert(plan) {
|
|
141
|
+
if (plan.records.length === 0) return;
|
|
142
|
+
validateRecords(plan.records);
|
|
143
|
+
const col = await this.#col(plan.collection);
|
|
144
|
+
const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection);
|
|
145
|
+
const ids = [];
|
|
146
|
+
try {
|
|
147
|
+
for (const r of plan.records) {
|
|
148
|
+
let vector = r.vector;
|
|
149
|
+
if (!vector && r.document) {
|
|
150
|
+
const [v] = await this.encode([r.document], "document");
|
|
151
|
+
vector = v;
|
|
152
|
+
}
|
|
153
|
+
if (!vector) throw new E_VECTOR_STORE_UPSERT_FAILED(["Record missing vector and document"]);
|
|
154
|
+
if (expected !== void 0 && vector.length !== expected) throw new E_VECTOR_STORE_DIMENSION_MISMATCH([expected, vector.length]);
|
|
155
|
+
await col.updateOne({ id: r.id }, { $set: {
|
|
156
|
+
id: r.id,
|
|
157
|
+
vec: vector,
|
|
158
|
+
document: r.document ?? "",
|
|
159
|
+
metadata: r.metadata ? JSON.stringify(r.metadata) : "{}"
|
|
160
|
+
} }, { upsert: true });
|
|
161
|
+
ids.push(r.id);
|
|
162
|
+
}
|
|
163
|
+
await this.#settlePresent(col, ids, expected ?? this.#dims.get(plan.collection) ?? 0);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
if (isInstanceOf(err, "E_VECTOR_STORE_DIMENSION_MISMATCH", E_VECTOR_STORE_DIMENSION_MISMATCH) || isInstanceOf(err, "E_VECTOR_STORE_UPSERT_FAILED", E_VECTOR_STORE_UPSERT_FAILED)) throw err;
|
|
166
|
+
throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)]);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async #settlePresent(col, ids, dims) {
|
|
170
|
+
if (ids.length === 0 || dims <= 0) return;
|
|
171
|
+
const probe = new Array(dims).fill(0);
|
|
172
|
+
probe[0] = 1;
|
|
173
|
+
const deadline = Date.now() + 1e4;
|
|
174
|
+
while (Date.now() < deadline) {
|
|
175
|
+
let seen;
|
|
176
|
+
try {
|
|
177
|
+
const res = await col.aggregate([{ $vectorSearch: {
|
|
178
|
+
index: INDEX,
|
|
179
|
+
path: "vec",
|
|
180
|
+
queryVector: probe,
|
|
181
|
+
numCandidates: Math.max(ids.length * 10, 50),
|
|
182
|
+
limit: Math.max(ids.length * 5, 50)
|
|
183
|
+
} }, { $project: { id: 1 } }]).toArray();
|
|
184
|
+
seen = new Set(res.map((d) => d.id));
|
|
185
|
+
} catch {
|
|
186
|
+
seen = /* @__PURE__ */ new Set();
|
|
187
|
+
}
|
|
188
|
+
if (ids.every((id) => seen.has(id))) return;
|
|
189
|
+
await this.#sleep(300);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async executeSearch(plan) {
|
|
193
|
+
const col = await this.#col(plan.collection);
|
|
194
|
+
let queryVector;
|
|
195
|
+
if (plan.near) {
|
|
196
|
+
if ("vector" in plan.near) queryVector = plan.near.vector;
|
|
197
|
+
else if ("serverText" in plan.near) {
|
|
198
|
+
const [v] = await this.encode([plan.near.serverText], "query");
|
|
199
|
+
queryVector = v;
|
|
200
|
+
} else if ("id" in plan.near) {
|
|
201
|
+
const doc = await col.findOne({ id: plan.near.id });
|
|
202
|
+
if (!doc) throw new E_VECTOR_STORE_SEARCH_FAILED(["Referenced id not found: " + plan.near.id]);
|
|
203
|
+
queryVector = doc.vec;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const offset = plan.offset ?? 0;
|
|
207
|
+
try {
|
|
208
|
+
if (queryVector) {
|
|
209
|
+
const k = (plan.filter ? 1e3 : plan.topK + offset) || 10;
|
|
210
|
+
const pipeline = [{ $vectorSearch: {
|
|
211
|
+
index: INDEX,
|
|
212
|
+
path: "vec",
|
|
213
|
+
queryVector,
|
|
214
|
+
numCandidates: Math.max(k * 10, 100),
|
|
215
|
+
limit: k
|
|
216
|
+
} }, { $project: {
|
|
217
|
+
id: 1,
|
|
218
|
+
vec: 1,
|
|
219
|
+
document: 1,
|
|
220
|
+
metadata: 1,
|
|
221
|
+
score: { $meta: "vectorSearchScore" }
|
|
222
|
+
} }];
|
|
223
|
+
const docs = await col.aggregate(pipeline).toArray();
|
|
224
|
+
return (plan.filter ? docs.filter((d) => evaluateFilter(plan.filter, this.#parseMeta(d.metadata))) : docs).slice(offset, offset + plan.topK).map((d) => this.#project(d, plan, true));
|
|
225
|
+
} else {
|
|
226
|
+
const docs = await col.find({}).toArray();
|
|
227
|
+
return (plan.filter ? docs.filter((d) => evaluateFilter(plan.filter, this.#parseMeta(d.metadata))) : docs).slice(offset, offset + plan.topK).map((d) => this.#project(d, plan, false));
|
|
228
|
+
}
|
|
229
|
+
} catch (err) {
|
|
230
|
+
throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)]);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
#parseMeta(val) {
|
|
234
|
+
if (typeof val === "string") try {
|
|
235
|
+
return JSON.parse(val);
|
|
236
|
+
} catch {
|
|
237
|
+
return {};
|
|
238
|
+
}
|
|
239
|
+
if (val && typeof val === "object") return val;
|
|
240
|
+
return {};
|
|
241
|
+
}
|
|
242
|
+
#project(doc, plan, isKnn) {
|
|
243
|
+
const proj = plan.projection;
|
|
244
|
+
const out = {};
|
|
245
|
+
if (proj.id) out.id = doc.id;
|
|
246
|
+
if (proj.vector && Array.isArray(doc.vec)) out.vector = doc.vec.map(Number);
|
|
247
|
+
if (proj.document) out.document = doc.document ?? void 0;
|
|
248
|
+
if (proj.metadata) out.metadata = this.#parseMeta(doc.metadata);
|
|
249
|
+
if (isKnn && typeof doc.score === "number") out.score = doc.score;
|
|
250
|
+
return out;
|
|
251
|
+
}
|
|
252
|
+
async executeDelete(plan) {
|
|
253
|
+
const col = await this.#col(plan.collection);
|
|
254
|
+
try {
|
|
255
|
+
if (plan.ids && plan.ids.length > 0) await col.deleteMany({ id: { $in: plan.ids } });
|
|
256
|
+
else if (plan.filter) {
|
|
257
|
+
const targets = (await col.find({}).toArray()).filter((d) => evaluateFilter(plan.filter, this.#parseMeta(d.metadata))).map((d) => d.id);
|
|
258
|
+
if (targets.length > 0) await col.deleteMany({ id: { $in: targets } });
|
|
259
|
+
} else await col.deleteMany({});
|
|
260
|
+
} catch (err) {
|
|
261
|
+
throw new E_VECTOR_STORE_DELETE_FAILED([String(err)]);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
//#endregion
|
|
266
|
+
export { MongoDBVectorStore };
|
|
267
|
+
|
|
268
|
+
//# sourceMappingURL=mongodb.mjs.map
|
|
@@ -0,0 +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":";;;;;;;;;;;;;;;;;;;;;;AAuCA,IAAM,QAAQ;AAgBd,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;CAEA,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"}
|