@sapiom/tools 0.18.0 → 0.19.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/dist/cjs/_generated/version.d.ts +1 -1
  4. package/dist/cjs/_generated/version.js +1 -1
  5. package/dist/cjs/client.d.ts +11 -8
  6. package/dist/cjs/client.d.ts.map +1 -1
  7. package/dist/cjs/client.js +2 -3
  8. package/dist/cjs/client.js.map +1 -1
  9. package/dist/cjs/memory/errors.d.ts +11 -6
  10. package/dist/cjs/memory/errors.d.ts.map +1 -1
  11. package/dist/cjs/memory/errors.js +11 -6
  12. package/dist/cjs/memory/errors.js.map +1 -1
  13. package/dist/cjs/memory/index.d.ts +116 -217
  14. package/dist/cjs/memory/index.d.ts.map +1 -1
  15. package/dist/cjs/memory/index.js +50 -97
  16. package/dist/cjs/memory/index.js.map +1 -1
  17. package/dist/cjs/stub/index.d.ts +0 -4
  18. package/dist/cjs/stub/index.d.ts.map +1 -1
  19. package/dist/cjs/stub/index.js +136 -30
  20. package/dist/cjs/stub/index.js.map +1 -1
  21. package/dist/esm/_generated/version.d.ts +1 -1
  22. package/dist/esm/_generated/version.js +1 -1
  23. package/dist/esm/client.d.ts +11 -8
  24. package/dist/esm/client.d.ts.map +1 -1
  25. package/dist/esm/client.js +2 -3
  26. package/dist/esm/client.js.map +1 -1
  27. package/dist/esm/memory/errors.d.ts +11 -6
  28. package/dist/esm/memory/errors.d.ts.map +1 -1
  29. package/dist/esm/memory/errors.js +11 -6
  30. package/dist/esm/memory/errors.js.map +1 -1
  31. package/dist/esm/memory/index.d.ts +116 -217
  32. package/dist/esm/memory/index.d.ts.map +1 -1
  33. package/dist/esm/memory/index.js +48 -94
  34. package/dist/esm/memory/index.js.map +1 -1
  35. package/dist/esm/stub/index.d.ts +0 -4
  36. package/dist/esm/stub/index.d.ts.map +1 -1
  37. package/dist/esm/stub/index.js +136 -30
  38. package/dist/esm/stub/index.js.map +1 -1
  39. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  40. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  41. package/package.json +1 -1
  42. package/src/memory/README.md +82 -37
@@ -1,70 +1,115 @@
1
1
  # memory
2
2
 
3
- Tenant-scoped long-term memory over the Sapiom memory gateway.
3
+ Tenant-scoped long-term memory backed by the Sapiom memory service.
4
4
 
5
5
  ```typescript
6
6
  import { createClient } from "@sapiom/tools";
7
7
 
8
8
  const sapiom = createClient({ apiKey: process.env.SAPIOM_API_KEY });
9
9
 
10
- const { id, decision } = await sapiom.memory.append({
10
+ const { id } = await sapiom.memory.append({
11
11
  content: "User prefers dark mode.",
12
- scope: "user",
13
- metadata: { source: "preference-survey" },
12
+ namespace: "user-42",
13
+ metadata: { source: "preference-survey", user_theme: "dark" },
14
14
  });
15
15
 
16
16
  const { results } = await sapiom.memory.recall({
17
17
  query: "ui preferences",
18
- scope: "user",
18
+ namespace: "user-42",
19
19
  topK: 5,
20
20
  });
21
21
 
22
- const record = await sapiom.memory.get(id);
23
- await sapiom.memory.forget(id);
22
+ await sapiom.memory.forget({ ids: [id], namespace: "user-42" });
23
+ await sapiom.memory.drop("user-42");
24
24
  ```
25
25
 
26
26
  Ambient import works too: `import { memory } from "@sapiom/tools"`.
27
27
 
28
28
  ## Operations
29
29
 
30
- | Method | Notes |
31
- | ---------------------- | ----------------------------------------------------------------------------------------------------- |
32
- | `append(input)` | Writes a memory or returns an existing near-duplicate. Success decisions are `"ADDED"` or `"NOOP"`. |
33
- | `recall(input)` | Searches memories by `query`; supports `strategy`, temporal `weight`, metadata `filter`, and `store`. |
34
- | `sweep(input?)` | Neon-only compaction. `dryRun` defaults to `true`; pass `false` to delete selected rows. |
35
- | `get(id, options?)` | Fetches one memory. Pass `options.store` when the write used a non-default store. |
36
- | `forget(id, options?)` | Hard-deletes one memory. Idempotent: already-gone rows still resolve successfully. |
30
+ | Method | Notes |
31
+ | ----------------- | ---------------------------------------------------------------------------------------------------------- |
32
+ | `append(input)` | Writes one memory into a namespace. Metered. |
33
+ | `recall(input)` | Searches one namespace by `query`; supports `strategy`, temporal `weight`, and metadata `filter`. Metered. |
34
+ | `forget(input)` | Hard-deletes memories by id. Blind-idempotent: already-gone ids still resolve successfully. Free. |
35
+ | `drop(namespace)` | Deletes an entire namespace. Idempotent. Free. |
37
36
 
38
- ## Store Identity
37
+ ## Namespaces
39
38
 
40
- `store` selects the physical store. Reads must pass the same selector used by the matching write.
39
+ `namespace` is the isolation boundary: reads only ever see one namespace, and
40
+ `drop` deletes one namespace wholesale.
41
+
42
+ **Default to a namespace per agent, per user, or per project.** A namespace has
43
+ bounded capacity, so prefer many small namespaces over one large one. Put
44
+ subsets into a single shared namespace — distinguished by `metadata` and
45
+ narrowed with a recall `filter` — only when a single recall must span those
46
+ subsets. For better performance, use a namespace instead if you'd always
47
+ filter to one value.
41
48
 
42
49
  ```typescript
43
- export interface MemoryStore {
44
- backend?: "neon-pgvector" | "upstash-vector";
45
- embedder?: {
46
- provider: string;
47
- model: string;
48
- };
49
- namespace?: string;
50
- }
50
+ // Preferred: one namespace per user
51
+ await sapiom.memory.append({ content, namespace: `user-${userId}` });
52
+
53
+ // Only when one recall must span subsets: shared namespace + metadata + filter
54
+ await sapiom.memory.append({
55
+ content,
56
+ namespace: "support-team",
57
+ metadata: { user_id: userId },
58
+ });
59
+ await sapiom.memory.recall({
60
+ query,
61
+ namespace: "support-team",
62
+ filter: { user_id: userId },
63
+ });
51
64
  ```
52
65
 
53
- Pass the same `store` to reads/deletes that was used when writing. Omit `store` for the v0 default: Neon pgvector, your default namespace, and OpenRouter `openai/text-embedding-3-small`.
66
+ ## Metadata
67
+
68
+ Metadata you WRITE is flat: a map of identifier keys to string, number, or
69
+ boolean values (arrays and nulls are rejected with `invalid_metadata`). Express
70
+ hierarchy through key naming conventions (e.g. `env_prod`, `user_theme`) rather
71
+ than nesting. Keys start with a letter and must not contain `.`. Key count and
72
+ sizes are bounded (enforced server-side).
73
+
74
+ Every metadata leaf is a scalar. Filter values match exactly, or against a set
75
+ with `{ in: [...] }`. For better performance, use `namespace` for a key you'd
76
+ filter on every recall — metadata suits optionally-filtered dimensions.
77
+
78
+ ## Limits
79
+
80
+ | Field | Limit |
81
+ | ------------------------- | --------------------------------------------- |
82
+ | `content` | ≤ 32,000 characters |
83
+ | `namespace` | 1–100 characters; letters, digits, `-`, `_` |
84
+ | `query` | ≤ 4,096 characters |
85
+ | `topK` | 1–50 (default 5) |
86
+ | `metadata` keys | ≤ 20 per memory |
87
+ | `metadata` key | ≤ 64 bytes; matches `^[a-zA-Z]\w*$` |
88
+ | `metadata` string value | ≤ 512 characters |
89
+ | `filter` keys | ≤ 20 |
90
+ | `filter` `{ in: [...] }` | ≤ 64 values |
91
+ | `forget` ids | ≤ 100 per call |
92
+ | `weight.halfLifeDays` | 1–365 (default 30) |
54
93
 
55
94
  ## Contract Notes
56
95
 
57
- - `append` is append-log only. It never mutates or supersedes existing rows.
58
- - Secret-like content or metadata is rejected before embedding with `MemoryHttpError` status `400` and body fields such as `error: "SecretDetected"` and `decision: "REJECTED"`.
59
- - `occurredAt` is optional event time. When omitted, the backend stores `null`; temporal recall falls back to `createdAt`.
60
- - `recall` defaults to `strategy: "cosine"`, `topK: 5`, and `minSimilarity: 0`.
61
- - `strategy: "keyword"` is Neon-only; requesting it on `upstash-vector` returns `400`.
62
- - `sweep` is Neon-only; for Upstash-backed stores, call `forget` on specific ids.
63
- - `upstash-vector` is experimental in v0. Append, cosine recall, get, and forget work; native Upstash embedding, keyword recall, and sweep are not part of this SDK contract yet.
64
- - The gateway is authoritative for embedder support. v0 currently supports OpenRouter-backed embedding providers/models and returns `400` for unsupported selectors.
65
- - `filter` is a hard metadata filter. Neon uses JSONB containment; Upstash supports scalar equality filters.
66
- - After the route gate succeeds, recall degrades child infra, billing, rate-limit, and timeout failures to `{ results: [], count: 0 }`. Bad requests, missing identity, and ownership failures still throw.
67
- - Every route has the near-zero x402 minimum gate. Embedding and store operations are child costs billed to the run.
96
+ - Memory is durable knowledge, not chat history: `recall` ranks by relevance,
97
+ never by recency it is not a way to page through recent turns. Keep last-N
98
+ context in your own store.
99
+ - `append` is append-log only; it never mutates existing memories.
100
+ - Secret-like content is rejected before anything is stored:
101
+ `MemoryHttpError` status `400`, body `code: "secret_detected"`.
102
+ - `occurredAt` is optional event time, distinct from `createdAt` (ingestion
103
+ time); it drives `weight.temporal` recall decay.
104
+ - `recall` defaults to `strategy: "semantic"` and `topK: 5`; `"keyword"` and
105
+ `"hybrid"` are also supported. Scores are a relevance ranking weight higher
106
+ is more relevant; compare only within one result set.
107
+ - Caller-safe validation failures surface as `400` with a stable `body.code`
108
+ (`invalid_metadata`, `invalid_filter`, `secret_detected`). Other request-shape
109
+ violations (e.g. oversized content) surface as a plain `400` without a stable
110
+ code. Infrastructure failures surface as generic `502`/`503`/`504` — details
111
+ are logged server-side, never returned to the caller.
68
112
  - Non-2xx responses throw `MemoryHttpError` with `status` and parsed `body`.
69
113
 
70
- The base URL follows the shared service resolver: `SAPIOM_MEMORY_URL`, then `SAPIOM_SERVICES_BASE`, then `https://memory.services.sapiom.ai`.
114
+ The base URL follows the shared service resolver: `SAPIOM_MEMORY_URL`, then
115
+ `SAPIOM_SERVICES_BASE`, then `https://memory.services.sapiom.ai`.