@wiscale/velesdb-sdk 1.17.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,17 @@
2
2
 
3
3
  Official TypeScript SDK for [VelesDB](https://github.com/cyberlife-coder/VelesDB) -- the local-first vector database for AI and RAG. Sub-millisecond semantic search in Browser and Node.js.
4
4
 
5
- **v1.17.0** | Node.js >= 18 | Browser (WASM) | MIT License
5
+ **v2.0.0** | Node.js >= 18 | Browser (WASM) | VelesDB Core License 1.0
6
+
7
+ ## What's New (unreleased)
8
+
9
+ - **Relation + durable-TTL surface** (REST backend): `relate()`, `unrelate()`, `getRelations()`, `setTtlDurable()` — now fully tested and documented (see [Knowledge Graph API](#knowledge-graph-api) and [Agent Memory API](#agent-memory-api) below). The WASM backend throws `NOT_SUPPORTED` for these methods.
10
+ - The shipped example (`examples/hybrid_queries.ts`) was rewritten against the real API and is now compile-checked in CI.
11
+
12
+ ## What's New in v2.0.0
13
+
14
+ - v2.0.0: graph dimension on agent memory — `relate()` / `relations()` / `unrelate()`; durable-TTL setters; aligns with the engine 2.0 release. See the root [CHANGELOG](../../CHANGELOG.md) for the breaking VelesQL changes.
15
+ - v1.18.0: agent-memory parity wave — temporal recall facades (`recallRecent` / `recallOlderThan`), id-coercion hardening for `deleteMemory(string | number)`.
6
16
 
7
17
  ## What's New in v1.16.0
8
18
 
@@ -30,7 +40,7 @@ Official TypeScript SDK for [VelesDB](https://github.com/cyberlife-coder/VelesDB
30
40
  ### Previous (v1.13.0)
31
41
 
32
42
  - **WASM VelesQL executor** -- full browser-side VelesQL execution: SELECT/INSERT/UPDATE/DELETE/DDL + aggregations (COUNT/SUM/AVG/MIN/MAX) + GROUP BY/HAVING/UNION/INTERSECT/EXCEPT/JOIN/FUSION/MATCH 1-2 hops + NOT De Morgan distribution
33
- - **TS SDK coverage raised to 94%** -- 423 tests, per-file thresholds codified in `vitest.config.ts`
43
+ - **TS SDK coverage raised** -- per-file thresholds codified in `vitest.config.ts` (423 tests as of v1.13.0; the vitest suite has since grown past 770 cases). Note: the suite runs locally via `npm test` and is not currently executed in CI
34
44
  - **SIFT1M standardized ANN benchmark** -- fvecs/ivecs loader + Criterion ef sweep on the INRIA TEXMEX dataset, feature-gated behind `--features bench-sift1m`
35
45
  - **Security hardening** -- `validateCollectionName()` helper on TS SDK prevents VelesQL injection in `trainPq`
36
46
  - **API consistency** -- `streamInsert` now serializes `payload: null` explicitly (matches `streamUpsertPoints`)
@@ -160,7 +170,13 @@ const queryVector = new Float32Array(1536).fill(0.1);
160
170
  const results = await db.search('products', queryVector, { k: 10 });
161
171
  ```
162
172
 
163
- > **REST backend note:** Document IDs must be numeric integers in the range `0..Number.MAX_SAFE_INTEGER`. String IDs are only supported with the WASM backend.
173
+ > **REST backend note:** Document IDs must be non-negative `u64` integers. Pass a JS
174
+ > number in the range `0..Number.MAX_SAFE_INTEGER`, or a decimal string for the full
175
+ > `u64` range — string ids above 2^53-1 (up to `18446744073709551615`) are kept
176
+ > verbatim on the wire, so the ids returned by `recordEvent`/`learnProcedure`
177
+ > round-trip through `get`/`delete` without precision loss. Exception: the NDJSON
178
+ > bulk endpoint (`streamUpsertPoints`) only accepts safe-range numeric ids.
179
+ > Arbitrary (non-numeric) string IDs are only supported with the WASM backend.
164
180
 
165
181
  > **Versioned routes:** The REST backend uses `/v1/` as the canonical route prefix
166
182
  > (e.g. `POST /v1/collections/{name}/search`). Legacy routes without the prefix
@@ -537,6 +553,14 @@ Get detailed collection configuration (dimension, metric, storage mode, point co
537
553
 
538
554
  Execute a VelesQL query. Supports SELECT, WHERE, vector NEAR, GROUP BY, HAVING, ORDER BY, JOIN, UNION/INTERSECT/EXCEPT, and USING FUSION.
539
555
 
556
+ > **Backend support:** full VelesQL execution requires the **REST backend** (`velesdb-server`).
557
+ > The WASM backend only executes pure top-k vector queries of the form
558
+ > `SELECT * FROM <collection> WHERE vector NEAR $param [LIMIT n]` (`vector` is the
559
+ > grammar keyword, not a column name) and throws a
560
+ > `NOT_SUPPORTED` error for anything else (WHERE predicates, JOIN, GROUP BY, MATCH,
561
+ > set operations, FUSION) instead of silently ignoring clauses. Accordingly,
562
+ > `db.capabilities().velesqlQuery` is `false` on WASM.
563
+
540
564
  ```typescript
541
565
  // Vector similarity search
542
566
  const result = await db.query(
@@ -717,6 +741,56 @@ for (const node of result.results) {
717
741
  }
718
742
  ```
719
743
 
744
+ #### `db.relate(collection, request)`
745
+
746
+ Create a typed relation edge between two existing points. Returns the
747
+ allocated edge ID (`RelateResponse = { edgeId: number | string }`). Point and
748
+ edge IDs are `number | string` — IDs above `Number.MAX_SAFE_INTEGER` travel as
749
+ decimal strings to avoid u64 precision loss. **REST backend only** (the WASM
750
+ backend throws `NOT_SUPPORTED`).
751
+
752
+ ```typescript
753
+ const { edgeId } = await db.relate('social', {
754
+ source: 100,
755
+ target: 200,
756
+ relType: 'FOLLOWS',
757
+ properties: { since: '2024-01-01' } // optional, defaults to {}
758
+ });
759
+ ```
760
+
761
+ #### `db.unrelate(collection, edgeId)`
762
+
763
+ Remove a relation edge by its ID. Returns `true` if the edge was removed,
764
+ `false` if it did not exist. **REST backend only.**
765
+
766
+ ```typescript
767
+ const removed = await db.unrelate('social', edgeId);
768
+ ```
769
+
770
+ #### `db.getRelations(collection, pointId)`
771
+
772
+ List the outgoing relation edges of a point. Returns
773
+ `RelationsResponse = { edges: RelationEdge[]; count: number }` where each edge
774
+ carries `{ id, source, target, relType, properties? }`. **REST backend only.**
775
+
776
+ ```typescript
777
+ const { edges, count } = await db.getRelations('social', 100);
778
+ for (const edge of edges) {
779
+ console.log(`${edge.source} -[${edge.relType}]-> ${edge.target}`);
780
+ }
781
+ ```
782
+
783
+ #### `db.setTtlDurable(collection, pointId, ttlSeconds)`
784
+
785
+ Durably set (or refresh) the time-to-live of a point, in **seconds**. The
786
+ expiry is persisted server-side (reserved `_veles_expires_at` payload field),
787
+ so it survives a restart. `ttlSeconds` must be a non-negative number.
788
+ **REST backend only.**
789
+
790
+ ```typescript
791
+ await db.setTtlDurable('social', 100, 3600); // expire point 100 in 1 hour
792
+ ```
793
+
720
794
  ---
721
795
 
722
796
  ### Property Indexes
@@ -772,7 +846,21 @@ const result = await db.trainPq('embeddings', {
772
846
 
773
847
  ### Agent Memory API
774
848
 
775
- The Agent Memory API provides three memory types for AI agents, built on top of VelesDB's vector and graph storage.
849
+ The Agent Memory API provides three memory types for AI agents, built on top of
850
+ VelesDB's vector storage. In the TypeScript/JavaScript SDK it is accessed **over
851
+ REST** against a running `velesdb-server` (the Python and Rust bindings use the
852
+ embedded engine instead).
853
+
854
+ > **You must create the collection first.** The TS facade does **not**
855
+ > auto-create a collection for you. Create it with the dimension that matches
856
+ > your embedding model and the metric you want (`'cosine'` is the usual choice
857
+ > for normalized text embeddings), then call `storeFact` / `recordEvent` /
858
+ > `learnProcedure` against that same collection name.
859
+
860
+ > **Embeddings are caller-supplied.** There is no auto-embedding: every
861
+ > `embedding` you pass must come from your own embedding model (see
862
+ > [Embedding helper](#embedding-helper)) and its length must equal the
863
+ > collection dimension.
776
864
 
777
865
  ```typescript
778
866
  import { VelesDB } from '@wiscale/velesdb-sdk';
@@ -780,13 +868,46 @@ import { VelesDB } from '@wiscale/velesdb-sdk';
780
868
  const db = new VelesDB({ backend: 'rest', url: 'http://localhost:8080' });
781
869
  await db.init();
782
870
 
871
+ // 1. Create the backing collection FIRST (nothing auto-creates it).
872
+ // The dimension must match your embedding model; cosine is typical.
873
+ await db.createCollection('knowledge', { dimension: 384, metric: 'cosine' });
874
+
875
+ // 2. Open the agent-memory facade.
783
876
  const memory = db.agentMemory({ dimension: 384 });
877
+
878
+ // 3. Store and recall (embedding is your own model's output, length 384).
879
+ await memory.storeFact('knowledge', {
880
+ id: 1,
881
+ text: 'VelesDB uses HNSW for vector indexing',
882
+ embedding: factEmbedding,
883
+ });
884
+ const facts = await memory.searchFacts('knowledge', queryEmbedding, 5);
885
+ ```
886
+
887
+ Each similarity-recall method (`searchFacts`, `recallEvents`,
888
+ `recallProcedures`) returns `SearchResult[]`:
889
+
890
+ ```typescript
891
+ // SearchResult = { id: number; score: number; payload?: Record<string, unknown>; vector?: number[] }
784
892
  ```
785
893
 
894
+ The temporal-recall methods (`recallRecent`, `recallOlderThan`) return
895
+ `EpisodicRecord[]` instead — see [Episodic Memory](#episodic-memory-events-and-experiences).
896
+
897
+ - `score` is the cosine similarity in `[0, 1]` (for a `cosine` collection);
898
+ higher means more similar.
899
+ - `payload` carries the stored fields (`content` for semantic text,
900
+ `event_type` / `timestamp` for episodic, `name` / `steps` for procedural,
901
+ plus your metadata). The reserved payload keys `_memory_type` / `content` /
902
+ `event_type` / `timestamp` / `name` / `steps` always take precedence over
903
+ caller `metadata`/`data` of the same name, so they cannot be clobbered.
904
+ Note: the `SemanticEntry.text` input field is stored as `content` in the
905
+ payload — `result.payload?.content` is the fact text on recall.
906
+
786
907
  #### Semantic Memory (facts and knowledge)
787
908
 
788
909
  ```typescript
789
- // Store a fact
910
+ // Store a fact (id is caller-assigned; reusing an id upserts)
790
911
  await memory.storeFact('knowledge', {
791
912
  id: 1,
792
913
  text: 'VelesDB uses HNSW for vector indexing',
@@ -801,25 +922,37 @@ const facts = await memory.searchFacts('knowledge', queryEmbedding, 5);
801
922
  #### Episodic Memory (events and experiences)
802
923
 
803
924
  ```typescript
804
- // Record an event
805
- await memory.recordEvent('events', {
925
+ // Record an event — returns the generated point id
926
+ const eventId = await memory.recordEvent('events', {
806
927
  eventType: 'user_query',
807
928
  data: { query: 'How does HNSW work?', response: '...' },
808
929
  embedding: eventEmbedding,
809
- metadata: { timestamp: Date.now() }
810
930
  });
811
931
 
812
932
  // Recall similar events
813
933
  const events = await memory.recallEvents('events', queryEmbedding, 5);
934
+
935
+ // Temporal recall — no embedding needed, most-recent-first.
936
+ // recallRecent(collection, since?): events with timestamp >= since
937
+ // (inclusive, unix-seconds); recallOlderThan(collection, before): strictly older.
938
+ const nowSecs = Math.floor(Date.now() / 1000);
939
+ const allRecent = await memory.recallRecent('events');
940
+ const lastHour = await memory.recallRecent('events', nowSecs - 3600);
941
+ const stale = await memory.recallOlderThan('events', nowSecs - 86_400);
942
+
943
+ // Both return EpisodicRecord[]:
944
+ // { id: string; timestamp: number; payload: Record<string, unknown> }
814
945
  ```
815
946
 
816
947
  #### Procedural Memory (learned patterns)
817
948
 
818
949
  ```typescript
819
- // Store a procedure
820
- await memory.learnProcedure('procedures', {
950
+ // Store a procedure — embedding is required so the pattern is recallable,
951
+ // and the generated point id is returned
952
+ const procId = await memory.learnProcedure('procedures', {
821
953
  name: 'deploy-to-prod',
822
954
  steps: ['Run tests', 'Build artifacts', 'Push to registry', 'Deploy'],
955
+ embedding: procedureEmbedding,
823
956
  metadata: { lastUsed: Date.now() }
824
957
  });
825
958
 
@@ -827,6 +960,27 @@ await memory.learnProcedure('procedures', {
827
960
  const procs = await memory.recallProcedures('procedures', queryEmbedding, 3);
828
961
  ```
829
962
 
963
+ #### Deleting memories
964
+
965
+ ```typescript
966
+ // Works for facts, events, and procedures — returns true if a point was removed
967
+ await memory.deleteMemory('procedures', procId);
968
+ ```
969
+
970
+ > **`dimension` is advisory.** `db.agentMemory({ dimension })` records a hint you
971
+ > can read back via `memory.dimension`, but it does **not** create or size any
972
+ > collection — the collection's own dimension (set at `createCollection`)
973
+ > governs storage and search, and your embeddings must match it.
974
+
975
+ > **TTL & snapshots.** Durable per-point TTL (in **seconds**) **is** available
976
+ > from this SDK: memory entries are regular points, so
977
+ > [`db.setTtlDurable(collection, pointId, ttlSeconds)`](#dbsetttldurablecollection-pointid-ttlseconds)
978
+ > expires a fact/event/procedure durably over REST. The subsystem-namespaced
979
+ > TTL helpers (`set_semantic_ttl`, `store_with_ttl`, `auto_expire`) and
980
+ > versioned snapshots remain embedded-only (Rust **and** Python bindings) and
981
+ > are not exposed over REST. See the API-availability table in the
982
+ > [Agent Memory guide](../../docs/guides/AGENT_MEMORY.md#api-availability-by-binding).
983
+
830
984
  ---
831
985
 
832
986
  ## Error Handling
@@ -904,10 +1058,14 @@ import {
904
1058
  type AddEdgeRequest,
905
1059
  type TraverseRequest,
906
1060
  type TraverseResponse,
1061
+ type RelateRequest,
1062
+ type RelateResponse,
1063
+ type RelationsResponse,
907
1064
  type QueryApiResponse,
908
1065
  type AgentMemoryConfig,
909
1066
  type SemanticEntry,
910
1067
  type EpisodicEvent,
1068
+ type EpisodicRecord,
911
1069
  type ProceduralPattern,
912
1070
  } from '@wiscale/velesdb-sdk';
913
1071
  ```
@@ -924,6 +1082,6 @@ import {
924
1082
 
925
1083
  ## License
926
1084
 
927
- MIT License -- See [LICENSE](./LICENSE) for details.
1085
+ Licensed under the [VelesDB Core License 1.0](./LICENSE) (source-available). The SDK bundles the VelesDB WASM engine and is governed by the Core License.
928
1086
 
929
1087
  VelesDB Core and Server are licensed under VelesDB Core License 1.0 (source-available).