@nhtio/adk 1.20260925.0 → 1.20260928.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 +39 -0
- package/artifact_methods-Cg0go7Q4.mjs +1 -0
- package/artifact_methods-CxeKTocm.cjs +1 -0
- package/batteries/artifacts/ecmascript.cjs +1 -1
- package/batteries/artifacts/ecmascript.mjs +1 -1
- package/batteries/artifacts/toon.cjs +1 -1
- package/batteries/artifacts/toon.mjs +1 -1
- package/batteries/artifacts/xml.cjs +1 -1
- package/batteries/artifacts/xml.mjs +1 -1
- package/batteries/artifacts/yaml.cjs +1 -1
- package/batteries/artifacts/yaml.mjs +1 -1
- package/batteries/artifacts.cjs +4 -4
- package/batteries/artifacts.mjs +4 -4
- package/batteries/dev-tools/forge.cjs +3 -3
- package/batteries/dev-tools/forge.mjs +3 -3
- package/batteries/dev-tools.cjs +3 -3
- package/batteries/dev-tools.mjs +3 -3
- package/batteries/encoding.cjs +7 -7
- package/batteries/encoding.mjs +7 -7
- package/batteries/generation/gemini/adapter.cjs +1 -1
- package/batteries/generation/gemini/adapter.mjs +1 -1
- package/batteries/generation/local_diffusion/adapter.cjs +1 -1
- package/batteries/generation/local_diffusion/adapter.mjs +1 -1
- package/batteries/generation/openai/adapter.cjs +1 -1
- package/batteries/generation/openai/adapter.mjs +1 -1
- package/batteries/isolation/child_process.cjs +1 -1
- package/batteries/isolation/child_process.mjs +1 -1
- package/batteries/isolation.cjs +1 -1
- package/batteries/isolation.mjs +1 -1
- package/batteries/llm/anthropic_messages/adapter.cjs +6 -6
- package/batteries/llm/anthropic_messages/adapter.mjs +6 -6
- package/batteries/llm/anthropic_messages/count_tokens.cjs +1 -1
- package/batteries/llm/anthropic_messages/count_tokens.mjs +1 -1
- package/batteries/llm/anthropic_messages/helpers.cjs +3 -3
- package/batteries/llm/anthropic_messages/helpers.mjs +3 -3
- package/batteries/llm/anthropic_messages/validation.cjs +2 -2
- package/batteries/llm/anthropic_messages/validation.mjs +2 -2
- package/batteries/llm/anthropic_messages.cjs +2 -2
- package/batteries/llm/anthropic_messages.mjs +2 -2
- package/batteries/llm/bedrock_converse/adapter.cjs +6 -6
- package/batteries/llm/bedrock_converse/adapter.mjs +6 -6
- package/batteries/llm/bedrock_converse/helpers.cjs +1 -1
- package/batteries/llm/bedrock_converse/helpers.mjs +1 -1
- package/batteries/llm/bedrock_converse/validation.cjs +2 -2
- package/batteries/llm/bedrock_converse/validation.mjs +2 -2
- package/batteries/llm/bedrock_converse.cjs +2 -2
- package/batteries/llm/bedrock_converse.mjs +2 -2
- package/batteries/llm/claude_code_cli/adapter.cjs +7 -7
- package/batteries/llm/claude_code_cli/adapter.mjs +7 -7
- package/batteries/llm/claude_code_cli/helpers.cjs +3 -3
- package/batteries/llm/claude_code_cli/helpers.mjs +3 -3
- package/batteries/llm/claude_code_cli/validation.cjs +2 -2
- package/batteries/llm/claude_code_cli/validation.mjs +2 -2
- package/batteries/llm/claude_code_cli.cjs +2 -2
- package/batteries/llm/claude_code_cli.mjs +2 -2
- package/batteries/llm/gemini_generate_content/adapter.cjs +6 -6
- package/batteries/llm/gemini_generate_content/adapter.mjs +6 -6
- package/batteries/llm/gemini_generate_content/helpers.cjs +1 -1
- package/batteries/llm/gemini_generate_content/helpers.mjs +1 -1
- package/batteries/llm/gemini_generate_content/validation.cjs +2 -2
- package/batteries/llm/gemini_generate_content/validation.mjs +2 -2
- package/batteries/llm/gemini_generate_content.cjs +1 -1
- package/batteries/llm/gemini_generate_content.mjs +1 -1
- package/batteries/llm/litert_lm/adapter.cjs +6 -6
- package/batteries/llm/litert_lm/adapter.mjs +6 -6
- package/batteries/llm/litert_lm/helpers.cjs +3 -3
- package/batteries/llm/litert_lm/helpers.mjs +3 -3
- package/batteries/llm/litert_lm/validation.cjs +2 -2
- package/batteries/llm/litert_lm/validation.mjs +2 -2
- package/batteries/llm/litert_lm.cjs +1 -1
- package/batteries/llm/litert_lm.mjs +1 -1
- package/batteries/llm/ollama/adapter.cjs +6 -6
- package/batteries/llm/ollama/adapter.mjs +6 -6
- package/batteries/llm/ollama/helpers.cjs +4 -4
- package/batteries/llm/ollama/helpers.mjs +4 -4
- package/batteries/llm/ollama/validation.cjs +2 -2
- package/batteries/llm/ollama/validation.mjs +2 -2
- package/batteries/llm/ollama.cjs +2 -2
- package/batteries/llm/ollama.mjs +2 -2
- package/batteries/llm/openai_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/openai_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/openai_chat_completions/helpers.cjs +4 -4
- package/batteries/llm/openai_chat_completions/helpers.mjs +4 -4
- package/batteries/llm/openai_chat_completions/validation.cjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.mjs +2 -2
- package/batteries/llm/openai_chat_completions.cjs +2 -2
- package/batteries/llm/openai_chat_completions.mjs +2 -2
- package/batteries/llm/openai_responses/adapter.cjs +6 -6
- package/batteries/llm/openai_responses/adapter.mjs +6 -6
- package/batteries/llm/openai_responses/helpers.cjs +3 -3
- package/batteries/llm/openai_responses/helpers.mjs +3 -3
- package/batteries/llm/openai_responses/validation.cjs +2 -2
- package/batteries/llm/openai_responses/validation.mjs +2 -2
- package/batteries/llm/openai_responses.cjs +2 -2
- package/batteries/llm/openai_responses.mjs +2 -2
- package/batteries/llm/transformers_js/adapter.cjs +6 -6
- package/batteries/llm/transformers_js/adapter.mjs +6 -6
- package/batteries/llm/transformers_js/helpers.cjs +3 -3
- package/batteries/llm/transformers_js/helpers.mjs +3 -3
- package/batteries/llm/transformers_js/validation.cjs +2 -2
- package/batteries/llm/transformers_js/validation.mjs +2 -2
- package/batteries/llm/transformers_js.cjs +1 -1
- package/batteries/llm/transformers_js.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/webllm_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/webllm_chat_completions/helpers.cjs +1 -1
- package/batteries/llm/webllm_chat_completions/helpers.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/validation.cjs +2 -2
- package/batteries/llm/webllm_chat_completions/validation.mjs +2 -2
- package/batteries/llm/webllm_chat_completions.cjs +2 -2
- package/batteries/llm/webllm_chat_completions.mjs +2 -2
- package/batteries/llm.cjs +2 -2
- package/batteries/llm.mjs +2 -2
- package/batteries/media/forge.cjs +4 -4
- package/batteries/media/forge.mjs +4 -4
- package/batteries/media/lint.cjs +1 -1
- package/batteries/media/lint.mjs +1 -1
- package/batteries/orchestration/cells/jexl.cjs +1 -1
- package/batteries/orchestration/cells/jexl.mjs +1 -1
- package/batteries/orchestration/cells/lua.cjs +1 -1
- package/batteries/orchestration/cells/lua.mjs +1 -1
- package/batteries/orchestration/cells/structured.cjs +1 -1
- package/batteries/orchestration/cells/structured.mjs +1 -1
- package/batteries/orchestration/dispatch_reasoner.cjs +4 -4
- package/batteries/orchestration/dispatch_reasoner.mjs +4 -4
- package/batteries/orchestration/executor.cjs +2 -2
- package/batteries/orchestration/executor.mjs +2 -2
- package/batteries/orchestration/forge.cjs +3 -3
- package/batteries/orchestration/forge.mjs +3 -3
- package/batteries/orchestration/validation.cjs +2 -2
- package/batteries/orchestration/validation.mjs +2 -2
- package/batteries/orchestration.cjs +3 -3
- package/batteries/orchestration.mjs +3 -3
- package/batteries/sandbox/js.cjs +1 -1
- package/batteries/sandbox/js.mjs +1 -1
- package/batteries/sandbox/tools.cjs +1 -1
- package/batteries/sandbox/tools.mjs +1 -1
- package/batteries/sandbox.cjs +4 -4
- package/batteries/sandbox.mjs +4 -4
- package/batteries/skills/in_memory.cjs +1 -1
- package/batteries/skills/in_memory.mjs +1 -1
- package/batteries/skills.cjs +9 -9
- package/batteries/skills.mjs +9 -9
- package/batteries/specialists/stt/transformers_js.cjs +1 -1
- package/batteries/specialists/stt/transformers_js.mjs +1 -1
- package/batteries/specialists/stt.cjs +1 -1
- package/batteries/specialists/stt.mjs +1 -1
- package/batteries/specialists.cjs +1 -1
- package/batteries/specialists.mjs +1 -1
- package/batteries/tools/_shared.cjs +2 -2
- package/batteries/tools/_shared.mjs +2 -2
- package/batteries/tools/color.cjs +2 -2
- package/batteries/tools/color.mjs +2 -2
- package/batteries/tools/comparison.cjs +2 -2
- package/batteries/tools/comparison.mjs +2 -2
- package/batteries/tools/data_structure.cjs +2 -2
- package/batteries/tools/data_structure.mjs +2 -2
- 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 +2 -2
- package/batteries/tools/encoding.mjs +2 -2
- package/batteries/tools/formatting.cjs +2 -2
- package/batteries/tools/formatting.mjs +2 -2
- package/batteries/tools/geo_basics.cjs +2 -2
- package/batteries/tools/geo_basics.mjs +2 -2
- package/batteries/tools/math.cjs +2 -2
- package/batteries/tools/math.mjs +2 -2
- package/batteries/tools/memory.cjs +4 -4
- package/batteries/tools/memory.mjs +4 -4
- package/batteries/tools/parsing.cjs +3 -3
- package/batteries/tools/parsing.mjs +3 -3
- package/batteries/tools/retrievables.cjs +4 -4
- package/batteries/tools/retrievables.mjs +4 -4
- package/batteries/tools/scrapper.cjs +1 -1
- package/batteries/tools/scrapper.mjs +1 -1
- package/batteries/tools/searxng.cjs +1 -1
- package/batteries/tools/searxng.mjs +1 -1
- package/batteries/tools/standing_instructions.cjs +3 -3
- package/batteries/tools/standing_instructions.mjs +3 -3
- package/batteries/tools/statistics.cjs +3 -3
- package/batteries/tools/statistics.mjs +3 -3
- package/batteries/tools/string_processing.cjs +2 -2
- package/batteries/tools/string_processing.mjs +2 -2
- package/batteries/tools/structured_data.cjs +2 -2
- package/batteries/tools/structured_data.mjs +2 -2
- 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/tools.cjs +2 -2
- package/batteries/tools.mjs +2 -2
- package/batteries/validation.cjs +5 -5
- package/batteries/validation.mjs +5 -5
- package/batteries/vector/conformance.cjs +59 -0
- package/batteries/vector/conformance.cjs.map +1 -1
- package/batteries/vector/conformance.mjs +59 -0
- package/batteries/vector/conformance.mjs.map +1 -1
- package/batteries/vector/lancedb.cjs +1 -1
- package/batteries/vector/lancedb.cjs.map +1 -1
- package/batteries/vector/lancedb.mjs +1 -1
- package/batteries/vector/lancedb.mjs.map +1 -1
- package/batteries/vector/retrievable.cjs +1 -1
- package/batteries/vector/retrievable.mjs +1 -1
- package/batteries/vector/sqlite_vec/index.d.ts +1 -1
- package/batteries/vector/sqlite_vec.cjs +19 -30
- package/batteries/vector/sqlite_vec.cjs.map +1 -1
- package/batteries/vector/sqlite_vec.mjs +20 -31
- package/batteries/vector/sqlite_vec.mjs.map +1 -1
- package/batteries.cjs +6 -6
- package/batteries.mjs +6 -6
- package/{chat_common-4huaTp6d.cjs → chat_common-CNayzS1V.cjs} +2 -2
- package/{chat_common-4huaTp6d.cjs.map → chat_common-CNayzS1V.cjs.map} +1 -1
- package/{chat_common-D_XGNjcK.mjs → chat_common-DKw8FDol.mjs} +2 -2
- package/{chat_common-D_XGNjcK.mjs.map → chat_common-DKw8FDol.mjs.map} +1 -1
- package/{common-BiRzOsxe.cjs → common-CqetsItm.cjs} +7 -7
- package/{common-BiRzOsxe.cjs.map → common-CqetsItm.cjs.map} +1 -1
- package/{common-DsLvTGmm.mjs → common-oI1niK9Z.mjs} +7 -7
- package/{common-DsLvTGmm.mjs.map → common-oI1niK9Z.mjs.map} +1 -1
- package/common.cjs +7 -7
- package/common.mjs +7 -7
- package/{dispatch_runner-DDH_dGPU.mjs → dispatch_runner-BZDXUe0G.mjs} +4 -4
- package/{dispatch_runner-DDH_dGPU.mjs.map → dispatch_runner-BZDXUe0G.mjs.map} +1 -1
- package/{dispatch_runner-C5S3KCqH.cjs → dispatch_runner-DDUxXJC3.cjs} +4 -4
- package/{dispatch_runner-C5S3KCqH.cjs.map → dispatch_runner-DDUxXJC3.cjs.map} +1 -1
- package/dispatch_runner.cjs +1 -1
- package/dispatch_runner.mjs +1 -1
- package/{ecmascript-CWLZ7bCX.mjs → ecmascript-B9Z2C24U.mjs} +5 -5
- package/{ecmascript-CWLZ7bCX.mjs.map → ecmascript-B9Z2C24U.mjs.map} +1 -1
- package/{ecmascript-BGr_0Dwn.cjs → ecmascript-BYfmjg7y.cjs} +5 -5
- package/{ecmascript-BGr_0Dwn.cjs.map → ecmascript-BYfmjg7y.cjs.map} +1 -1
- package/eslint/rules.cjs +1 -1
- package/eslint/rules.mjs +1 -1
- package/eslint.cjs +3 -3
- package/eslint.mjs +3 -3
- package/exceptions.cjs +1 -1
- package/exceptions.mjs +1 -1
- package/forge.cjs +2 -2
- package/forge.mjs +2 -2
- package/guards.cjs +7 -7
- package/guards.mjs +7 -7
- package/{helpers-BPi_iwxv.cjs → helpers-DPlh_7Bn.cjs} +3 -3
- package/{helpers-BPi_iwxv.cjs.map → helpers-DPlh_7Bn.cjs.map} +1 -1
- package/{helpers-D47G8WQb.mjs → helpers-mbn_EsDV.mjs} +3 -3
- package/{helpers-D47G8WQb.mjs.map → helpers-mbn_EsDV.mjs.map} +1 -1
- package/index.cjs +11 -11
- package/index.mjs +11 -11
- package/{isolation-B2FgKbap.cjs → isolation-B01xCIoV.cjs} +2 -2
- package/{isolation-B2FgKbap.cjs.map → isolation-B01xCIoV.cjs.map} +1 -1
- package/{isolation-BRGpiU-K.mjs → isolation-CO0NiK8R.mjs} +2 -2
- package/{isolation-BRGpiU-K.mjs.map → isolation-CO0NiK8R.mjs.map} +1 -1
- package/{manifest-B5bWMHgj.mjs → manifest-D8UTRohY.mjs} +2 -2
- package/{manifest-B5bWMHgj.mjs.map → manifest-D8UTRohY.mjs.map} +1 -1
- package/{manifest-Chjh-3s1.cjs → manifest-IP1IOJcg.cjs} +2 -2
- package/{manifest-Chjh-3s1.cjs.map → manifest-IP1IOJcg.cjs.map} +1 -1
- package/mcp/adk-docs-corpus.json +2 -2
- package/package.json +538 -538
- package/{predicates-C9jl2QPZ.cjs → predicates-Bzaa7gNI.cjs} +2 -2
- package/{predicates-C9jl2QPZ.cjs.map → predicates-Bzaa7gNI.cjs.map} +1 -1
- package/{predicates-2dZQ82LY.mjs → predicates-CM27Z3TF.mjs} +2 -2
- package/{predicates-2dZQ82LY.mjs.map → predicates-CM27Z3TF.mjs.map} +1 -1
- package/{retrievable-ReauMJxJ.cjs → retrievable-Bq-O3k6r.cjs} +3 -3
- package/{retrievable-ReauMJxJ.cjs.map → retrievable-Bq-O3k6r.cjs.map} +1 -1
- package/{retrievable-mFgC1aty.mjs → retrievable-CXTAUuuv.mjs} +3 -3
- package/{retrievable-mFgC1aty.mjs.map → retrievable-CXTAUuuv.mjs.map} +1 -1
- package/{scrapper-BsEY0Wo6.cjs → scrapper-B8xG9lTD.cjs} +5 -5
- package/{scrapper-BsEY0Wo6.cjs.map → scrapper-B8xG9lTD.cjs.map} +1 -1
- package/{scrapper-bShwZxKP.mjs → scrapper-DiQ5FfDL.mjs} +5 -5
- package/{scrapper-bShwZxKP.mjs.map → scrapper-DiQ5FfDL.mjs.map} +1 -1
- package/{searxng-CAY-bOMl.mjs → searxng-BFTJ6rTE.mjs} +5 -5
- package/{searxng-CAY-bOMl.mjs.map → searxng-BFTJ6rTE.mjs.map} +1 -1
- package/{searxng-CLF0vBMT.cjs → searxng-EJhWRnIE.cjs} +5 -5
- package/{searxng-CLF0vBMT.cjs.map → searxng-EJhWRnIE.cjs.map} +1 -1
- package/server.json +2 -2
- package/skills/adk-assembly/SKILL.md +2 -2
- package/{spooled_artifact-CFjf6ULg.cjs → spooled_artifact---DmicFW.cjs} +384 -384
- package/spooled_artifact---DmicFW.cjs.map +1 -0
- package/{spooled_artifact-B710Rb0d.mjs → spooled_artifact-Bw_7swIp.mjs} +385 -385
- package/spooled_artifact-Bw_7swIp.mjs.map +1 -0
- package/spooled_artifact.cjs +2 -2
- package/spooled_artifact.mjs +2 -2
- package/{spooled_markdown_artifact-PWppwnPQ.cjs → spooled_markdown_artifact-Rjzj-kyh.cjs} +3 -3
- package/{spooled_markdown_artifact-PWppwnPQ.cjs.map → spooled_markdown_artifact-Rjzj-kyh.cjs.map} +1 -1
- package/{spooled_markdown_artifact-1C4mmi73.mjs → spooled_markdown_artifact-vd6eNtIP.mjs} +3 -3
- package/{spooled_markdown_artifact-1C4mmi73.mjs.map → spooled_markdown_artifact-vd6eNtIP.mjs.map} +1 -1
- package/{thought-BKXwUZoq.mjs → thought-CxSaF6Xf.mjs} +3 -3
- package/{thought-BKXwUZoq.mjs.map → thought-CxSaF6Xf.mjs.map} +1 -1
- package/{thought-D5fJsxBW.cjs → thought-Dp3sMWW6.cjs} +3 -3
- package/{thought-D5fJsxBW.cjs.map → thought-Dp3sMWW6.cjs.map} +1 -1
- package/{tokenizable-DDIdXbJN.cjs → tokenizable-BcodRtoW.cjs} +29 -29
- package/{tokenizable-DDIdXbJN.cjs.map → tokenizable-BcodRtoW.cjs.map} +1 -1
- package/{tokenizable-xPXj1AQX.mjs → tokenizable-VB4Av8GF.mjs} +30 -30
- package/{tokenizable-xPXj1AQX.mjs.map → tokenizable-VB4Av8GF.mjs.map} +1 -1
- package/{tool_call-CDV5pW13.cjs → tool_call-B9px4W9k.cjs} +3 -3
- package/{tool_call-CDV5pW13.cjs.map → tool_call-B9px4W9k.cjs.map} +1 -1
- package/{tool_call-D-LqMvpU.mjs → tool_call-Cfaj-6zK.mjs} +3 -3
- package/{tool_call-D-LqMvpU.mjs.map → tool_call-Cfaj-6zK.mjs.map} +1 -1
- package/{tools-CvCMdAd7.mjs → tools-D0MBDh2R.mjs} +6 -6
- package/{tools-CvCMdAd7.mjs.map → tools-D0MBDh2R.mjs.map} +1 -1
- package/{tools-CACuuMV4.cjs → tools-aNbi6JyA.cjs} +6 -6
- package/{tools-CACuuMV4.cjs.map → tools-aNbi6JyA.cjs.map} +1 -1
- package/{toon-CCjuuzd_.mjs → toon-BSTQnHed.mjs} +6 -6
- package/{toon-CCjuuzd_.mjs.map → toon-BSTQnHed.mjs.map} +1 -1
- package/{toon-B7Q9RWJF.cjs → toon-DmLwZ6H1.cjs} +6 -6
- package/{toon-B7Q9RWJF.cjs.map → toon-DmLwZ6H1.cjs.map} +1 -1
- package/{transformers_js-DM01eAzh.cjs → transformers_js-7OzeS_Tp.cjs} +2 -2
- package/{transformers_js-DM01eAzh.cjs.map → transformers_js-7OzeS_Tp.cjs.map} +1 -1
- package/{transformers_js-BR2Ov0Su.mjs → transformers_js-p3lAkHFH.mjs} +2 -2
- package/{transformers_js-BR2Ov0Su.mjs.map → transformers_js-p3lAkHFH.mjs.map} +1 -1
- package/{turn_runner-BgPw9uqb.mjs → turn_runner-BHHD6h77.mjs} +4 -4
- package/{turn_runner-BgPw9uqb.mjs.map → turn_runner-BHHD6h77.mjs.map} +1 -1
- package/{turn_runner-CP2zxSlu.cjs → turn_runner-Dj7JsUTQ.cjs} +4 -4
- package/{turn_runner-CP2zxSlu.cjs.map → turn_runner-Dj7JsUTQ.cjs.map} +1 -1
- package/turn_runner.cjs +1 -1
- package/turn_runner.mjs +1 -1
- package/{xml-BqTTIFhv.mjs → xml-CYseDztH.mjs} +6 -6
- package/{xml-BqTTIFhv.mjs.map → xml-CYseDztH.mjs.map} +1 -1
- package/{xml-viE54OTe.cjs → xml-zJul8jMQ.cjs} +6 -6
- package/{xml-viE54OTe.cjs.map → xml-zJul8jMQ.cjs.map} +1 -1
- package/{yaml-B1So-pUR.mjs → yaml-BPBoiOjx.mjs} +6 -6
- package/{yaml-B1So-pUR.mjs.map → yaml-BPBoiOjx.mjs.map} +1 -1
- package/{yaml-cGhhPyZq.cjs → yaml-D0PzoRAr.cjs} +6 -6
- package/{yaml-cGhhPyZq.cjs.map → yaml-D0PzoRAr.cjs.map} +1 -1
- package/artifact_methods-9BemAvd4.mjs +0 -1
- package/artifact_methods-FKgk4q_1.cjs +0 -1
- package/spooled_artifact-B710Rb0d.mjs.map +0 -1
- package/spooled_artifact-CFjf6ULg.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conformance.cjs","names":[],"sources":["../../../src/batteries/vector/conformance/index.ts"],"sourcesContent":["/**\n * Shared conformance suite for vector-store adapters. Drive any adapter through\n * {@link runVectorStoreConformance} to verify it honours the same contract all shipped adapters do.\n * Public, deep-import-only (`@nhtio/adk/batteries/vector/conformance`). The suite has no test-runner\n * dependency: callers invoke it and await the returned promise from any test framework.\n *\n * @module @nhtio/adk/batteries/vector/conformance\n */\n\nimport type { CallableVectorStore } from '../contract'\n\n/** A deterministic stub encoder producing a 3-dim vector from simple text features. */\nexport const stubEncoder = async (\n texts: string[],\n _kind: 'query' | 'document'\n): Promise<number[][]> =>\n texts.map((tx) => [tx.length, tx.includes('cat') ? 1 : 0, tx.includes('dog') ? 1 : 0])\n\n/**\n * A dimension-padding encoder factory: wraps {@link stubEncoder} and zero-extends to `dim`. Used by\n * backends that enforce a minimum dimension (e.g. Cloudflare Vectorize requires 32–1536).\n */\nexport const paddedStubEncoder =\n (dim: number) =>\n async (texts: string[], kind: 'query' | 'document'): Promise<number[][]> => {\n const base = await stubEncoder(texts, kind)\n return base.map((v) => padVector(v, dim))\n }\n\n// Zero-extend (or truncate) a vector to exactly `dim` entries. dim===3 (the default) returns the\n// vector unchanged, so existing callers are byte-for-byte identical.\nconst padVector = (v: number[], dim: number): number[] => {\n if (v.length === dim) return v\n if (v.length > dim) return v.slice(0, dim)\n return [...v, ...new Array(dim - v.length).fill(0)]\n}\n\n/**\n * Drive a vector-store adapter through the shared contract suite.\n *\n * @remarks\n * `makeStore` must return an already-connected store whose `'docs'` collection is created at the\n * matching dimension; it is re-invoked per test so retries are self-contained. `dim` defaults to 3\n * — pass a larger value for backends with a dimension floor (the harness pads every test vector to\n * `dim`). `opts.retry` / `opts.timeout` are forwarded to every `it()` (defaults: retry 0, 5s) and\n * exist for aggressively eventually-consistent managed backends whose read-after-write can flap for\n * seconds — a retried attempt re-runs `makeStore()` against an index that has had more time to\n * settle, without weakening any assertion.\n *\n * @param label - Human-readable label for the suite (the adapter name).\n * @param makeStore - Factory returning a fresh, connected store with the `'docs'` collection.\n * @param dim - Vector dimensionality the harness pads to (default 3).\n * @param opts - Per-`it` retry/timeout overrides.\n */\nconst assert: (condition: boolean, message: string) => asserts condition = (condition, message) => {\n if (!condition) throw new Error(message)\n}\nconst equal = (actual: unknown, expected: unknown): boolean => {\n if (actual === expected) return true\n if (\n actual === null ||\n expected === null ||\n typeof actual !== 'object' ||\n typeof expected !== 'object'\n )\n return false\n if (Array.isArray(actual) !== Array.isArray(expected)) return false\n const actualRecord = actual as Record<string, unknown>\n const expectedRecord = expected as Record<string, unknown>\n const keysA = Object.keys(actualRecord)\n const keysB = Object.keys(expectedRecord)\n if (keysA.length !== keysB.length) return false\n return keysA.every(\n (key) => Object.hasOwn(expectedRecord, key) && equal(actualRecord[key], expectedRecord[key])\n )\n}\nconst match = (actual: unknown, expected: unknown): boolean => {\n if (expected === null || typeof expected !== 'object') return equal(actual, expected)\n if (actual === null || typeof actual !== 'object') return false\n return Object.entries(expected).every(([key, value]) =>\n match((actual as Record<string, unknown>)[key], value)\n )\n}\nconst expectValue = (actual: unknown) => ({\n toBe: (expected: unknown) =>\n assert(equal(actual, expected), `expected ${String(actual)} to be ${String(expected)}`),\n toEqual: (expected: unknown) => assert(equal(actual, expected), 'values were not equal'),\n toMatchObject: (expected: unknown) =>\n assert(match(actual, expected), 'value did not match expected object'),\n toBeDefined: () => assert(actual !== undefined, 'value was undefined'),\n toBeUndefined: () => assert(actual === undefined, 'value was defined'),\n toHaveLength: (length: number) =>\n assert((actual as { length: number }).length === length, 'unexpected length'),\n rejects: {\n toThrow: async () => {\n try {\n await (actual as Promise<unknown>)\n } catch {\n return\n }\n throw new Error('expected promise to reject')\n },\n },\n})\n\n/**\n * Run the framework-free vector-store conformance suite against a consumer implementation.\n *\n * Each check creates a fresh store through `makeStore`; the returned promise rejects when any\n * contract assertion fails. Consumers can await this function from any test runner without\n * importing a test framework from the conformance module.\n *\n * @param label - Human-readable name used to identify the implementation under test.\n * @param makeStore - Factory returning a fresh, connected store with the `docs` collection.\n * @param dim - Vector dimensionality used by the suite (defaults to 3).\n * @param opts - Retry count and per-attempt timeout in milliseconds for eventually consistent stores.\n */\nexport const runVectorStoreConformance = async (\n label: string,\n makeStore: () => Promise<CallableVectorStore>,\n dim = 3,\n opts: { retry?: number; timeout?: number } = {}\n): Promise<void> => {\n const p = (v: number[]): number[] => padVector(v, dim)\n const pending: Array<() => Promise<void>> = []\n const retry = opts.retry ?? 0\n const timeout = opts.timeout ?? 5000\n const runCase = async (test: () => Promise<void>): Promise<void> => {\n let last: unknown\n for (let attempt = 0; attempt <= retry; attempt++) {\n let timedOut = false\n const operation = Promise.resolve().then(test)\n let timer: ReturnType<typeof setTimeout> | undefined\n const deadline = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n timedOut = true\n reject(new Error(`conformance check timed out after ${timeout}ms`))\n }, timeout)\n })\n try {\n await Promise.race([operation, deadline])\n return\n } catch (error) {\n // A timeout cannot cancel an arbitrary backend operation. Drain it before retrying so a\n // late write/read from this attempt cannot race the fresh store made by the next attempt.\n if (timedOut) {\n last = error\n break\n }\n last = error\n } finally {\n if (timer !== undefined) clearTimeout(timer)\n }\n }\n throw last\n }\n const it = (_name: string, _io: unknown, test: () => Promise<void>) => {\n pending.push(() => runCase(test))\n }\n const describe = (_name: string, suite: () => void) => suite()\n const expect = expectValue\n const io = undefined\n describe('conformance: ' + label, () => {\n it('upserts vectors and searches by nearVector with [0,1] score', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([\n { id: '1', vector: p([3, 1, 0]), metadata: { kind: 'animal' } },\n { id: '2', vector: p([3, 0, 1]), metadata: { kind: 'animal' } },\n ])\n const res = await vs('docs')\n .nearVector(p([3, 1, 0]))\n .select('id', 'score')\n .limit(2)\n expect(res.length).toBe(2)\n expect(res[0].id).toBeDefined()\n expect(typeof res[0].score).toBe('number')\n expect(res[0].score! >= 0 && res[0].score! <= 1).toBe(true)\n })\n it('encodes text on upsert+nearText when an encoder is configured', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: 'c', document: 'cat', metadata: {} }])\n const res = await vs('docs').nearText('cat').select('id').limit(1)\n expect(res.length).toBe(1)\n expect(res[0].id).toBe('c')\n })\n it('requires .select() on reads', io, async () => {\n const vs = await makeStore()\n await expect(\n (async () => {\n await vs('docs').nearVector(p([1, 1, 1]))\n })()\n ).rejects.toThrow()\n })\n it('filter-scan (no near) returns rows without score', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: '1', vector: p([1, 0, 0]), metadata: { kind: 'x' } }])\n const res = await vs('docs').where('kind', 'x').select('id', 'metadata').limit(10)\n expect(res.length).toBe(1)\n expect(res[0].score).toBeUndefined()\n })\n it('nested filter A AND (B OR C) selects the right subset', io, async () => {\n const vs = await makeStore()\n // Every record carries all three fields so the test probes nested AND/OR routing, not\n // backend-specific missing-field semantics (e.g. Chroma's $or excludes records missing a\n // referenced key, where the JS evaluator treats that clause as merely false).\n await vs('docs').upsert([\n { id: 'a', vector: p([1, 0, 0]), metadata: { kind: 'doc', year: 2024, pinned: false } }, // kept (year arm)\n { id: 'b', vector: p([0, 1, 0]), metadata: { kind: 'doc', year: 2010, pinned: false } }, // dropped (neither arm)\n { id: 'c', vector: p([0, 0, 1]), metadata: { kind: 'doc', year: 2010, pinned: true } }, // kept (pinned arm)\n { id: 'd', vector: p([1, 1, 0]), metadata: { kind: 'other', year: 2024, pinned: true } }, // dropped (kind mismatch)\n ])\n // kind = 'doc' AND (year >= 2024 OR pinned = true)\n const res = await vs('docs')\n .where('kind', 'doc')\n .andWhere((qb) => qb.where('year', '>=', 2024).orWhere('pinned', true))\n .select('id')\n .limit(10)\n expect(res.map((r) => r.id).sort()).toEqual(['a', 'c'])\n })\n it('projection: vector excluded unless selected', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: '1', vector: p([1, 0, 0]) }])\n const noVec = await vs('docs')\n .nearVector(p([1, 0, 0]))\n .select('id')\n .limit(1)\n expect(noVec[0].vector).toBeUndefined()\n const withVec = await vs('docs')\n .nearVector(p([1, 0, 0]))\n .select('id', 'vector')\n .limit(1)\n expect(Array.isArray(withVec[0].vector)).toBe(true)\n })\n it('deletes by id', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([\n { id: '1', vector: p([1, 0, 0]) },\n { id: '2', vector: p([0, 1, 0]) },\n ])\n await vs('docs').whereIn('id', ['1']).delete()\n const all = await vs('docs').select('id').limit(10)\n expect(all.length).toBe(1)\n })\n it('throws transaction-unsupported when capabilities.transactions is false', io, async () => {\n const vs = await makeStore()\n if (!vs.capabilities.transactions) {\n await expect(vs.transaction(async () => {})).rejects.toThrow()\n }\n })\n })\n for (const fn of pending) {\n await fn()\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"conformance.cjs","names":[],"sources":["../../../src/batteries/vector/conformance/index.ts"],"sourcesContent":["/**\n * Shared conformance suite for vector-store adapters. Drive any adapter through\n * {@link runVectorStoreConformance} to verify it honours the same contract all shipped adapters do.\n * Public, deep-import-only (`@nhtio/adk/batteries/vector/conformance`). The suite has no test-runner\n * dependency: callers invoke it and await the returned promise from any test framework.\n *\n * @module @nhtio/adk/batteries/vector/conformance\n */\n\nimport type { CallableVectorStore } from '../contract'\n\n/** A deterministic stub encoder producing a 3-dim vector from simple text features. */\nexport const stubEncoder = async (\n texts: string[],\n _kind: 'query' | 'document'\n): Promise<number[][]> =>\n texts.map((tx) => [tx.length, tx.includes('cat') ? 1 : 0, tx.includes('dog') ? 1 : 0])\n\n/**\n * A dimension-padding encoder factory: wraps {@link stubEncoder} and zero-extends to `dim`. Used by\n * backends that enforce a minimum dimension (e.g. Cloudflare Vectorize requires 32–1536).\n */\nexport const paddedStubEncoder =\n (dim: number) =>\n async (texts: string[], kind: 'query' | 'document'): Promise<number[][]> => {\n const base = await stubEncoder(texts, kind)\n return base.map((v) => padVector(v, dim))\n }\n\n// Zero-extend (or truncate) a vector to exactly `dim` entries. dim===3 (the default) returns the\n// vector unchanged, so existing callers are byte-for-byte identical.\nconst padVector = (v: number[], dim: number): number[] => {\n if (v.length === dim) return v\n if (v.length > dim) return v.slice(0, dim)\n return [...v, ...new Array(dim - v.length).fill(0)]\n}\n\n/**\n * Drive a vector-store adapter through the shared contract suite.\n *\n * @remarks\n * `makeStore` must return an already-connected store whose `'docs'` collection is created at the\n * matching dimension; it is re-invoked per test so retries are self-contained. `dim` defaults to 3\n * — pass a larger value for backends with a dimension floor (the harness pads every test vector to\n * `dim`). `opts.retry` / `opts.timeout` are forwarded to every `it()` (defaults: retry 0, 5s) and\n * exist for aggressively eventually-consistent managed backends whose read-after-write can flap for\n * seconds — a retried attempt re-runs `makeStore()` against an index that has had more time to\n * settle, without weakening any assertion.\n *\n * @param label - Human-readable label for the suite (the adapter name).\n * @param makeStore - Factory returning a fresh, connected store with the `'docs'` collection.\n * @param dim - Vector dimensionality the harness pads to (default 3).\n * @param opts - Per-`it` retry/timeout overrides.\n */\nconst assert: (condition: boolean, message: string) => asserts condition = (condition, message) => {\n if (!condition) throw new Error(message)\n}\nconst equal = (actual: unknown, expected: unknown): boolean => {\n if (actual === expected) return true\n if (\n actual === null ||\n expected === null ||\n typeof actual !== 'object' ||\n typeof expected !== 'object'\n )\n return false\n if (Array.isArray(actual) !== Array.isArray(expected)) return false\n const actualRecord = actual as Record<string, unknown>\n const expectedRecord = expected as Record<string, unknown>\n const keysA = Object.keys(actualRecord)\n const keysB = Object.keys(expectedRecord)\n if (keysA.length !== keysB.length) return false\n return keysA.every(\n (key) => Object.hasOwn(expectedRecord, key) && equal(actualRecord[key], expectedRecord[key])\n )\n}\nconst match = (actual: unknown, expected: unknown): boolean => {\n if (expected === null || typeof expected !== 'object') return equal(actual, expected)\n if (actual === null || typeof actual !== 'object') return false\n return Object.entries(expected).every(([key, value]) =>\n match((actual as Record<string, unknown>)[key], value)\n )\n}\nconst expectValue = (actual: unknown) => ({\n toBe: (expected: unknown) =>\n assert(equal(actual, expected), `expected ${String(actual)} to be ${String(expected)}`),\n toEqual: (expected: unknown) => assert(equal(actual, expected), 'values were not equal'),\n toMatchObject: (expected: unknown) =>\n assert(match(actual, expected), 'value did not match expected object'),\n toBeDefined: () => assert(actual !== undefined, 'value was undefined'),\n toBeUndefined: () => assert(actual === undefined, 'value was defined'),\n toHaveLength: (length: number) =>\n assert((actual as { length: number }).length === length, 'unexpected length'),\n rejects: {\n toThrow: async () => {\n try {\n await (actual as Promise<unknown>)\n } catch {\n return\n }\n throw new Error('expected promise to reject')\n },\n },\n})\n\n/**\n * Run the framework-free vector-store conformance suite against a consumer implementation.\n *\n * Each check creates a fresh store through `makeStore`; the returned promise rejects when any\n * contract assertion fails. Consumers can await this function from any test runner without\n * importing a test framework from the conformance module.\n *\n * @param label - Human-readable name used to identify the implementation under test.\n * @param makeStore - Factory returning a fresh, connected store with the `docs` collection.\n * @param dim - Vector dimensionality used by the suite (defaults to 3).\n * @param opts - Retry count and per-attempt timeout in milliseconds for eventually consistent stores.\n */\nexport const runVectorStoreConformance = async (\n label: string,\n makeStore: () => Promise<CallableVectorStore>,\n dim = 3,\n opts: { retry?: number; timeout?: number } = {}\n): Promise<void> => {\n const p = (v: number[]): number[] => padVector(v, dim)\n const pending: Array<() => Promise<void>> = []\n const retry = opts.retry ?? 0\n const timeout = opts.timeout ?? 5000\n const runCase = async (test: () => Promise<void>): Promise<void> => {\n let last: unknown\n for (let attempt = 0; attempt <= retry; attempt++) {\n let timedOut = false\n const operation = Promise.resolve().then(test)\n let timer: ReturnType<typeof setTimeout> | undefined\n const deadline = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n timedOut = true\n reject(new Error(`conformance check timed out after ${timeout}ms`))\n }, timeout)\n })\n try {\n await Promise.race([operation, deadline])\n return\n } catch (error) {\n // A timeout cannot cancel an arbitrary backend operation. Drain it before retrying so a\n // late write/read from this attempt cannot race the fresh store made by the next attempt.\n if (timedOut) {\n last = error\n break\n }\n last = error\n } finally {\n if (timer !== undefined) clearTimeout(timer)\n }\n }\n throw last\n }\n const it = (_name: string, _io: unknown, test: () => Promise<void>) => {\n pending.push(() => runCase(test))\n }\n const describe = (_name: string, suite: () => void) => suite()\n const expect = expectValue\n const io = undefined\n describe('conformance: ' + label, () => {\n it('upserts vectors and searches by nearVector with [0,1] score', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([\n { id: '1', vector: p([3, 1, 0]), metadata: { kind: 'animal' } },\n { id: '2', vector: p([3, 0, 1]), metadata: { kind: 'animal' } },\n ])\n const res = await vs('docs')\n .nearVector(p([3, 1, 0]))\n .select('id', 'score')\n .limit(2)\n expect(res.length).toBe(2)\n expect(res[0].id).toBeDefined()\n expect(typeof res[0].score).toBe('number')\n expect(res[0].score! >= 0 && res[0].score! <= 1).toBe(true)\n })\n it('encodes text on upsert+nearText when an encoder is configured', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: 'c', document: 'cat', metadata: {} }])\n const res = await vs('docs').nearText('cat').select('id').limit(1)\n expect(res.length).toBe(1)\n expect(res[0].id).toBe('c')\n })\n it('requires .select() on reads', io, async () => {\n const vs = await makeStore()\n await expect(\n (async () => {\n await vs('docs').nearVector(p([1, 1, 1]))\n })()\n ).rejects.toThrow()\n })\n it('filter-scan (no near) returns rows without score', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: '1', vector: p([1, 0, 0]), metadata: { kind: 'x' } }])\n const res = await vs('docs').where('kind', 'x').select('id', 'metadata').limit(10)\n expect(res.length).toBe(1)\n expect(res[0].score).toBeUndefined()\n })\n it('nested filter A AND (B OR C) selects the right subset', io, async () => {\n const vs = await makeStore()\n // Every record carries all three fields so the test probes nested AND/OR routing, not\n // backend-specific missing-field semantics (e.g. Chroma's $or excludes records missing a\n // referenced key, where the JS evaluator treats that clause as merely false).\n await vs('docs').upsert([\n { id: 'a', vector: p([1, 0, 0]), metadata: { kind: 'doc', year: 2024, pinned: false } }, // kept (year arm)\n { id: 'b', vector: p([0, 1, 0]), metadata: { kind: 'doc', year: 2010, pinned: false } }, // dropped (neither arm)\n { id: 'c', vector: p([0, 0, 1]), metadata: { kind: 'doc', year: 2010, pinned: true } }, // kept (pinned arm)\n { id: 'd', vector: p([1, 1, 0]), metadata: { kind: 'other', year: 2024, pinned: true } }, // dropped (kind mismatch)\n ])\n // kind = 'doc' AND (year >= 2024 OR pinned = true)\n const res = await vs('docs')\n .where('kind', 'doc')\n .andWhere((qb) => qb.where('year', '>=', 2024).orWhere('pinned', true))\n .select('id')\n .limit(10)\n expect(res.map((r) => r.id).sort()).toEqual(['a', 'c'])\n })\n it('projection: vector excluded unless selected', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: '1', vector: p([1, 0, 0]) }])\n const noVec = await vs('docs')\n .nearVector(p([1, 0, 0]))\n .select('id')\n .limit(1)\n expect(noVec[0].vector).toBeUndefined()\n const withVec = await vs('docs')\n .nearVector(p([1, 0, 0]))\n .select('id', 'vector')\n .limit(1)\n expect(Array.isArray(withVec[0].vector)).toBe(true)\n })\n it('deletes by id', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([\n { id: '1', vector: p([1, 0, 0]) },\n { id: '2', vector: p([0, 1, 0]) },\n ])\n await vs('docs').whereIn('id', ['1']).delete()\n const all = await vs('docs').select('id').limit(10)\n expect(all.length).toBe(1)\n })\n it('throws transaction-unsupported when capabilities.transactions is false', io, async () => {\n const vs = await makeStore()\n if (!vs.capabilities.transactions) {\n await expect(vs.transaction(async () => {})).rejects.toThrow()\n }\n })\n it('renameCollection: honours capabilities.rename', io, async () => {\n const vs = await makeStore()\n if (vs.capabilities.rename) {\n await vs.schema.dropCollectionIfExists('docs_renamed')\n let bodyFailed = false\n let bodyError: unknown\n try {\n await vs('docs').upsert([\n { id: '1', vector: p([3, 1, 0]) },\n { id: '2', vector: p([3, 0, 1]) },\n ])\n await vs.schema.renameCollection('docs', 'docs_renamed')\n expect(await vs.schema.hasCollection('docs')).toBe(false)\n expect(await vs.schema.hasCollection('docs_renamed')).toBe(true)\n const res = await vs('docs_renamed')\n .nearVector(p([3, 1, 0]))\n .select('id', 'score')\n .limit(2)\n expect(res.length).toBe(2)\n expect(res[0].id).toBe('1')\n expect(typeof res[0].score).toBe('number')\n expect(res[0].score! >= 0 && res[0].score! <= 1).toBe(true)\n await vs('docs_renamed').upsert([{ id: '3', vector: p([1, 1, 1]) }])\n const all = await vs('docs_renamed').select('id').limit(10)\n expect(all.map((r) => r.id).sort()).toEqual(['1', '2', '3'])\n } catch (e) {\n bodyFailed = true\n bodyError = e\n }\n // A cleanup failure here must never mask a real failure from the try block above: only\n // swallow it when the body already failed (there's nothing left to mask); otherwise let it\n // propagate, since a passing body followed by a broken cleanup is itself a real failure.\n try {\n await vs.schema.dropCollectionIfExists('docs_renamed')\n } catch (cleanupErr) {\n if (!bodyFailed) throw cleanupErr\n }\n if (bodyFailed) throw bodyError\n } else {\n await expect(vs.schema.renameCollection('docs', 'docs_renamed')).rejects.toThrow()\n }\n })\n })\n for (const fn of pending) {\n await fn()\n }\n}\n"],"mappings":"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"}
|
|
@@ -289,6 +289,65 @@ var runVectorStoreConformance = async (label, makeStore, dim = 3, opts = {}) =>
|
|
|
289
289
|
const vs = await makeStore();
|
|
290
290
|
if (!vs.capabilities.transactions) await expect(vs.transaction(async () => {})).rejects.toThrow();
|
|
291
291
|
});
|
|
292
|
+
it("renameCollection: honours capabilities.rename", io, async () => {
|
|
293
|
+
const vs = await makeStore();
|
|
294
|
+
if (vs.capabilities.rename) {
|
|
295
|
+
await vs.schema.dropCollectionIfExists("docs_renamed");
|
|
296
|
+
let bodyFailed = false;
|
|
297
|
+
let bodyError;
|
|
298
|
+
try {
|
|
299
|
+
await vs("docs").upsert([{
|
|
300
|
+
id: "1",
|
|
301
|
+
vector: p([
|
|
302
|
+
3,
|
|
303
|
+
1,
|
|
304
|
+
0
|
|
305
|
+
])
|
|
306
|
+
}, {
|
|
307
|
+
id: "2",
|
|
308
|
+
vector: p([
|
|
309
|
+
3,
|
|
310
|
+
0,
|
|
311
|
+
1
|
|
312
|
+
])
|
|
313
|
+
}]);
|
|
314
|
+
await vs.schema.renameCollection("docs", "docs_renamed");
|
|
315
|
+
expect(await vs.schema.hasCollection("docs")).toBe(false);
|
|
316
|
+
expect(await vs.schema.hasCollection("docs_renamed")).toBe(true);
|
|
317
|
+
const res = await vs("docs_renamed").nearVector(p([
|
|
318
|
+
3,
|
|
319
|
+
1,
|
|
320
|
+
0
|
|
321
|
+
])).select("id", "score").limit(2);
|
|
322
|
+
expect(res.length).toBe(2);
|
|
323
|
+
expect(res[0].id).toBe("1");
|
|
324
|
+
expect(typeof res[0].score).toBe("number");
|
|
325
|
+
expect(res[0].score >= 0 && res[0].score <= 1).toBe(true);
|
|
326
|
+
await vs("docs_renamed").upsert([{
|
|
327
|
+
id: "3",
|
|
328
|
+
vector: p([
|
|
329
|
+
1,
|
|
330
|
+
1,
|
|
331
|
+
1
|
|
332
|
+
])
|
|
333
|
+
}]);
|
|
334
|
+
expect((await vs("docs_renamed").select("id").limit(10)).map((r) => r.id).sort()).toEqual([
|
|
335
|
+
"1",
|
|
336
|
+
"2",
|
|
337
|
+
"3"
|
|
338
|
+
]);
|
|
339
|
+
} catch (e) {
|
|
340
|
+
bodyFailed = true;
|
|
341
|
+
bodyError = e;
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
await vs.schema.dropCollectionIfExists("docs_renamed");
|
|
345
|
+
} catch (cleanupErr) {
|
|
346
|
+
if (!bodyFailed) throw cleanupErr;
|
|
347
|
+
}
|
|
348
|
+
if (bodyFailed) throw bodyError;
|
|
349
|
+
} else await expect(vs.schema.renameCollection("docs", "docs_renamed")).rejects.toThrow();
|
|
350
|
+
});
|
|
292
351
|
});
|
|
293
352
|
for (const fn of pending) await fn();
|
|
294
353
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conformance.mjs","names":[],"sources":["../../../src/batteries/vector/conformance/index.ts"],"sourcesContent":["/**\n * Shared conformance suite for vector-store adapters. Drive any adapter through\n * {@link runVectorStoreConformance} to verify it honours the same contract all shipped adapters do.\n * Public, deep-import-only (`@nhtio/adk/batteries/vector/conformance`). The suite has no test-runner\n * dependency: callers invoke it and await the returned promise from any test framework.\n *\n * @module @nhtio/adk/batteries/vector/conformance\n */\n\nimport type { CallableVectorStore } from '../contract'\n\n/** A deterministic stub encoder producing a 3-dim vector from simple text features. */\nexport const stubEncoder = async (\n texts: string[],\n _kind: 'query' | 'document'\n): Promise<number[][]> =>\n texts.map((tx) => [tx.length, tx.includes('cat') ? 1 : 0, tx.includes('dog') ? 1 : 0])\n\n/**\n * A dimension-padding encoder factory: wraps {@link stubEncoder} and zero-extends to `dim`. Used by\n * backends that enforce a minimum dimension (e.g. Cloudflare Vectorize requires 32–1536).\n */\nexport const paddedStubEncoder =\n (dim: number) =>\n async (texts: string[], kind: 'query' | 'document'): Promise<number[][]> => {\n const base = await stubEncoder(texts, kind)\n return base.map((v) => padVector(v, dim))\n }\n\n// Zero-extend (or truncate) a vector to exactly `dim` entries. dim===3 (the default) returns the\n// vector unchanged, so existing callers are byte-for-byte identical.\nconst padVector = (v: number[], dim: number): number[] => {\n if (v.length === dim) return v\n if (v.length > dim) return v.slice(0, dim)\n return [...v, ...new Array(dim - v.length).fill(0)]\n}\n\n/**\n * Drive a vector-store adapter through the shared contract suite.\n *\n * @remarks\n * `makeStore` must return an already-connected store whose `'docs'` collection is created at the\n * matching dimension; it is re-invoked per test so retries are self-contained. `dim` defaults to 3\n * — pass a larger value for backends with a dimension floor (the harness pads every test vector to\n * `dim`). `opts.retry` / `opts.timeout` are forwarded to every `it()` (defaults: retry 0, 5s) and\n * exist for aggressively eventually-consistent managed backends whose read-after-write can flap for\n * seconds — a retried attempt re-runs `makeStore()` against an index that has had more time to\n * settle, without weakening any assertion.\n *\n * @param label - Human-readable label for the suite (the adapter name).\n * @param makeStore - Factory returning a fresh, connected store with the `'docs'` collection.\n * @param dim - Vector dimensionality the harness pads to (default 3).\n * @param opts - Per-`it` retry/timeout overrides.\n */\nconst assert: (condition: boolean, message: string) => asserts condition = (condition, message) => {\n if (!condition) throw new Error(message)\n}\nconst equal = (actual: unknown, expected: unknown): boolean => {\n if (actual === expected) return true\n if (\n actual === null ||\n expected === null ||\n typeof actual !== 'object' ||\n typeof expected !== 'object'\n )\n return false\n if (Array.isArray(actual) !== Array.isArray(expected)) return false\n const actualRecord = actual as Record<string, unknown>\n const expectedRecord = expected as Record<string, unknown>\n const keysA = Object.keys(actualRecord)\n const keysB = Object.keys(expectedRecord)\n if (keysA.length !== keysB.length) return false\n return keysA.every(\n (key) => Object.hasOwn(expectedRecord, key) && equal(actualRecord[key], expectedRecord[key])\n )\n}\nconst match = (actual: unknown, expected: unknown): boolean => {\n if (expected === null || typeof expected !== 'object') return equal(actual, expected)\n if (actual === null || typeof actual !== 'object') return false\n return Object.entries(expected).every(([key, value]) =>\n match((actual as Record<string, unknown>)[key], value)\n )\n}\nconst expectValue = (actual: unknown) => ({\n toBe: (expected: unknown) =>\n assert(equal(actual, expected), `expected ${String(actual)} to be ${String(expected)}`),\n toEqual: (expected: unknown) => assert(equal(actual, expected), 'values were not equal'),\n toMatchObject: (expected: unknown) =>\n assert(match(actual, expected), 'value did not match expected object'),\n toBeDefined: () => assert(actual !== undefined, 'value was undefined'),\n toBeUndefined: () => assert(actual === undefined, 'value was defined'),\n toHaveLength: (length: number) =>\n assert((actual as { length: number }).length === length, 'unexpected length'),\n rejects: {\n toThrow: async () => {\n try {\n await (actual as Promise<unknown>)\n } catch {\n return\n }\n throw new Error('expected promise to reject')\n },\n },\n})\n\n/**\n * Run the framework-free vector-store conformance suite against a consumer implementation.\n *\n * Each check creates a fresh store through `makeStore`; the returned promise rejects when any\n * contract assertion fails. Consumers can await this function from any test runner without\n * importing a test framework from the conformance module.\n *\n * @param label - Human-readable name used to identify the implementation under test.\n * @param makeStore - Factory returning a fresh, connected store with the `docs` collection.\n * @param dim - Vector dimensionality used by the suite (defaults to 3).\n * @param opts - Retry count and per-attempt timeout in milliseconds for eventually consistent stores.\n */\nexport const runVectorStoreConformance = async (\n label: string,\n makeStore: () => Promise<CallableVectorStore>,\n dim = 3,\n opts: { retry?: number; timeout?: number } = {}\n): Promise<void> => {\n const p = (v: number[]): number[] => padVector(v, dim)\n const pending: Array<() => Promise<void>> = []\n const retry = opts.retry ?? 0\n const timeout = opts.timeout ?? 5000\n const runCase = async (test: () => Promise<void>): Promise<void> => {\n let last: unknown\n for (let attempt = 0; attempt <= retry; attempt++) {\n let timedOut = false\n const operation = Promise.resolve().then(test)\n let timer: ReturnType<typeof setTimeout> | undefined\n const deadline = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n timedOut = true\n reject(new Error(`conformance check timed out after ${timeout}ms`))\n }, timeout)\n })\n try {\n await Promise.race([operation, deadline])\n return\n } catch (error) {\n // A timeout cannot cancel an arbitrary backend operation. Drain it before retrying so a\n // late write/read from this attempt cannot race the fresh store made by the next attempt.\n if (timedOut) {\n last = error\n break\n }\n last = error\n } finally {\n if (timer !== undefined) clearTimeout(timer)\n }\n }\n throw last\n }\n const it = (_name: string, _io: unknown, test: () => Promise<void>) => {\n pending.push(() => runCase(test))\n }\n const describe = (_name: string, suite: () => void) => suite()\n const expect = expectValue\n const io = undefined\n describe('conformance: ' + label, () => {\n it('upserts vectors and searches by nearVector with [0,1] score', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([\n { id: '1', vector: p([3, 1, 0]), metadata: { kind: 'animal' } },\n { id: '2', vector: p([3, 0, 1]), metadata: { kind: 'animal' } },\n ])\n const res = await vs('docs')\n .nearVector(p([3, 1, 0]))\n .select('id', 'score')\n .limit(2)\n expect(res.length).toBe(2)\n expect(res[0].id).toBeDefined()\n expect(typeof res[0].score).toBe('number')\n expect(res[0].score! >= 0 && res[0].score! <= 1).toBe(true)\n })\n it('encodes text on upsert+nearText when an encoder is configured', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: 'c', document: 'cat', metadata: {} }])\n const res = await vs('docs').nearText('cat').select('id').limit(1)\n expect(res.length).toBe(1)\n expect(res[0].id).toBe('c')\n })\n it('requires .select() on reads', io, async () => {\n const vs = await makeStore()\n await expect(\n (async () => {\n await vs('docs').nearVector(p([1, 1, 1]))\n })()\n ).rejects.toThrow()\n })\n it('filter-scan (no near) returns rows without score', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: '1', vector: p([1, 0, 0]), metadata: { kind: 'x' } }])\n const res = await vs('docs').where('kind', 'x').select('id', 'metadata').limit(10)\n expect(res.length).toBe(1)\n expect(res[0].score).toBeUndefined()\n })\n it('nested filter A AND (B OR C) selects the right subset', io, async () => {\n const vs = await makeStore()\n // Every record carries all three fields so the test probes nested AND/OR routing, not\n // backend-specific missing-field semantics (e.g. Chroma's $or excludes records missing a\n // referenced key, where the JS evaluator treats that clause as merely false).\n await vs('docs').upsert([\n { id: 'a', vector: p([1, 0, 0]), metadata: { kind: 'doc', year: 2024, pinned: false } }, // kept (year arm)\n { id: 'b', vector: p([0, 1, 0]), metadata: { kind: 'doc', year: 2010, pinned: false } }, // dropped (neither arm)\n { id: 'c', vector: p([0, 0, 1]), metadata: { kind: 'doc', year: 2010, pinned: true } }, // kept (pinned arm)\n { id: 'd', vector: p([1, 1, 0]), metadata: { kind: 'other', year: 2024, pinned: true } }, // dropped (kind mismatch)\n ])\n // kind = 'doc' AND (year >= 2024 OR pinned = true)\n const res = await vs('docs')\n .where('kind', 'doc')\n .andWhere((qb) => qb.where('year', '>=', 2024).orWhere('pinned', true))\n .select('id')\n .limit(10)\n expect(res.map((r) => r.id).sort()).toEqual(['a', 'c'])\n })\n it('projection: vector excluded unless selected', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: '1', vector: p([1, 0, 0]) }])\n const noVec = await vs('docs')\n .nearVector(p([1, 0, 0]))\n .select('id')\n .limit(1)\n expect(noVec[0].vector).toBeUndefined()\n const withVec = await vs('docs')\n .nearVector(p([1, 0, 0]))\n .select('id', 'vector')\n .limit(1)\n expect(Array.isArray(withVec[0].vector)).toBe(true)\n })\n it('deletes by id', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([\n { id: '1', vector: p([1, 0, 0]) },\n { id: '2', vector: p([0, 1, 0]) },\n ])\n await vs('docs').whereIn('id', ['1']).delete()\n const all = await vs('docs').select('id').limit(10)\n expect(all.length).toBe(1)\n })\n it('throws transaction-unsupported when capabilities.transactions is false', io, async () => {\n const vs = await makeStore()\n if (!vs.capabilities.transactions) {\n await expect(vs.transaction(async () => {})).rejects.toThrow()\n }\n })\n })\n for (const fn of pending) {\n await fn()\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"conformance.mjs","names":[],"sources":["../../../src/batteries/vector/conformance/index.ts"],"sourcesContent":["/**\n * Shared conformance suite for vector-store adapters. Drive any adapter through\n * {@link runVectorStoreConformance} to verify it honours the same contract all shipped adapters do.\n * Public, deep-import-only (`@nhtio/adk/batteries/vector/conformance`). The suite has no test-runner\n * dependency: callers invoke it and await the returned promise from any test framework.\n *\n * @module @nhtio/adk/batteries/vector/conformance\n */\n\nimport type { CallableVectorStore } from '../contract'\n\n/** A deterministic stub encoder producing a 3-dim vector from simple text features. */\nexport const stubEncoder = async (\n texts: string[],\n _kind: 'query' | 'document'\n): Promise<number[][]> =>\n texts.map((tx) => [tx.length, tx.includes('cat') ? 1 : 0, tx.includes('dog') ? 1 : 0])\n\n/**\n * A dimension-padding encoder factory: wraps {@link stubEncoder} and zero-extends to `dim`. Used by\n * backends that enforce a minimum dimension (e.g. Cloudflare Vectorize requires 32–1536).\n */\nexport const paddedStubEncoder =\n (dim: number) =>\n async (texts: string[], kind: 'query' | 'document'): Promise<number[][]> => {\n const base = await stubEncoder(texts, kind)\n return base.map((v) => padVector(v, dim))\n }\n\n// Zero-extend (or truncate) a vector to exactly `dim` entries. dim===3 (the default) returns the\n// vector unchanged, so existing callers are byte-for-byte identical.\nconst padVector = (v: number[], dim: number): number[] => {\n if (v.length === dim) return v\n if (v.length > dim) return v.slice(0, dim)\n return [...v, ...new Array(dim - v.length).fill(0)]\n}\n\n/**\n * Drive a vector-store adapter through the shared contract suite.\n *\n * @remarks\n * `makeStore` must return an already-connected store whose `'docs'` collection is created at the\n * matching dimension; it is re-invoked per test so retries are self-contained. `dim` defaults to 3\n * — pass a larger value for backends with a dimension floor (the harness pads every test vector to\n * `dim`). `opts.retry` / `opts.timeout` are forwarded to every `it()` (defaults: retry 0, 5s) and\n * exist for aggressively eventually-consistent managed backends whose read-after-write can flap for\n * seconds — a retried attempt re-runs `makeStore()` against an index that has had more time to\n * settle, without weakening any assertion.\n *\n * @param label - Human-readable label for the suite (the adapter name).\n * @param makeStore - Factory returning a fresh, connected store with the `'docs'` collection.\n * @param dim - Vector dimensionality the harness pads to (default 3).\n * @param opts - Per-`it` retry/timeout overrides.\n */\nconst assert: (condition: boolean, message: string) => asserts condition = (condition, message) => {\n if (!condition) throw new Error(message)\n}\nconst equal = (actual: unknown, expected: unknown): boolean => {\n if (actual === expected) return true\n if (\n actual === null ||\n expected === null ||\n typeof actual !== 'object' ||\n typeof expected !== 'object'\n )\n return false\n if (Array.isArray(actual) !== Array.isArray(expected)) return false\n const actualRecord = actual as Record<string, unknown>\n const expectedRecord = expected as Record<string, unknown>\n const keysA = Object.keys(actualRecord)\n const keysB = Object.keys(expectedRecord)\n if (keysA.length !== keysB.length) return false\n return keysA.every(\n (key) => Object.hasOwn(expectedRecord, key) && equal(actualRecord[key], expectedRecord[key])\n )\n}\nconst match = (actual: unknown, expected: unknown): boolean => {\n if (expected === null || typeof expected !== 'object') return equal(actual, expected)\n if (actual === null || typeof actual !== 'object') return false\n return Object.entries(expected).every(([key, value]) =>\n match((actual as Record<string, unknown>)[key], value)\n )\n}\nconst expectValue = (actual: unknown) => ({\n toBe: (expected: unknown) =>\n assert(equal(actual, expected), `expected ${String(actual)} to be ${String(expected)}`),\n toEqual: (expected: unknown) => assert(equal(actual, expected), 'values were not equal'),\n toMatchObject: (expected: unknown) =>\n assert(match(actual, expected), 'value did not match expected object'),\n toBeDefined: () => assert(actual !== undefined, 'value was undefined'),\n toBeUndefined: () => assert(actual === undefined, 'value was defined'),\n toHaveLength: (length: number) =>\n assert((actual as { length: number }).length === length, 'unexpected length'),\n rejects: {\n toThrow: async () => {\n try {\n await (actual as Promise<unknown>)\n } catch {\n return\n }\n throw new Error('expected promise to reject')\n },\n },\n})\n\n/**\n * Run the framework-free vector-store conformance suite against a consumer implementation.\n *\n * Each check creates a fresh store through `makeStore`; the returned promise rejects when any\n * contract assertion fails. Consumers can await this function from any test runner without\n * importing a test framework from the conformance module.\n *\n * @param label - Human-readable name used to identify the implementation under test.\n * @param makeStore - Factory returning a fresh, connected store with the `docs` collection.\n * @param dim - Vector dimensionality used by the suite (defaults to 3).\n * @param opts - Retry count and per-attempt timeout in milliseconds for eventually consistent stores.\n */\nexport const runVectorStoreConformance = async (\n label: string,\n makeStore: () => Promise<CallableVectorStore>,\n dim = 3,\n opts: { retry?: number; timeout?: number } = {}\n): Promise<void> => {\n const p = (v: number[]): number[] => padVector(v, dim)\n const pending: Array<() => Promise<void>> = []\n const retry = opts.retry ?? 0\n const timeout = opts.timeout ?? 5000\n const runCase = async (test: () => Promise<void>): Promise<void> => {\n let last: unknown\n for (let attempt = 0; attempt <= retry; attempt++) {\n let timedOut = false\n const operation = Promise.resolve().then(test)\n let timer: ReturnType<typeof setTimeout> | undefined\n const deadline = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n timedOut = true\n reject(new Error(`conformance check timed out after ${timeout}ms`))\n }, timeout)\n })\n try {\n await Promise.race([operation, deadline])\n return\n } catch (error) {\n // A timeout cannot cancel an arbitrary backend operation. Drain it before retrying so a\n // late write/read from this attempt cannot race the fresh store made by the next attempt.\n if (timedOut) {\n last = error\n break\n }\n last = error\n } finally {\n if (timer !== undefined) clearTimeout(timer)\n }\n }\n throw last\n }\n const it = (_name: string, _io: unknown, test: () => Promise<void>) => {\n pending.push(() => runCase(test))\n }\n const describe = (_name: string, suite: () => void) => suite()\n const expect = expectValue\n const io = undefined\n describe('conformance: ' + label, () => {\n it('upserts vectors and searches by nearVector with [0,1] score', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([\n { id: '1', vector: p([3, 1, 0]), metadata: { kind: 'animal' } },\n { id: '2', vector: p([3, 0, 1]), metadata: { kind: 'animal' } },\n ])\n const res = await vs('docs')\n .nearVector(p([3, 1, 0]))\n .select('id', 'score')\n .limit(2)\n expect(res.length).toBe(2)\n expect(res[0].id).toBeDefined()\n expect(typeof res[0].score).toBe('number')\n expect(res[0].score! >= 0 && res[0].score! <= 1).toBe(true)\n })\n it('encodes text on upsert+nearText when an encoder is configured', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: 'c', document: 'cat', metadata: {} }])\n const res = await vs('docs').nearText('cat').select('id').limit(1)\n expect(res.length).toBe(1)\n expect(res[0].id).toBe('c')\n })\n it('requires .select() on reads', io, async () => {\n const vs = await makeStore()\n await expect(\n (async () => {\n await vs('docs').nearVector(p([1, 1, 1]))\n })()\n ).rejects.toThrow()\n })\n it('filter-scan (no near) returns rows without score', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: '1', vector: p([1, 0, 0]), metadata: { kind: 'x' } }])\n const res = await vs('docs').where('kind', 'x').select('id', 'metadata').limit(10)\n expect(res.length).toBe(1)\n expect(res[0].score).toBeUndefined()\n })\n it('nested filter A AND (B OR C) selects the right subset', io, async () => {\n const vs = await makeStore()\n // Every record carries all three fields so the test probes nested AND/OR routing, not\n // backend-specific missing-field semantics (e.g. Chroma's $or excludes records missing a\n // referenced key, where the JS evaluator treats that clause as merely false).\n await vs('docs').upsert([\n { id: 'a', vector: p([1, 0, 0]), metadata: { kind: 'doc', year: 2024, pinned: false } }, // kept (year arm)\n { id: 'b', vector: p([0, 1, 0]), metadata: { kind: 'doc', year: 2010, pinned: false } }, // dropped (neither arm)\n { id: 'c', vector: p([0, 0, 1]), metadata: { kind: 'doc', year: 2010, pinned: true } }, // kept (pinned arm)\n { id: 'd', vector: p([1, 1, 0]), metadata: { kind: 'other', year: 2024, pinned: true } }, // dropped (kind mismatch)\n ])\n // kind = 'doc' AND (year >= 2024 OR pinned = true)\n const res = await vs('docs')\n .where('kind', 'doc')\n .andWhere((qb) => qb.where('year', '>=', 2024).orWhere('pinned', true))\n .select('id')\n .limit(10)\n expect(res.map((r) => r.id).sort()).toEqual(['a', 'c'])\n })\n it('projection: vector excluded unless selected', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([{ id: '1', vector: p([1, 0, 0]) }])\n const noVec = await vs('docs')\n .nearVector(p([1, 0, 0]))\n .select('id')\n .limit(1)\n expect(noVec[0].vector).toBeUndefined()\n const withVec = await vs('docs')\n .nearVector(p([1, 0, 0]))\n .select('id', 'vector')\n .limit(1)\n expect(Array.isArray(withVec[0].vector)).toBe(true)\n })\n it('deletes by id', io, async () => {\n const vs = await makeStore()\n await vs('docs').upsert([\n { id: '1', vector: p([1, 0, 0]) },\n { id: '2', vector: p([0, 1, 0]) },\n ])\n await vs('docs').whereIn('id', ['1']).delete()\n const all = await vs('docs').select('id').limit(10)\n expect(all.length).toBe(1)\n })\n it('throws transaction-unsupported when capabilities.transactions is false', io, async () => {\n const vs = await makeStore()\n if (!vs.capabilities.transactions) {\n await expect(vs.transaction(async () => {})).rejects.toThrow()\n }\n })\n it('renameCollection: honours capabilities.rename', io, async () => {\n const vs = await makeStore()\n if (vs.capabilities.rename) {\n await vs.schema.dropCollectionIfExists('docs_renamed')\n let bodyFailed = false\n let bodyError: unknown\n try {\n await vs('docs').upsert([\n { id: '1', vector: p([3, 1, 0]) },\n { id: '2', vector: p([3, 0, 1]) },\n ])\n await vs.schema.renameCollection('docs', 'docs_renamed')\n expect(await vs.schema.hasCollection('docs')).toBe(false)\n expect(await vs.schema.hasCollection('docs_renamed')).toBe(true)\n const res = await vs('docs_renamed')\n .nearVector(p([3, 1, 0]))\n .select('id', 'score')\n .limit(2)\n expect(res.length).toBe(2)\n expect(res[0].id).toBe('1')\n expect(typeof res[0].score).toBe('number')\n expect(res[0].score! >= 0 && res[0].score! <= 1).toBe(true)\n await vs('docs_renamed').upsert([{ id: '3', vector: p([1, 1, 1]) }])\n const all = await vs('docs_renamed').select('id').limit(10)\n expect(all.map((r) => r.id).sort()).toEqual(['1', '2', '3'])\n } catch (e) {\n bodyFailed = true\n bodyError = e\n }\n // A cleanup failure here must never mask a real failure from the try block above: only\n // swallow it when the body already failed (there's nothing left to mask); otherwise let it\n // propagate, since a passing body followed by a broken cleanup is itself a real failure.\n try {\n await vs.schema.dropCollectionIfExists('docs_renamed')\n } catch (cleanupErr) {\n if (!bodyFailed) throw cleanupErr\n }\n if (bodyFailed) throw bodyError\n } else {\n await expect(vs.schema.renameCollection('docs', 'docs_renamed')).rejects.toThrow()\n }\n })\n })\n for (const fn of pending) {\n await fn()\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lancedb.cjs","names":["#opts","#db","#ensure","#dims","#parseMeta","#project"],"sources":["../../../src/batteries/vector/lancedb/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/lancedb\n *\n * Embedded LanceDB adapter (no server — file-based, like sqlite_vec/duckdb). Each collection\n * is a Lance table with an explicit Arrow schema (`id` Utf8, `vec` FixedSizeList<Float32>,\n * `document` Utf8, `metadata` Utf8-JSON). KNN uses `table.search(vector).distanceType(...)`;\n * metadata is filtered with the neutral filter tree's JS reference evaluator for exact\n * cross-adapter parity. Upsert is a merge-insert on `id`.\n *\n * Drivers: `@lancedb/lancedb` + `apache-arrow` (prebuilt binary; no native compile).\n */\n\nimport { evaluateFilter } from '../filters'\nimport { normalizeScore } from '../helpers'\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 LanceDBVectorStoreOptions extends BaseVectorStoreOptions {\n /** Connection and authentication parameters for the backend. */\n connection: { uri: string }\n}\n\nconst getLanceDB = async () => {\n try {\n return await import('@lancedb/lancedb')\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['@lancedb/lancedb'])\n }\n}\n\nconst getArrow = async () => {\n try {\n return await import('apache-arrow')\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['apache-arrow'])\n }\n}\n\nconst lanceMetric = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'l2' : metric === 'dot' ? 'dot' : 'cosine'\n\n// LanceDB SQL string literal (single-quoted, escape embedded quotes).\nconst lit = (value: string): string => `'${value.replace(/'/g, \"''\")}'`\n\nexport class LanceDBVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: true,\n rawSql: false,\n builtInEncoding: false,\n // Embedded and synchronous: a write is visible on resolve. The option is a no-op.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #db: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): LanceDBVectorStoreOptions {\n return this.options as LanceDBVectorStoreOptions\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.#db) return\n const lancedb = await getLanceDB()\n const uri = this.#opts.connection?.uri\n if (!uri) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([\n 'LanceDB requires connection.uri (a directory path)',\n ])\n }\n try {\n this.#db = await lancedb.connect(uri)\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n this.#db = null\n }\n\n async #ensure(): Promise<any> {\n if (!this.#db) await this.connect()\n return this.#db!\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const db = await this.#ensure()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n if (ifNotExists && (await this.hasCollection(spec.collection))) return\n const arrow = await getArrow()\n const schema = new arrow.Schema([\n new arrow.Field('id', new arrow.Utf8(), false),\n new arrow.Field(\n 'vec',\n new arrow.FixedSizeList(\n spec.vector.dimensions,\n new arrow.Field('item', new arrow.Float32(), true)\n ),\n false\n ),\n new arrow.Field('document', new arrow.Utf8(), true),\n new arrow.Field('metadata', new arrow.Utf8(), true),\n ])\n try {\n await db.createEmptyTable(spec.collection, schema, { mode: 'overwrite' })\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 db = await this.#ensure()\n if (ifExists && !(await this.hasCollection(collection))) return\n try {\n await db.dropTable(collection)\n this.#dims.delete(collection)\n } catch (err) {\n const msg = String(err)\n if (ifExists && msg.includes('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 db = await this.#ensure()\n try {\n const names = await db.tableNames()\n return names.includes(collection)\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', 'lancedb'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const db = await this.#ensure()\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\n try {\n const rows: 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 rows.push({\n id: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n })\n }\n const tbl = await db.openTable(plan.collection)\n // Merge-insert on id = upsert (update matched, insert unmatched).\n await tbl.mergeInsert('id').whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(rows)\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 db = await this.#ensure()\n const metric = this.#opts.metric ?? 'cosine'\n let queryVector: number[] | undefined\n let tbl: any\n try {\n tbl = await db.openTable(plan.collection)\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n\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 rows = await tbl\n .query()\n .where(`id = ${lit(plan.near.id)}`)\n .limit(1)\n .toArray()\n if (rows.length === 0) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = Array.from(rows[0].vec as ArrayLike<number>)\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n if (queryVector) {\n // Over-fetch then JS-filter for exact cross-adapter filter semantics.\n const k = plan.filter ? 1000 : plan.topK + offset\n const rows = await tbl\n .search(queryVector)\n .distanceType(lanceMetric(metric))\n .limit(k)\n .toArray()\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, metric, true))\n } else {\n const rows = await tbl\n .query()\n .limit(plan.filter ? 100000 : plan.topK + offset)\n .toArray()\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, metric, 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, metric: string, 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 && row.vec) out.vector = Array.from(row.vec as ArrayLike<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._distance !== undefined && row._distance !== null) {\n out.score = normalizeScore(Number(row._distance), metric as DistanceMetric, 'distance')\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const db = await this.#ensure()\n try {\n const tbl = await db.openTable(plan.collection)\n if (plan.ids && plan.ids.length > 0) {\n const list = plan.ids.map((id) => lit(id)).join(', ')\n await tbl.delete(`id IN (${list})`)\n } else if (plan.filter) {\n const rows = await tbl.query().limit(100000).toArray()\n const targets: string[] = rows\n .filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n .map((row: any) => row.id as string)\n if (targets.length > 0) {\n const list = targets.map((id) => lit(id)).join(', ')\n await tbl.delete(`id IN (${list})`)\n }\n } else {\n await tbl.delete('true')\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":"lancedb.cjs","names":["#opts","#db","#ensure","#dims","#parseMeta","#project"],"sources":["../../../src/batteries/vector/lancedb/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/lancedb\n *\n * Embedded LanceDB adapter (no server — file-based, like sqlite_vec/duckdb). Each collection\n * is a Lance table with an explicit Arrow schema (`id` Utf8, `vec` FixedSizeList<Float32>,\n * `document` Utf8, `metadata` Utf8-JSON). KNN uses `table.search(vector).distanceType(...)`;\n * metadata is filtered with the neutral filter tree's JS reference evaluator for exact\n * cross-adapter parity. Upsert is a merge-insert on `id`.\n *\n * Drivers: `@lancedb/lancedb` + `apache-arrow` (prebuilt binary; no native compile).\n */\n\nimport { evaluateFilter } from '../filters'\nimport { normalizeScore } from '../helpers'\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 LanceDBVectorStoreOptions extends BaseVectorStoreOptions {\n /** Connection and authentication parameters for the backend. */\n connection: { uri: string }\n}\n\nconst getLanceDB = async () => {\n try {\n return await import('@lancedb/lancedb')\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['@lancedb/lancedb'])\n }\n}\n\nconst getArrow = async () => {\n try {\n return await import('apache-arrow')\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['apache-arrow'])\n }\n}\n\nconst lanceMetric = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'l2' : metric === 'dot' ? 'dot' : 'cosine'\n\n// LanceDB SQL string literal (single-quoted, escape embedded quotes).\nconst lit = (value: string): string => `'${value.replace(/'/g, \"''\")}'`\n\nexport class LanceDBVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n // Probed against @lancedb/lancedb 0.30.0 (local directory database): connection.renameTable\n // rejects with \"LanceDBError: not supported: rename_table is not supported in LanceDB OSS\".\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Embedded and synchronous: a write is visible on resolve. The option is a no-op.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #db: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): LanceDBVectorStoreOptions {\n return this.options as LanceDBVectorStoreOptions\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.#db) return\n const lancedb = await getLanceDB()\n const uri = this.#opts.connection?.uri\n if (!uri) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([\n 'LanceDB requires connection.uri (a directory path)',\n ])\n }\n try {\n this.#db = await lancedb.connect(uri)\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n this.#db = null\n }\n\n async #ensure(): Promise<any> {\n if (!this.#db) await this.connect()\n return this.#db!\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const db = await this.#ensure()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n if (ifNotExists && (await this.hasCollection(spec.collection))) return\n const arrow = await getArrow()\n const schema = new arrow.Schema([\n new arrow.Field('id', new arrow.Utf8(), false),\n new arrow.Field(\n 'vec',\n new arrow.FixedSizeList(\n spec.vector.dimensions,\n new arrow.Field('item', new arrow.Float32(), true)\n ),\n false\n ),\n new arrow.Field('document', new arrow.Utf8(), true),\n new arrow.Field('metadata', new arrow.Utf8(), true),\n ])\n try {\n await db.createEmptyTable(spec.collection, schema, { mode: 'overwrite' })\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 db = await this.#ensure()\n if (ifExists && !(await this.hasCollection(collection))) return\n try {\n await db.dropTable(collection)\n this.#dims.delete(collection)\n } catch (err) {\n const msg = String(err)\n if (ifExists && msg.includes('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 db = await this.#ensure()\n try {\n const names = await db.tableNames()\n return names.includes(collection)\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', 'lancedb'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const db = await this.#ensure()\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\n try {\n const rows: 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 rows.push({\n id: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n })\n }\n const tbl = await db.openTable(plan.collection)\n // Merge-insert on id = upsert (update matched, insert unmatched).\n await tbl.mergeInsert('id').whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(rows)\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 db = await this.#ensure()\n const metric = this.#opts.metric ?? 'cosine'\n let queryVector: number[] | undefined\n let tbl: any\n try {\n tbl = await db.openTable(plan.collection)\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n\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 rows = await tbl\n .query()\n .where(`id = ${lit(plan.near.id)}`)\n .limit(1)\n .toArray()\n if (rows.length === 0) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = Array.from(rows[0].vec as ArrayLike<number>)\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n if (queryVector) {\n // Over-fetch then JS-filter for exact cross-adapter filter semantics.\n const k = plan.filter ? 1000 : plan.topK + offset\n const rows = await tbl\n .search(queryVector)\n .distanceType(lanceMetric(metric))\n .limit(k)\n .toArray()\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, metric, true))\n } else {\n const rows = await tbl\n .query()\n .limit(plan.filter ? 100000 : plan.topK + offset)\n .toArray()\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, metric, 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, metric: string, 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 && row.vec) out.vector = Array.from(row.vec as ArrayLike<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._distance !== undefined && row._distance !== null) {\n out.score = normalizeScore(Number(row._distance), metric as DistanceMetric, 'distance')\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const db = await this.#ensure()\n try {\n const tbl = await db.openTable(plan.collection)\n if (plan.ids && plan.ids.length > 0) {\n const list = plan.ids.map((id) => lit(id)).join(', ')\n await tbl.delete(`id IN (${list})`)\n } else if (plan.filter) {\n const rows = await tbl.query().limit(100000).toArray()\n const targets: string[] = rows\n .filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n .map((row: any) => row.id as string)\n if (targets.length > 0) {\n const list = targets.map((id) => lit(id)).join(', ')\n await tbl.delete(`id IN (${list})`)\n }\n } else {\n await tbl.delete('true')\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lancedb.mjs","names":["#opts","#db","#ensure","#dims","#parseMeta","#project"],"sources":["../../../src/batteries/vector/lancedb/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/lancedb\n *\n * Embedded LanceDB adapter (no server — file-based, like sqlite_vec/duckdb). Each collection\n * is a Lance table with an explicit Arrow schema (`id` Utf8, `vec` FixedSizeList<Float32>,\n * `document` Utf8, `metadata` Utf8-JSON). KNN uses `table.search(vector).distanceType(...)`;\n * metadata is filtered with the neutral filter tree's JS reference evaluator for exact\n * cross-adapter parity. Upsert is a merge-insert on `id`.\n *\n * Drivers: `@lancedb/lancedb` + `apache-arrow` (prebuilt binary; no native compile).\n */\n\nimport { evaluateFilter } from '../filters'\nimport { normalizeScore } from '../helpers'\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 LanceDBVectorStoreOptions extends BaseVectorStoreOptions {\n /** Connection and authentication parameters for the backend. */\n connection: { uri: string }\n}\n\nconst getLanceDB = async () => {\n try {\n return await import('@lancedb/lancedb')\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['@lancedb/lancedb'])\n }\n}\n\nconst getArrow = async () => {\n try {\n return await import('apache-arrow')\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['apache-arrow'])\n }\n}\n\nconst lanceMetric = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'l2' : metric === 'dot' ? 'dot' : 'cosine'\n\n// LanceDB SQL string literal (single-quoted, escape embedded quotes).\nconst lit = (value: string): string => `'${value.replace(/'/g, \"''\")}'`\n\nexport class LanceDBVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n rename: true,\n rawSql: false,\n builtInEncoding: false,\n // Embedded and synchronous: a write is visible on resolve. The option is a no-op.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #db: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): LanceDBVectorStoreOptions {\n return this.options as LanceDBVectorStoreOptions\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.#db) return\n const lancedb = await getLanceDB()\n const uri = this.#opts.connection?.uri\n if (!uri) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([\n 'LanceDB requires connection.uri (a directory path)',\n ])\n }\n try {\n this.#db = await lancedb.connect(uri)\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n this.#db = null\n }\n\n async #ensure(): Promise<any> {\n if (!this.#db) await this.connect()\n return this.#db!\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const db = await this.#ensure()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n if (ifNotExists && (await this.hasCollection(spec.collection))) return\n const arrow = await getArrow()\n const schema = new arrow.Schema([\n new arrow.Field('id', new arrow.Utf8(), false),\n new arrow.Field(\n 'vec',\n new arrow.FixedSizeList(\n spec.vector.dimensions,\n new arrow.Field('item', new arrow.Float32(), true)\n ),\n false\n ),\n new arrow.Field('document', new arrow.Utf8(), true),\n new arrow.Field('metadata', new arrow.Utf8(), true),\n ])\n try {\n await db.createEmptyTable(spec.collection, schema, { mode: 'overwrite' })\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 db = await this.#ensure()\n if (ifExists && !(await this.hasCollection(collection))) return\n try {\n await db.dropTable(collection)\n this.#dims.delete(collection)\n } catch (err) {\n const msg = String(err)\n if (ifExists && msg.includes('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 db = await this.#ensure()\n try {\n const names = await db.tableNames()\n return names.includes(collection)\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', 'lancedb'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const db = await this.#ensure()\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\n try {\n const rows: 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 rows.push({\n id: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n })\n }\n const tbl = await db.openTable(plan.collection)\n // Merge-insert on id = upsert (update matched, insert unmatched).\n await tbl.mergeInsert('id').whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(rows)\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 db = await this.#ensure()\n const metric = this.#opts.metric ?? 'cosine'\n let queryVector: number[] | undefined\n let tbl: any\n try {\n tbl = await db.openTable(plan.collection)\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n\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 rows = await tbl\n .query()\n .where(`id = ${lit(plan.near.id)}`)\n .limit(1)\n .toArray()\n if (rows.length === 0) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = Array.from(rows[0].vec as ArrayLike<number>)\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n if (queryVector) {\n // Over-fetch then JS-filter for exact cross-adapter filter semantics.\n const k = plan.filter ? 1000 : plan.topK + offset\n const rows = await tbl\n .search(queryVector)\n .distanceType(lanceMetric(metric))\n .limit(k)\n .toArray()\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, metric, true))\n } else {\n const rows = await tbl\n .query()\n .limit(plan.filter ? 100000 : plan.topK + offset)\n .toArray()\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, metric, 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, metric: string, 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 && row.vec) out.vector = Array.from(row.vec as ArrayLike<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._distance !== undefined && row._distance !== null) {\n out.score = normalizeScore(Number(row._distance), metric as DistanceMetric, 'distance')\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const db = await this.#ensure()\n try {\n const tbl = await db.openTable(plan.collection)\n if (plan.ids && plan.ids.length > 0) {\n const list = plan.ids.map((id) => lit(id)).join(', ')\n await tbl.delete(`id IN (${list})`)\n } else if (plan.filter) {\n const rows = await tbl.query().limit(100000).toArray()\n const targets: string[] = rows\n .filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n .map((row: any) => row.id as string)\n if (targets.length > 0) {\n const list = targets.map((id) => lit(id)).join(', ')\n await tbl.delete(`id IN (${list})`)\n }\n } else {\n await tbl.delete('true')\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":"lancedb.mjs","names":["#opts","#db","#ensure","#dims","#parseMeta","#project"],"sources":["../../../src/batteries/vector/lancedb/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/lancedb\n *\n * Embedded LanceDB adapter (no server — file-based, like sqlite_vec/duckdb). Each collection\n * is a Lance table with an explicit Arrow schema (`id` Utf8, `vec` FixedSizeList<Float32>,\n * `document` Utf8, `metadata` Utf8-JSON). KNN uses `table.search(vector).distanceType(...)`;\n * metadata is filtered with the neutral filter tree's JS reference evaluator for exact\n * cross-adapter parity. Upsert is a merge-insert on `id`.\n *\n * Drivers: `@lancedb/lancedb` + `apache-arrow` (prebuilt binary; no native compile).\n */\n\nimport { evaluateFilter } from '../filters'\nimport { normalizeScore } from '../helpers'\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 LanceDBVectorStoreOptions extends BaseVectorStoreOptions {\n /** Connection and authentication parameters for the backend. */\n connection: { uri: string }\n}\n\nconst getLanceDB = async () => {\n try {\n return await import('@lancedb/lancedb')\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['@lancedb/lancedb'])\n }\n}\n\nconst getArrow = async () => {\n try {\n return await import('apache-arrow')\n } catch {\n throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['apache-arrow'])\n }\n}\n\nconst lanceMetric = (metric: DistanceMetric): string =>\n metric === 'euclidean' ? 'l2' : metric === 'dot' ? 'dot' : 'cosine'\n\n// LanceDB SQL string literal (single-quoted, escape embedded quotes).\nconst lit = (value: string): string => `'${value.replace(/'/g, \"''\")}'`\n\nexport class LanceDBVectorStore extends BaseVectorStore {\n readonly capabilities: VectorStoreCapabilities = {\n transactions: false,\n namedVectors: false,\n // Probed against @lancedb/lancedb 0.30.0 (local directory database): connection.renameTable\n // rejects with \"LanceDBError: not supported: rename_table is not supported in LanceDB OSS\".\n rename: false,\n rawSql: false,\n builtInEncoding: false,\n // Embedded and synchronous: a write is visible on resolve. The option is a no-op.\n consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n }\n\n #db: any | null = null\n #dims: Map<string, number> = new Map()\n\n get #opts(): LanceDBVectorStoreOptions {\n return this.options as LanceDBVectorStoreOptions\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.#db) return\n const lancedb = await getLanceDB()\n const uri = this.#opts.connection?.uri\n if (!uri) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([\n 'LanceDB requires connection.uri (a directory path)',\n ])\n }\n try {\n this.#db = await lancedb.connect(uri)\n } catch (err) {\n throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n }\n }\n\n async close(): Promise<void> {\n this.#db = null\n }\n\n async #ensure(): Promise<any> {\n if (!this.#db) await this.connect()\n return this.#db!\n }\n\n async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n const db = await this.#ensure()\n this.#dims.set(spec.collection, spec.vector.dimensions)\n if (ifNotExists && (await this.hasCollection(spec.collection))) return\n const arrow = await getArrow()\n const schema = new arrow.Schema([\n new arrow.Field('id', new arrow.Utf8(), false),\n new arrow.Field(\n 'vec',\n new arrow.FixedSizeList(\n spec.vector.dimensions,\n new arrow.Field('item', new arrow.Float32(), true)\n ),\n false\n ),\n new arrow.Field('document', new arrow.Utf8(), true),\n new arrow.Field('metadata', new arrow.Utf8(), true),\n ])\n try {\n await db.createEmptyTable(spec.collection, schema, { mode: 'overwrite' })\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 db = await this.#ensure()\n if (ifExists && !(await this.hasCollection(collection))) return\n try {\n await db.dropTable(collection)\n this.#dims.delete(collection)\n } catch (err) {\n const msg = String(err)\n if (ifExists && msg.includes('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 db = await this.#ensure()\n try {\n const names = await db.tableNames()\n return names.includes(collection)\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', 'lancedb'])\n }\n\n async executeUpsert(plan: UpsertPlan): Promise<void> {\n if (plan.records.length === 0) return\n validateRecords(plan.records)\n const db = await this.#ensure()\n const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\n try {\n const rows: 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 rows.push({\n id: r.id,\n vec: vector,\n document: r.document ?? '',\n metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n })\n }\n const tbl = await db.openTable(plan.collection)\n // Merge-insert on id = upsert (update matched, insert unmatched).\n await tbl.mergeInsert('id').whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(rows)\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 db = await this.#ensure()\n const metric = this.#opts.metric ?? 'cosine'\n let queryVector: number[] | undefined\n let tbl: any\n try {\n tbl = await db.openTable(plan.collection)\n } catch (err) {\n throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n }\n\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 rows = await tbl\n .query()\n .where(`id = ${lit(plan.near.id)}`)\n .limit(1)\n .toArray()\n if (rows.length === 0) {\n throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n }\n queryVector = Array.from(rows[0].vec as ArrayLike<number>)\n }\n }\n\n const offset = plan.offset ?? 0\n try {\n if (queryVector) {\n // Over-fetch then JS-filter for exact cross-adapter filter semantics.\n const k = plan.filter ? 1000 : plan.topK + offset\n const rows = await tbl\n .search(queryVector)\n .distanceType(lanceMetric(metric))\n .limit(k)\n .toArray()\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, metric, true))\n } else {\n const rows = await tbl\n .query()\n .limit(plan.filter ? 100000 : plan.topK + offset)\n .toArray()\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, metric, 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, metric: string, 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 && row.vec) out.vector = Array.from(row.vec as ArrayLike<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._distance !== undefined && row._distance !== null) {\n out.score = normalizeScore(Number(row._distance), metric as DistanceMetric, 'distance')\n }\n return out\n }\n\n async executeDelete(plan: DeletePlan): Promise<void> {\n const db = await this.#ensure()\n try {\n const tbl = await db.openTable(plan.collection)\n if (plan.ids && plan.ids.length > 0) {\n const list = plan.ids.map((id) => lit(id)).join(', ')\n await tbl.delete(`id IN (${list})`)\n } else if (plan.filter) {\n const rows = await tbl.query().limit(100000).toArray()\n const targets: string[] = rows\n .filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n .map((row: any) => row.id as string)\n if (targets.length > 0) {\n const list = targets.map((id) => lit(id)).join(', ')\n await tbl.delete(`id IN (${list})`)\n }\n } else {\n await tbl.delete('true')\n }\n } catch (err) {\n throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../chunk-Cek0wNdY.cjs");
|
|
3
|
-
const require_retrievable = require("../../retrievable-
|
|
3
|
+
const require_retrievable = require("../../retrievable-Bq-O3k6r.cjs");
|
|
4
4
|
require("../../index.cjs");
|
|
5
5
|
//#region src/batteries/vector/retrievable_glue.ts
|
|
6
6
|
/**
|
|
@@ -25,7 +25,7 @@ export declare class SqliteVecVectorStore extends BaseVectorStore {
|
|
|
25
25
|
createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void>;
|
|
26
26
|
dropCollection(collection: string, ifExists: boolean): Promise<void>;
|
|
27
27
|
hasCollection(collection: string): Promise<boolean>;
|
|
28
|
-
renameCollection(
|
|
28
|
+
renameCollection(_from: string, _to: string): Promise<void>;
|
|
29
29
|
executeUpsert(plan: UpsertPlan): Promise<void>;
|
|
30
30
|
executeSearch(plan: SearchPlan): Promise<VectorMatch[]>;
|
|
31
31
|
executeDelete(plan: DeletePlan): Promise<void>;
|
|
@@ -9,11 +9,12 @@ const require_batteries_vector_validation = require("./validation.cjs");
|
|
|
9
9
|
/**
|
|
10
10
|
* @module @nhtio/adk/batteries/vector/sqlite_vec
|
|
11
11
|
*/
|
|
12
|
+
var ident = (name) => `"${name.replace(/"/g, "\"\"")}"`;
|
|
12
13
|
var SqliteVecVectorStore = class extends require_batteries_vector_contract.BaseVectorStore {
|
|
13
14
|
capabilities = {
|
|
14
15
|
transactions: true,
|
|
15
16
|
namedVectors: false,
|
|
16
|
-
rename:
|
|
17
|
+
rename: false,
|
|
17
18
|
rawSql: true,
|
|
18
19
|
builtInEncoding: false,
|
|
19
20
|
consistency: {
|
|
@@ -82,8 +83,8 @@ var SqliteVecVectorStore = class extends require_batteries_vector_contract.BaseV
|
|
|
82
83
|
await this.connect();
|
|
83
84
|
const { collection, vector } = spec;
|
|
84
85
|
const dims = vector.dimensions;
|
|
85
|
-
const tbl =
|
|
86
|
-
const metaTbl =
|
|
86
|
+
const tbl = ident(collection);
|
|
87
|
+
const metaTbl = ident(collection + "__meta");
|
|
87
88
|
const { db } = this;
|
|
88
89
|
const exists = await this.hasCollection(collection);
|
|
89
90
|
if (!ifNotExists && exists) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_COLLECTION_FAILED(["create", "collection exists"]);
|
|
@@ -97,8 +98,8 @@ var SqliteVecVectorStore = class extends require_batteries_vector_contract.BaseV
|
|
|
97
98
|
}
|
|
98
99
|
async dropCollection(collection, ifExists) {
|
|
99
100
|
await this.connect();
|
|
100
|
-
const tbl =
|
|
101
|
-
const metaTbl =
|
|
101
|
+
const tbl = ident(collection);
|
|
102
|
+
const metaTbl = ident(collection + "__meta");
|
|
102
103
|
if (!await this.hasCollection(collection)) {
|
|
103
104
|
if (!ifExists) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_COLLECTION_FAILED(["drop", "collection does not exist"]);
|
|
104
105
|
return;
|
|
@@ -121,22 +122,8 @@ var SqliteVecVectorStore = class extends require_batteries_vector_contract.BaseV
|
|
|
121
122
|
return false;
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
|
-
async renameCollection(
|
|
125
|
-
|
|
126
|
-
if (!await this.hasCollection(from)) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_COLLECTION_FAILED(["rename", "source collection does not exist"]);
|
|
127
|
-
if (await this.hasCollection(to)) throw new require_batteries_vector_exceptions.E_VECTOR_STORE_COLLECTION_FAILED(["rename", "target collection already exists"]);
|
|
128
|
-
const { db } = this;
|
|
129
|
-
try {
|
|
130
|
-
db.exec(`ALTER TABLE "${from}" RENAME TO "${to}"`);
|
|
131
|
-
db.exec(`ALTER TABLE "${from}__meta" RENAME TO "${to}__meta"`);
|
|
132
|
-
const dims = this.#_dims.get(from);
|
|
133
|
-
if (dims !== void 0) {
|
|
134
|
-
this.#_dims.set(to, dims);
|
|
135
|
-
this.#_dims.delete(from);
|
|
136
|
-
}
|
|
137
|
-
} catch (e) {
|
|
138
|
-
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_COLLECTION_FAILED(["rename", e?.message ?? String(e)]);
|
|
139
|
-
}
|
|
125
|
+
async renameCollection(_from, _to) {
|
|
126
|
+
throw new require_batteries_vector_exceptions.E_VECTOR_STORE_UNSUPPORTED_OPERATION(["renameCollection", "sqlite_vec"]);
|
|
140
127
|
}
|
|
141
128
|
async executeUpsert(plan) {
|
|
142
129
|
await this.connect();
|
|
@@ -159,11 +146,13 @@ var SqliteVecVectorStore = class extends require_batteries_vector_contract.BaseV
|
|
|
159
146
|
metadata: r.metadata
|
|
160
147
|
});
|
|
161
148
|
}
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
const
|
|
149
|
+
const metaTbl = ident(collection + "__meta");
|
|
150
|
+
const tbl = ident(collection);
|
|
151
|
+
const stmtMetaInsert = db.prepare(`INSERT INTO ${metaTbl} (id, document, metadata) VALUES (?, ?, ?)`);
|
|
152
|
+
const stmtMetaUpdate = db.prepare(`UPDATE ${metaTbl} SET document = ?, metadata = ? WHERE id = ?`);
|
|
153
|
+
const stmtRowid = db.prepare(`SELECT rowid FROM ${metaTbl} WHERE id = ?`);
|
|
154
|
+
const stmtVecDelete = db.prepare(`DELETE FROM ${tbl} WHERE rowid = ?`);
|
|
155
|
+
const stmtVecInsert = db.prepare(`INSERT INTO ${tbl} (rowid, embedding) VALUES (?, ?)`);
|
|
167
156
|
const txn = db.transaction(() => {
|
|
168
157
|
for (const r of resolvedRows) {
|
|
169
158
|
const buf = new Float32Array(r.vector);
|
|
@@ -191,8 +180,8 @@ var SqliteVecVectorStore = class extends require_batteries_vector_contract.BaseV
|
|
|
191
180
|
await this.connect();
|
|
192
181
|
const { db } = this;
|
|
193
182
|
const collection = plan.collection;
|
|
194
|
-
const tbl =
|
|
195
|
-
const metaTbl =
|
|
183
|
+
const tbl = ident(collection);
|
|
184
|
+
const metaTbl = ident(collection + "__meta");
|
|
196
185
|
const near = plan.near;
|
|
197
186
|
const limit = (plan.offset ?? 0) + plan.topK;
|
|
198
187
|
try {
|
|
@@ -270,8 +259,8 @@ var SqliteVecVectorStore = class extends require_batteries_vector_contract.BaseV
|
|
|
270
259
|
async executeDelete(plan) {
|
|
271
260
|
await this.connect();
|
|
272
261
|
const collection = plan.collection;
|
|
273
|
-
const metaTbl =
|
|
274
|
-
const tbl =
|
|
262
|
+
const metaTbl = ident(collection + "__meta");
|
|
263
|
+
const tbl = ident(collection);
|
|
275
264
|
const { db } = this;
|
|
276
265
|
try {
|
|
277
266
|
if (plan.ids && plan.ids.length > 0) {
|