A Chroma vector database HTTP client for MoonBit: collections, records, queries and embeddings.
moon add SundayT1998/chroma-client///|
async fn example() -> Unit raise @chroma.ChromaError {
// `AsyncHttpTransport` is bundled; point the config at your Chroma server.
let client = @chroma.ChromaClient::new(
@chroma.AsyncHttpTransport::new(),
config=@chroma.Config::new(endpoint="http://localhost:8000"),
)
let collection = client.get_or_create_collection_async("notes")
// Chroma 1.x stores vectors, not text: every record needs coordinates.
client.add_async(collection.id, [
@chroma.Record::of_embedding("r1", [1.0, 0.0, 0.0]).with_document(
"MoonBit is a language for the web",
),
@chroma.Record::of_embedding("r2", [0.0, 1.0, 0.0]).with_document(
"Chroma stores embeddings",
),
])
let result = client.query_embeddings_async(
collection.id,
[[1.0, 0.0, 0.0]],
n_results=2,
)
for id in result.ids {
println(id)
}
}Chroma 1.x has no server-side embedding. An add whose records carry documents but no vectors is rejected by the server, so the client refuses it locally and points at Record::with_embedding. Produce the vectors with whatever embedding model you already use; Record::of_document(...).with_embedding(vec) is the usual shape.
client.query_embeddings_async(
collection.id,
[[0.1, 0.9, 0.0]],
n_results=5,
include_fields=@chroma.Include::all(),
)let filter = @chroma.Filter::new()
.with_metadata("source", @chroma.MString("handbook"))
.with_limit(20)
client.get_async(collection.id, filter=filter)@chroma.MetadataValue::MString("hello")
@chroma.MetadataValue::MInt(42)
@chroma.MetadataValue::MFloat(0.5)
@chroma.MetadataValue::MBool(true)
@chroma.MetadataValue::MNull///|
impl @chroma.AsyncTransport for MyTransport with fn send_async(self, request) {
let headers : @ah.Headers = Map([])
for entry in request.headers {
let (key, value) = entry
headers[key] = value
}
let payload : &@aio.Data = match request.body {
Some(body) => body
None => ""
}
let (response, response_body) = @ah.request(
request.url,
to_ah_method(request.verb),
headers,
payload,
)
{
status: response.code,
headers: converted(response.headers),
body: response_body.text(),
}
}///|
pub extend MyTransport with @chroma.AsyncTransport::{send_async}moon run cmd/main --target native -- http://localhost:8000 my-collection///|
let client = @chroma.ChromaClient::new(
transport,
config=@chroma.Config::new()
.with_token("my-api-token")
.with_basic_auth("user", "password"),
)///|
let client = @chroma.ChromaClient::new(
@chroma.TimeoutTransport::new(http_stack, 5000),
// or, to pick up Config::timeout_ms:
// @chroma.TimeoutTransport::from_config(http_stack, config)
)///|
let total = client.count(collection.id)
///|
let sample = client.peek(collection.id, limit=5)///|
client.get_async(
collection.id,
filter=@chroma.Filter::new(limit=Some(10), offset=Some(5)),
)///|
// Vector first, text attached afterwards.
@chroma.Record::of_embedding("r1", [1.0, 0.0]).with_document("hello")
///|
// Text first, vector attached afterwards.
@chroma.Record::of_document("r2", "world").with_embedding([0.0, 1.0])
///|
// Metadata, either way.
@chroma.Record::of_embedding("r3", [1.0, 1.0]).with_metadata([
("source", @chroma.MString("handbook")),
])///|
match result {
Err(error) =>
if error.status_code() == Some(404) {
// nothing there
} else if error.is_retryable() {
// 429 or 5xx, worth trying again
} else {
println(error.message())
}
Ok(value) => ignore(value)
}///|
let client = @chroma.ChromaClient::new(
@chroma.RetryTransport::new(
http_stack,
policy=@chroma.RetryPolicy::new(
enabled=true,
max_attempts=3,
initial_delay_ms=200,
max_delay_ms=5000,
backoff_factor=2.0,
),
),
)///|
let transport = @chroma.RetryTransport::new(http_stack).on_retry((
attempt,
delay_ms,
error,
) => {
println(
"retry " +
attempt.to_string() +
" in " +
delay_ms.to_string() +
"ms: " +
error.to_string(),
)
})moon run cmd/main --target native -- http://localhost:8000 my-collectionsh scripts/ci.shsh scripts/ci.sh fmt check # just formatting and type-checking
sh scripts/ci.sh test coverage # just tests and coveragesh scripts/integration.sh # starts chromadb/chroma, runs, tears downCHROMA_ENDPOINT=http://localhost:8000 \
moon test --target native -p SundayT1998/chroma-clientpub(all) suberror ChromaError {
Transport(String)
Status(Int, String)
Api(ApiError)
Decode(String)
InvalidArgument(String)
}pub struct AsyncHttpTransport {
}impl AsyncTransport for AsyncHttpTransportfn[T : Transport] ChromaClient::add(self : ChromaClient[T], collection_id : String, records : Array[Record]) -> Unit raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::add_async(self : ChromaClient[T], collection_id : String, records : Array[Record]) -> Unit raise ChromaErrorfn[T : Transport] ChromaClient::count(self : ChromaClient[T], collection_id : String) -> Int raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::count_async(self : ChromaClient[T], collection_id : String) -> Int raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::count_collections_async(self : ChromaClient[T]) -> Int raise ChromaErrorfn[T : Transport] ChromaClient::create_collection(self : ChromaClient[T], name : String, config? : CollectionConfig) -> Collection raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::create_collection_async(self : ChromaClient[T], name : String, config? : CollectionConfig) -> Collection raise ChromaErrorfn[T : Transport] ChromaClient::delete(self : ChromaClient[T], collection_id : String, filter? : Filter) -> Unit raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::delete_async(self : ChromaClient[T], collection_id : String, filter? : Filter) -> Unit raise ChromaErrorfn[T : Transport] ChromaClient::delete_collection(self : ChromaClient[T], name : String) -> Unit raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::delete_collection_async(self : ChromaClient[T], name : String) -> Unit raise ChromaErrorfn[T : Transport] ChromaClient::get(self : ChromaClient[T], collection_id : String, filter? : Filter) -> QueryResult raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::get_async(self : ChromaClient[T], collection_id : String, filter? : Filter) -> QueryResult raise ChromaErrorfn[T : Transport] ChromaClient::get_collection(self : ChromaClient[T], name : String) -> Collection? raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::get_collection_async(self : ChromaClient[T], name : String) -> Collection? raise ChromaErrorfn[T : Transport] ChromaClient::get_or_create_collection(self : ChromaClient[T], name : String, config? : CollectionConfig) -> Collection raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::get_or_create_collection_async(self : ChromaClient[T], name : String, config? : CollectionConfig) -> Collection raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::heartbeat_async(self : ChromaClient[T]) -> Int64 raise ChromaErrorfn[T : Transport] ChromaClient::list_collections(self : ChromaClient[T]) -> Array[Collection] raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::list_collections_async(self : ChromaClient[T]) -> Array[Collection] raise ChromaErrorfn[T : Transport] ChromaClient::modify_collection(self : ChromaClient[T], name : String, new_name? : String?, metadata? : Array[(String, MetadataValue)]?) -> Unit raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::modify_collection_async(self : ChromaClient[T], name : String, new_name? : String?, metadata? : Array[(String, MetadataValue)]?) -> Unit raise ChromaErrorfn[T : Transport] ChromaClient::peek(self : ChromaClient[T], collection_id : String, limit? : Int, include_fields? : Include) -> QueryResult raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::peek_async(self : ChromaClient[T], collection_id : String, limit? : Int, include_fields? : Include) -> QueryResult raise ChromaErrorfn[T : Transport] ChromaClient::query_embeddings(self : ChromaClient[T], collection_id : String, embeddings : Array[Array[Double]], n_results? : Int, include_fields? : Include, filter? : Filter) -> QueryResult raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::query_embeddings_async(self : ChromaClient[T], collection_id : String, embeddings : Array[Array[Double]], n_results? : Int, include_fields? : Include, filter? : Filter) -> QueryResult raise ChromaErrorfn[T : Transport] ChromaClient::update(self : ChromaClient[T], collection_id : String, records : Array[Record], filter? : Filter) -> Unit raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::update_async(self : ChromaClient[T], collection_id : String, records : Array[Record], filter? : Filter) -> Unit raise ChromaErrorfn[T : Transport] ChromaClient::upsert(self : ChromaClient[T], collection_id : String, records : Array[Record]) -> Unit raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::upsert_async(self : ChromaClient[T], collection_id : String, records : Array[Record]) -> Unit raise ChromaErrorasync fn[T : AsyncTransport] ChromaClient::version_async(self : ChromaClient[T]) -> String raise ChromaErrorpub(all) struct Collection {
id : String
name : String
metadata : Array[(String, MetadataValue)]
configuration : Json
log_position : Int
version : Int
} derive(Eq, Debug)pub(all) struct CollectionConfig {
metadata : Array[(String, MetadataValue)]
configuration : Json?
} derive(Eq, Debug)fn CollectionConfig::new(metadata? : Array[(String, MetadataValue)], configuration? : Json?) -> CollectionConfigimpl Transport for MemoryTransportpub(all) struct Record {
id : String
document : String?
embedding : Array[Double]?
metadata : Array[(String, MetadataValue)]
} derive(Eq, Debug)fn Record::of_document(id : String, document : String, metadata? : Array[(String, MetadataValue)]) -> Recordfn Record::of_embedding(id : String, embedding : Array[Double], metadata? : Array[(String, MetadataValue)]) -> Recordfn RetryPolicy::new(enabled? : Bool, max_attempts? : Int, initial_delay_ms? : Int, max_delay_ms? : Int, backoff_factor? : Double) -> RetryPolicypub(all) struct RetryTransport[T] {
inner : T
policy : RetryPolicy
on_retry : (Int, Int, ChromaError) -> Unit?
}impl Transport for RetryTransport[T]fn[T] RetryTransport::on_retry(self : RetryTransport[T], handler : (Int, Int, ChromaError) -> Unit) -> RetryTransport[T]fn[T : Transport] RetryTransport::send(self : RetryTransport[T], request : Request) -> Response raisefn[T] RetryTransport::with_policy(self : RetryTransport[T], policy : RetryPolicy) -> RetryTransport[T]pub(all) struct TimeoutTransport[T] {
inner : T
timeout_ms : Int
}let client = ChromaClient::new(TimeoutTransport::new(http_stack, 5000))impl Transport for TimeoutTransport[T]fn[T : Transport] TimeoutTransport::send(self : TimeoutTransport[T], request : Request) -> Response raiselet MAX_RESPONSE_BYTES : Intlet RETRY_DELAY_HEADER : Stringfn encode_path_segment(segment : String) -> Stringfn encode_query_component(value : String) -> Stringfn join_url(base : String, path : String) -> StringInstall
Download zipA Chroma vector database HTTP client for MoonBit: collections, records, queries and embeddings.