wontopos 2.2.21 → 2.2.23

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.
@@ -76,8 +76,6 @@ export declare class RateLimitError extends WosError {
76
76
  /** 5xx — the service failed. Safe to retry. */
77
77
  export declare class ServerError extends WosError {
78
78
  }
79
- /** Build the most specific WosError subclass for an HTTP status. */
80
- export declare function errorFor(status: number, message: string, requestId?: string): WosError;
81
79
  export interface Usage {
82
80
  input_tokens?: number;
83
81
  output_tokens?: number;
@@ -242,6 +240,12 @@ export interface ClientOptions {
242
240
  * 502/503 and connection errors only when a retry can never double-process a
243
241
  * write. 0 disables retries (default 2). */
244
242
  maxRetries?: number;
243
+ /** Alias of `maxRetries`. The Python SDK calls this option `retries`, and these
244
+ * SDKs are published in lockstep as "the same surface" — so code ported between
245
+ * them silently lost its retry setting instead of failing loudly (an unknown
246
+ * key on an options object is not an error in TS at runtime). Both names work;
247
+ * `maxRetries` wins if somehow both are given. */
248
+ retries?: number;
245
249
  }
246
250
  /** Wontopos memory client. Store and recall memories, isolated per `userId`. */
247
251
  export declare class Client {
package/dist/wontopos.js CHANGED
@@ -37,7 +37,7 @@
37
37
  * runtime's (never disabled by this SDK; Node 18+ floors TLS at 1.2). Prefer
38
38
  * `Client.fromEnv()` over keys in source code.
39
39
  */
40
- const VERSION = "2.2.21";
40
+ const VERSION = "2.2.23";
41
41
  /** Runtime info helps support debug a report ("node 18 on Windows...") —
42
42
  * platform only, never anything identifying. Browsers have no `process` (and
43
43
  * silently drop the UA header anyway). */
@@ -138,6 +138,26 @@ const asObj = (x) => (x != null && typeof x === "object" && !Array.isArray(x) ?
138
138
  const asRecords = (x) => asList(x).filter((m) => m != null && typeof m === "object" && !Array.isArray(m));
139
139
  // Attach a delivery-form override (memoir/archive) + tz to a body, the way search
140
140
  // passes them; on Scroll 1.2+ this renders each returned memory's time in that form.
141
+ /** Every memory a search returned — main lane and self lane together.
142
+ *
143
+ * On a self-lane model the service splits the result: the assistant's OWN words
144
+ * come back in `self_memories` and are REMOVED from `memories`, so the two never
145
+ * double-count. `search()` read only `memories`, so on Scroll 1.2 an assistant
146
+ * turn stored with `addTurn` was silently missing from search while the same
147
+ * query on tablet-1 returned it — upgrading the model made search return LESS,
148
+ * and the dropped memories were already on the wire and already paid for.
149
+ *
150
+ * Both lanes, de-duplicated by id, each memory keeping its `speaker` so the
151
+ * caller can still tell who said what. Callers who want the lanes kept apart use
152
+ * `searchSelf()`, which exists for exactly that. */
153
+ function mergeLanes(r) {
154
+ const main = asRecords(r?.memories);
155
+ const mine = asRecords(r?.self_memories);
156
+ if (mine.length === 0)
157
+ return main;
158
+ const seen = new Set(main.map((m) => m.id).filter((id) => typeof id === "string"));
159
+ return main.concat(mine.filter((m) => !(typeof m.id === "string" && seen.has(m.id))));
160
+ }
141
161
  function withForm(body, form, tz) {
142
162
  if (form !== undefined)
143
163
  body.form = form;
@@ -195,7 +215,8 @@ const STATUS_ERRORS = {
195
215
  429: RateLimitError,
196
216
  };
197
217
  /** Build the most specific WosError subclass for an HTTP status. */
198
- export function errorFor(status, message, requestId) {
218
+ // Internal factory — the typed error CLASSES are the public surface.
219
+ function errorFor(status, message, requestId) {
199
220
  const Cls = status === 0
200
221
  ? APIConnectionError
201
222
  : STATUS_ERRORS[status] ?? (status >= 500 && status < 600 ? ServerError : WosError);
@@ -242,7 +263,7 @@ export class Client {
242
263
  // Coerce a non-finite maxRetries (NaN/Infinity) back to the default — otherwise
243
264
  // NaN makes `attempts = NaN + 1` and the loop runs zero requests then throws
244
265
  // "retries exhausted"; Infinity would retry forever.
245
- const mr = opts.maxRetries;
266
+ const mr = opts.maxRetries ?? opts.retries;
246
267
  this.maxRetries = typeof mr === "number" && Number.isFinite(mr) ? Math.max(0, Math.floor(mr)) : 2;
247
268
  this.headers = {
248
269
  "X-API-Key": this.apiKey,
@@ -350,7 +371,7 @@ export class Client {
350
371
  // Reserved fields win over ...opts: an app that forwards untrusted input as
351
372
  // opts must not be able to override the store (user_id), query, or limit.
352
373
  const r = await this.post("/api/v1/memory/search", { ...opts, user_id: this.uid(userId), query, max_results: limit });
353
- return asRecords(r.memories);
374
+ return mergeLanes(r);
354
375
  }
355
376
  /** Search a self-memory model (Scroll 1.2+): both lanes from ONE call. Returns
356
377
  * `{ memories, self_memories }` — `memories` is the main lane (what others said /
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wontopos",
3
- "version": "2.2.21",
3
+ "version": "2.2.23",
4
4
  "description": "Wontopos — long-term memory for AI agents. Pure semantic retrieval, identical recall in every language, ~100× lower LLM bill.",
5
5
  "keywords": [
6
6
  "memory",