wontopos 2.2.33 → 2.2.35
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 +87 -9
- package/dist/wontopos.d.ts +124 -76
- package/dist/wontopos.js +303 -149
- package/package.json +5 -7
package/README.md
CHANGED
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
npm install wontopos
|
|
5
5
|
```
|
|
6
6
|
|
|
7
|
+
Get an API key in the [console](https://wontopos.com). Keys look like `wos-live-...`;
|
|
8
|
+
the client also reads `WONTOPOS_API_KEY` from the environment.
|
|
9
|
+
|
|
7
10
|
```ts
|
|
8
11
|
import { Client } from "wontopos";
|
|
9
12
|
|
|
10
|
-
const mem = new Client({ apiKey: "wos-..." });
|
|
13
|
+
const mem = new Client({ apiKey: "wos-live-..." });
|
|
11
14
|
|
|
12
15
|
// Each end-user / agent / topic gets its own store — create it once.
|
|
13
16
|
// (A `default` store already exists, so you can skip this and omit the id.)
|
|
@@ -20,15 +23,23 @@ const ctx = await mem.recall("what does alice drink?", "alice");
|
|
|
20
23
|
|
|
21
24
|
## Why
|
|
22
25
|
|
|
23
|
-
- **
|
|
24
|
-
- **No LLM in the loop** — `store` / `search` / `recall` never call a language model. You pay
|
|
26
|
+
- **The same in every language** — identical recall whichever language a memory was written in (Korean · Japanese · Chinese · English).
|
|
27
|
+
- **No LLM in the loop** — `store` / `search` / `recall` never call a language model. You pay retrieval, not generation.
|
|
25
28
|
- **Bounded retrieval** — `recall()` returns a small, fixed-size slice (~1,200 tokens) regardless of how much you've stored.
|
|
26
29
|
|
|
27
30
|
## Methods
|
|
28
31
|
|
|
29
|
-
`add` · `addTurn` · `addBulk` · `update` · `search` · `recall` · `history` · `stats` · `get` · `listMemories` · `delete` · `deleteAll`
|
|
32
|
+
`add` · `addTurn` · `addBulk` · `update` · `search` · `searchFull` · `recall` · `history` · `stats` · `get` · `listMemories` · `delete` · `deleteAll`
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
Where the store id goes depends on whether the method takes a payload. A method that
|
|
35
|
+
writes or searches puts the payload first and the store second — `mem.add("...", "alice")`,
|
|
36
|
+
`mem.search("...", "alice")`. A method that only addresses a store takes it first —
|
|
37
|
+
`mem.listMemories("alice")`, `mem.stats("alice")`, `mem.delete("alice", memoryId)`.
|
|
38
|
+
Most of them let you leave it out for the client's default store. Four take it
|
|
39
|
+
positionally and cannot — `get`, `delete`, `lineage` and `forgetImage` want an explicit
|
|
40
|
+
`undefined` there, because a second required argument follows it. Python omits it in
|
|
41
|
+
all four; this is the one place the three clients differ in shape rather than meaning.
|
|
42
|
+
Let your editor confirm the order: every signature is typed. A store is one isolated memory space per end-user, agent, or topic. WHO said each memory inside a store is the `speaker` tag below — storing the assistant's own words never needs a separate id.
|
|
32
43
|
|
|
33
44
|
## Who said it (speakers)
|
|
34
45
|
|
|
@@ -69,7 +80,12 @@ const hits = await mem.search("...the conversation so far...", "alice", 10,
|
|
|
69
80
|
|
|
70
81
|
Built in, no configuration needed:
|
|
71
82
|
|
|
72
|
-
- **Automatic retries** — 429
|
|
83
|
+
- **Automatic retries** — 429 always, and 502 / 503 or a connection error only when a
|
|
84
|
+
retry cannot double-process a write. The writes and the searches are POSTs, and a
|
|
85
|
+
502 on one of those may have been returned *after* the service already stored and
|
|
86
|
+
billed it, so those get 429 and connect-level failures only. The reads and the
|
|
87
|
+
deletes that address a whole store — `listStores`, `listSpeakers`, `deleteStore`,
|
|
88
|
+
`removeSpeaker`, `forgetImage` — are GET or DELETE and do retry a 502. Twice, with
|
|
73
89
|
exponential backoff + jitter, honoring the server's `Retry-After`. Tune with
|
|
74
90
|
`new Client({ maxRetries })`; `0` disables.
|
|
75
91
|
- **Redirects refused** — the API key never follows a 3xx to another host.
|
|
@@ -87,6 +103,9 @@ egress proxy this SDK could not connect at all — while the Python and Rust SDK
|
|
|
87
103
|
through, because `requests` and `reqwest` both read those variables. Pass a
|
|
88
104
|
proxy-aware `fetch` and the three behave the same:
|
|
89
105
|
|
|
106
|
+
This one needs `npm i undici` — Node's global `fetch` is built on undici, but the
|
|
107
|
+
package itself is not installed for you.
|
|
108
|
+
|
|
90
109
|
```ts
|
|
91
110
|
import { ProxyAgent } from "undici";
|
|
92
111
|
|
|
@@ -126,10 +145,17 @@ update. `search` options are typed too (`SearchOptions`: `cache_control`,
|
|
|
126
145
|
`speaker`, plus pass-through).
|
|
127
146
|
|
|
128
147
|
```ts
|
|
148
|
+
import { type Memory } from "wontopos";
|
|
149
|
+
|
|
129
150
|
const hits: Memory[] = await mem.search("what did Bob say?", "alice", 10, { speaker: "Bob" });
|
|
130
151
|
console.log(hits[0].speaker, hits[0].time_bucket); // typed: string | undefined
|
|
131
152
|
```
|
|
132
153
|
|
|
154
|
+
`hits` arrives best-first — take it in the order given. `similarity` is a raw
|
|
155
|
+
closeness score, not the ranking key: what produces the order is internal and is
|
|
156
|
+
not returned, so sorting by `similarity` overrides the ranking and makes results
|
|
157
|
+
worse. There is no `score` field.
|
|
158
|
+
|
|
133
159
|
## Errors
|
|
134
160
|
|
|
135
161
|
Any non-2xx response throws `WosError` with `status`, `message`, and — when the
|
|
@@ -162,8 +188,7 @@ const mem = new Client({ apiKey: "...", baseUrl: "https://wos.your-host.com" });
|
|
|
162
188
|
|
|
163
189
|
## Reporting a bug
|
|
164
190
|
|
|
165
|
-
Found something wrong, or something that looks unsafe? Tell us —
|
|
166
|
-
every report.
|
|
191
|
+
Found something wrong, or something that looks unsafe? Tell us — every report gets read.
|
|
167
192
|
|
|
168
193
|
- Bugs: <https://wontopos.com/contact?topic=bug>
|
|
169
194
|
- Security: <https://wontopos.com/contact?topic=security> (also published at
|
|
@@ -177,7 +202,60 @@ data to fix it.
|
|
|
177
202
|
|
|
178
203
|
The three clients release in lockstep — same version, same surface, same day.
|
|
179
204
|
Patch releases are additive: nothing is removed or reordered within a minor line.
|
|
180
|
-
|
|
205
|
+
Two have bent that, deliberately and named at the top of their entry — 2.2.34 moved the
|
|
206
|
+
default engine, and 2.2.35 gives `search` the count range `recall` has always had. A
|
|
207
|
+
rule you can bend without saying so is not a rule, so both are stated rather than left
|
|
208
|
+
for a reader to hit.
|
|
209
|
+
|
|
210
|
+
- **2.2.35** — fixes, and **two behaviour changes**, both listed first because a patch
|
|
211
|
+
release is not the place to find one by surprise.
|
|
212
|
+
|
|
213
|
+
⚠️ **`search`'s count is now 5–20, and out of range is refused rather than
|
|
214
|
+
adjusted.** `recall` has carried that range from the start; search had no contract
|
|
215
|
+
anywhere, so the clients sent whatever they were given and the service capped at 50
|
|
216
|
+
with no floor. `search(q, limit=50)` and `search(q, limit=3)` both worked on 2.2.34
|
|
217
|
+
and now raise. The default is still 10, so a call that passes no count is unaffected.
|
|
218
|
+
Asking for 20 and silently getting 10 reads as "that is all there is", which is why
|
|
219
|
+
this refuses instead of clamping.
|
|
220
|
+
|
|
221
|
+
⚠️ **A Rust `limit` of 0 is no longer rewritten to 10.** It was, and the caller whose
|
|
222
|
+
prompt budget computed zero was handed ten memories and the bill for them. It is now
|
|
223
|
+
refused under the range above rather than quietly changed to something nobody asked
|
|
224
|
+
for.
|
|
225
|
+
|
|
226
|
+
The fixes: a `null` idempotency key no longer becomes the literal key `"null"`, which
|
|
227
|
+
had made every write on that path share one key so the second onward stored nothing
|
|
228
|
+
(TypeScript). The async client no longer reads an explicit `retries=2` as "the caller
|
|
229
|
+
said nothing" (Python). The image read is actually streamed, so the 64MB cap bounds a
|
|
230
|
+
compressed body instead of measuring bytes already in memory (Python async), and that
|
|
231
|
+
route's ERROR body is capped too (Rust). `iter_images` stops on a repeated cursor the
|
|
232
|
+
way `iter_memories` always did (Python). `iterImages` no longer throws on the ordinary
|
|
233
|
+
end of a walk (TypeScript). `get_image` retries a 429 and a connect-level failure like
|
|
234
|
+
every other call — it had none at all — in the **sync Python client and TypeScript**;
|
|
235
|
+
the async Python client and the Rust crate still make a single attempt there, and say
|
|
236
|
+
so at the method. An empty or control-character API key is refused at the call site
|
|
237
|
+
rather than at the network in **Python and Rust**; TypeScript still refuses only empty
|
|
238
|
+
and whitespace. And a page walk that reaches its ceiling now raises instead of
|
|
239
|
+
returning a truncated list that looks complete.
|
|
240
|
+
- **2.2.34** — the default engine is `tablet-2`: same token price as `tablet-1`, and
|
|
241
|
+
the one that serves images and re-ask. Pin the old one with
|
|
242
|
+
`model="tablet-1"` for the previous behaviour exactly. (The engine's own default
|
|
243
|
+
count differs between the two, but these SDKs always send one, so a call through
|
|
244
|
+
them is unaffected.) New `search_full` /
|
|
245
|
+
`searchFull` keeps every field the answer came with — `search` was merging away
|
|
246
|
+
the photos and `verify_used`, both of which you were billed for. Also: results arrive
|
|
247
|
+
best-first — take the order as given. `similarity` is a raw closeness score, and
|
|
248
|
+
sorting by it makes results worse.
|
|
249
|
+
- **2.2.33** — `get_image` can return a different FORMAT than you uploaded: the
|
|
250
|
+
service re-encodes on downscale, so a large PNG comes back as WebP. Take the file
|
|
251
|
+
extension from the response Content-Type, not from what you sent.
|
|
252
|
+
- **2.2.32** — `get_image` returns the picture the SERVICE holds, not your original.
|
|
253
|
+
An image whose long edge is over 1568px is downscaled on the way in, and that
|
|
254
|
+
smaller picture is what is stored and handed back. Keep your own copy if you need
|
|
255
|
+
the full file.
|
|
256
|
+
- **2.2.31** — images, by-speaker, lineage and revisions are SDK methods in all three
|
|
257
|
+
clients; `search` and `recall` take `verify`, `max_images` and recall's `limit` /
|
|
258
|
+
`context_limit`.
|
|
181
259
|
- **2.2.30** — documentation only: this changelog, which had not been updated
|
|
182
260
|
in the shipped package since 2.2.10.
|
|
183
261
|
- **2.2.29** — a store id that was PASSED but unusable no longer becomes the
|
package/dist/wontopos.d.ts
CHANGED
|
@@ -15,12 +15,15 @@
|
|
|
15
15
|
* so with no `userId` anywhere the zero-setup path just works.
|
|
16
16
|
*
|
|
17
17
|
* The API key picks *which memory* (your account); `model` picks *which engine*
|
|
18
|
-
* reads it.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* reads it. Models on the shared pool read the same memory, so you can store with
|
|
19
|
+
* one and recall with another; `listModels()` reports each model's `memory` as
|
|
20
|
+
* `"shared"` or `"isolated"`, and an isolated one starts empty. Set a default in
|
|
21
|
+
* the constructor, or override a single call with
|
|
22
|
+
* `mem.withModel("tablet-1").recall(...)`.
|
|
21
23
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
+
* Recall quality does not depend on which language a memory was written in: a
|
|
25
|
+
* memory stored in one language is found by a question asked in another. Storing
|
|
26
|
+
* and searching call no LLM.
|
|
24
27
|
*
|
|
25
28
|
* Reliability: every call retries transient failures with exponential backoff +
|
|
26
29
|
* jitter, honoring `Retry-After` — 429 always; 502/503 and connection errors only
|
|
@@ -39,6 +42,8 @@
|
|
|
39
42
|
*/
|
|
40
43
|
/** Test hook — the warn-once set is process-global by design. */
|
|
41
44
|
export declare function _resetStoreIdWarnings(): void;
|
|
45
|
+
export declare const SEARCH_LIMIT_MIN = 5;
|
|
46
|
+
export declare const SEARCH_LIMIT_MAX = 20;
|
|
42
47
|
/** Quota from a response's `X-RateLimit-*` headers, or `null` if absent. */
|
|
43
48
|
export interface RateLimit {
|
|
44
49
|
limit: number | null;
|
|
@@ -84,8 +89,8 @@ export declare class RateLimitError extends WosError {
|
|
|
84
89
|
* `501` is NOT transient. It means the engine behind the model you selected does
|
|
85
90
|
* not implement that endpoint at all (the error carries `model` and `endpoint`).
|
|
86
91
|
* Retrying can never succeed — pick a model that supports it (`listModels`) or
|
|
87
|
-
* drop the call.
|
|
88
|
-
*
|
|
92
|
+
* drop the call. Treating the whole 5xx range as retryable sends a caller into a
|
|
93
|
+
* loop that cannot end.
|
|
89
94
|
*/
|
|
90
95
|
export declare class ServerError extends WosError {
|
|
91
96
|
}
|
|
@@ -99,9 +104,12 @@ export interface Memory {
|
|
|
99
104
|
content?: string;
|
|
100
105
|
/** Cognitive category, e.g. "general". */
|
|
101
106
|
category?: string;
|
|
102
|
-
/**
|
|
107
|
+
/** Raw closeness to the query — higher is closer. NOT the ranking key: results already
|
|
108
|
+
* arrive best-first, and what produces that order is internal and not returned, so
|
|
109
|
+
* re-sorting by `similarity` overrides the ranking and makes results worse. Take the
|
|
110
|
+
* list in the order given. There is no `score` field. */
|
|
103
111
|
similarity?: number;
|
|
104
|
-
/**
|
|
112
|
+
/** Importance weight the service assigns to the memory. */
|
|
105
113
|
importance?: number;
|
|
106
114
|
/** Month bucket the memory belongs to (e.g. "2026-07"). Omitted when temporal fields are stripped. */
|
|
107
115
|
time_bucket?: string;
|
|
@@ -125,11 +133,11 @@ export interface StoreResult {
|
|
|
125
133
|
/**
|
|
126
134
|
* Present when `status` is `"duplicate"`: the id of the memory this write collided with.
|
|
127
135
|
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
136
|
+
* A genuinely new fact that only varies a detail of one already stored ("no meetings
|
|
137
|
+
* before 10am" next to "no meetings on Fridays") can land here too, so a duplicate is
|
|
138
|
+
* not always a harmless no-op: read this id, and either store one sentence that states
|
|
139
|
+
* both or `update()` the existing memory with the combined statement. Without it a
|
|
140
|
+
* dropped write gave the caller nothing to act on.
|
|
133
141
|
*/
|
|
134
142
|
duplicate_of?: string;
|
|
135
143
|
/** Present when the store was a duplicate and something (e.g. a speaker tag) was dropped. */
|
|
@@ -150,9 +158,9 @@ export interface StatusResult {
|
|
|
150
158
|
*
|
|
151
159
|
* What the service keeps is NOT your original. An image whose long edge is over
|
|
152
160
|
* 1568px is downscaled to 1568 before anything else happens, and that smaller
|
|
153
|
-
* picture is what gets
|
|
154
|
-
*
|
|
155
|
-
*
|
|
161
|
+
* picture is what gets stored, and handed back by `getImage`. Nothing on our side
|
|
162
|
+
* ever uses more than 1568, so the extra pixels would be bytes nobody reads. This
|
|
163
|
+
* is a memory
|
|
156
164
|
* service, not a photo host: the picture it holds has the resolution of a memory.
|
|
157
165
|
*
|
|
158
166
|
* It can also come back in a different FORMAT. Downscaling means re-encoding, and
|
|
@@ -231,7 +239,7 @@ export interface RevisionsResult {
|
|
|
231
239
|
revised?: number;
|
|
232
240
|
/** Memories nothing has touched since they were written. Always `total - revised`. */
|
|
233
241
|
unrevised?: number;
|
|
234
|
-
/** Every memory in the store.
|
|
242
|
+
/** Every memory in the store. Internal records nobody stored directly are not counted. */
|
|
235
243
|
total?: number;
|
|
236
244
|
/** What `revised` counts, spelled out by the service. */
|
|
237
245
|
counts?: string;
|
|
@@ -280,7 +288,7 @@ export interface LineageResult {
|
|
|
280
288
|
export interface SpeakerPage {
|
|
281
289
|
speaker?: string;
|
|
282
290
|
memories: Memory[];
|
|
283
|
-
/**
|
|
291
|
+
/** How many underlying records a delete would actually remove, beyond what was returned. */
|
|
284
292
|
chunks?: number;
|
|
285
293
|
points_to_delete?: number;
|
|
286
294
|
returned?: number;
|
|
@@ -296,6 +304,26 @@ export interface UpdateResult {
|
|
|
296
304
|
status?: string;
|
|
297
305
|
[key: string]: unknown;
|
|
298
306
|
}
|
|
307
|
+
/** `searchFull` → everything one search answered with, not just the merged memories.
|
|
308
|
+
*
|
|
309
|
+
* `search` returns the memories and nothing else, which is the right answer for
|
|
310
|
+
* almost every call. Two options make it the wrong one: `max_images` asks for
|
|
311
|
+
* photos, which arrive in their own field, and `verify` is reported on by
|
|
312
|
+
* `verify_used`. Merging away both means paying for a
|
|
313
|
+
* search you shaped and never seeing what came of it. */
|
|
314
|
+
export interface SearchResult {
|
|
315
|
+
/** What others said, and general memories. */
|
|
316
|
+
memories: Memory[];
|
|
317
|
+
/** The assistant's own words (speaker "me"); `[]` on a model that does not keep
|
|
318
|
+
* them apart. */
|
|
319
|
+
self_memories: Memory[];
|
|
320
|
+
/** Image memories, when `max_images` asked for any; `[]` otherwise. */
|
|
321
|
+
images: Memory[];
|
|
322
|
+
/** Re-ask passes actually performed. Present only when `verify` was sent; lower
|
|
323
|
+
* than you asked for means the store had nothing further to add. */
|
|
324
|
+
verify_used?: number;
|
|
325
|
+
[key: string]: unknown;
|
|
326
|
+
}
|
|
299
327
|
export interface RecallResult {
|
|
300
328
|
short_term: {
|
|
301
329
|
turns: unknown[];
|
|
@@ -333,7 +361,7 @@ export interface StatsResult {
|
|
|
333
361
|
short_term_turns?: number;
|
|
334
362
|
[key: string]: unknown;
|
|
335
363
|
}
|
|
336
|
-
/** `listMemories` → one page of a store's raw memories (
|
|
364
|
+
/** `listMemories` → one page of a store's raw memories (the text you stored, and its metadata). */
|
|
337
365
|
export interface MemoryPage {
|
|
338
366
|
memories: Memory[];
|
|
339
367
|
count: number;
|
|
@@ -341,9 +369,9 @@ export interface MemoryPage {
|
|
|
341
369
|
next_cursor: string | null;
|
|
342
370
|
[key: string]: unknown;
|
|
343
371
|
}
|
|
344
|
-
/** `searchSelf` result:
|
|
372
|
+
/** `searchSelf` result: general memories and the assistant's own, kept apart. */
|
|
345
373
|
export interface SelfSearchResult {
|
|
346
|
-
/**
|
|
374
|
+
/** What others said, and general memories. */
|
|
347
375
|
memories: Memory[];
|
|
348
376
|
/** The assistant's own words (stored with speaker "me"); `[]` on non-self models. */
|
|
349
377
|
self_memories: Memory[];
|
|
@@ -406,10 +434,11 @@ export interface SpeakersList {
|
|
|
406
434
|
[key: string]: unknown;
|
|
407
435
|
}
|
|
408
436
|
/**
|
|
409
|
-
* Narrow a search to part of a store
|
|
410
|
-
*
|
|
437
|
+
* Narrow a search to part of a store. The filter chooses what is searched, not what
|
|
438
|
+
* is kept afterwards — so a narrow filter still returns your full `limit` when that
|
|
439
|
+
* many matches sit inside it.
|
|
411
440
|
*
|
|
412
|
-
* Retrieval
|
|
441
|
+
* Retrieval behaves the same in every language, so these behave
|
|
413
442
|
* identically in every language. Unlisted keys are dropped by the API rather than
|
|
414
443
|
* rejected, so a typo silently widens the search — spell them exactly.
|
|
415
444
|
*/
|
|
@@ -443,7 +472,7 @@ export interface SearchOptions {
|
|
|
443
472
|
/**
|
|
444
473
|
* Re-ask passes, 0–3. After the first retrieval the service asks the engine again up
|
|
445
474
|
* to this many times, each time telling it what was already returned so it skips
|
|
446
|
-
* those and reaches further back.
|
|
475
|
+
* those and reaches further back. No LLM runs at any
|
|
447
476
|
* value. Stops early when a pass finds nothing new; `verify_used` in the response
|
|
448
477
|
* says how many actually ran.
|
|
449
478
|
*
|
|
@@ -452,7 +481,7 @@ export interface SearchOptions {
|
|
|
452
481
|
* that need several distinct memories from far apart in the history; it does little
|
|
453
482
|
* on a single-fact lookup.
|
|
454
483
|
*
|
|
455
|
-
*
|
|
484
|
+
* Requires a re-ask-capable model. Older ones REFUSE the call (403) rather than
|
|
456
485
|
* quietly charging you for passes that never happened.
|
|
457
486
|
*/
|
|
458
487
|
verify?: number;
|
|
@@ -461,7 +490,7 @@ export interface SearchOptions {
|
|
|
461
490
|
* Out of range is refused, not clamped — silently cutting 5 to 1 would leave you
|
|
462
491
|
* believing you got five.
|
|
463
492
|
*
|
|
464
|
-
*
|
|
493
|
+
* Requires an image-capable model, and is refused (403) on one without it rather
|
|
465
494
|
* than answering with no images.
|
|
466
495
|
*/
|
|
467
496
|
max_images?: number;
|
|
@@ -473,8 +502,11 @@ export interface SearchOptions {
|
|
|
473
502
|
* `idempotencyKey` makes repeating THIS EXACT write safe: the API replays the first
|
|
474
503
|
* response instead of storing again, for 10 minutes, and answers 422 if the same key
|
|
475
504
|
* arrives with a different body. Use it when a retry is your own (a job that died and
|
|
476
|
-
* was re-run, a queue that redelivers)
|
|
477
|
-
*
|
|
505
|
+
* was re-run, a queue that redelivers). The SDK retries a write on exactly one
|
|
506
|
+
* status: 429, which the service answers before it processes anything, so nothing
|
|
507
|
+
* was stored. It never retries a write on 502 / 503 or a dropped body, where the
|
|
508
|
+
* request may already have been stored and billed — without a key it cannot know
|
|
509
|
+
* whether that first attempt landed.
|
|
478
510
|
*
|
|
479
511
|
* The key must be UNIQUE PER LOGICAL WRITE — derive it from the thing being stored
|
|
480
512
|
* (`` `import:${row.id}` ``), never a constant, or the second write replays the first
|
|
@@ -578,8 +610,7 @@ export declare class Client {
|
|
|
578
610
|
withRetries(maxRetries: number): Client;
|
|
579
611
|
/** Store one memory. `metadata` optional — e.g. `{ event_date: "2026-03-01" }` for when the
|
|
580
612
|
* content actually happened. A plain date works (read as UTC midnight); a full RFC3339
|
|
581
|
-
* timestamp also works
|
|
582
|
-
* an opaque 400, which is why older examples here show the long one.
|
|
613
|
+
* timestamp also works; older examples here show the long form.
|
|
583
614
|
* `metadata.speaker`: "me" = the assistant's own words, or a person's name (up to 50 per store).
|
|
584
615
|
*
|
|
585
616
|
* `opts.idempotencyKey`: see {@link WriteOptions} — pass one to make YOUR retry
|
|
@@ -589,27 +620,42 @@ export declare class Client {
|
|
|
589
620
|
store(content: string, userId?: string, metadata?: Record<string, unknown>, opts?: WriteOptions): Promise<StoreResult>;
|
|
590
621
|
/** Store a conversation turn (user + assistant). Payload first, userId last — same shape as add/search. */
|
|
591
622
|
addTurn(userMsg: string, assistantMsg: string, userId?: string, opts?: WriteOptions): Promise<StatusResult>;
|
|
592
|
-
/** Bulk-ingest a large blob of text
|
|
623
|
+
/** Bulk-ingest a large blob of text in one call. For backfilling.
|
|
593
624
|
* The call most worth an `opts.idempotencyKey`: a backfill that dies halfway and is
|
|
594
|
-
* re-run would otherwise re-
|
|
625
|
+
* re-run would otherwise re-ingest and re-bill the whole blob. */
|
|
595
626
|
addBulk(content: string, userId?: string, category?: string, timestamp?: string, opts?: WriteOptions): Promise<StatusResult>;
|
|
596
627
|
/** Supersede an old memory with new content. Payload first, userId last — same shape as add/search. */
|
|
597
628
|
update(oldMemoryId: string, newContent: string, userId?: string, opts?: WriteOptions): Promise<UpdateResult>;
|
|
598
|
-
/**
|
|
599
|
-
*
|
|
600
|
-
* `limit` bounds
|
|
601
|
-
* (Scroll 1.2+)
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
629
|
+
/** Search a store's memories. Returns them most relevant first.
|
|
630
|
+
*
|
|
631
|
+
* `limit` bounds `memories`, not the returned array. On a model that keeps the
|
|
632
|
+
* assistant's own words separate (Scroll 1.2+) those come back as well, so the
|
|
633
|
+
* array can hold more than `limit`. They were retrieved and billed either way;
|
|
634
|
+
* dropping them would only hide what you already paid for. Size a prompt window
|
|
635
|
+
* on the array you get back, not on `limit`. `searchSelf()` hands the two back
|
|
636
|
+
* apart. */
|
|
606
637
|
search(query: string, userId?: string, limit?: number, opts?: SearchOptions): Promise<Memory[]>;
|
|
607
|
-
/** Search a self-memory model (Scroll 1.2+): both
|
|
608
|
-
* `{ memories, self_memories }` — `memories` is
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
638
|
+
/** Search a self-memory model (Scroll 1.2+): both fields from ONE call. Returns
|
|
639
|
+
* `{ memories, self_memories }` — `memories` is what others said and general
|
|
640
|
+
* memories, `self_memories` is the assistant's OWN words (stored with speaker
|
|
641
|
+
* "me"), kept apart so whoever reads them never confuses who said what. On a model
|
|
642
|
+
* that does not keep them apart, `self_memories` is `[]`. `userId` may be omitted. */
|
|
612
643
|
searchSelf(query: string, userId?: string, limit?: number, opts?: SearchOptions): Promise<SelfSearchResult>;
|
|
644
|
+
/**
|
|
645
|
+
* Search, and keep every field the answer came with.
|
|
646
|
+
*
|
|
647
|
+
* Same request as {@link Client.search} — reach for this one when the options make
|
|
648
|
+
* the merged array an incomplete answer:
|
|
649
|
+
*
|
|
650
|
+
* const r = await mem.searchFull("the day we moved", "alice", 10,
|
|
651
|
+
* { max_images: 3, verify: 2 });
|
|
652
|
+
* r.images.length; // the photos, which `search` drops
|
|
653
|
+
* r.verify_used; // how many re-ask passes actually ran (you are billed per pass)
|
|
654
|
+
*
|
|
655
|
+
* Both options need Tablet 2 or newer and are refused (403) on an older engine
|
|
656
|
+
* rather than accepted and ignored.
|
|
657
|
+
*/
|
|
658
|
+
searchFull(query: string, userId?: string, limit?: number, opts?: SearchOptions): Promise<SearchResult>;
|
|
613
659
|
/** One-call LLM context: short-term turns + long-term matches + surrounding context.
|
|
614
660
|
* `form` ("memoir"/"archive", Scroll 1.2+) renders each long-term memory's time in
|
|
615
661
|
* that form; `tz` is your UTC-offset hours for that rendering. */
|
|
@@ -620,16 +666,18 @@ export declare class Client {
|
|
|
620
666
|
* Long-term memories to recall, 5–20. Default 10. Out of range is refused, not
|
|
621
667
|
* clamped — asking for 20 and silently getting 10 reads as "that is all there is".
|
|
622
668
|
*
|
|
623
|
-
*
|
|
669
|
+
* Needs a limit-aware model. An older one recalls a fixed ten no matter what you
|
|
624
670
|
* send, so the API refuses the call (403) rather than answering with a number you
|
|
625
671
|
* did not ask for.
|
|
626
672
|
*/
|
|
627
673
|
limit?: number;
|
|
628
|
-
/**
|
|
674
|
+
/** How much surrounding context is attached around the best match, 0–20. Default 10;
|
|
629
675
|
* 0 attaches none. Same model floor as `limit`. */
|
|
630
676
|
context_limit?: number;
|
|
631
677
|
}): Promise<RecallResult>;
|
|
632
|
-
/** Run a built-in engram ("deep_recall" | "timeline" | "gather"
|
|
678
|
+
/** Run a built-in engram ("deep_recall" | "timeline" | "gather" | "equilibrium" |
|
|
679
|
+
* "tone_stabilizer"; the service is the authority — an unknown name comes back with
|
|
680
|
+
* the list it accepts). Returns the merged result.
|
|
633
681
|
* `form`/`tz` render memory times (memoir/archive) on Scroll 1.2+, same as search/recall. */
|
|
634
682
|
engram(name: string, query: string, userId?: string, opts?: {
|
|
635
683
|
form?: string;
|
|
@@ -639,13 +687,14 @@ export declare class Client {
|
|
|
639
687
|
history(userId?: string): Promise<HistoryTurn[]>;
|
|
640
688
|
/** Memory counts for a store: { total_memories, short_term_turns }. */
|
|
641
689
|
stats(userId?: string): Promise<StatsResult>;
|
|
642
|
-
/** Fetch ONE memory by id — the
|
|
690
|
+
/** Fetch ONE memory by id — the text you stored, and its metadata.
|
|
643
691
|
* The id is what `add`/`store` or `listMemories` returned. Same visibility as
|
|
644
|
-
* `listMemories`: an id from another store,
|
|
645
|
-
* invalidated memory rejects with `NotFoundError`. `
|
|
692
|
+
* `listMemories`: an id from another store, an internal record id, or an
|
|
693
|
+
* invalidated memory rejects with `NotFoundError`. Pass `undefined` as `userId` for
|
|
694
|
+
* the default store — it is positional here, not omittable as it is in Python. */
|
|
646
695
|
get(userId: string | undefined, memoryId: string): Promise<Memory>;
|
|
647
|
-
/** List a store's stored memories — the
|
|
648
|
-
*
|
|
696
|
+
/** List a store's stored memories — the text you stored, plus its metadata.
|
|
697
|
+
* Paginated: pass the returned `next_cursor` back as `cursor` for the next
|
|
649
698
|
* page; a `null` cursor means the last page. Use it to browse or export a store.
|
|
650
699
|
*
|
|
651
700
|
* let cursor: string | null = null;
|
|
@@ -661,14 +710,14 @@ export declare class Client {
|
|
|
661
710
|
cursor?: string;
|
|
662
711
|
}): Promise<MemoryPage>;
|
|
663
712
|
/** Async-iterate every stored memory in a store, paging under the hood — no cursor
|
|
664
|
-
* bookkeeping.
|
|
713
|
+
* bookkeeping. The text you stored and its metadata only.
|
|
665
714
|
*
|
|
666
715
|
* for await (const m of mem.iterMemories()) console.log(m.id, m.content);
|
|
667
716
|
*/
|
|
668
717
|
iterMemories(userId?: string, opts?: {
|
|
669
718
|
pageSize?: number;
|
|
670
719
|
}): AsyncGenerator<Memory>;
|
|
671
|
-
/** Collect ALL of a store's memories into an array (
|
|
720
|
+
/** Collect ALL of a store's memories into an array (the text you stored, and its metadata). */
|
|
672
721
|
exportMemories(userId?: string): Promise<Memory[]>;
|
|
673
722
|
/**
|
|
674
723
|
* Fetch the bytes of an image memory — the picture the SERVICE holds.
|
|
@@ -676,8 +725,8 @@ export declare class Client {
|
|
|
676
725
|
* Not necessarily your upload, in size OR in format: an image whose long edge was
|
|
677
726
|
* over 1568px was downscaled to 1568 on the way in and re-encoded — lossless
|
|
678
727
|
* formats as WebP, so a PNG comes back as `image/webp`; JPEG stays JPEG — and that
|
|
679
|
-
* smaller picture is what
|
|
680
|
-
*
|
|
728
|
+
* smaller picture is what is stored and comes back here. Nothing on our side ever
|
|
729
|
+
* uses more than 1568, so the extra pixels would be bytes nobody reads.
|
|
681
730
|
* Keep your own copy for the full-resolution file.
|
|
682
731
|
*
|
|
683
732
|
* The type is sniffed from the bytes themselves rather than from whatever the file
|
|
@@ -735,10 +784,10 @@ export declare class Client {
|
|
|
735
784
|
*
|
|
736
785
|
* Counts memories a transform touched (supersede, update, retract, image removed).
|
|
737
786
|
* Deletions are NOT counted: a deleted memory leaves nothing to count. Neither are
|
|
738
|
-
*
|
|
739
|
-
* do not belong in a ratio that answers "how much of MY memory changed".
|
|
787
|
+
* the internal records derived from what you stored — nobody stored those directly,
|
|
788
|
+
* so they do not belong in a ratio that answers "how much of MY memory changed".
|
|
740
789
|
*
|
|
741
|
-
*
|
|
790
|
+
* By default this returns COUNTS ONLY, and the answer is the same size for a store
|
|
742
791
|
* of a hundred memories and a store of a hundred million. That is deliberate: a model
|
|
743
792
|
* asks this mid-conversation, and an answer that grew with the store would be
|
|
744
793
|
* unusable for exactly the customers who most need to ask.
|
|
@@ -759,10 +808,10 @@ export declare class Client {
|
|
|
759
808
|
* }
|
|
760
809
|
* ```
|
|
761
810
|
*
|
|
762
|
-
*
|
|
811
|
+
* Pages are ordered by when each memory was STORED, not by when it was edited.
|
|
763
812
|
* The response says so in `ordered_by`.
|
|
764
813
|
*
|
|
765
|
-
*
|
|
814
|
+
* Served from `/api/v1/won/*`, not `/api/v1/memory/*`. Won is the surface for calls
|
|
766
815
|
* a model makes ABOUT its memory rather than calls an application makes WITH it, and
|
|
767
816
|
* the address says so. The old path still answers, for clients published before
|
|
768
817
|
* 2026-08-18, and both share one rate-limit budget.
|
|
@@ -795,9 +844,9 @@ export declare class Client {
|
|
|
795
844
|
* assistant's own words, otherwise a person's name. Same cursor paging as
|
|
796
845
|
* `listImages`.
|
|
797
846
|
*
|
|
798
|
-
* `chunks` / `points_to_delete` report
|
|
799
|
-
*
|
|
800
|
-
*
|
|
847
|
+
* `chunks` / `points_to_delete` report how many internal records a delete would
|
|
848
|
+
* actually remove — usually more than `returned`, and worth showing to whoever is
|
|
849
|
+
* about to confirm one.
|
|
801
850
|
*/
|
|
802
851
|
bySpeaker(speaker: string, userId?: string, opts?: {
|
|
803
852
|
limit?: number;
|
|
@@ -813,10 +862,9 @@ export declare class Client {
|
|
|
813
862
|
/**
|
|
814
863
|
* The engrams (and delivery forms) the selected model can actually run.
|
|
815
864
|
*
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
819
|
-
* and stopped hard-coding for the same reason. The service is the authority: what
|
|
865
|
+
* Ask rather than hard-code: a name copied from the docs freezes a caller to the
|
|
866
|
+
* catalogue as it was that day, and anything added later stays invisible. The
|
|
867
|
+
* service is the authority. What
|
|
820
868
|
* comes back depends on the model (delivery forms need Scroll 1.2+), so pass
|
|
821
869
|
* `withModel()` if you want another model's catalogue.
|
|
822
870
|
*
|
|
@@ -840,7 +888,8 @@ export declare class Client {
|
|
|
840
888
|
listSpeakers(userId?: string): Promise<SpeakersList>;
|
|
841
889
|
/** Unregister a person. Their memories stay; the name tag goes. */
|
|
842
890
|
removeSpeaker(speaker: string, userId?: string): Promise<SpeakerOpResult>;
|
|
843
|
-
/** Delete a single memory by id. `userId`
|
|
891
|
+
/** Delete a single memory by id. Pass `undefined` as `userId` for the default
|
|
892
|
+
* store — it is positional here, not omittable as it is in Python. */
|
|
844
893
|
delete(userId: string | undefined, memoryId: string): Promise<StatusResult>;
|
|
845
894
|
/** Delete ALL memories for a store (GDPR erase). `userId` is required on purpose -
|
|
846
895
|
* this is destructive, so it never falls back to the default store. */
|
|
@@ -870,10 +919,9 @@ export declare class Client {
|
|
|
870
919
|
private readCapped;
|
|
871
920
|
/** The same cap, for a body that is not text.
|
|
872
921
|
*
|
|
873
|
-
* `
|
|
874
|
-
*
|
|
875
|
-
*
|
|
876
|
-
* megabytes was not. One implementation, two callers, so they cannot drift. */
|
|
922
|
+
* `arrayBuffer()` would buffer whatever arrives. The cap exists for a hostile or
|
|
923
|
+
* broken `baseUrl`, and an endpoint that returns megabytes is where that costs the
|
|
924
|
+
* most. One implementation, two callers, so they cannot drift. */
|
|
877
925
|
private readCappedBytes;
|
|
878
926
|
private request;
|
|
879
927
|
}
|