Skip to content

Releases: ChromaDotNet/ChromaDB.Client

2.11.0

Choose a tag to compare

@Laurianti Laurianti released this 07 Oct 13:34

ChromaDotNet.Client and ChromaDotNet.Client.DependencyInjection 2.11.0, released together.

New

  • ChromaConfigurationOptions.WithChromaCloud() says the server is Chroma Cloud behind a proxy or another address, for the rules of Chroma Cloud.

Changes of behavior

  • A record without metadata keys comes back with an empty Metadata, not null, when the read includes the metadatas.
  • AddAsync, UpdateAsync and UpsertAsync throw an ArgumentException for a metadata without keys and for a list of values of more than one type, as the Python client does.
  • GetAsync throws an ArgumentOutOfRangeException for a negative limit or offset, and returns no record for a limit of 0 without a request.
  • A write that fails after some of its batches went says how many records went, and a collection client made by name does not run it again.
  • With deleteRecordsFirst, records that the server returns after their delete make the client throw a ChromaException and keep the collection.
  • ChromaQuery.NResults rejects a negative number.

Fixes

  • An id condition sends each id once.
  • CreateCollectionAsync and GetOrCreateCollectionAsync reject the names . and ...
  • A connection string takes http and https endpoints only.
  • The weight of the text in ChromaRank.HybridRrf never goes below 0.
  • AddKeyedChromaClient gives each key its own HttpClient, and a null key throws an ArgumentNullException.

NuGet: https://www.nuget.org/packages/ChromaDotNet.Client/2.11.0 and https://www.nuget.org/packages/ChromaDotNet.Client.DependencyInjection/2.11.0

2.10.3

Choose a tag to compare

@Laurianti Laurianti released this 07 Oct 10:35

ChromaDotNet.Client and ChromaDotNet.Client.DependencyInjection 2.10.3, released together.

  • AddAsync, UpdateAsync and UpsertAsync throw an ArgumentException before any request when the embeddings, metadatas, documents or URIs are not as many as the ids, or an embedding has NaN or an infinity, also when the embeddings go as base64.
  • DeleteAsync with an empty list of ids and no filters throws an ArgumentException.
  • GetAsync with more ids than the batch size returns an id given twice once.
  • On Chroma 0.x a collection without a space reports L2, the default of Chroma.
  • docs/COMPATIBILITY.md numbers the known defects of the servers, and the code that works around one names it.

NuGet: https://www.nuget.org/packages/ChromaDotNet.Client/2.10.3 and https://www.nuget.org/packages/ChromaDotNet.Client.DependencyInjection/2.10.3

2.10.2

Choose a tag to compare

@Laurianti Laurianti released this 06 Oct 23:44

ChromaDotNet.Client and ChromaDotNet.Client.DependencyInjection 2.10.2, released together. The client has the same code as 2.10.1: GetAsync with ids sends a limit of at most the number of the ids, within the quota of 300 of Chroma Cloud.

NuGet: https://www.nuget.org/packages/ChromaDotNet.Client/2.10.2 and https://www.nuget.org/packages/ChromaDotNet.Client.DependencyInjection/2.10.2

2.10.1

Choose a tag to compare

@Laurianti Laurianti released this 06 Oct 23:17

GetAsync with ids sends a limit of at most the number of the ids: a larger one, like 1000, went over the quota of 300 of Chroma Cloud, which rejected the request also for a few ids.

NuGet: https://www.nuget.org/packages/ChromaDotNet.Client/2.10.1

2.10.0

Choose a tag to compare

@Laurianti Laurianti released this 06 Oct 21:22
ff657da

Minor release of ChromaDotNet.Client and ChromaDotNet.Client.DependencyInjection: what an integration like Microsoft.Extensions.VectorData needs, done in the client.

dotnet add package ChromaDotNet.Client

Added

  • Collections by name: GetCollectionClient(name) follows the collection with that name, also after it is created again elsewhere. DeleteCollectionIfExistsAsync.
  • Updates and upserts: a null value or an empty list deletes the key, with the sparse vectors of its text. ChromaRecords.NullDocumentsDelete deletes the documents. WithDocumentCopyKey(key) copies each document into a metadata key, for a where filter on the whole text.
  • Filters: ChromaWhereOperator.Not, All and None, and ChromaWhereDocumentOperator.Not. ChromaWhereOperator also filters ids and documents.
  • BM25: ChromaCollectionSchema.WithBm25Index(sourceKey), FindBm25IndexAsync, and ChromaRank.HybridRrf for hybrid search on Chroma Cloud.
  • Also: ChromaQuery.Offset and ExpectedSpace, ChromaMetadataConvert, ChromaCloudQuotas.

Changed

  • In and NotIn without values no longer throw an ArgumentException: they are None and All.
  • GetOrCreateCollectionAsync throws when the collection exists with another space.
  • A query whose ids include some without a record leaves them out, as Chroma Cloud does, instead of failing on Chroma 1.x.

Tested

The whole suite on Chroma 1.5.9, 1.0.0, 0.6.3, 0.4.23 and Chroma Cloud, with the .NET 8 and .NET Standard 2.0 builds. The CI runs it against Chroma 0.4.10 to latest. See the compatibility table.

v2.9.2

Choose a tag to compare

@Laurianti Laurianti released this 06 Oct 03:47

Patch release of ChromaDotNet.Client and ChromaDotNet.Client.DependencyInjection. Package validation against 2.9.1 finds no breaking change, and there is no new public API.

dotnet add package ChromaDotNet.Client

Fixed

  • Floats that Chroma cannot write. Chroma 1.x sends null for an embedding beyond the range of a float in a cosine collection, and for the distance to it in an l2 or ip collection. GetAsync and QueryAsync threw a ChromaException for the whole answer. Now null reads as NaN, and the other records come back as they are, as with the Python client. A distance beyond the range of a float, which Chroma 0.6.3 sends, reads as an infinity with its sign.

Documentation

  • Shorter texts in the README and in the migration guide from 1.x.
  • docs/COMPATIBILITY.md: the null embeddings and distances of Chroma 1.x, and -0.0 in metadata, which Chroma 0.6.3, 1.0.0 and 1.5.9 return as 0.0.

v2.9.1

Choose a tag to compare

@Laurianti Laurianti released this 05 Oct 19:31

Patch release of ChromaDotNet.Client and ChromaDotNet.Client.DependencyInjection. Package validation against 2.9.0 finds no breaking change, and there is no new public API.

dotnet add package ChromaDotNet.Client

Fixed

  • Buckets of db.client.operation.duration: the histogram advises the boundaries of the OpenTelemetry semantic conventions, 0.001 to 10 seconds, which OpenTelemetry 1.10 and later apply. Before, it had the default boundaries, made for milliseconds, and P50, P90 and P99 were always 5 s in the Aspire dashboard. The net8.0 build now takes System.Diagnostics.DiagnosticSource 9.0.20. On the netstandard2.0 build, the one of applications on .NET Core 3.1 to 7, the application adds a view, which the README shows.
  • Chains of filters: a & b & c, or a chain built in a loop, goes as one $and list, as the Python client writes it, for the filters on the metadata, on the documents and in the Search API. Before, a chain of 32 filters threw a JsonException about an object cycle.
  • Very long chains: a single Chroma server turns a list of filters into an SQLite expression as deep as the list; Chroma 1.5.9 answers 500 beyond 987 to 994 filters in one list, and crashes from about 4,400. The client counts that depth, and beyond 900 splits each long list into lists with the same meaning: Chroma 1.0.0, 1.0.21 and 1.5.9 then take 4,000 filters and stay up with more.
  • A null value in AddAsync: it throws an ArgumentException before the request. Chroma 0.x would drop the key without an error, and 1.x rejects the request. In UpdateAsync and UpsertAsync a null deletes the key, as before.

Documentation

  • Known defects of the servers, in docs/COMPATIBILITY.md, each reproduced without the client:
    • $contains reading _ and % as wildcards up to 1.0.12;
    • the text after a NUL character;
    • floats truncated against int metadata, doubles read with an error in the last digit, and embeddings of a cosine collection read back different in the last bit, on 1.x;
    • wrong query results under concurrent writes on 0.4.24 and 0.6.3;
    • the limits of long filters.
  • Chroma Cloud takes at most 8 predicates in a filter, the default quota of a tenant.
  • Null values and Metadata: how to delete a key with a null value, and that a record without keys comes back with Metadata null.

Whole doubles already stored

Whole doubles that an earlier version of the client wrote as 2 instead of 2.0 stay integers in Chroma: on those records LessThan("d", 2.2) does not find d = 2 until they are written again.

v2.9.0

Choose a tag to compare

@Laurianti Laurianti released this 05 Oct 15:13

Minor release of ChromaDotNet.Client and ChromaDotNet.Client.DependencyInjection: the settings of a new collection, the indexes of a schema, and numbers and texts that reach the server as written.

dotnet add package ChromaDotNet.Client

New

  • The settings of a new collection, in ChromaCollectionDefinition.Configuration:

    • Hnsw, the index of a single Chroma server: EfConstruction, EfSearch, MaxNeighbors, ResizeFactor, SyncThreshold, BatchSize and NumThreads;
    • Spann, the index of Chroma Cloud, also with the settings that Chroma takes only in a schema;
    • EmbeddingFunction, the embedding function the collection declares, which ModifyConfigurationAsync can now change too.

    The client sends each setting where Chroma applies it: the HNSW settings as the hnsw: metadata, the SPANN settings and the embedding function in the configuration of the request, and all of them in the schema when there is one. Hnsw and Spann together throw an ArgumentException, and a server that ignores the settings of the other index gives a ChromaException.

  • The indexes of the values in a schema, as create_index and delete_index of the Python client: WithIndex and WithoutIndex with a ChromaSchemaIndex, for one metadata key or for all of them, and for the full-text search index of the documents.

  • On Chroma Cloud: ChromaSparseIndexAlgorithm.MaxScore for a sparse vector index, read back in ChromaSparseVectorIndex.Algorithm, and a customer-managed key of Google Cloud KMS, WithGcpCmek.

  • ChromaCollection.Dimension, Version and LogPosition, as the server reports them.

Fixed

  • Numbers:
    • Doubles and floats go with the fewest digits that read back as them, the same on every build, and whole ones as floats (2.0, not 2). Before, Chroma stored a whole double as an integer, and ChromaWhereOperator.In("k", 0.0, 2.25) went as [0, 2.25], which Chroma rejects.
    • The HNSW settings that Chroma takes only as integers, hnsw:M, hnsw:construction_ef, hnsw:search_ef, hnsw:num_threads, hnsw:batch_size and hnsw:sync_threshold, go as integers also when the metadata has a whole double. Another number there throws an ArgumentException, where Chroma would answer 400.
    • On .NET Framework, the doubles of the answers are read right and -0.0 keeps its sign.
  • What a server would store changed or drop throws an ArgumentException before the request:
    • a text with a lone half of a surrogate pair;
    • a ulong above long.MaxValue;
    • an empty list in the metadata of a record, or any list in the metadata of a collection;
    • a name that the path of a URL drops, like ..;
    • an HNSW index with fewer than 2 neighbors, on which Chroma 1.5.9 crashes or misses the nearest records.
  • .NET 6 and 7: the netstandard2.0 build takes the 8.0 packages of System.Text.Json and System.Diagnostics.DiagnosticSource, as in 2.7.1, so these applications build with no warnings.

Packages

  • The ChromaDotNet icon, and the vector-database tag.
  • The README has a section on collections and records.

v2.8.0

Choose a tag to compare

@Laurianti Laurianti released this 05 Oct 08:12

Minor release of ChromaDotNet.Client and ChromaDotNet.Client.DependencyInjection: hybrid search computed by the client, large reads and writes handled for you, Chroma Cloud by connection string, traces and metrics, and an API aligned with the .NET conventions.

dotnet add package ChromaDotNet.Client

New

  • Hybrid search, as the Python client of Chroma does it:
    • AddAsync, UpdateAsync and UpsertAsync compute the BM25 vectors of the chroma_bm25 indexes of the schema, from the document or from a metadata key;
    • ChromaRank.SparseKnn(text, key) takes a text, which SearchAsync turns into a sparse vector;
    • ChromaSparseVectorIndex.Bm25Function is the ChromaBm25 with the settings of the schema, also for a collection created by Python.
  • A collection with a schema keeps its space. The space goes in the schema, as the Python client writes it: Chroma Cloud rejects the space as a configuration together with a schema.
  • Large reads and writes, by default:
    • writes go in batches of the max_batch_size of the server, and GetAsync reads in pages;
    • on Chroma Cloud, 300 records at a time, its quota;
    • when a server rejects a batch beyond its quota of records, the client sends it again in batches of that quota.
  • Chroma Cloud by connection string: ChromaConfigurationOptions.FromConnectionString("Endpoint=...;Token=...;Tenant=...;Database=...").
  • Traces and metrics with OpenTelemetry: AddSource(ChromaTelemetry.ActivitySourceName) and AddMeter(ChromaTelemetry.MeterName). A span for each operation, with the attributes of the semantic conventions for database clients, and its duration in db.client.operation.duration.
  • Mocks in tests: the members of ChromaClient and ChromaCollectionClient are virtual, and a protected constructor makes a client without a server, as in the Azure SDKs.
  • QueryAsync with ids, with one or more query embeddings.
  • .NET Framework 4.6.2: a build of its own, which runs next to OpenTelemetry without binding redirects.
  • Dependency injection: IServiceProvider.CreateChromaClient(options, httpClientName) makes the client that AddChromaClient registers, for an integration with an HttpClient name of its own.
  • Documentation: every parameter and result of the public API, for IntelliSense; ChromaCollectionSchema.ToString() gives the JSON of a schema.

Aligned with the .NET conventions

2.8.0 brings the API in line with the .NET design guidelines. What to change in the code:

Change What to do
Asynchronous methods end in Async GetOrCreateCollection → GetOrCreateCollectionAsync, Add → AddAsync, Query → QueryAsync, and so on
Read-only lists Parameters, results and models are IReadOnlyList<T>: a List<T> or a collection expression still goes in
Read-only dictionaries Metadata are IReadOnlyDictionary<string, object>: write them new Dictionary<string, object> { ["key"] = value }
One embedding, one URI per record ChromaCollectionEntry and ChromaCollectionQueryEntry have Embedding and Uri; Data is gone, as no Chroma server fills it
Parameters named as the properties new ChromaConfigurationOptions(uri, tenant: ..., database: ...)
Metadata values read as written Strings stay strings and lists are List<object>; WithMetadataValues(ChromaMetadataValues.Inferred) reads them as before
Batches and pages by default WithBatchSplitting(false) sends a write in one request
ChromaException for the failures of a request Network errors, answers that are not the expected JSON and timeouts; other exceptions, like an assembly that does not load, go as they are
AddChromaClient and AddKeyedChromaClient return the services Code that ignores the result compiles as before
One type for each filter ChromaWhereOperator and ChromaWhereDocumentOperator, the types the methods take; ChromaWhere and ChromaWhereDocument are gone

v2.7.1

Choose a tag to compare

@Laurianti Laurianti released this 05 Oct 06:58

Patch release of ChromaDotNet.Client and ChromaDotNet.Client.DependencyInjection: only the metadata of the packages. The code is the one of 2.7.0, and package validation against 2.7.0 finds no breaking change.

dotnet add package ChromaDotNet.Client
  • Package descriptions: both packages say that the project is a community project, not affiliated with Chroma, and have the chroma-cloud tag.
  • Releases only on NuGet: NuGet gets only the version tags. The previews built from main are no longer published there, and the earlier ones are unlisted.