@tanstack/ai-persistence 0.7.1 → 0.7.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-persistence",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Composable state persistence for TanStack AI messages, runs, interrupts, metadata, and locks.",
5
5
  "author": "",
6
6
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "peerDependencies": {
45
45
  "vitest": "^4.1.10",
46
- "@tanstack/ai": "^0.63.0"
46
+ "@tanstack/ai": "^0.64.0"
47
47
  },
48
48
  "peerDependenciesMeta": {
49
49
  "vitest": {
@@ -53,7 +53,7 @@
53
53
  "devDependencies": {
54
54
  "@vitest/coverage-v8": "4.1.10",
55
55
  "vitest": "^4.1.10",
56
- "@tanstack/ai": "0.63.0"
56
+ "@tanstack/ai": "0.64.0"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "vite build",
@@ -273,11 +273,26 @@ distinct records, and the conformance suite checks it.
273
273
  then a `findOne` — `$setOnInsert` is the insert-if-absent primitive. Guard the
274
274
  `E11000` duplicate-key race and re-read. `list*` need `.sort({ requestedAt: 1 })`.
275
275
 
276
- **Redis / Upstash** — workable for `metadata` and excellent for `LockStore`, but
277
- think before putting `interrupts` there: the listings need ordered secondary
278
- indexes you have to maintain by hand (a sorted set per thread and per run,
279
- scored by `requestedAt`). A common split is Postgres for `messages`/`runs`/
280
- `interrupts` and Redis for locks; compose them with `composePersistence`.
276
+ **Redis / Upstash** — all four stores fit, and Redis is excellent for
277
+ `LockStore` too. Store each record as one JSON document (RedisJSON, or a JSON
278
+ string) and list `runs` and `interrupts` through sorted-set indexes: one per
279
+ thread and one per run, scored by `startedAt` / `requestedAt`. Those indexes
280
+ are only safe when the record and every index it joins are written by **one
281
+ Lua script** (`EVAL`), never as separate commands: insert the record if absent
282
+ (`JSON.SET ... NX` or `SET ... NX`), `ZADD` each index only when that insert
283
+ happened, and return the stored record. Pass every key the script touches in
284
+ `KEYS`, so it also works on a cluster. That one script is `createOrResume`
285
+ and `interrupts.create` (invariants 3 and 6), and it stays correct across
286
+ instances. `interrupts.commitBatch` is one script too: check every id exists
287
+ and is pending, then write them all, or write nothing. If `listReclaimable`
288
+ reads a sorted set of detached runs, the `runs.update` that changes `status` or
289
+ `detachedSince` must move the run in or out of it in the same script; as two
290
+ commands, a crash between them hides a detached run from the reaper. `ZRANGE` on the index
291
+ gives the `requestedAt` ordering for free. For `metadata`, build the key so
292
+ `('a:b','c')` and `('a','b:c')` stay distinct, for example by escaping the
293
+ delimiter. `@upstash/agentkit-tanstack-ai` (`upstashPersistence()`) is a
294
+ published implementation of this layout that passes the conformance suite with
295
+ all seven stores; on Upstash the app can use it instead of writing this file.
281
296
 
282
297
  **Anything else** — you only need the seven invariants above. The core never
283
298
  inspects your storage.