wontopos 2.2.34 → 2.2.36

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
@@ -23,15 +23,23 @@ const ctx = await mem.recall("what does alice drink?", "alice");
23
23
 
24
24
  ## Why
25
25
 
26
- - **Pure semantic retrieval** — no keyword/BM25. Identical recall in every language (Korean · Japanese · Chinese · English).
27
- - **No LLM in the loop** — `store` / `search` / `recall` never call a language model. You pay embeddings, not generation.
28
- - **Bounded retrieval** — `recall()` returns a small, fixed-size slice (~1,200 tokens) regardless of how much you've stored.
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.
28
+ - **Bounded retrieval** — `recall()` returns a small, fixed-size slice regardless of how much you've stored (~1,000 tokens on `tablet-2`, the default engine).
29
29
 
30
30
  ## Methods
31
31
 
32
32
  `add` · `addTurn` · `addBulk` · `update` · `search` · `searchFull` · `recall` · `history` · `stats` · `get` · `listMemories` · `delete` · `deleteAll`
33
33
 
34
- Every method takes the store id as its second argument — `mem.add("...", "alice")`. Omit it to use the client's default store. 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.
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.
35
43
 
36
44
  ## Who said it (speakers)
37
45
 
@@ -72,11 +80,23 @@ const hits = await mem.search("...the conversation so far...", "alice", 10,
72
80
 
73
81
  Built in, no configuration needed:
74
82
 
75
- - **Automatic retries** — 429 / 502 / 503 and connection errors retry twice with
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
76
89
  exponential backoff + jitter, honoring the server's `Retry-After`. Tune with
77
90
  `new Client({ maxRetries })`; `0` disables.
78
91
  - **Redirects refused** — the API key never follows a 3xx to another host.
79
- - **Timeouts** — 30s per attempt by default (`timeoutMs`).
92
+ - **Timeouts** — 30s per attempt by default (`timeoutMs`), and a total budget for
93
+ the whole call across every retry with `deadlineMs` / `withDeadline(ms)`. At the
94
+ defaults one call can hold for 30s + backoff + 30s + backoff + 30s, which a
95
+ request handler with five seconds cannot use.
96
+ - **Cancellable** — pass the caller's `AbortSignal` (`new Client({ signal })` or
97
+ `withSignal(signal)`). Aborting ends the request in flight and any backoff sleep
98
+ waiting to retry it.
99
+ - **CommonJS and ESM** — `require("wontopos")` and `import` both resolve.
80
100
  - **Key never in logs** — `JSON.stringify(client)` and Node's `console.log(client)`
81
101
  print a masked key.
82
102
  - **Wipe guard** — `delete()` without a `memoryId` throws instead of silently
@@ -162,10 +182,13 @@ try {
162
182
  }
163
183
  ```
164
184
 
165
- ## Self-host
185
+ ## A different API host
186
+
187
+ Point the client somewhere other than the default endpoint - a dedicated region,
188
+ a proxy of your own, or a local test server:
166
189
 
167
190
  ```ts
168
- const mem = new Client({ apiKey: "...", baseUrl: "https://wos.your-host.com" });
191
+ const mem = new Client({ apiKey: "...", baseUrl: "https://api.example.com" });
169
192
  ```
170
193
 
171
194
  ## Links
@@ -189,7 +212,82 @@ data to fix it.
189
212
 
190
213
  The three clients release in lockstep — same version, same surface, same day.
191
214
  Patch releases are additive: nothing is removed or reordered within a minor line.
192
-
215
+ Two have bent that, deliberately and named at the top of their entry — 2.2.34 moved the
216
+ default engine, and 2.2.35 gives `search` the count range `recall` has always had. A
217
+ rule you can bend without saying so is not a rule, so both are stated rather than left
218
+ for a reader to hit.
219
+
220
+ - **2.2.36** — an outside review, read by a different model with no knowledge of why
221
+ any of this was written. The one that mattered: `recall()` promised in its own
222
+ documentation that a count outside 5–20 was refused rather than clamped, and
223
+ nothing checked — so `{ limit: 500 }` travelled to the service and failed there, for a
224
+ mistake visible before opening a socket. `context_limit` (0–20) was unchecked the same way.
225
+ Both are refused here now, and `0` still passes for `context_limit` because "attach none" is
226
+ an answer, not a missing value.
227
+ An argument mistake now throws a plain `Error`, not a `WosError`. A `WosError` with
228
+ status 0 is `APIConnectionError` — "the request never got a response" — so
229
+ `if (e.status === 0) retry()` would have retried a typo forever. And `recall` is
230
+ now `async`: validating inside a non-async method threw synchronously, so
231
+ `mem.recall(...).catch(h)` walked past the handler while the same mistake in
232
+ `search` landed in it.
233
+ New `deadlineMs` / `withDeadline(ms)`: a TOTAL budget for one call across every
234
+ retry. `timeoutMs` bounds one ATTEMPT, so at the defaults a call could hold for 30s
235
+ + backoff + 30s + backoff + 30s and a request handler with five seconds had no way
236
+ to say so. New `signal` / `withSignal(signal)`: cancel work in flight — an abort
237
+ ends the request AND any backoff sleep waiting to retry it.
238
+ `require("wontopos")` now resolves: the package ships CommonJS and ESM from one
239
+ source. Previously `"type": "module"` with no `require` condition meant Node's CJS
240
+ resolver could not resolve this package at all.
241
+ `replayed` is set only when the service did not send that field itself.
242
+ - **2.2.35** — fixes, and **two behaviour changes**, both listed first because a patch
243
+ release is not the place to find one by surprise.
244
+
245
+ ⚠️ **`search`'s count is now 5–20, and out of range is refused rather than
246
+ adjusted.** `recall` has carried that range from the start; search had no contract
247
+ anywhere, so the clients sent whatever they were given and the service capped at 50
248
+ with no floor. `search(q, limit=50)` and `search(q, limit=3)` both worked on 2.2.34
249
+ and now raise. The default is still 10, so a call that passes no count is unaffected.
250
+ Asking for 20 and silently getting 10 reads as "that is all there is", which is why
251
+ this refuses instead of clamping.
252
+
253
+ ⚠️ **A Rust `limit` of 0 is no longer rewritten to 10.** It was, and the caller whose
254
+ prompt budget computed zero was handed ten memories and the bill for them. It is now
255
+ refused under the range above rather than quietly changed to something nobody asked
256
+ for.
257
+
258
+ The fixes: a `null` idempotency key no longer becomes the literal key `"null"`, which
259
+ had made every write on that path share one key so the second onward stored nothing
260
+ (TypeScript). The async client no longer reads an explicit `retries=2` as "the caller
261
+ said nothing" (Python). The image read is actually streamed, so the 64MB cap bounds a
262
+ compressed body instead of measuring bytes already in memory (Python async), and that
263
+ route's ERROR body is capped too (Rust). `iter_images` stops on a repeated cursor the
264
+ way `iter_memories` always did (Python). `iterImages` no longer throws on the ordinary
265
+ end of a walk (TypeScript). `get_image` retries a 429 and a connect-level failure like
266
+ every other call — it had none at all — in the **sync Python client and TypeScript**;
267
+ the async Python client and the Rust crate still make a single attempt there, and say
268
+ so at the method. An empty or control-character API key is refused at the call site
269
+ rather than at the network in **Python and Rust**; TypeScript still refuses only empty
270
+ and whitespace. And a page walk that reaches its ceiling now raises instead of
271
+ returning a truncated list that looks complete.
272
+ - **2.2.34** — the default engine is `tablet-2`: same token price as `tablet-1`, and
273
+ the one that serves images and re-ask. Pin the old one with
274
+ `model="tablet-1"` for the previous behaviour exactly. (The engine's own default
275
+ count differs between the two, but these SDKs always send one, so a call through
276
+ them is unaffected.) New `search_full` /
277
+ `searchFull` keeps every field the answer came with — `search` was merging away
278
+ the photos and `verify_used`, both of which you were billed for. Also: results arrive
279
+ best-first — take the order as given. `similarity` is a raw closeness score, and
280
+ sorting by it makes results worse.
281
+ - **2.2.33** — `get_image` can return a different FORMAT than you uploaded: the
282
+ service re-encodes on downscale, so a large PNG comes back as WebP. Take the file
283
+ extension from the response Content-Type, not from what you sent.
284
+ - **2.2.32** — `get_image` returns the picture the SERVICE holds, not your original.
285
+ An image whose long edge is over 1568px is downscaled on the way in, and that
286
+ smaller picture is what is stored and handed back. Keep your own copy if you need
287
+ the full file.
288
+ - **2.2.31** — images, by-speaker, lineage and revisions are SDK methods in all three
289
+ clients; `search` and `recall` take `verify`, `max_images` and recall's `limit` /
290
+ `context_limit`.
193
291
  - **2.2.30** — documentation only: this changelog, which had not been updated
194
292
  in the shipped package since 2.2.10.
195
293
  - **2.2.29** — a store id that was PASSED but unusable no longer becomes the
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}