Aetherfy vector SDK reference
Installing the Aetherfy vector SDKs
Both Aetherfy client libraries are distributed as aetherfy-vectors — the same
name in PyPI and npm. The npm package is unscoped: it is aetherfy-vectors,
not @aetherfy/vectors.
| Python | JavaScript / TypeScript | |
|---|---|---|
| Distribution name | aetherfy-vectors | aetherfy-vectors |
| Install | pip install aetherfy-vectors | npm install aetherfy-vectors |
| Version | 1.0.0 | 1.0.0 |
| Minimum runtime | Python >= 3.9 | Node >= 20 |
| Packaging metadata | setup.py (there is no pyproject.toml) | package.json |
The Aetherfy Python distribution ships two import packages from the one
install: aetherfy_vectors (the vector client) and aetherfy_memory (the memory
layer).
pip install aetherfy-vectorsimport aetherfy_vectors
import aetherfy_memoryThe Aetherfy JavaScript package declares an exports map with only the "."
entry. There are no subpath entry points, so aetherfy-vectors/memory does
not resolve. Import everything — including the memory-layer classes — from
the package root.
npm install aetherfy-vectors// Correct: everything comes from the package root.
import { AetherfyVectorsClient, MemoryClient } from 'aetherfy-vectors';
console.log(typeof AetherfyVectorsClient, typeof MemoryClient);Importing from the Aetherfy SDKs
The Aetherfy Python root package re-exports the client, the exception classes, and six models — but not every type you will need. This split is exact:
Exported from the aetherfy_vectors root | Only in aetherfy_vectors.models |
|---|---|
Point, SearchResult, Collection, Schema, FieldDefinition, AnalysisResult | VectorConfig, DistanceMetric, Filter |
Those six root-exported models also resolve from aetherfy_vectors.models, so
both from aetherfy_vectors import Point and
from aetherfy_vectors.models import Point work — pick one spelling and stay
with it. VectorConfig,
DistanceMetric, and Filter are absent from the root __all__ and have only
the .models path.
# Root package: client, models, exceptions.
from aetherfy_vectors import (
AetherfyVectorsClient,
Point,
SearchResult,
Collection,
AetherfyVectorsException,
AuthenticationError,
RateLimitExceededError,
ServiceUnavailableError,
SchemaValidationError,
SchemaNotFoundError,
PartialUpsertError,
CollectionInUseError,
CollectionInOtherRegionError,
QuotaExceededError,
)
# NOT re-exported at the root — import these from aetherfy_vectors.models.
from aetherfy_vectors.models import VectorConfig, DistanceMetric, Filter
print(VectorConfig(size=4, distance=DistanceMetric.COSINE))The Aetherfy JavaScript root export includes the client (also the default
export), createClient(), the DistanceMetric enum, every exception class, the
memory-layer classes, DEFAULT_VECTOR_SIZE, and the public types. Two type names
are not root-exported: ScrollOptions and ScrollResult. Do not put them in
an import statement.
import AetherfyVectorsClient, {
createClient,
DistanceMetric,
DEFAULT_VECTOR_SIZE,
MemoryClient,
Namespace,
Thread,
} from 'aetherfy-vectors';
import type {
ClientConfig,
Collection,
CountOptions,
FieldDefinition,
Filter,
Point,
RetrieveOptions,
Schema,
ScrollIterOptions,
ScrollPoint,
SearchOptions,
SearchResult,
VectorConfig,
} from 'aetherfy-vectors';
const config: ClientConfig = { apiKey: process.env.AETHERFY_API_KEY };
const client = new AetherfyVectorsClient(config);
console.log(DEFAULT_VECTOR_SIZE, DistanceMetric.COSINE, typeof createClient);
console.log(typeof MemoryClient, typeof Namespace, typeof Thread);
client.dispose();Constructing an Aetherfy client
The Aetherfy Python client is synchronous; the Aetherfy JavaScript client is
asynchronous. Both default to the endpoint https://vectors.aetherfy.com.
Python — AetherfyVectorsClient(api_key=None, endpoint=None, api_region=None, timeout=30.0, workspace=None, **kwargs)
| Parameter | Default | Meaning |
|---|---|---|
api_key | None | API key; falls back to the environment |
endpoint | None | Base URL; defaults to https://vectors.aetherfy.com |
api_region | None | Pin the client to one region |
timeout | 30.0 | Request timeout in seconds |
workspace | None | Scope all collection calls to a workspace |
JavaScript — new AetherfyVectorsClient(config: ClientConfig = {})
ClientConfig field | Default | Meaning |
|---|---|---|
apiKey | unset | API key; falls back to the environment |
endpoint | unset | Base URL; defaults to https://vectors.aetherfy.com |
timeout | 30000 | Request timeout in milliseconds |
workspace | unset | Scope all collection calls to a workspace |
apiRegion | unset | Pin the client to one region — see the region section below |
import os
from aetherfy_vectors import AetherfyVectorsClient
client = AetherfyVectorsClient(
api_key=os.environ["AETHERFY_API_KEY"],
timeout=60.0, # seconds
)
print(client.get_collections())
client.close()import { AetherfyVectorsClient } from 'aetherfy-vectors';
const client = new AetherfyVectorsClient({
apiKey: process.env.AETHERFY_API_KEY,
timeout: 60000, // milliseconds
});
console.log(await client.getCollections());
client.dispose();Authenticating an Aetherfy client
When you do not pass a key, both Aetherfy SDKs resolve one from the environment in this order:
| Order | Environment variable |
|---|---|
| 1 | AETHERFY_API_KEY |
| 2 | AETHERFY_VECTORS_API_KEY |
Keys are validated client-side against ^afy_(live|test)_[a-zA-Z0-9]{16,}$, so a
truncated or mistyped key fails before any Aetherfy request is made. That regex
is a deliberately permissive client-side check, not the issued format: Aetherfy
generates afy_live_ or afy_test_ followed by exactly 32 hexadecimal
characters — see API keys for the canonical format. Manage
keys at https://app.aetherfy.com/dashboard/settings/api-keys .
import os
from aetherfy_vectors import AetherfyVectorsClient
# Explicit — equivalent to leaving api_key unset when AETHERFY_API_KEY is present.
explicit = AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"])
implicit = AetherfyVectorsClient()
print(explicit.collection_exists("articles"), implicit.collection_exists("articles"))
explicit.close()
implicit.close()import { AetherfyVectorsClient } from 'aetherfy-vectors';
// Explicit — equivalent to `new AetherfyVectorsClient()` when AETHERFY_API_KEY is set.
const explicit = new AetherfyVectorsClient({ apiKey: process.env.AETHERFY_API_KEY });
const implicit = new AetherfyVectorsClient();
console.log(
await explicit.collectionExists('articles'),
await implicit.collectionExists('articles'),
);
explicit.dispose();
implicit.dispose();A note on the Aetherfy JavaScript exception namespace: the package contains two
different classes named AuthenticationError. The one defined in src/auth.ts is
re-exported from the package root as AuthError so the two do not collide.
AuthenticationError at the root is the transport-level one.
Pinning an Aetherfy client to a region
The Aetherfy SDKs accept three region identifiers:
| Region |
|---|
us-east-1 |
eu-central-1 |
ap-southeast-1 |
Multi-region replication is a property of the plan, not the client: Free and Starter accounts are single-region, with the region fixed by the first resource created, and replication across regions begins at the tier named Performance. Pinning a client does not change what your plan replicates.
In Python, pass api_region to the constructor:
import os
from aetherfy_vectors import AetherfyVectorsClient
client = AetherfyVectorsClient(
api_key=os.environ["AETHERFY_API_KEY"],
api_region="eu-central-1",
)
print(client.get_collections())
client.close()In JavaScript, apiRegion requires region discovery, which is asynchronous.
Passing apiRegion to the new constructor (without an endpoint or environment
override) throws. Use the static create() factory instead:
import { AetherfyVectorsClient } from 'aetherfy-vectors';
// Correct: `create` performs region discovery before returning a client.
const client = await AetherfyVectorsClient.create({
apiKey: process.env.AETHERFY_API_KEY,
apiRegion: 'eu-central-1',
});
console.log(await client.getCollections());
client.dispose();Collection operations in the Aetherfy SDKs
| Operation | Python | JavaScript |
|---|---|---|
| Create | create_collection(collection_name, vectors_config, distance=None, description=None, regions=None) -> Collection | createCollection(collectionName, vectorsConfig, description?, regions?) -> Promise<Collection> |
| Delete | delete_collection(collection_name) -> bool | deleteCollection(collectionName) -> Promise<boolean> |
| List | get_collections() -> List[Collection] | getCollections() -> Promise<Collection[]> |
| Exists | collection_exists(collection_name) -> bool | collectionExists(collectionName) -> Promise<boolean> |
| Get one | get_collection(collection_name) -> Collection | getCollection(collectionName) -> Promise<Collection> |
The Python signature carries a separate distance parameter alongside
vectors_config; the JavaScript signature does not — the distance lives inside
the config object. Aetherfy fixes the rest of the collection configuration
server-side, so there is no place to pass optimizer or index settings in either
SDK.
import os
from aetherfy_vectors import AetherfyVectorsClient
from aetherfy_vectors.models import VectorConfig, DistanceMetric
client = AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"])
collection = client.create_collection(
collection_name="articles",
vectors_config=VectorConfig(size=4, distance=DistanceMetric.COSINE),
description="Article embeddings",
)
print(collection.name, collection.points_count, collection.regions)
print(client.collection_exists("articles"))
print([c.name for c in client.get_collections()])
print(client.delete_collection("articles"))
client.close()import { AetherfyVectorsClient, DistanceMetric } from 'aetherfy-vectors';
const client = new AetherfyVectorsClient({ apiKey: process.env.AETHERFY_API_KEY });
const collection = await client.createCollection(
'articles',
{ size: 4, distance: DistanceMetric.COSINE },
'Article embeddings',
);
console.log(collection.name, collection.pointsCount, collection.regions);
console.log(await client.collectionExists('articles'));
console.log((await client.getCollections()).map((c) => c.name));
console.log(await client.deleteCollection('articles'));
client.dispose();Upserting points with the Aetherfy SDKs
upsert writes points, creating or replacing them by id. Aetherfy caps a single
upsert call at 10 000 points; see limits.
| Operation | Python | JavaScript |
|---|---|---|
| Upsert | upsert(collection_name, points) -> bool | upsert(collectionName, points) -> Promise<boolean> |
Both Aetherfy SDKs accept two shapes for points. Python is typed
Sequence[Union[Point, Dict[str, Any]]], so a Point dataclass and a plain
dict are equally valid; JavaScript is typed
Point[] | Record<string, unknown>[]. The Aetherfy quickstart writes plain
dicts and the Aetherfy examples write Point(...) — both are correct, and
there is no behavioural difference between them.
import os
from aetherfy_vectors import AetherfyVectorsClient, Point
client = AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"])
ok = client.upsert(
collection_name="articles",
points=[
Point(id=1, vector=[0.1, 0.2, 0.3, 0.4], payload={"lang": "en", "year": 2024}),
Point(id=2, vector=[0.4, 0.3, 0.2, 0.1], payload={"lang": "fr", "year": 2025}),
],
)
print(ok)
client.close()import { AetherfyVectorsClient } from 'aetherfy-vectors';
const client = new AetherfyVectorsClient({ apiKey: process.env.AETHERFY_API_KEY });
const ok = await client.upsert('articles', [
{ id: 1, vector: [0.1, 0.2, 0.3, 0.4], payload: { lang: 'en', year: 2024 } },
{ id: 2, vector: [0.4, 0.3, 0.2, 0.1], payload: { lang: 'fr', year: 2025 } },
]);
console.log(ok);
client.dispose();If some points are written and some are not, the Aetherfy SDKs raise
PartialUpsertError, which carries .saved, .total, and .failed.
Searching with the Aetherfy SDKs
Python takes the search options as keyword arguments; JavaScript takes a
SearchOptions object.
Python — search(collection_name, query_vector, limit=10, offset=0, query_filter=None, with_payload=True, with_vectors=False, score_threshold=None, search_params=None) -> List[SearchResult]
JavaScript — search(collectionName, queryVector, options: SearchOptions = {}) -> Promise<SearchResult[]>
| Python keyword | JavaScript SearchOptions field | Default |
|---|---|---|
limit | limit | 10 |
offset | offset | 0 |
query_filter | queryFilter | none |
with_payload | withPayload | True / true |
with_vectors | withVectors | False / false |
score_threshold | scoreThreshold | none |
search_params | searchParams | none |
import os
from aetherfy_vectors import AetherfyVectorsClient
client = AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"])
results = client.search(
collection_name="articles",
query_vector=[0.1, 0.2, 0.3, 0.4],
limit=5,
query_filter={"must": [{"key": "lang", "match": {"value": "en"}}]},
with_payload=True,
with_vectors=False,
score_threshold=0.5,
)
for hit in results:
print(hit.id, hit.score, hit.payload)
client.close()import { AetherfyVectorsClient } from 'aetherfy-vectors';
const client = new AetherfyVectorsClient({ apiKey: process.env.AETHERFY_API_KEY });
const results = await client.search('articles', [0.1, 0.2, 0.3, 0.4], {
limit: 5,
queryFilter: { must: [{ key: 'lang', match: { value: 'en' } }] },
withPayload: true,
withVectors: false,
scoreThreshold: 0.5,
});
for (const hit of results) {
console.log(hit.id, hit.score, hit.payload);
}
client.dispose();Filter syntax is on filtering; engine-level tuning through
search_params / searchParams is on search tuning.
Retrieving, counting, and deleting points with the Aetherfy SDKs
| Operation | Python | JavaScript |
|---|---|---|
| Retrieve by id | retrieve(collection_name, ids, with_payload=True, with_vectors=False) -> List[Dict] | retrieve(collectionName, ids, options: RetrieveOptions = {}) -> Promise<Point[]> |
| Count | count(collection_name, count_filter=None, exact=True) -> int | count(collectionName, options: CountOptions = {}) -> Promise<number> |
| Delete | delete(collection_name, points_selector) -> bool | delete(collectionName, pointsSelector) -> Promise<boolean> |
Two traps live in this group of Aetherfy methods. First, retrieve returns
plain dictionaries in Python but typed Point objects in JavaScript. Second,
count defaults exact to True in Python and false in JavaScript — the
same nominal call computes its answer differently in the two languages, so pass
exact explicitly whenever the number matters.
delete accepts either a list of point ids or a filter object; a list is sent as
points, anything else as filter.
import os
from aetherfy_vectors import AetherfyVectorsClient
client = AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"])
points = client.retrieve("articles", ids=[1, 2], with_payload=True, with_vectors=True)
for point in points: # dicts in Python
print(point["id"], point.get("payload"))
print(client.count("articles", exact=True))
print(client.count("articles", count_filter={"must": [{"key": "lang", "match": {"value": "en"}}]}, exact=True))
print(client.delete("articles", [1, 2]))
print(client.delete("articles", {"must": [{"key": "lang", "match": {"value": "fr"}}]}))
client.close()import { AetherfyVectorsClient } from 'aetherfy-vectors';
const client = new AetherfyVectorsClient({ apiKey: process.env.AETHERFY_API_KEY });
const points = await client.retrieve('articles', [1, 2], {
withPayload: true,
withVectors: true,
});
for (const point of points) {
// typed Point objects in JavaScript
console.log(point.id, point.payload);
}
console.log(await client.count('articles', { exact: true }));
console.log(
await client.count('articles', {
countFilter: { must: [{ key: 'lang', match: { value: 'en' } }] },
exact: true,
}),
);
console.log(await client.delete('articles', [1, 2]));
console.log(
await client.delete('articles', { must: [{ key: 'lang', match: { value: 'fr' } }] }),
);
client.dispose();Scrolling a collection with the Aetherfy SDKs
scroll is one page; scroll_iter / scrollIter walks the whole collection for
you. Aetherfy accepts a batch size between 1 and 1000 — outside that range the
Python SDK raises ValueError and the JavaScript SDK raises RangeError, before
any request is sent.
| Operation | Python | JavaScript |
|---|---|---|
| One page | scroll(collection_name, limit=10, offset=None, scroll_filter=None, with_payload=True, with_vectors=False) -> Dict | scroll(collectionName, options) -> Promise<ScrollResult> |
| Iterate | scroll_iter(collection_name, *, batch_size=256, scroll_filter=None, with_payload=True, with_vectors=False) -> Iterator[Dict] | async *scrollIter(collectionName, options: ScrollIterOptions = {}) -> AsyncGenerator<ScrollPoint> |
The page result keys differ: Python returns {"points", "next_page_offset"},
JavaScript returns {points, nextPageOffset}. scroll_iter is keyword-only
in Python — batch_size cannot be passed positionally.
import os
from aetherfy_vectors import AetherfyVectorsClient
client = AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"])
page = client.scroll("articles", limit=100, with_payload=True)
print(len(page["points"]), page["next_page_offset"])
for point in client.scroll_iter("articles", batch_size=256, with_payload=True):
print(point["id"])
client.close()import { AetherfyVectorsClient } from 'aetherfy-vectors';
const client = new AetherfyVectorsClient({ apiKey: process.env.AETHERFY_API_KEY });
const page = await client.scroll('articles', { limit: 100, withPayload: true });
console.log(page.points.length, page.nextPageOffset);
for await (const point of client.scrollIter('articles', {
batchSize: 256,
withPayload: true,
})) {
console.log(point.id);
}
client.dispose();Mutating payloads with the Aetherfy SDKs
Aetherfy exposes three payload mutations, and every one of them is capped at 512 points per call in both SDKs.
| Operation | Python | JavaScript | Effect |
|---|---|---|---|
| Set (merge) | set_payload(collection_name, payload, points, key=None) | setPayload(collectionName, payload, points, options = {}) | Adds or overwrites the named keys; other keys survive |
| Overwrite (replace) | overwrite_payload(collection_name, payload, points) | overwritePayload(collectionName, payload, points) | Replaces the whole payload |
| Delete keys | delete_payload(collection_name, keys, points) | deletePayload(collectionName, keys, points) | Removes only the named keys |
Payload keys beginning __aetherfy_ are reserved: Aetherfy rejects them on write
with 400 RESERVED_FIELD and strips them from reads.
import os
from aetherfy_vectors import AetherfyVectorsClient
client = AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"])
client.set_payload("articles", payload={"reviewed": True}, points=[1, 2])
client.overwrite_payload("articles", payload={"lang": "en"}, points=[1])
client.delete_payload("articles", keys=["reviewed"], points=[1, 2])
client.close()import { AetherfyVectorsClient } from 'aetherfy-vectors';
const client = new AetherfyVectorsClient({ apiKey: process.env.AETHERFY_API_KEY });
await client.setPayload('articles', { reviewed: true }, [1, 2]);
await client.overwritePayload('articles', { lang: 'en' }, [1]);
await client.deletePayload('articles', ['reviewed'], [1, 2]);
client.dispose();Managing payload schemas with the Aetherfy SDKs
Aetherfy can hold a payload schema per collection and enforce it at one of three levels.
| Operation | Python | JavaScript |
|---|---|---|
| Read | get_schema(name) | getSchema(name) |
| Write | set_schema(name, schema, enforcement="off", description=None) -> etag | setSchema(name, schema, enforcementMode='off', description?) |
| Delete | delete_schema(name) | deleteSchema(name) |
| Infer from data | analyze_schema(collection_name, sample_size=1000) | analyzeSchema(collectionName, sampleSize = 1000) |
| Enforcement mode | Behaviour |
|---|---|
off | Schema stored, not enforced |
warn | Violations reported, writes proceed |
strict | Violations reject the write |
set_schema returns the new ETag, which is what you pass to the REST layer’s
If-Match for a compare-and-set update. analyze_schema samples between 100 and
10 000 points; outside that range the call raises before any Aetherfy request.
A collection with no schema raises SchemaNotFoundError, and a write that
violates a strict schema raises SchemaValidationError (Python’s carries
.errors).
import os
from aetherfy_vectors import AetherfyVectorsClient, SchemaNotFoundError
client = AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"])
analysis = client.analyze_schema("articles", sample_size=500)
print(analysis)
try:
print(client.get_schema("articles"))
except SchemaNotFoundError:
print("no schema defined for this collection")
client.close()import { AetherfyVectorsClient, SchemaNotFoundError } from 'aetherfy-vectors';
const client = new AetherfyVectorsClient({ apiKey: process.env.AETHERFY_API_KEY });
const analysis = await client.analyzeSchema('articles', 500);
console.log(analysis);
try {
console.log(await client.getSchema('articles'));
} catch (err) {
if (err instanceof SchemaNotFoundError) {
console.log('no schema defined for this collection');
} else {
throw err;
}
}
client.dispose();Point ID rules in the Aetherfy SDKs
Both Aetherfy SDKs validate point ids client-side, identically, before any request leaves the process.
| Accepted | Notes |
|---|---|
| Unsigned integer | 0 <= id <= 2**53 - 1 |
| UUID string | Canonical, 32-hex simple, braced, or urn:uuid: form; case-insensitive |
Anything else raises ValidationError with the message:
Point ID '<id>' is invalid — use an unsigned integer or a UUID string.
The upper bound is 2^53 − 1 because the server’s JSON layer parses numbers as
IEEE-754 doubles; a larger integer could not survive the round trip intact.
In Python, bool is explicitly rejected even though it subclasses int.
Aetherfy performs no coercion in either direction: an integer id comes back
an integer, and a UUID comes back a string. 1 and "1" are not
interchangeable, and "1" is not a valid id at all.
import os
from aetherfy_vectors import AetherfyVectorsClient, Point
client = AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"])
client.upsert(
"articles",
[
Point(id=42, vector=[0.1, 0.2, 0.3, 0.4]),
Point(id="6f8b9a1c-2d3e-4f50-8a1b-2c3d4e5f6071", vector=[0.4, 0.3, 0.2, 0.1]),
],
)
fetched = client.retrieve("articles", ids=[42, "6f8b9a1c-2d3e-4f50-8a1b-2c3d4e5f6071"])
for point in fetched:
print(type(point["id"]).__name__, point["id"])
client.close()import { AetherfyVectorsClient } from 'aetherfy-vectors';
const client = new AetherfyVectorsClient({ apiKey: process.env.AETHERFY_API_KEY });
await client.upsert('articles', [
{ id: 42, vector: [0.1, 0.2, 0.3, 0.4] },
{ id: '6f8b9a1c-2d3e-4f50-8a1b-2c3d4e5f6071', vector: [0.4, 0.3, 0.2, 0.1] },
]);
const fetched = await client.retrieve('articles', [
42,
'6f8b9a1c-2d3e-4f50-8a1b-2c3d4e5f6071',
]);
for (const point of fetched) {
console.log(typeof point.id, point.id);
}
client.dispose();Model shapes in the Aetherfy SDKs
The Aetherfy Python SDK models are dataclasses; the JavaScript models are interfaces. Field names differ where the language convention differs.
| Model | Python | JavaScript |
|---|---|---|
| Point | Point(id: Union[str, int], vector: List[float], payload: Optional[Dict] = None) | Point{id, vector, payload?} |
| Search hit | SearchResult(id, score: float, payload=None, vector=None) | SearchResult{id, score, payload?, vector?} |
| Vector config | VectorConfig(size: int, distance: DistanceMetric) | VectorConfig{size, distance} |
| Collection | Collection(name, config, description=None, points_count=None, status=None, regions=None) | Collection{name, description?, config, pointsCount?, status?, regions?} |
| Filter | Filter(must=None, must_not=None, should=None) | Filter — see filtering |
| Scroll point | not a distinct type | ScrollPoint{id, vector?, payload?} |
| Scroll page | plain dict {"points", "next_page_offset"} | ScrollResult{points, nextPageOffset} |
DistanceMetric has the same four members in both Aetherfy SDKs. The value you
send and the value Aetherfy stores are not always the same string:
| Member | Wire value sent | Value Aetherfy stores and returns |
|---|---|---|
COSINE | Cosine | Cosine |
EUCLIDEAN | Euclidean | Euclid |
DOT | Dot | Dot |
MANHATTAN | Manhattan | Manhattan |
EUCLIDEAN does not round-trip. Aetherfy normalises distance names
case-insensitively and stores both euclid and euclidean as Euclid, so a
collection created with DistanceMetric.EUCLIDEAN reads back
config.distance == "Euclid" — an equality check against 'Euclidean'
silently fails. Cosine, Dot and Manhattan round-trip unchanged.
Managing an Aetherfy client’s lifetime
The Aetherfy Python client supports the context-manager protocol and an explicit
close(). The Aetherfy JavaScript client has dispose() and destroy(), plus a
testConnection() probe that the Python SDK does not have.
import os
from aetherfy_vectors import AetherfyVectorsClient
# Context manager closes the client on exit.
with AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"]) as client:
print(client.get_collections())
# Or close it yourself.
client = AetherfyVectorsClient(api_key=os.environ["AETHERFY_API_KEY"])
try:
print(client.collection_exists("articles"))
finally:
client.close()import { AetherfyVectorsClient } from 'aetherfy-vectors';
const client = new AetherfyVectorsClient({ apiKey: process.env.AETHERFY_API_KEY });
try {
console.log(await client.testConnection());
console.log(await client.getCollections());
} finally {
client.dispose();
}Divergences between the two Aetherfy SDKs
These are the differences that change behaviour, not just spelling. Read this table before porting code between the two Aetherfy SDKs.
| Concern | Python | JavaScript |
|---|---|---|
count() default exact | True | false |
| Timeout unit | seconds (30.0) | milliseconds (30000) |
| Scroll page keys | {"points", "next_page_offset"} | {points, nextPageOffset} |
| Collection point count field | points_count | pointsCount |
retrieve return type | List[Dict] | Point[] |
| Base exception class | AetherfyVectorsException | AetherfyVectorsError |
| Call style | synchronous | async / await |
| Region pinning | api_region on the constructor | apiRegion requires await Client.create(); new throws |
| Lifecycle | context manager, close() | dispose(), destroy() |
| Connection probe | none | testConnection() |
| Batch-size range error | ValueError | RangeError |
| Unknown search option | native TypeError (no **kwargs sink) | explicit runtime guard throws |
| Memory layer import | import aetherfy_memory | package root only; no aetherfy-vectors/memory subpath |
| Payload mutation cap | 512 points per call | 512 points per call |
Complete Aetherfy SDK method map
| Operation | Python | JavaScript |
|---|---|---|
| Create collection | create_collection | createCollection |
| Delete collection | delete_collection | deleteCollection |
| List collections | get_collections | getCollections |
| Collection exists | collection_exists | collectionExists |
| Get collection | get_collection | getCollection |
| Upsert | upsert | upsert |
| Search | search | search |
| Retrieve | retrieve | retrieve |
| Delete points | delete | delete |
| Count | count | count |
| Scroll one page | scroll | scroll |
| Scroll iterator | scroll_iter | scrollIter |
| Set payload | set_payload | setPayload |
| Overwrite payload | overwrite_payload | overwritePayload |
| Delete payload keys | delete_payload | deletePayload |
| Get schema | get_schema | getSchema |
| Set schema | set_schema | setSchema |
| Delete schema | delete_schema | deleteSchema |
| Analyze schema | analyze_schema | analyzeSchema |
| Close | close / with | dispose / destroy |
| Connection probe | — | testConnection |
The exception classes each Aetherfy SDK raises, and the error codes behind them, are on errors.