From e98265d0c665c548652437ac6880499c6e0f8eb9 Mon Sep 17 00:00:00 2001 From: Trayan Azarov Date: Fri, 6 Feb 2026 10:49:04 +0200 Subject: [PATCH] feat(vectorstores/chroma): upgrade to chroma-go v0.3.x with Cloud and Search API support - Upgrade from legacy chroma-go API to v0.3.2 (pkg/api/v2) - Add WithClient option for pre-configured client injection - Add WithCloudAPIKey, WithTenant, WithDatabase options for Chroma Cloud - Add Search() method using Chroma's Search API (relevance scores, pagination, read levels) - Add Collection() getter as escape hatch for advanced search patterns (RRF, grouping) - Refactor New() to support three client modes: pre-configured, cloud, and HTTP - Add rawWhereClause adapter for Search API filtering --- go.mod | 93 ++++++----- go.sum | 193 ++++++++++++---------- vectorstores/chroma/chroma.go | 247 +++++++++++++++++++++-------- vectorstores/chroma/chroma_test.go | 246 +++++++++++++++++++++++----- vectorstores/chroma/embedder.go | 33 ++-- vectorstores/chroma/options.go | 72 ++++++--- vectorstores/chroma/search.go | 111 +++++++++++++ 7 files changed, 719 insertions(+), 276 deletions(-) create mode 100644 vectorstores/chroma/search.go diff --git a/go.mod b/go.mod index ca9eaef46..b291a14ca 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/tmc/langchaingo -go 1.24.4 - -toolchain go1.24.6 +go 1.24.11 // Note: Thanks to Go's module graph pruning (https://go.dev/ref/mod#graph-pruning), // importing langchaingo does NOT pull in all dependencies listed below. You only @@ -16,9 +14,9 @@ require github.com/google/uuid v1.6.0 // Testing require ( - github.com/stretchr/testify v1.10.0 - github.com/testcontainers/testcontainers-go v0.38.0 - github.com/testcontainers/testcontainers-go/modules/chroma v0.37.0 + github.com/stretchr/testify v1.11.1 + github.com/testcontainers/testcontainers-go v0.40.0 + github.com/testcontainers/testcontainers-go/modules/chroma v0.40.1-0.20260206153225-b3c2ab185bc7 github.com/testcontainers/testcontainers-go/modules/milvus v0.37.0 github.com/testcontainers/testcontainers-go/modules/mongodb v0.37.0 github.com/testcontainers/testcontainers-go/modules/mysql v0.37.0 @@ -33,13 +31,13 @@ require ( github.com/IBM/watsonx-go v1.0.0 github.com/cohere-ai/tokenizer v1.1.2 github.com/gage-technologies/mistral-go v1.1.0 - github.com/google/generative-ai-go v0.15.1 + github.com/google/generative-ai-go v0.19.0 github.com/pkoukk/tiktoken-go v0.1.6 ) // Vector stores require ( - github.com/amikos-tech/chroma-go v0.1.4 + github.com/amikos-tech/chroma-go v0.3.3 github.com/milvus-io/milvus-sdk-go/v2 v2.4.0 github.com/opensearch-project/opensearch-go v1.1.0 github.com/pgvector/pgvector-go v0.1.1 @@ -55,13 +53,13 @@ require ( require ( cloud.google.com/go/aiplatform v1.69.0 cloud.google.com/go/vertexai v0.12.0 - github.com/aws/aws-sdk-go-v2 v1.36.3 - github.com/aws/aws-sdk-go-v2/config v1.29.4 + github.com/aws/aws-sdk-go-v2 v1.41.1 + github.com/aws/aws-sdk-go-v2/config v1.32.7 github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.40.0 github.com/aws/aws-sdk-go-v2/service/bedrockagentruntime v1.41.0 - github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.24.3 + github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.49.0 github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2 - github.com/aws/smithy-go v1.22.2 + github.com/aws/smithy-go v1.24.0 golang.org/x/oauth2 v0.30.0 google.golang.org/api v0.218.0 google.golang.org/grpc v1.70.0 @@ -107,8 +105,8 @@ require ( github.com/google/go-cmp v0.7.0 github.com/nikolalohinski/gonja v1.5.3 github.com/zeebo/blake3 v0.2.4 - golang.org/x/sync v0.16.0 - golang.org/x/tools v0.35.0 + golang.org/x/sync v0.19.0 + golang.org/x/tools v0.39.0 sigs.k8s.io/yaml v1.3.0 ) @@ -117,27 +115,27 @@ require ( // Cloud platforms and AI services - indirect require ( cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/ai v0.7.0 // indirect + cloud.google.com/go/ai v0.8.0 // indirect cloud.google.com/go/alloydb v1.14.0 // indirect cloud.google.com/go/auth v0.14.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect cloud.google.com/go/iam v1.2.2 // indirect cloud.google.com/go/longrunning v0.6.2 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.57 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.12 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.14.1 // indirect @@ -208,12 +206,12 @@ require ( github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/containerd/platforms v0.2.1 // indirect + github.com/containerd/platforms v1.0.0-rc.1 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker v28.2.2+incompatible // indirect - github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/docker v28.5.2+incompatible // indirect + github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/getsentry/sentry-go v0.30.0 // indirect github.com/mdelapenya/tlscert v0.2.0 // indirect @@ -234,8 +232,7 @@ require ( require ( dario.cat/mergo v1.0.2 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver v1.5.0 // indirect - github.com/Masterminds/semver/v3 v3.2.0 // indirect + github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -245,7 +242,7 @@ require ( github.com/deepmap/oapi-codegen/v2 v2.1.0 // indirect github.com/dlclark/regexp2 v1.10.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/ebitengine/purego v0.8.4 // indirect + github.com/ebitengine/purego v0.9.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -293,22 +290,22 @@ require ( github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rs/zerolog v1.31.0 // indirect - github.com/shirou/gopsutil/v4 v4.25.5 // indirect + github.com/shirou/gopsutil/v4 v4.25.12 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/tidwall/gjson v1.17.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect - github.com/tklauser/go-sysconf v0.3.15 // indirect - github.com/tklauser/numcpus v0.10.0 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect github.com/yargevad/filepathx v1.0.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - golang.org/x/crypto v0.41.0 // indirect + golang.org/x/crypto v0.46.0 // indirect golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.9.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -320,6 +317,8 @@ require ( ) require ( + github.com/amikos-tech/pure-tokenizers v0.1.1 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -327,14 +326,21 @@ require ( github.com/containerd/cgroups/v3 v3.0.3 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/creasty/defaults v1.8.0 // indirect github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect + github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.30.1 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus/v5 v5.0.4 // indirect github.com/google/btree v1.1.3 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/jonboulle/clockwork v0.2.2 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect @@ -354,6 +360,7 @@ require ( github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect + github.com/yalue/onnxruntime_go v1.22.0 // indirect go.etcd.io/bbolt v1.3.11 // indirect go.etcd.io/etcd/api/v3 v3.5.5 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.5 // indirect @@ -362,10 +369,10 @@ require ( go.etcd.io/etcd/pkg/v3 v3.5.5 // indirect go.etcd.io/etcd/raft/v3 v3.5.5 // indirect go.etcd.io/etcd/server/v3 v3.5.5 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 // indirect go.opentelemetry.io/otel/sdk v1.36.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/automaxprocs v1.5.3 // indirect go.uber.org/multierr v1.11.0 // indirect diff --git a/go.sum b/go.sum index 3108b9131..2386f9e74 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTj cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/ai v0.7.0 h1:P6+b5p4gXlza5E+u7uvcgYlzZ7103ACg70YdZeC6oGE= -cloud.google.com/go/ai v0.7.0/go.mod h1:7ozuEcraovh4ABsPbrec3o4LmFl9HigNI3D5haxYeQo= +cloud.google.com/go/ai v0.8.0 h1:rXUEz8Wp2OlrM8r1bfmpF2+VKqc1VJpafE3HgzRnD/w= +cloud.google.com/go/ai v0.8.0/go.mod h1:t3Dfk4cM61sytiggo2UyGsDVW3RF1qGZaUKDrZFyqkE= cloud.google.com/go/aiplatform v1.69.0 h1:XvBzK8e6/6ufbi/i129Vmn/gVqFwbNPmRQ89K+MGlgc= cloud.google.com/go/aiplatform v1.69.0/go.mod h1:nUsIqzS3khlnWvpjfJbP+2+h+VrFyYsTm7RNCAViiY8= cloud.google.com/go/alloydb v1.14.0 h1:aEmmIHmiHDs46wTr/YqXuumuUGNc5QKYA7317nEFj2Y= @@ -61,8 +61,9 @@ github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJ github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= @@ -81,8 +82,10 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/amikos-tech/chroma-go v0.1.4 h1:MQXFBuKHOuZtlLOF6fLRb1VdXKKWp6TwdWxm6v/RUII= -github.com/amikos-tech/chroma-go v0.1.4/go.mod h1:sT6uXOo/L5S/Q0v9jpYtoR1iOM68hUE2itWw8sOwLHY= +github.com/amikos-tech/chroma-go v0.3.3 h1:e0eIcxWpWvzlEawzxYLhlRTqAp5FK1+845/OKKM0ZmQ= +github.com/amikos-tech/chroma-go v0.3.3/go.mod h1:npSAl5gvRNdUSPuk854u/BBNHa4V0hWvC+Ot06HG6JA= +github.com/amikos-tech/pure-tokenizers v0.1.1 h1:AOPMW+GLd7/FapGiyBV7CGKj766zd1VDFbv+0wqGOWA= +github.com/amikos-tech/pure-tokenizers v0.1.1/go.mod h1:o0ICQtz7tM7pukqwfybBk6FvWKFZLyIWs4uFYbH+CG4= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= @@ -105,48 +108,50 @@ github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:W github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.42.27/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= -github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= -github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 h1:zAybnyUQXIZ5mok5Jqwlf58/TFE7uvd3IAsa1aF9cXs= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10/go.mod h1:qqvMj6gHLR/EXWZw4ZbqlPbQUyenf4h82UQUlKc+l14= -github.com/aws/aws-sdk-go-v2/config v1.29.4 h1:ObNqKsDYFGr2WxnoXKOhCvTlf3HhwtoGgc+KmZ4H5yg= -github.com/aws/aws-sdk-go-v2/config v1.29.4/go.mod h1:j2/AF7j/qxVmsNIChw1tWfsVKOayJoGRDjg1Tgq7NPk= -github.com/aws/aws-sdk-go-v2/credentials v1.17.57 h1:kFQDsbdBAR3GZsB8xA+51ptEnq9TIj3tS4MuP5b+TcQ= -github.com/aws/aws-sdk-go-v2/credentials v1.17.57/go.mod h1:2kerxPUUbTagAr/kkaHiqvj/bcYHzi2qiJS/ZinllU0= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 h1:7lOW8NUwE9UZekS1DYoiPdVAqZ6A+LheHWb+mHbNOq8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27/go.mod h1:w1BASFIPOPUae7AgaH4SbjNbfdkxuggLyGfNFTn8ITY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= +github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4= +github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY= +github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY= +github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8= +github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs= github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.40.0 h1:MhnbAEHLZZQ4bQ7OJT/HbH5IYpo9UGogsdl/GfabG9E= github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.40.0/go.mod h1:WlMBqEPeaBywfaXoMAfpitHvwezq555o8waYL3cCPqo= github.com/aws/aws-sdk-go-v2/service/bedrockagentruntime v1.41.0 h1:Q2U7RCZKbWf6B+i8PCvG+LsgY+ANQvi2NueuLGfUMdw= github.com/aws/aws-sdk-go-v2/service/bedrockagentruntime v1.41.0/go.mod h1:Kek1IWlEDT1bp8kO+soWZh37Cb13LppHUTbMiJunna0= -github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.24.3 h1:GXQrb3kyg4EU94onCRH/oG2IsVjHMNE+IPE4RGkgSa4= -github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.24.3/go.mod h1:PKGlRhLmSZuA6iCbRD1oZKrTJHdm6NWwWBvHxfDNHTA= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= +github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.49.0 h1:osqN479arsxXAIHmBbiAn+0nj7jCkuXtzgtZPSwt0sc= +github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.49.0/go.mod h1:siKVmJdui4dwPPtsKr3F5BAeJxW1MANWaLJnTDfgu7c= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 h1:lguz0bmOoGzozP9XfRJR1QIayEYo+2vP/No3OfLF0pU= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA= github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2 h1:jIiopHEV22b4yQP2q36Y0OmwLbsxNWdWwfZRR5QRRO4= github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2/go.mod h1:U5SNqwhXB3Xe6F47kXvWihPl/ilGaEDe8HD/50Z9wxc= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 h1:c5WJ3iHz7rLIgArznb3JCSQT3uUMiz9DLZhIX+1G8ok= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.14/go.mod h1:+JJQTxB6N4niArC14YNtxcQtwEqzS3o9Z32n7q33Rfs= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 h1:f1L/JtUkVODD+k1+IiSJUUv8A++2qVr+Xvb3xWXETMU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13/go.mod h1:tvqlFoja8/s0o+UruA1Nrezo/df0PzdunMDDurUfg6U= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.12 h1:fqg6c1KVrc3SYWma/egWue5rKI4G2+M4wMQN2JosNAA= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.12/go.mod h1:7Yn+p66q/jt38qMoVfNvjbm3D89mGBnkwDcijgtih8w= -github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= -github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ= +github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= +github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= @@ -215,8 +220,8 @@ github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151X github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= -github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E= +github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -237,6 +242,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= +github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -254,18 +261,18 @@ github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw= -github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= +github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= -github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= +github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -286,8 +293,8 @@ github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= +github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/gage-technologies/mistral-go v1.1.0 h1:POv1wM9jA/9OBXGV2YdPi9Y/h09+MjCbUF+9hRYlVUI= github.com/gage-technologies/mistral-go v1.1.0/go.mod h1:tF++Xt7U975GcLlzhrjSQb8l/x+PrriO9QEdsgm9l28= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= @@ -369,6 +376,8 @@ github.com/go-pg/pg/v10 v10.11.0/go.mod h1:4BpHRoxE61y4Onpof3x1a2SQvi9c+q1dJnrNd github.com/go-pg/zerochecker v0.2.0 h1:pp7f72c3DobMWOb2ErtZsnrPaSvHd2W4o9//8HtF4mU= github.com/go-pg/zerochecker v0.2.0/go.mod h1:NJZ4wKL0NmTtz0GKCoJ8kym6Xn/EQzXRl2OnAe7MmDo= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -376,12 +385,14 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= -github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= +github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= @@ -436,8 +447,6 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2V github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.3 h1:oDTdz9f5VGVVNGu/Q7UXKWYsD0873HXLHdJUNBsSEKM= -github.com/golang/glog v1.2.3/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -474,8 +483,8 @@ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/generative-ai-go v0.15.1 h1:n8aQUpvhPOlGVuM2DRkJ2jvx04zpp42B778AROJa+pQ= -github.com/google/generative-ai-go v0.15.1/go.mod h1:AAucpWZjXsDKhQYWvCYuP6d0yB1kX998pJlOW1rAesw= +github.com/google/generative-ai-go v0.19.0 h1:R71szggh8wHMCUlEMsW2A/3T+5LdEIkiaHSYgSpUgdg= +github.com/google/generative-ai-go v0.19.0/go.mod h1:JYolL13VG7j79kM5BtHz4qwONHkeJQzOCkKXnpqtS/E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -519,8 +528,8 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -530,8 +539,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -637,6 +646,8 @@ github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYW github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/kljensen/snowball v0.10.0 h1:8qgaBLraSuUVHtGH5tJ+VdGpqgfcaE2WkswL/C3nVhY= +github.com/kljensen/snowball v0.10.0/go.mod h1:bJcxtur1W5Qw4fVj9tk5W88zyRcGQQjqahFErdcDTHk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -653,11 +664,13 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= @@ -891,8 +904,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= -github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc= -github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= +github.com/shirou/gopsutil/v4 v4.25.12 h1:e7PvW/0RmJ8p8vPGJH4jvNkOyLmbkXgXW4m6ZPic6CY= +github.com/shirou/gopsutil/v4 v4.25.12/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -946,15 +959,15 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/temoto/robotstxt v1.1.2 h1:W2pOjSJ6SWvldyEuiFXNxz3xZ8aiWX5LbfDiOFd7Fxg= github.com/temoto/robotstxt v1.1.2/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo= -github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw= -github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w= -github.com/testcontainers/testcontainers-go/modules/chroma v0.37.0 h1:vb9fb1mogtlQuF3l0vSAu6rqv3y2j9wozve4xnhVyz8= -github.com/testcontainers/testcontainers-go/modules/chroma v0.37.0/go.mod h1:IWJavzQy7rxM40OqOgSN5iyckgAw21wDyE+NhSctatk= +github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU= +github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY= +github.com/testcontainers/testcontainers-go/modules/chroma v0.40.1-0.20260206153225-b3c2ab185bc7 h1:2n3EZMIzwGmw/v1pUTKoLeFuT8WfWWoapQPy5Sn+de8= +github.com/testcontainers/testcontainers-go/modules/chroma v0.40.1-0.20260206153225-b3c2ab185bc7/go.mod h1:eGu6HHcD1n2x+h9VygYhcjWiN1HiXjeY7r92hYt8lM8= github.com/testcontainers/testcontainers-go/modules/mariadb v0.38.0 h1:RfilPieRalCavWFa+XQtatazPn1L57Do/tRxe/B45I8= github.com/testcontainers/testcontainers-go/modules/mariadb v0.38.0/go.mod h1:26mrWngnaRhxmgy942aVfUihLnihbIGsuIds6gGBnIE= github.com/testcontainers/testcontainers-go/modules/milvus v0.37.0 h1:q+gx0A10DM0VJMJjo9VOXOB1t8Dv3B6EgxXZf2TIzOw= @@ -980,10 +993,10 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= -github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= -github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= -github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -991,6 +1004,8 @@ github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYm github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= +github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -1043,6 +1058,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yalue/onnxruntime_go v1.22.0 h1:SzqOfFRRrLRRAFR5VoSxABjTiQSAi8Y4ETYKrMFK1jk= +github.com/yalue/onnxruntime_go v1.22.0/go.mod h1:b4X26A8pekNb1ACJ58wAXgNKeUCGEAQ9dmACut9Sm/4= github.com/yargevad/filepathx v1.0.0 h1:SYcT+N3tYGi+NvazubCNlvgIPbzAk7i7y2dwg3I5FYc= github.com/yargevad/filepathx v1.0.0/go.mod h1:BprfX/gpYNJHJfc35GjRRpVcwWXS89gGulUIU5tK3tA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= @@ -1115,8 +1132,8 @@ go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0= @@ -1134,8 +1151,8 @@ go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKr go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg= go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1175,8 +1192,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1243,8 +1260,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1263,8 +1280,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1326,8 +1343,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1336,8 +1353,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -1350,8 +1367,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1393,8 +1410,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= -golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1412,6 +1429,8 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genai v1.45.0 h1:s80ZpS42XW0zu/ogiOtenCio17nJ7reEFJjoCftukpA= +google.golang.org/genai v1.45.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= diff --git a/vectorstores/chroma/chroma.go b/vectorstores/chroma/chroma.go index 3e6827076..538a63e71 100644 --- a/vectorstores/chroma/chroma.go +++ b/vectorstores/chroma/chroma.go @@ -2,13 +2,14 @@ package chroma import ( "context" + "encoding/json" "errors" "fmt" "maps" + "os" - chromago "github.com/amikos-tech/chroma-go" - "github.com/amikos-tech/chroma-go/openai" - chromatypes "github.com/amikos-tech/chroma-go/types" + chroma "github.com/amikos-tech/chroma-go/pkg/api/v2" + chromaembed "github.com/amikos-tech/chroma-go/pkg/embeddings" "github.com/google/uuid" "github.com/tmc/langchaingo/embeddings" "github.com/tmc/langchaingo/schema" @@ -26,17 +27,17 @@ var ( // Store is a wrapper around the chromaGo API and client. type Store struct { - client *chromago.Client - collection *chromago.Collection - distanceFunction chromatypes.DistanceFunction - chromaURL string - openaiAPIKey string - openaiOrganization string - - nameSpace string - nameSpaceKey string - embedder embeddings.Embedder - includes []chromatypes.QueryEnum + client chroma.Client + collection chroma.Collection + distanceFunction chromaembed.DistanceMetric + chromaURL string + cloudAPIKey string + tenant string + database string + nameSpace string + nameSpaceKey string + embedder embeddings.Embedder + includes []chroma.Include } var _ vectorstores.VectorStore = Store{} @@ -49,35 +50,28 @@ func New(opts ...Option) (Store, error) { return s, coErr } - // create the client connection and confirm that we can access the server with it - chromaClient, err := chromago.NewClient(s.chromaURL) - if err != nil { - return s, err - } - - if _, errHb := chromaClient.Heartbeat(context.Background()); errHb != nil { - return s, errHb - } - s.client = chromaClient - - var embeddingFunction chromatypes.EmbeddingFunction - if s.embedder != nil { - // inject user's embedding function, if provided - embeddingFunction = chromaGoEmbedder{Embedder: s.embedder} - } else { - // otherwise use standard langchaingo OpenAI embedding function - var options []openai.Option - if s.openaiOrganization != "" { - options = append(options, openai.WithOpenAIOrganizationID(s.openaiOrganization)) + if s.client == nil { + var err error + if s.cloudAPIKey != "" || os.Getenv(ChromaAPIKeyEnvVarName) != "" { + s.client, err = createCloudClient(&s) + } else { + s.client, err = createHTTPClient(&s) } - embeddingFunction, err = openai.NewOpenAIEmbeddingFunction(s.openaiAPIKey, options...) if err != nil { return s, err } } - col, errCc := s.client.CreateCollection(context.Background(), s.nameSpace, map[string]any{}, true, - embeddingFunction, s.distanceFunction) + if errHb := s.client.Heartbeat(context.Background()); errHb != nil { + return s, errHb + } + + ef := chromaGoEmbedder{Embedder: s.embedder} + + col, errCc := s.client.GetOrCreateCollection(context.Background(), s.nameSpace, + chroma.WithEmbeddingFunctionCreate(ef), + chroma.WithHNSWSpaceCreate(s.distanceFunction), + ) if errCc != nil { return s, fmt.Errorf("%w: %w", ErrNewClient, errCc) } @@ -86,6 +80,38 @@ func New(opts ...Option) (Store, error) { return s, nil } +func createHTTPClient(s *Store) (chroma.Client, error) { + return chroma.NewHTTPClient(chroma.WithBaseURL(s.chromaURL)) +} + +func createCloudClient(s *Store) (chroma.Client, error) { + var opts []chroma.ClientOption + apiKey := s.cloudAPIKey + if apiKey == "" { + apiKey = os.Getenv(ChromaAPIKeyEnvVarName) + } + if apiKey != "" { + opts = append(opts, chroma.WithCloudAPIKey(apiKey)) + } + if s.tenant != "" && s.database != "" { + opts = append(opts, chroma.WithDatabaseAndTenant(s.database, s.tenant)) + } + return chroma.NewCloudClient(opts...) +} + +// Close releases client resources. +func (s Store) Close() error { + if s.client != nil { + return s.client.Close() + } + return nil +} + +// Collection returns the underlying Chroma collection for advanced operations. +func (s Store) Collection() chroma.Collection { + return s.collection +} + // AddDocuments adds the text and metadata from the documents to the Chroma collection associated with 'Store'. // and returns the ids of the added documents. func (s Store) AddDocuments(ctx context.Context, @@ -102,25 +128,37 @@ func (s Store) AddDocuments(ctx context.Context, return nil, fmt.Errorf("%w: nameSpace without nameSpaceKey", ErrUnsupportedOptions) } - ids := make([]string, len(docs)) + ids := make([]chroma.DocumentID, len(docs)) + strIDs := make([]string, len(docs)) texts := make([]string, len(docs)) - metadatas := make([]map[string]any, len(docs)) - for docIdx, doc := range docs { - ids[docIdx] = uuid.New().String() // TODO (noodnik2): find & use something more meaningful - texts[docIdx] = doc.PageContent - mc := make(map[string]any, 0) + metadatas := make([]chroma.DocumentMetadata, len(docs)) + + for i, doc := range docs { + id := uuid.New().String() + ids[i] = chroma.DocumentID(id) + strIDs[i] = id + texts[i] = doc.PageContent + mc := make(map[string]any) maps.Copy(mc, doc.Metadata) - metadatas[docIdx] = mc if nameSpace != "" { - metadatas[docIdx][s.nameSpaceKey] = nameSpace + mc[s.nameSpaceKey] = nameSpace } + dm, err := chroma.NewDocumentMetadataFromMap(mc) + if err != nil { + return nil, fmt.Errorf("%w: %w", ErrAddDocument, err) + } + metadatas[i] = dm } col := s.collection - if _, addErr := col.Add(ctx, nil, metadatas, texts, ids); addErr != nil { + if addErr := col.Add(ctx, + chroma.WithIDs(ids...), + chroma.WithTexts(texts...), + chroma.WithMetadatas(metadatas...), + ); addErr != nil { return nil, fmt.Errorf("%w: %w", ErrAddDocument, addErr) } - return ids, nil + return strIDs, nil } func (s Store) SimilaritySearch(ctx context.Context, query string, numDocuments int, @@ -129,7 +167,6 @@ func (s Store) SimilaritySearch(ctx context.Context, query string, numDocuments opts := s.getOptions(options...) if opts.Embedder != nil { - // embedder is not used by this method, so shouldn't ever be specified return nil, fmt.Errorf("%w: Embedder", ErrUnsupportedOptions) } @@ -139,23 +176,43 @@ func (s Store) SimilaritySearch(ctx context.Context, query string, numDocuments } filter := s.getNamespacedFilter(opts) - qr, queryErr := s.collection.Query(ctx, []string{query}, safeIntToInt32(numDocuments), filter, nil, s.includes) + + queryOpts := []chroma.CollectionQueryOption{ + chroma.WithQueryTexts(query), + chroma.WithNResults(numDocuments), + } + + if filter != nil { + queryOpts = append(queryOpts, chroma.WithWhere(&rawWhereFilter{data: filter})) + } + + if len(s.includes) > 0 { + queryOpts = append(queryOpts, chroma.WithInclude(s.includes...)) + } + + qr, queryErr := s.collection.Query(ctx, queryOpts...) if queryErr != nil { return nil, queryErr } - if len(qr.Documents) != len(qr.Metadatas) || len(qr.Metadatas) != len(qr.Distances) { - return nil, fmt.Errorf("%w: qr.Documents[%d], qr.Metadatas[%d], qr.Distances[%d]", - ErrUnexpectedResponseLength, len(qr.Documents), len(qr.Metadatas), len(qr.Distances)) + docGroups := qr.GetDocumentsGroups() + metaGroups := qr.GetMetadatasGroups() + distGroups := qr.GetDistancesGroups() + + if len(docGroups) != len(metaGroups) || len(metaGroups) != len(distGroups) { + return nil, fmt.Errorf("%w: documents[%d], metadatas[%d], distances[%d]", + ErrUnexpectedResponseLength, len(docGroups), len(metaGroups), len(distGroups)) } + var sDocs []schema.Document - for docsI := range qr.Documents { - for docI := range qr.Documents[docsI] { - if score := 1.0 - qr.Distances[docsI][docI]; score >= scoreThreshold { + for g := range docGroups { + for i := range docGroups[g] { + dist := float64(distGroups[g][i]) + if score := 1.0 - dist; score >= float64(scoreThreshold) { sDocs = append(sDocs, schema.Document{ - Metadata: qr.Metadatas[docsI][docI], - PageContent: qr.Documents[docsI][docI], - Score: score, + Metadata: documentMetadataToMap(metaGroups[g][i]), + PageContent: docGroups[g][i].ContentString(), + Score: float32(score), }) } } @@ -168,9 +225,9 @@ func (s Store) RemoveCollection() error { if s.client == nil || s.collection == nil { return fmt.Errorf("%w: no collection", ErrRemoveCollection) } - _, errDc := s.client.DeleteCollection(context.Background(), s.collection.Name) - if errDc != nil { - return fmt.Errorf("%w(%s): %w", ErrRemoveCollection, s.collection.Name, errDc) + name := s.collection.Name() + if errDc := s.client.DeleteCollection(context.Background(), name); errDc != nil { + return fmt.Errorf("%w(%s): %w", ErrRemoveCollection, name, errDc) } return nil } @@ -213,6 +270,70 @@ func (s Store) getNamespacedFilter(opts vectorstores.Options) map[string]any { return map[string]any{"$and": []map[string]any{nameSpaceFilter, filter}} } -func safeIntToInt32(n int) int32 { - return int32(max(0, n)) +func (s Store) getNamespacedSearchFilter(filter map[string]any) map[string]any { + if s.nameSpace == "" || s.nameSpaceKey == "" { + return filter + } + + nameSpaceFilter := map[string]any{s.nameSpaceKey: s.nameSpace} + if filter == nil { + return nameSpaceFilter + } + + return map[string]any{"$and": []map[string]any{nameSpaceFilter, filter}} +} + +// rawWhereFilter wraps a map[string]any to implement chroma.WhereFilter, +// allowing users to pass arbitrary filter maps through the vectorstores API. +type rawWhereFilter struct { + data map[string]any +} + +func (r *rawWhereFilter) String() string { + b, _ := json.Marshal(r.data) + return string(b) +} + +func (r *rawWhereFilter) Validate() error { return nil } + +func (r *rawWhereFilter) MarshalJSON() ([]byte, error) { + return json.Marshal(r.data) +} + +func (r *rawWhereFilter) UnmarshalJSON(b []byte) error { + return json.Unmarshal(b, &r.data) +} + +// rawWhereClause wraps a map[string]any to implement chroma.WhereClause +// for use with the Search API filtering. +type rawWhereClause struct { + data map[string]any +} + +func (r *rawWhereClause) Operator() chroma.WhereFilterOperator { return "" } +func (r *rawWhereClause) Key() string { return "" } +func (r *rawWhereClause) Operand() any { return r.data } + +func (r *rawWhereClause) String() string { + b, _ := json.Marshal(r.data) + return string(b) +} + +func (r *rawWhereClause) Validate() error { return nil } +func (r *rawWhereClause) MarshalJSON() ([]byte, error) { return json.Marshal(r.data) } +func (r *rawWhereClause) UnmarshalJSON(b []byte) error { return json.Unmarshal(b, &r.data) } + +func documentMetadataToMap(dm chroma.DocumentMetadata) map[string]any { + if dm == nil { + return nil + } + b, err := json.Marshal(dm) + if err != nil { + return nil + } + var m map[string]any + if err := json.Unmarshal(b, &m); err != nil { + return nil + } + return m } diff --git a/vectorstores/chroma/chroma_test.go b/vectorstores/chroma/chroma_test.go index d11fbe675..6f95fa210 100644 --- a/vectorstores/chroma/chroma_test.go +++ b/vectorstores/chroma/chroma_test.go @@ -8,7 +8,8 @@ import ( "strings" "testing" - chromatypes "github.com/amikos-tech/chroma-go/types" + chromav2 "github.com/amikos-tech/chroma-go/pkg/api/v2" + chromaembed "github.com/amikos-tech/chroma-go/pkg/embeddings" "github.com/google/uuid" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" @@ -24,15 +25,6 @@ import ( "github.com/tmc/langchaingo/vectorstores/chroma" ) -// TODO (noodnik2): -// add relevant tests from "weaviate_test.go" (the initial tests are based upon those found in "pinecone_test.go") -// consider refactoring out standard set of vectorstore unit tests to run across all implementations - -// -// NOTE: View the 'getValues()' function to see which environment variables are required to run these tests. -// WARNING: When these values are not provided, the tests will not fail, but will be (silently) skipped. -// - // createOpenAIEmbedder creates an OpenAI embedder with httprr support for testing. func createOpenAIEmbedder(t *testing.T) *embeddings.EmbedderImpl { t.Helper() @@ -77,13 +69,12 @@ func TestChromaGoStoreRest(t *testing.T) { t.Parallel() } - testChromaURL, openaiAPIKey := getValues(t) + testChromaURL := getValues(t) e := createOpenAIEmbedder(t) s, err := chroma.New( - chroma.WithOpenAIAPIKey(openaiAPIKey), chroma.WithChromaURL(testChromaURL), - chroma.WithDistanceFunction(chromatypes.COSINE), + chroma.WithDistanceFunction(chromaembed.COSINE), chroma.WithNameSpace(getTestNameSpace()), chroma.WithEmbedder(e), ) @@ -116,13 +107,12 @@ func TestChromaStoreRestWithScoreThreshold(t *testing.T) { t.Parallel() } - testChromaURL, openaiAPIKey := getValues(t) + testChromaURL := getValues(t) e := createOpenAIEmbedder(t) s, err := chroma.New( - chroma.WithOpenAIAPIKey(openaiAPIKey), chroma.WithChromaURL(testChromaURL), - chroma.WithDistanceFunction(chromatypes.COSINE), + chroma.WithDistanceFunction(chromaembed.COSINE), chroma.WithNameSpace(getTestNameSpace()), chroma.WithEmbedder(e), ) @@ -167,11 +157,10 @@ func TestSimilaritySearchWithInvalidScoreThreshold(t *testing.T) { t.Parallel() } - testChromaURL, openaiAPIKey := getValues(t) + testChromaURL := getValues(t) e := createOpenAIEmbedder(t) s, err := chroma.New( - chroma.WithOpenAIAPIKey(openaiAPIKey), chroma.WithChromaURL(testChromaURL), chroma.WithNameSpace(getTestNameSpace()), chroma.WithEmbedder(e), @@ -213,12 +202,11 @@ func TestChromaAsRetriever(t *testing.T) { t.Parallel() } - testChromaURL, openaiAPIKey := getValues(t) + testChromaURL := getValues(t) llm, e := createOpenAILLMAndEmbedder(t) s, err := chroma.New( - chroma.WithOpenAIAPIKey(openaiAPIKey), chroma.WithChromaURL(testChromaURL), chroma.WithNameSpace(getTestNameSpace()), chroma.WithEmbedder(e), @@ -257,14 +245,13 @@ func TestChromaAsRetrieverWithScoreThreshold(t *testing.T) { t.Parallel() } - testChromaURL, openaiAPIKey := getValues(t) + testChromaURL := getValues(t) llm, e := createOpenAILLMAndEmbedder(t) s, err := chroma.New( - chroma.WithOpenAIAPIKey(openaiAPIKey), chroma.WithChromaURL(testChromaURL), - chroma.WithDistanceFunction(chromatypes.COSINE), + chroma.WithDistanceFunction(chromaembed.COSINE), chroma.WithNameSpace(getTestNameSpace()), chroma.WithEmbedder(e), ) @@ -294,9 +281,6 @@ func TestChromaAsRetrieverWithScoreThreshold(t *testing.T) { ) require.NoError(t, err) - // TODO (noodnik2): clarify - WHY should we see "orange" in the result, - // as required by (expected in) the original "Pinecone" test?? - // require.Contains(t, result, "orange", "expected orange in result") require.Contains(t, result, "black", "expected black in result") require.Contains(t, result, "beige", "expected beige in result") } @@ -309,12 +293,11 @@ func TestChromaAsRetrieverWithMetadataFilterEqualsClause(t *testing.T) { t.Parallel() } - testChromaURL, openaiAPIKey := getValues(t) + testChromaURL := getValues(t) llm, e := createOpenAILLMAndEmbedder(t) s, err := chroma.New( - chroma.WithOpenAIAPIKey(openaiAPIKey), chroma.WithChromaURL(testChromaURL), chroma.WithNameSpace(getTestNameSpace()), chroma.WithEmbedder(e), @@ -386,12 +369,11 @@ func TestChromaAsRetrieverWithMetadataFilterInClause(t *testing.T) { t.Parallel() } - testChromaURL, openaiAPIKey := getValues(t) + testChromaURL := getValues(t) llm, e := createOpenAILLMAndEmbedder(t) s, newChromaErr := chroma.New( - chroma.WithOpenAIAPIKey(openaiAPIKey), chroma.WithChromaURL(testChromaURL), chroma.WithEmbedder(e), ) @@ -467,12 +449,11 @@ func TestChromaAsRetrieverWithMetadataFilterNotSelected(t *testing.T) { t.Parallel() } - testChromaURL, openaiAPIKey := getValues(t) + testChromaURL := getValues(t) llm, e := createOpenAILLMAndEmbedder(t) s, err := chroma.New( - chroma.WithOpenAIAPIKey(openaiAPIKey), chroma.WithChromaURL(testChromaURL), chroma.WithNameSpace(getTestNameSpace()), chroma.WithEmbedder(e), @@ -544,12 +525,11 @@ func TestChromaAsRetrieverWithMetadataFilters(t *testing.T) { t.Parallel() } - testChromaURL, openaiAPIKey := getValues(t) + testChromaURL := getValues(t) llm, e := createOpenAILLMAndEmbedder(t) s, err := chroma.New( - chroma.WithOpenAIAPIKey(openaiAPIKey), chroma.WithChromaURL(testChromaURL), chroma.WithNameSpace(getTestNameSpace()), chroma.WithEmbedder(e), @@ -586,15 +566,15 @@ func TestChromaAsRetrieverWithMetadataFilters(t *testing.T) { ) require.NoError(t, err) - filter := map[string]interface{}{ - "$and": []map[string]interface{}{ + filter := map[string]any{ + "$and": []map[string]any{ { - "location": map[string]interface{}{ + "location": map[string]any{ "$eq": "sitting room", }, }, { - "square_feet": map[string]interface{}{ + "square_feet": map[string]any{ "$gte": 300, }, }, @@ -615,7 +595,7 @@ func TestChromaAsRetrieverWithMetadataFilters(t *testing.T) { require.Contains(t, result, "purple", "expected purple in result") } -func getValues(t *testing.T) (string, string) { +func getValues(t *testing.T) string { t.Helper() testctr.SkipIfDockerNotAvailable(t) @@ -623,14 +603,14 @@ func getValues(t *testing.T) (string, string) { t.Skip("Skipping test in short mode") } - openaiAPIKey := os.Getenv(chroma.OpenAIAPIKeyEnvVarName) + openaiAPIKey := os.Getenv("OPENAI_API_KEY") if openaiAPIKey == "" { - t.Skipf("Must set %s to run test", chroma.OpenAIAPIKeyEnvVarName) + t.Skipf("Must set OPENAI_API_KEY to run test") } chromaURL := os.Getenv(chroma.ChromaURLKeyEnvVarName) if chromaURL == "" { - chromaContainer, err := tcchroma.Run(context.Background(), "chromadb/chroma:0.4.24", testcontainers.WithLogger(log.TestLogger(t))) + chromaContainer, err := tcchroma.Run(context.Background(), "chromadb/chroma:0.6.3", testcontainers.WithLogger(log.TestLogger(t))) if err != nil && strings.Contains(err.Error(), "Cannot connect to the Docker daemon") { t.Skip("Docker not available") } @@ -647,14 +627,194 @@ func getValues(t *testing.T) (string, string) { } } - return chromaURL, openaiAPIKey + return chromaURL } func cleanupTestArtifacts(t *testing.T, s chroma.Store) { t.Helper() require.NoError(t, s.RemoveCollection()) + _ = s.Close() } func getTestNameSpace() string { return fmt.Sprintf("test-namespace-%s", uuid.New().String()) } + +func TestCollectionGetter(t *testing.T) { + httprr.SkipIfNoCredentialsAndRecordingMissing(t, "CHROMA_URL") + rr := httprr.OpenForTest(t, http.DefaultTransport) + _ = rr + if !rr.Recording() { + t.Parallel() + } + + testChromaURL := getValues(t) + e := createOpenAIEmbedder(t) + + s, err := chroma.New( + chroma.WithChromaURL(testChromaURL), + chroma.WithNameSpace(getTestNameSpace()), + chroma.WithEmbedder(e), + ) + require.NoError(t, err) + defer cleanupTestArtifacts(t, s) + + col := s.Collection() + require.NotNil(t, col) + require.NotEmpty(t, col.Name()) +} + +func TestSearch(t *testing.T) { + httprr.SkipIfNoCredentialsAndRecordingMissing(t, "CHROMA_URL") + rr := httprr.OpenForTest(t, http.DefaultTransport) + _ = rr + if !rr.Recording() { + t.Parallel() + } + + testChromaURL := getValues(t) + e := createOpenAIEmbedder(t) + + s, err := chroma.New( + chroma.WithChromaURL(testChromaURL), + chroma.WithDistanceFunction(chromaembed.COSINE), + chroma.WithNameSpace(getTestNameSpace()), + chroma.WithEmbedder(e), + ) + require.NoError(t, err) + defer cleanupTestArtifacts(t, s) + + _, err = s.AddDocuments(context.Background(), []schema.Document{ + {PageContent: "tokyo", Metadata: map[string]any{"country": "japan"}}, + {PageContent: "paris", Metadata: map[string]any{"country": "france"}}, + {PageContent: "london", Metadata: map[string]any{"country": "uk"}}, + }) + require.NoError(t, err) + + docs, err := s.Search(context.Background(), "japan", 3) + require.NoError(t, err) + require.NotEmpty(t, docs) + require.Equal(t, "tokyo", docs[0].PageContent) + require.True(t, docs[0].Score > 0, "expected positive relevance score") +} + +func TestSearchWithFilter(t *testing.T) { + httprr.SkipIfNoCredentialsAndRecordingMissing(t, "CHROMA_URL") + rr := httprr.OpenForTest(t, http.DefaultTransport) + _ = rr + if !rr.Recording() { + t.Parallel() + } + + testChromaURL := getValues(t) + e := createOpenAIEmbedder(t) + + s, err := chroma.New( + chroma.WithChromaURL(testChromaURL), + chroma.WithDistanceFunction(chromaembed.COSINE), + chroma.WithNameSpace(getTestNameSpace()), + chroma.WithEmbedder(e), + ) + require.NoError(t, err) + defer cleanupTestArtifacts(t, s) + + _, err = s.AddDocuments(context.Background(), []schema.Document{ + {PageContent: "tokyo", Metadata: map[string]any{"country": "japan"}}, + {PageContent: "osaka", Metadata: map[string]any{"country": "japan"}}, + {PageContent: "paris", Metadata: map[string]any{"country": "france"}}, + }) + require.NoError(t, err) + + filter := map[string]any{ + "country": map[string]any{"$eq": "japan"}, + } + + docs, err := s.Search(context.Background(), "city", 3, + chroma.WithSearchFilter(filter), + ) + require.NoError(t, err) + require.Len(t, docs, 2) + for _, doc := range docs { + require.Equal(t, "japan", doc.Metadata["country"]) + } +} + +func TestSearchWithScoreThreshold(t *testing.T) { + httprr.SkipIfNoCredentialsAndRecordingMissing(t, "CHROMA_URL") + rr := httprr.OpenForTest(t, http.DefaultTransport) + _ = rr + if !rr.Recording() { + t.Parallel() + } + + testChromaURL := getValues(t) + e := createOpenAIEmbedder(t) + + s, err := chroma.New( + chroma.WithChromaURL(testChromaURL), + chroma.WithDistanceFunction(chromaembed.COSINE), + chroma.WithNameSpace(getTestNameSpace()), + chroma.WithEmbedder(e), + ) + require.NoError(t, err) + defer cleanupTestArtifacts(t, s) + + _, err = s.AddDocuments(context.Background(), []schema.Document{ + {PageContent: "tokyo"}, + {PageContent: "potato"}, + }) + require.NoError(t, err) + + // Invalid threshold + _, err = s.Search(context.Background(), "japan", 2, + chroma.WithSearchScoreThreshold(-0.5), + ) + require.ErrorIs(t, err, chroma.ErrInvalidScoreThreshold) + + _, err = s.Search(context.Background(), "japan", 2, + chroma.WithSearchScoreThreshold(1.5), + ) + require.ErrorIs(t, err, chroma.ErrInvalidScoreThreshold) + + // High threshold should filter results + docs, err := s.Search(context.Background(), "japan", 2, + chroma.WithSearchScoreThreshold(0.9), + ) + require.NoError(t, err) + for _, doc := range docs { + require.GreaterOrEqual(t, doc.Score, float32(0.9)) + } +} + +func TestWithClientOption(t *testing.T) { + httprr.SkipIfNoCredentialsAndRecordingMissing(t, "CHROMA_URL") + rr := httprr.OpenForTest(t, http.DefaultTransport) + _ = rr + if !rr.Recording() { + t.Parallel() + } + + testChromaURL := getValues(t) + e := createOpenAIEmbedder(t) + + client, err := chromav2.NewHTTPClient(chromav2.WithBaseURL(testChromaURL)) + require.NoError(t, err) + + s, err := chroma.New( + chroma.WithClient(client), + chroma.WithNameSpace(getTestNameSpace()), + chroma.WithEmbedder(e), + ) + require.NoError(t, err) + defer cleanupTestArtifacts(t, s) + + _, err = s.AddDocuments(context.Background(), []schema.Document{ + {PageContent: "test document"}, + }) + require.NoError(t, err) + + docs, err := s.SimilaritySearch(context.Background(), "test", 1) + require.NoError(t, err) + require.Len(t, docs, 1) + require.Equal(t, "test document", docs[0].PageContent) +} diff --git a/vectorstores/chroma/embedder.go b/vectorstores/chroma/embedder.go index 6e7023b8a..383afde11 100644 --- a/vectorstores/chroma/embedder.go +++ b/vectorstores/chroma/embedder.go @@ -3,37 +3,42 @@ package chroma import ( "context" - chromatypes "github.com/amikos-tech/chroma-go/types" + chromaembed "github.com/amikos-tech/chroma-go/pkg/embeddings" "github.com/tmc/langchaingo/embeddings" ) -var _ chromatypes.EmbeddingFunction = chromaGoEmbedder{} // compile-time check +var _ chromaembed.EmbeddingFunction = chromaGoEmbedder{} // compile-time check -// chromaGoEmbedder adapts an 'embeddings.Embedder' to a 'chroma_go.EmbeddingFunction'. type chromaGoEmbedder struct { embeddings.Embedder } -func (e chromaGoEmbedder) EmbedDocuments(ctx context.Context, texts []string) ([]*chromatypes.Embedding, error) { - _embeddings, err := e.Embedder.EmbedDocuments(ctx, texts) +func (e chromaGoEmbedder) EmbedDocuments(ctx context.Context, texts []string) ([]chromaembed.Embedding, error) { + vecs, err := e.Embedder.EmbedDocuments(ctx, texts) if err != nil { return nil, err } - _chrmembeddings := make([]*chromatypes.Embedding, len(_embeddings)) - for i, emb := range _embeddings { - _chrmembeddings[i] = chromatypes.NewEmbeddingFromFloat32(emb) + out := make([]chromaembed.Embedding, len(vecs)) + for i, v := range vecs { + out[i] = chromaembed.NewEmbeddingFromFloat32(v) } - return _chrmembeddings, nil + return out, nil } -func (e chromaGoEmbedder) EmbedQuery(ctx context.Context, text string) (*chromatypes.Embedding, error) { - _embedding, err := e.Embedder.EmbedQuery(ctx, text) +func (e chromaGoEmbedder) EmbedQuery(ctx context.Context, text string) (chromaembed.Embedding, error) { + v, err := e.Embedder.EmbedQuery(ctx, text) if err != nil { return nil, err } - return chromatypes.NewEmbeddingFromFloat32(_embedding), nil + return chromaembed.NewEmbeddingFromFloat32(v), nil } -func (e chromaGoEmbedder) EmbedRecords(ctx context.Context, records []*chromatypes.Record, force bool) error { - return chromatypes.EmbedRecordsDefaultImpl(e, ctx, records, force) +func (e chromaGoEmbedder) Name() string { return "langchaingo" } + +func (e chromaGoEmbedder) GetConfig() chromaembed.EmbeddingFunctionConfig { return nil } + +func (e chromaGoEmbedder) DefaultSpace() chromaembed.DistanceMetric { return chromaembed.L2 } + +func (e chromaGoEmbedder) SupportedSpaces() []chromaembed.DistanceMetric { + return []chromaembed.DistanceMetric{chromaembed.L2, chromaembed.COSINE, chromaembed.IP} } diff --git a/vectorstores/chroma/options.go b/vectorstores/chroma/options.go index a09dbec27..515853f3e 100644 --- a/vectorstores/chroma/options.go +++ b/vectorstores/chroma/options.go @@ -5,17 +5,17 @@ import ( "fmt" "os" - chromatypes "github.com/amikos-tech/chroma-go/types" + chroma "github.com/amikos-tech/chroma-go/pkg/api/v2" + chromaembed "github.com/amikos-tech/chroma-go/pkg/embeddings" "github.com/tmc/langchaingo/embeddings" ) const ( - OpenAIAPIKeyEnvVarName = "OPENAI_API_KEY" // #nosec G101 - OpenAIOrgIDEnvVarName = "OPENAI_ORGANIZATION" ChromaURLKeyEnvVarName = "CHROMA_URL" + ChromaAPIKeyEnvVarName = "CHROMA_API_KEY" //nolint:gosec // env var name, not a credential DefaultNameSpace = "langchain" DefaultNameSpaceKey = "nameSpace" - DefaultDistanceFunc = chromatypes.L2 + DefaultDistanceFunc = chromaembed.L2 ) // ErrInvalidOptions is returned when the options given are invalid. @@ -45,50 +45,75 @@ func WithEmbedder(e embeddings.Embedder) Option { } } -// WithDistanceFunction specifies the distance function which will be used (default is L2) -// see: https://github.com/amikos-tech/chroma-go/blob/ab1339d0ee1a863be7d6773bcdedc1cfd08e3d77/types/types.go#L22 -func WithDistanceFunction(distanceFunction chromatypes.DistanceFunction) Option { +// WithDistanceFunction specifies the distance function which will be used (default is L2). +func WithDistanceFunction(distanceFunction chromaembed.DistanceMetric) Option { return func(p *Store) { p.distanceFunction = distanceFunction } } // WithIncludes is an option for setting the includes to query the vectors. -func WithIncludes(includes []chromatypes.QueryEnum) Option { +func WithIncludes(includes []chroma.Include) Option { return func(p *Store) { p.includes = includes } } -// WithOpenAIAPIKey is an option for setting the OpenAI api key. If the option is not set -// the api key is read from the OPENAI_API_KEY environment variable. If the -// variable is not present, an error will be returned. -func WithOpenAIAPIKey(openAiAPIKey string) Option { +// WithClient injects a pre-configured Chroma client, skipping URL/cloud validation. +func WithClient(client chroma.Client) Option { return func(p *Store) { - p.openaiAPIKey = openAiAPIKey + p.client = client } } -// WithOpenAIOrganization is an option for setting the OpenAI organization id. -func WithOpenAIOrganization(openAiOrganization string) Option { +// WithCloudAPIKey sets the API key for Chroma Cloud. +// See https://docs.trychroma.com/cloud/getting-started for details. +func WithCloudAPIKey(apiKey string) Option { return func(p *Store) { - p.openaiOrganization = openAiOrganization + p.cloudAPIKey = apiKey + } +} + +// WithTenant sets the tenant for Chroma Cloud. +func WithTenant(tenant string) Option { + return func(p *Store) { + p.tenant = tenant + } +} + +// WithDatabase sets the database for Chroma Cloud. +func WithDatabase(database string) Option { + return func(p *Store) { + p.database = database } } func applyClientOptions(opts ...Option) (Store, error) { o := &Store{ - nameSpace: DefaultNameSpace, - nameSpaceKey: DefaultNameSpaceKey, - distanceFunction: DefaultDistanceFunc, - openaiAPIKey: os.Getenv(OpenAIAPIKeyEnvVarName), - openaiOrganization: os.Getenv(OpenAIOrgIDEnvVarName), + nameSpace: DefaultNameSpace, + nameSpaceKey: DefaultNameSpaceKey, + distanceFunction: DefaultDistanceFunc, } for _, opt := range opts { opt(o) } + if o.embedder == nil { + return Store{}, fmt.Errorf("%w: missing embedder", ErrInvalidOptions) + } + + // If a pre-configured client was provided, skip URL/cloud validation. + if o.client != nil { + return *o, nil + } + + // Cloud mode: API key provided via option or env var. + if o.cloudAPIKey != "" || os.Getenv(ChromaAPIKeyEnvVarName) != "" { + return *o, nil + } + + // HTTP mode: require chromaURL. if o.chromaURL == "" { o.chromaURL = os.Getenv(ChromaURLKeyEnvVarName) if o.chromaURL == "" { @@ -98,10 +123,5 @@ func applyClientOptions(opts ...Option) (Store, error) { } } - // a embedder or an openai api key must be provided - if o.openaiAPIKey == "" && o.embedder == nil { - return Store{}, fmt.Errorf("%w: missing embedder or openai api key", ErrInvalidOptions) - } - return *o, nil } diff --git a/vectorstores/chroma/search.go b/vectorstores/chroma/search.go new file mode 100644 index 000000000..2aedc16ad --- /dev/null +++ b/vectorstores/chroma/search.go @@ -0,0 +1,111 @@ +package chroma + +import ( + "context" + "fmt" + + chroma "github.com/amikos-tech/chroma-go/pkg/api/v2" + "github.com/tmc/langchaingo/schema" +) + +// SearchOption configures a Search call. +type SearchOption func(*searchConfig) + +type searchConfig struct { + scoreThreshold float32 + filter map[string]any + offset int + readLevel chroma.ReadLevel +} + +// WithSearchScoreThreshold filters results below the given relevance score (0-1, higher is better). +func WithSearchScoreThreshold(threshold float32) SearchOption { + return func(c *searchConfig) { + c.scoreThreshold = threshold + } +} + +// WithSearchFilter adds a metadata filter to the search using Chroma's where clause syntax. +func WithSearchFilter(filter map[string]any) SearchOption { + return func(c *searchConfig) { + c.filter = filter + } +} + +// WithSearchOffset sets the pagination offset for search results. +func WithSearchOffset(offset int) SearchOption { + return func(c *searchConfig) { + c.offset = offset + } +} + +// WithSearchReadLevel sets the read consistency level for the search. +func WithSearchReadLevel(level chroma.ReadLevel) SearchOption { + return func(c *searchConfig) { + c.readLevel = level + } +} + +// Search performs a KNN text search using Chroma's Search API, which returns relevance scores +// (higher is better) rather than distances. This provides richer functionality than SimilaritySearch +// including pagination, read levels, and composable ranking via the Collection() escape hatch. +// See https://docs.trychroma.com/cloud/search-api/overview for details. +func (s Store) Search(ctx context.Context, query string, numDocuments int, opts ...SearchOption) ([]schema.Document, error) { + cfg := &searchConfig{} + for _, opt := range opts { + opt(cfg) + } + + if cfg.scoreThreshold < 0 || cfg.scoreThreshold > 1 { + return nil, ErrInvalidScoreThreshold + } + + filter := s.getNamespacedSearchFilter(cfg.filter) + + searchReqOpts := []chroma.SearchRequestOption{ + chroma.WithKnnRank(chroma.KnnQueryText(query), chroma.WithKnnLimit(numDocuments)), + chroma.WithLimit(numDocuments), + chroma.WithSelect(chroma.KDocument, chroma.KMetadata, chroma.KScore, chroma.KID), + } + + if cfg.offset > 0 { + searchReqOpts = append(searchReqOpts, chroma.WithOffset(cfg.offset)) + } + + if filter != nil { + searchReqOpts = append(searchReqOpts, + chroma.WithSearchFilter(&chroma.SearchFilter{Where: &rawWhereClause{data: filter}}), + ) + } + + collOpts := []chroma.SearchCollectionOption{ + chroma.NewSearchRequest(searchReqOpts...), + } + if cfg.readLevel != "" { + collOpts = append(collOpts, chroma.WithReadLevel(cfg.readLevel)) + } + + result, err := s.collection.Search(ctx, collOpts...) + if err != nil { + return nil, err + } + + searchResult, ok := result.(*chroma.SearchResultImpl) + if !ok { + return nil, fmt.Errorf("unexpected search result type: %T", result) + } + + var docs []schema.Document + for _, row := range searchResult.Rows() { + score := float32(row.Score) + if score >= cfg.scoreThreshold { + docs = append(docs, schema.Document{ + PageContent: row.Document, + Metadata: documentMetadataToMap(row.Metadata), + Score: score, + }) + } + } + + return docs, nil +}