wontopos 2.2.41 → 2.2.43

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
@@ -209,7 +209,7 @@ data to fix it.
209
209
  ## Changelog
210
210
 
211
211
  The three clients release in lockstep — same version, same surface, same day. Patch
212
- releases are additive. Seven inside 2.2 were not, deliberately and each with its
212
+ releases are additive. Eight inside 2.2 were not, deliberately and each with its
213
213
  reason; the changelog lists them.
214
214
 
215
215
  See [CHANGELOG.md](https://github.com/wontopos/wontopos-node/blob/main/CHANGELOG.md).
@@ -15,11 +15,10 @@
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. `listModels()` reports each model's `memory` as `"shared"` or
19
- * `"isolated"`, and an isolated one starts empty. Every model on the shared pool
20
- * lists, fetches and deletes the same memories, but a search may not find memories
21
- * stored through a different model; store and search with the same one. Set a
22
- * default in the constructor, or override a single call with
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
23
22
  * `mem.withModel("tablet-1").recall(...)`.
24
23
  *
25
24
  * Recall quality does not depend on which language a memory was written in: a
@@ -157,13 +156,16 @@ export interface Memory {
157
156
  speaker?: string;
158
157
  [key: string]: unknown;
159
158
  }
160
- /** `add` / `store` → `{ id, status }` (`status: "stored" | "stored (async)" | "duplicate"`). */
159
+ /** `add` / `store` → `{ id, status }`. `status` starts with `"stored"` (more text can
160
+ * follow) or is `"duplicate"`; match on the prefix. */
161
161
  export interface StoreResult {
162
162
  id?: string;
163
- /** `"stored"`, or `"duplicate"` when nothing was saved. */
163
+ /** Starts with `"stored"`, or is `"duplicate"` when nothing was saved. */
164
164
  status?: string;
165
165
  /**
166
- * Present when `status` is `"duplicate"`: the id of the memory this write collided with.
166
+ * On a duplicate, the id of the memory this write collided with, when the reply has
167
+ * it. A duplicate can arrive with an empty `id` and no `duplicate_of`; then search with
168
+ * the same text to find the memory it matched.
167
169
  *
168
170
  * A genuinely new fact that only varies a detail of one already stored ("no meetings
169
171
  * before 10am" next to "no meetings on Fridays") can land here too, so a duplicate is
@@ -325,6 +327,8 @@ export interface SpeakerPage {
325
327
  memories: Memory[];
326
328
  chunks?: number;
327
329
  /** The count to show before anyone confirms a delete of this speaker's memories. */
330
+ records_to_delete?: number;
331
+ /** @deprecated The same number as `records_to_delete`, under its old name. */
328
332
  points_to_delete?: number;
329
333
  returned?: number;
330
334
  has_more?: boolean;
@@ -382,10 +386,16 @@ export interface EngramResult {
382
386
  usage?: Usage;
383
387
  [key: string]: unknown;
384
388
  }
389
+ /** One turn of the short-term window, as `history()` returns it. */
385
390
  export interface HistoryTurn {
391
+ /** `"user"` or `"assistant"`. */
392
+ role?: string;
393
+ content?: string;
394
+ timestamp?: string;
395
+ /** @deprecated Not sent: a turn comes back as `role` and `content`. */
386
396
  user_msg?: string;
397
+ /** @deprecated Not sent: a turn comes back as `role` and `content`. */
387
398
  assistant_msg?: string;
388
- timestamp?: string;
389
399
  [key: string]: unknown;
390
400
  }
391
401
  /** `usage` → what this key has spent, and what is left to spend. */
@@ -405,7 +415,7 @@ export interface UsageResult {
405
415
  requests?: number;
406
416
  cost_cents?: number;
407
417
  };
408
- /** Per-store spend over the window, busiest first, and at most 50 rows — a longer
418
+ /** Per-store spend over the window, highest spend first, and at most 50 rows — a longer
409
419
  * list is cut, so these need not sum to `workspace`. `other`, when present, is an
410
420
  * overflow bucket rather than a store. */
411
421
  stores?: {
@@ -461,12 +471,14 @@ export interface ModelInfo {
461
471
  id: string;
462
472
  name: string;
463
473
  available: boolean;
464
- /** "shared" — lists, fetches and deletes the common memory pool, though a search
465
- * may not find memories stored through a different model; "isolated" — its own
466
- * dedicated store. */
474
+ /** "shared" — reads the common memory pool; "isolated" — its own dedicated store. */
467
475
  memory: "shared" | "isolated";
468
476
  /** What this model can do. Check it before relying on a feature. */
469
477
  capabilities?: ModelCapabilities;
478
+ /** Present on a live model that is scheduled to retire (RFC3339). From that instant
479
+ * the model leaves this list and calls naming it are refused. */
480
+ retires_at?: string;
481
+ [key: string]: unknown;
470
482
  }
471
483
  /** One entry of the engram / delivery-form catalogue (`listEngrams`). */
472
484
  export interface EngramInfo {
@@ -934,9 +946,9 @@ export declare class Client {
934
946
  get(userId: string | undefined, memoryId: string): Promise<Memory>;
935
947
  /** List a store's stored memories — the text you stored, plus its metadata.
936
948
  * Paginated: pass the returned `next_cursor` back as `cursor` for the next
937
- * page, and only a cursor the service returned. A `null` cursor means there is no
938
- * next page; a non-null one can still be followed by an empty page. Use it to
939
- * browse or export a store.
949
+ * page, and only a cursor the service returned, with the model that returned it. A
950
+ * `null` cursor means there is no next page; a non-null one can still be followed by
951
+ * an empty page. Use it to browse or export a store.
940
952
  *
941
953
  * `limit` is 1-500 (default 100); anything else is refused before the request.
942
954
  *
@@ -1096,8 +1108,8 @@ export declare class Client {
1096
1108
  * assistant's own words, otherwise a person's name. Same cursor paging as
1097
1109
  * `listImages`; `limit` is 5-20.
1098
1110
  *
1099
- * `points_to_delete` is the count to show before anyone confirms a delete of this
1100
- * speaker's memories.
1111
+ * `records_to_delete` is the count to show before anyone confirms a delete of this
1112
+ * speaker's memories; `points_to_delete` is the same number under its old name.
1101
1113
  */
1102
1114
  bySpeaker(speaker: string, userId?: string, opts?: {
1103
1115
  limit?: number;
@@ -1108,7 +1120,8 @@ export declare class Client {
1108
1120
  * `AuthenticationError` (bad key), `PaymentRequiredError` (valid key but no card /
1109
1121
  * depleted balance), or `APIConnectionError` (unreachable). Makes one metered request. */
1110
1122
  ping(): Promise<boolean>;
1111
- /** Available models: `[{ id, name, available, memory }, ...]`. Needs no API key. */
1123
+ /** Available models: `[{ id, name, available, memory, capabilities, retires_at? }, ...]`.
1124
+ * Needs no API key. */
1112
1125
  listModels(): Promise<ModelInfo[]>;
1113
1126
  /**
1114
1127
  * The engrams (and delivery forms) the selected model can actually run.
@@ -1194,9 +1207,9 @@ export declare class Client {
1194
1207
  * dropped connections on idempotent methods; connect failures on every method. A
1195
1208
  * retry whose wait is over the cap, or does not fit the deadline, is not made: the
1196
1209
  * call fails with the error of the response it has. So does a retry the deadline
1197
- * leaves no time to send, and the retry of an idempotent method or `getImage` that
1198
- * the deadline cuts short. Any other retry cut short stays a status-0 deadline error:
1199
- * a write may have been applied.
1210
+ * leaves no time to send, and the retry of an idempotent method or of a POST that
1211
+ * only reads that the deadline cuts short. Any other retry cut short stays a status-0
1212
+ * deadline error: a write may have been applied.
1200
1213
  */
1201
1214
  private send;
1202
1215
  /**
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WME = exports.Client = exports.ServerError = exports.RateLimitError = exports.ConflictError = exports.NotFoundError = exports.PermissionDeniedError = exports.PaymentRequiredError = exports.AuthenticationError = exports.BadRequestError = exports.APIConnectionError = exports.WosError = exports.CONTEXT_LIMIT_MAX = exports.CONTEXT_LIMIT_MIN = exports.SEARCH_LIMIT_MAX = exports.SEARCH_LIMIT_MIN = void 0;
4
4
  exports._resetStoreIdWarnings = _resetStoreIdWarnings;
5
5
  exports._resetFilterWarnings = _resetFilterWarnings;
6
- const VERSION = "2.2.41";
6
+ const VERSION = "2.2.43";
7
7
  const RUNTIME = (() => {
8
8
  const p = globalThis?.process;
9
9
  return p?.version ? ` (node/${p.version}; ${p.platform}-${p.arch})` : "";
@@ -22,6 +22,20 @@ const MAX_RETRY_WAIT_MS = 30_000;
22
22
  const MAX_TIMER_MS = 2_147_483_647;
23
23
  const RETRY_IF_IDEMPOTENT = new Set([408, 502, 503, 504]);
24
24
  const IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
25
+ const READ_POSTS = new Set([
26
+ "/api/v1/memory/search",
27
+ "/api/v1/memory/recall",
28
+ "/api/v1/memory/get",
29
+ "/api/v1/memory/list",
30
+ "/api/v1/memory/stats",
31
+ "/api/v1/memory/history",
32
+ "/api/v1/memory/lineage",
33
+ "/api/v1/memory/by-speaker",
34
+ "/api/v1/memory/images",
35
+ "/api/v1/memory/image",
36
+ "/api/v1/engram/run",
37
+ "/api/v1/won/revisions",
38
+ ]);
25
39
  const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "::1", "0.0.0.0"]);
26
40
  const MAX_RESPONSE_BYTES = 64 * 1024 * 1024;
27
41
  const MODEL_RE = /^[A-Za-z0-9._-]+$/;
@@ -1099,8 +1113,9 @@ class Client {
1099
1113
  };
1100
1114
  const cutShort = () => {
1101
1115
  const why = att.why();
1102
- if (why === "deadline" && (idempotent || reads) && previous)
1116
+ if (why === "deadline" && (idempotent || reads || (upper === "POST" && READ_POSTS.has(logPath))) && previous) {
1103
1117
  return previous;
1118
+ }
1104
1119
  return new APIConnectionError(0, this.abortMessage(why));
1105
1120
  };
1106
1121
  let res;
@@ -15,11 +15,10 @@
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. `listModels()` reports each model's `memory` as `"shared"` or
19
- * `"isolated"`, and an isolated one starts empty. Every model on the shared pool
20
- * lists, fetches and deletes the same memories, but a search may not find memories
21
- * stored through a different model; store and search with the same one. Set a
22
- * default in the constructor, or override a single call with
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
23
22
  * `mem.withModel("tablet-1").recall(...)`.
24
23
  *
25
24
  * Recall quality does not depend on which language a memory was written in: a
@@ -157,13 +156,16 @@ export interface Memory {
157
156
  speaker?: string;
158
157
  [key: string]: unknown;
159
158
  }
160
- /** `add` / `store` → `{ id, status }` (`status: "stored" | "stored (async)" | "duplicate"`). */
159
+ /** `add` / `store` → `{ id, status }`. `status` starts with `"stored"` (more text can
160
+ * follow) or is `"duplicate"`; match on the prefix. */
161
161
  export interface StoreResult {
162
162
  id?: string;
163
- /** `"stored"`, or `"duplicate"` when nothing was saved. */
163
+ /** Starts with `"stored"`, or is `"duplicate"` when nothing was saved. */
164
164
  status?: string;
165
165
  /**
166
- * Present when `status` is `"duplicate"`: the id of the memory this write collided with.
166
+ * On a duplicate, the id of the memory this write collided with, when the reply has
167
+ * it. A duplicate can arrive with an empty `id` and no `duplicate_of`; then search with
168
+ * the same text to find the memory it matched.
167
169
  *
168
170
  * A genuinely new fact that only varies a detail of one already stored ("no meetings
169
171
  * before 10am" next to "no meetings on Fridays") can land here too, so a duplicate is
@@ -325,6 +327,8 @@ export interface SpeakerPage {
325
327
  memories: Memory[];
326
328
  chunks?: number;
327
329
  /** The count to show before anyone confirms a delete of this speaker's memories. */
330
+ records_to_delete?: number;
331
+ /** @deprecated The same number as `records_to_delete`, under its old name. */
328
332
  points_to_delete?: number;
329
333
  returned?: number;
330
334
  has_more?: boolean;
@@ -382,10 +386,16 @@ export interface EngramResult {
382
386
  usage?: Usage;
383
387
  [key: string]: unknown;
384
388
  }
389
+ /** One turn of the short-term window, as `history()` returns it. */
385
390
  export interface HistoryTurn {
391
+ /** `"user"` or `"assistant"`. */
392
+ role?: string;
393
+ content?: string;
394
+ timestamp?: string;
395
+ /** @deprecated Not sent: a turn comes back as `role` and `content`. */
386
396
  user_msg?: string;
397
+ /** @deprecated Not sent: a turn comes back as `role` and `content`. */
387
398
  assistant_msg?: string;
388
- timestamp?: string;
389
399
  [key: string]: unknown;
390
400
  }
391
401
  /** `usage` → what this key has spent, and what is left to spend. */
@@ -405,7 +415,7 @@ export interface UsageResult {
405
415
  requests?: number;
406
416
  cost_cents?: number;
407
417
  };
408
- /** Per-store spend over the window, busiest first, and at most 50 rows — a longer
418
+ /** Per-store spend over the window, highest spend first, and at most 50 rows — a longer
409
419
  * list is cut, so these need not sum to `workspace`. `other`, when present, is an
410
420
  * overflow bucket rather than a store. */
411
421
  stores?: {
@@ -461,12 +471,14 @@ export interface ModelInfo {
461
471
  id: string;
462
472
  name: string;
463
473
  available: boolean;
464
- /** "shared" — lists, fetches and deletes the common memory pool, though a search
465
- * may not find memories stored through a different model; "isolated" — its own
466
- * dedicated store. */
474
+ /** "shared" — reads the common memory pool; "isolated" — its own dedicated store. */
467
475
  memory: "shared" | "isolated";
468
476
  /** What this model can do. Check it before relying on a feature. */
469
477
  capabilities?: ModelCapabilities;
478
+ /** Present on a live model that is scheduled to retire (RFC3339). From that instant
479
+ * the model leaves this list and calls naming it are refused. */
480
+ retires_at?: string;
481
+ [key: string]: unknown;
470
482
  }
471
483
  /** One entry of the engram / delivery-form catalogue (`listEngrams`). */
472
484
  export interface EngramInfo {
@@ -934,9 +946,9 @@ export declare class Client {
934
946
  get(userId: string | undefined, memoryId: string): Promise<Memory>;
935
947
  /** List a store's stored memories — the text you stored, plus its metadata.
936
948
  * Paginated: pass the returned `next_cursor` back as `cursor` for the next
937
- * page, and only a cursor the service returned. A `null` cursor means there is no
938
- * next page; a non-null one can still be followed by an empty page. Use it to
939
- * browse or export a store.
949
+ * page, and only a cursor the service returned, with the model that returned it. A
950
+ * `null` cursor means there is no next page; a non-null one can still be followed by
951
+ * an empty page. Use it to browse or export a store.
940
952
  *
941
953
  * `limit` is 1-500 (default 100); anything else is refused before the request.
942
954
  *
@@ -1096,8 +1108,8 @@ export declare class Client {
1096
1108
  * assistant's own words, otherwise a person's name. Same cursor paging as
1097
1109
  * `listImages`; `limit` is 5-20.
1098
1110
  *
1099
- * `points_to_delete` is the count to show before anyone confirms a delete of this
1100
- * speaker's memories.
1111
+ * `records_to_delete` is the count to show before anyone confirms a delete of this
1112
+ * speaker's memories; `points_to_delete` is the same number under its old name.
1101
1113
  */
1102
1114
  bySpeaker(speaker: string, userId?: string, opts?: {
1103
1115
  limit?: number;
@@ -1108,7 +1120,8 @@ export declare class Client {
1108
1120
  * `AuthenticationError` (bad key), `PaymentRequiredError` (valid key but no card /
1109
1121
  * depleted balance), or `APIConnectionError` (unreachable). Makes one metered request. */
1110
1122
  ping(): Promise<boolean>;
1111
- /** Available models: `[{ id, name, available, memory }, ...]`. Needs no API key. */
1123
+ /** Available models: `[{ id, name, available, memory, capabilities, retires_at? }, ...]`.
1124
+ * Needs no API key. */
1112
1125
  listModels(): Promise<ModelInfo[]>;
1113
1126
  /**
1114
1127
  * The engrams (and delivery forms) the selected model can actually run.
@@ -1194,9 +1207,9 @@ export declare class Client {
1194
1207
  * dropped connections on idempotent methods; connect failures on every method. A
1195
1208
  * retry whose wait is over the cap, or does not fit the deadline, is not made: the
1196
1209
  * call fails with the error of the response it has. So does a retry the deadline
1197
- * leaves no time to send, and the retry of an idempotent method or `getImage` that
1198
- * the deadline cuts short. Any other retry cut short stays a status-0 deadline error:
1199
- * a write may have been applied.
1210
+ * leaves no time to send, and the retry of an idempotent method or of a POST that
1211
+ * only reads that the deadline cuts short. Any other retry cut short stays a status-0
1212
+ * deadline error: a write may have been applied.
1200
1213
  */
1201
1214
  private send;
1202
1215
  /**
package/dist/wontopos.js CHANGED
@@ -1,4 +1,4 @@
1
- const VERSION = "2.2.41";
1
+ const VERSION = "2.2.43";
2
2
  const RUNTIME = (() => {
3
3
  const p = globalThis?.process;
4
4
  return p?.version ? ` (node/${p.version}; ${p.platform}-${p.arch})` : "";
@@ -17,6 +17,20 @@ const MAX_RETRY_WAIT_MS = 30_000;
17
17
  const MAX_TIMER_MS = 2_147_483_647;
18
18
  const RETRY_IF_IDEMPOTENT = new Set([408, 502, 503, 504]);
19
19
  const IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
20
+ const READ_POSTS = new Set([
21
+ "/api/v1/memory/search",
22
+ "/api/v1/memory/recall",
23
+ "/api/v1/memory/get",
24
+ "/api/v1/memory/list",
25
+ "/api/v1/memory/stats",
26
+ "/api/v1/memory/history",
27
+ "/api/v1/memory/lineage",
28
+ "/api/v1/memory/by-speaker",
29
+ "/api/v1/memory/images",
30
+ "/api/v1/memory/image",
31
+ "/api/v1/engram/run",
32
+ "/api/v1/won/revisions",
33
+ ]);
20
34
  const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "::1", "0.0.0.0"]);
21
35
  const MAX_RESPONSE_BYTES = 64 * 1024 * 1024;
22
36
  const MODEL_RE = /^[A-Za-z0-9._-]+$/;
@@ -1084,8 +1098,9 @@ export class Client {
1084
1098
  };
1085
1099
  const cutShort = () => {
1086
1100
  const why = att.why();
1087
- if (why === "deadline" && (idempotent || reads) && previous)
1101
+ if (why === "deadline" && (idempotent || reads || (upper === "POST" && READ_POSTS.has(logPath))) && previous) {
1088
1102
  return previous;
1103
+ }
1089
1104
  return new APIConnectionError(0, this.abortMessage(why));
1090
1105
  };
1091
1106
  let res;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wontopos",
3
- "version": "2.2.41",
3
+ "version": "2.2.43",
4
4
  "description": "Wontopos \u2014 long-term memory for AI agents. Identical recall in every language, ~100\u00d7 lower LLM bill.",
5
5
  "keywords": [
6
6
  "memory",