wontopos 2.2.43 → 2.2.45

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
@@ -5,7 +5,7 @@ npm install wontopos
5
5
  ```
6
6
 
7
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.
8
+ `Client.fromEnv()` reads `WONTOPOS_API_KEY` from the environment instead.
9
9
 
10
10
  ```ts
11
11
  import { Client } from "wontopos";
@@ -35,10 +35,10 @@ Where the store id goes depends on whether the method takes a payload. A method
35
35
  writes or searches puts the payload first and the store second — `mem.add("...", "alice")`,
36
36
  `mem.search("...", "alice")`. A method that only addresses a store takes it first —
37
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.
38
+ Most of them let you leave it out for the client's default store. Five take it
39
+ positionally and cannot — `get`, `getImage`, `delete`, `lineage` and `forgetImage` want
40
+ an explicit `undefined` there, because a second required argument follows it. Python
41
+ omits it in all five; this is the one place the three clients differ in shape rather than meaning.
42
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.
43
43
 
44
44
  ## Who said it (speakers)
@@ -112,6 +112,7 @@ This one needs `npm i undici` — Node's global `fetch` is built on undici, but
112
112
  package itself is not installed for you.
113
113
 
114
114
  ```ts
115
+ import { Client } from "wontopos";
115
116
  import { ProxyAgent } from "undici";
116
117
 
117
118
  const agent = new ProxyAgent(process.env.HTTPS_PROXY!);
@@ -147,7 +148,7 @@ Every method returns a documented shape — `StoreResult`, `UpdateResult`,
147
148
  `RecallResult`, `EngramResult`, `StatsResult`, `SpeakersList`, `Memory[]`, ... —
148
149
  each with an index signature, so new server fields flow through without an SDK
149
150
  update. `search` options are typed too (`SearchOptions`: `cache_control`,
150
- `speaker`, plus pass-through).
151
+ `speaker`, plus `extra` for pass-through).
151
152
 
152
153
  ```ts
153
154
  import { type Memory } from "wontopos";
@@ -180,6 +181,10 @@ try {
180
181
  }
181
182
  ```
182
183
 
184
+ A retired model answers `410`, thrown as `GoneError`: retrying cannot succeed, so name a
185
+ live model (`listModels()` lists them, with `retires_at` on one that is scheduled to
186
+ retire). `deleteStore` still works under a retired model.
187
+
183
188
  ## A different API host
184
189
 
185
190
  Point the client somewhere other than the default endpoint - a dedicated region,
@@ -202,14 +207,14 @@ Found something wrong, or something that looks unsafe? Tell us — every report
202
207
  - Security: <https://wontopos.com/contact?topic=security> (also published at
203
208
  [`/.well-known/security.txt`](https://wontopos.com/.well-known/security.txt))
204
209
 
205
- Include the SDK version (`the version in package.json`) and the language. If it involves a store id or a
210
+ Include the SDK version (the one in package.json) and the language. If it involves a store id or a
206
211
  memory, describe the shape rather than pasting the contents — we do not need your
207
212
  data to fix it.
208
213
 
209
214
  ## Changelog
210
215
 
211
216
  The three clients release in lockstep — same version, same surface, same day. Patch
212
- releases are additive. Eight inside 2.2 were not, deliberately and each with its
217
+ releases are additive. Nine inside 2.2 were not, deliberately and each with its
213
218
  reason; the changelog lists them.
214
219
 
215
220
  See [CHANGELOG.md](https://github.com/wontopos/wontopos-node/blob/main/CHANGELOG.md).
@@ -106,6 +106,11 @@ export declare class ConflictError extends WosError {
106
106
  readonly conflictsWith?: string;
107
107
  constructor(status: number, message: string, requestId?: string, init?: WosErrorInit);
108
108
  }
109
+ /** 410 — the model this call named is retired. Retrying cannot succeed: name a live
110
+ * model instead (`listModels()` lists them). `deleteStore` still works under a
111
+ * retired model. */
112
+ export declare class GoneError extends WosError {
113
+ }
109
114
  /** 429 — too many requests. Back off and retry (the client already retries these,
110
115
  * unless `Retry-After` asks for more than 30 seconds). */
111
116
  export declare class RateLimitError extends WosError {
@@ -647,9 +652,10 @@ export interface SearchOptions {
647
652
  export interface WriteOptions {
648
653
  idempotencyKey?: string;
649
654
  /**
650
- * An image to store alongside the text. Needs a model that lists `images` in its
651
- * `listModels()` capabilities; any other refuses the write rather than store the
652
- * caption and quietly drop the image.
655
+ * An image to store alongside the text, read by `add` (and `store`) only: `addTurn`,
656
+ * `addBulk` and `update` warn about it and do not send it. Needs a model that lists
657
+ * `images` in its `listModels()` capabilities; any other refuses the write rather than
658
+ * store the caption and quietly drop the image.
653
659
  *
654
660
  * A caption is required: the service refuses empty `content` (400) even with an
655
661
  * image attached.
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
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;
3
+ exports.WME = exports.Client = exports.ServerError = exports.RateLimitError = exports.GoneError = 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.43";
6
+ const VERSION = "2.2.45";
7
7
  const RUNTIME = (() => {
8
8
  const p = globalThis?.process;
9
9
  return p?.version ? ` (node/${p.version}; ${p.platform}-${p.arch})` : "";
@@ -456,6 +456,9 @@ class ConflictError extends WosError {
456
456
  }
457
457
  }
458
458
  exports.ConflictError = ConflictError;
459
+ class GoneError extends WosError {
460
+ }
461
+ exports.GoneError = GoneError;
459
462
  class RateLimitError extends WosError {
460
463
  retryAfter;
461
464
  constructor(status, message, requestId, init) {
@@ -468,6 +471,7 @@ exports.RateLimitError = RateLimitError;
468
471
  class ServerError extends WosError {
469
472
  }
470
473
  exports.ServerError = ServerError;
474
+ const GONE_HINT = "This model is retired; listModels() lists the ones you can use.";
471
475
  const STATUS_ERRORS = {
472
476
  400: BadRequestError,
473
477
  401: AuthenticationError,
@@ -475,6 +479,7 @@ const STATUS_ERRORS = {
475
479
  403: PermissionDeniedError,
476
480
  404: NotFoundError,
477
481
  409: ConflictError,
482
+ 410: GoneError,
478
483
  413: BadRequestError,
479
484
  422: BadRequestError,
480
485
  429: RateLimitError,
@@ -503,7 +508,7 @@ const KNOWN_ENGRAM_KEYS = new Set(["form", "tz"]);
503
508
  function checkSearchOpts(opts) {
504
509
  checkOpts(opts, KNOWN_SEARCH_KEYS, "search");
505
510
  const o = opts;
506
- optRange(o.max_images !== undefined ? o.max_images : o.extra?.max_images, "max_images", 0, MAX_IMAGES_MAX);
511
+ optRange(o.max_images != null ? o.max_images : o.extra?.max_images, "max_images", 0, MAX_IMAGES_MAX);
507
512
  }
508
513
  function checkOpts(opts, known, what) {
509
514
  for (const k of Object.keys(opts)) {
@@ -553,6 +558,17 @@ function warnOnceUnknownKeys(obj, known, warned, message) {
553
558
  console.warn(message(k));
554
559
  }
555
560
  }
561
+ function givenOpts(known) {
562
+ return Object.fromEntries(Object.entries(known).filter(([, v]) => v !== null));
563
+ }
564
+ const ADD_KEYS = new Set(["idempotencyKey", "image"]);
565
+ const WRITE_KEYS = new Set(["idempotencyKey"]);
566
+ const warnedWriteKeys = new Set();
567
+ function writeKey(opts, takesImage = false) {
568
+ warnOnceUnknownKeys(opts, takesImage ? ADD_KEYS : WRITE_KEYS, warnedWriteKeys, (k) => `wontopos: write option ${JSON.stringify(k)} is not sent. ` +
569
+ (takesImage ? "add takes idempotencyKey and image." : "This call takes idempotencyKey only."));
570
+ return opts.idempotencyKey;
571
+ }
556
572
  function warnOnUnknownFilters(filters) {
557
573
  warnOnceUnknownKeys(filters, KNOWN_FILTER_KEYS, warnedFilterKeys, (k) => `wontopos: unknown search filter ${JSON.stringify(k)} — the API drops keys it does not know, ` +
558
574
  `so this filter has NO effect and the search is wider than you think. ` +
@@ -713,22 +729,22 @@ class Client {
713
729
  if (opts.image !== undefined)
714
730
  body.image = normalizeImage(opts.image);
715
731
  warnOnUnknownMetadata(metadata);
716
- return this.post("/api/v1/memory/store", body, opts.idempotencyKey);
732
+ return this.post("/api/v1/memory/store", body, writeKey(opts, true));
717
733
  }
718
734
  async store(content, userId, metadata = {}, opts = {}) {
719
735
  return this.add(content, userId, metadata, opts);
720
736
  }
721
737
  async addTurn(userMsg, assistantMsg, userId, opts = {}) {
722
- return this.post("/api/v1/memory/store-turn", { user_id: this.uid(userId), user_msg: userMsg, assistant_msg: assistantMsg }, opts.idempotencyKey);
738
+ return this.post("/api/v1/memory/store-turn", { user_id: this.uid(userId), user_msg: userMsg, assistant_msg: assistantMsg }, writeKey(opts));
723
739
  }
724
740
  async addBulk(content, userId, category = "general", timestamp, opts = {}) {
725
- const body = { user_id: this.uid(userId), content, category };
741
+ const body = { user_id: this.uid(userId), content, category: category ?? "general" };
726
742
  if (timestamp)
727
743
  body.timestamp = timestamp;
728
- return this.post("/api/v1/memory/bulk-store", body, opts.idempotencyKey);
744
+ return this.post("/api/v1/memory/bulk-store", body, writeKey(opts));
729
745
  }
730
746
  async update(oldMemoryId, newContent, userId, opts = {}) {
731
- return this.post("/api/v1/memory/supersede", { user_id: this.uid(userId), old_memory_id: oldMemoryId, new_content: newContent }, opts.idempotencyKey);
747
+ return this.post("/api/v1/memory/supersede", { user_id: this.uid(userId), old_memory_id: oldMemoryId, new_content: newContent }, writeKey(opts));
732
748
  }
733
749
  async search(query, userId, limit = 10, opts = {}) {
734
750
  checkSearchOpts(opts);
@@ -736,7 +752,7 @@ class Client {
736
752
  limit ??= 10;
737
753
  checkCount(limit, "limit");
738
754
  const { extra, ...known } = opts;
739
- const r = await this.post("/api/v1/memory/search", { ...extra, ...known, user_id: this.uid(userId), query, max_results: limit });
755
+ const r = await this.post("/api/v1/memory/search", { ...extra, ...givenOpts(known), user_id: this.uid(userId), query, max_results: limit });
740
756
  return mergeResults(r);
741
757
  }
742
758
  async searchSelf(query, userId, limit = 10, opts = {}) {
@@ -745,7 +761,7 @@ class Client {
745
761
  limit ??= 10;
746
762
  checkCount(limit, "limit");
747
763
  const { extra, ...known } = opts;
748
- const r = await this.post("/api/v1/memory/search", { ...extra, ...known, user_id: this.uid(userId), query, max_results: limit });
764
+ const r = await this.post("/api/v1/memory/search", { ...extra, ...givenOpts(known), user_id: this.uid(userId), query, max_results: limit });
749
765
  return { memories: asRecords(r.memories), self_memories: asRecords(r.self_memories) };
750
766
  }
751
767
  async searchFull(query, userId, limit = 10, opts = {}) {
@@ -754,7 +770,7 @@ class Client {
754
770
  limit ??= 10;
755
771
  checkCount(limit, "limit");
756
772
  const { extra, ...known } = opts;
757
- const r = await this.post("/api/v1/memory/search", { ...extra, ...known, user_id: this.uid(userId), query, max_results: limit });
773
+ const r = await this.post("/api/v1/memory/search", { ...extra, ...givenOpts(known), user_id: this.uid(userId), query, max_results: limit });
758
774
  return {
759
775
  ...r,
760
776
  memories: asRecords(r.memories),
@@ -889,9 +905,13 @@ class Client {
889
905
  throw truncatedWalk(`stopped after ${MAX_PAGES} pages — the store did not end.`);
890
906
  }
891
907
  async revisions(userId, opts = {}) {
908
+ const inc = opts.include;
909
+ if (inc !== undefined && inc !== null && inc !== "revised" && inc !== "unrevised") {
910
+ throw new Error(`include must be "revised" or "unrevised", got ${JSON.stringify(inc)}.`);
911
+ }
892
912
  const limit = optRange(opts.limit, "limit", PAGE_LIMIT_MIN, PAGE_LIMIT_MAX);
893
913
  const body = {};
894
- if (opts.include !== undefined)
914
+ if (opts.include != null)
895
915
  body.include = opts.include;
896
916
  if (limit !== undefined)
897
917
  body.limit = limit;
@@ -1072,6 +1092,8 @@ class Client {
1072
1092
  errorFromAnswer(res, body, retryAfter, mayBeDeleted = false, unread) {
1073
1093
  const e = parseErrorText(new TextDecoder().decode(body));
1074
1094
  let msg = cleanServerText(e.message) || `HTTP ${res.status}`;
1095
+ if (res.status === 410)
1096
+ msg += ` ${GONE_HINT}`;
1075
1097
  if (unread)
1076
1098
  msg += ` (the error body could not be read: ${cleanServerText(unread, 512)})`;
1077
1099
  const requestId = e.requestId === undefined ? undefined : cleanServerText(e.requestId, 256) || undefined;
@@ -106,6 +106,11 @@ export declare class ConflictError extends WosError {
106
106
  readonly conflictsWith?: string;
107
107
  constructor(status: number, message: string, requestId?: string, init?: WosErrorInit);
108
108
  }
109
+ /** 410 — the model this call named is retired. Retrying cannot succeed: name a live
110
+ * model instead (`listModels()` lists them). `deleteStore` still works under a
111
+ * retired model. */
112
+ export declare class GoneError extends WosError {
113
+ }
109
114
  /** 429 — too many requests. Back off and retry (the client already retries these,
110
115
  * unless `Retry-After` asks for more than 30 seconds). */
111
116
  export declare class RateLimitError extends WosError {
@@ -647,9 +652,10 @@ export interface SearchOptions {
647
652
  export interface WriteOptions {
648
653
  idempotencyKey?: string;
649
654
  /**
650
- * An image to store alongside the text. Needs a model that lists `images` in its
651
- * `listModels()` capabilities; any other refuses the write rather than store the
652
- * caption and quietly drop the image.
655
+ * An image to store alongside the text, read by `add` (and `store`) only: `addTurn`,
656
+ * `addBulk` and `update` warn about it and do not send it. Needs a model that lists
657
+ * `images` in its `listModels()` capabilities; any other refuses the write rather than
658
+ * store the caption and quietly drop the image.
653
659
  *
654
660
  * A caption is required: the service refuses empty `content` (400) even with an
655
661
  * image attached.
package/dist/wontopos.js CHANGED
@@ -1,4 +1,4 @@
1
- const VERSION = "2.2.43";
1
+ const VERSION = "2.2.45";
2
2
  const RUNTIME = (() => {
3
3
  const p = globalThis?.process;
4
4
  return p?.version ? ` (node/${p.version}; ${p.platform}-${p.arch})` : "";
@@ -443,6 +443,8 @@ export class ConflictError extends WosError {
443
443
  this.conflictsWith = typeof c === "string" ? c : undefined;
444
444
  }
445
445
  }
446
+ export class GoneError extends WosError {
447
+ }
446
448
  export class RateLimitError extends WosError {
447
449
  retryAfter;
448
450
  constructor(status, message, requestId, init) {
@@ -453,6 +455,7 @@ export class RateLimitError extends WosError {
453
455
  }
454
456
  export class ServerError extends WosError {
455
457
  }
458
+ const GONE_HINT = "This model is retired; listModels() lists the ones you can use.";
456
459
  const STATUS_ERRORS = {
457
460
  400: BadRequestError,
458
461
  401: AuthenticationError,
@@ -460,6 +463,7 @@ const STATUS_ERRORS = {
460
463
  403: PermissionDeniedError,
461
464
  404: NotFoundError,
462
465
  409: ConflictError,
466
+ 410: GoneError,
463
467
  413: BadRequestError,
464
468
  422: BadRequestError,
465
469
  429: RateLimitError,
@@ -488,7 +492,7 @@ const KNOWN_ENGRAM_KEYS = new Set(["form", "tz"]);
488
492
  function checkSearchOpts(opts) {
489
493
  checkOpts(opts, KNOWN_SEARCH_KEYS, "search");
490
494
  const o = opts;
491
- optRange(o.max_images !== undefined ? o.max_images : o.extra?.max_images, "max_images", 0, MAX_IMAGES_MAX);
495
+ optRange(o.max_images != null ? o.max_images : o.extra?.max_images, "max_images", 0, MAX_IMAGES_MAX);
492
496
  }
493
497
  function checkOpts(opts, known, what) {
494
498
  for (const k of Object.keys(opts)) {
@@ -538,6 +542,17 @@ function warnOnceUnknownKeys(obj, known, warned, message) {
538
542
  console.warn(message(k));
539
543
  }
540
544
  }
545
+ function givenOpts(known) {
546
+ return Object.fromEntries(Object.entries(known).filter(([, v]) => v !== null));
547
+ }
548
+ const ADD_KEYS = new Set(["idempotencyKey", "image"]);
549
+ const WRITE_KEYS = new Set(["idempotencyKey"]);
550
+ const warnedWriteKeys = new Set();
551
+ function writeKey(opts, takesImage = false) {
552
+ warnOnceUnknownKeys(opts, takesImage ? ADD_KEYS : WRITE_KEYS, warnedWriteKeys, (k) => `wontopos: write option ${JSON.stringify(k)} is not sent. ` +
553
+ (takesImage ? "add takes idempotencyKey and image." : "This call takes idempotencyKey only."));
554
+ return opts.idempotencyKey;
555
+ }
541
556
  function warnOnUnknownFilters(filters) {
542
557
  warnOnceUnknownKeys(filters, KNOWN_FILTER_KEYS, warnedFilterKeys, (k) => `wontopos: unknown search filter ${JSON.stringify(k)} — the API drops keys it does not know, ` +
543
558
  `so this filter has NO effect and the search is wider than you think. ` +
@@ -698,22 +713,22 @@ export class Client {
698
713
  if (opts.image !== undefined)
699
714
  body.image = normalizeImage(opts.image);
700
715
  warnOnUnknownMetadata(metadata);
701
- return this.post("/api/v1/memory/store", body, opts.idempotencyKey);
716
+ return this.post("/api/v1/memory/store", body, writeKey(opts, true));
702
717
  }
703
718
  async store(content, userId, metadata = {}, opts = {}) {
704
719
  return this.add(content, userId, metadata, opts);
705
720
  }
706
721
  async addTurn(userMsg, assistantMsg, userId, opts = {}) {
707
- return this.post("/api/v1/memory/store-turn", { user_id: this.uid(userId), user_msg: userMsg, assistant_msg: assistantMsg }, opts.idempotencyKey);
722
+ return this.post("/api/v1/memory/store-turn", { user_id: this.uid(userId), user_msg: userMsg, assistant_msg: assistantMsg }, writeKey(opts));
708
723
  }
709
724
  async addBulk(content, userId, category = "general", timestamp, opts = {}) {
710
- const body = { user_id: this.uid(userId), content, category };
725
+ const body = { user_id: this.uid(userId), content, category: category ?? "general" };
711
726
  if (timestamp)
712
727
  body.timestamp = timestamp;
713
- return this.post("/api/v1/memory/bulk-store", body, opts.idempotencyKey);
728
+ return this.post("/api/v1/memory/bulk-store", body, writeKey(opts));
714
729
  }
715
730
  async update(oldMemoryId, newContent, userId, opts = {}) {
716
- return this.post("/api/v1/memory/supersede", { user_id: this.uid(userId), old_memory_id: oldMemoryId, new_content: newContent }, opts.idempotencyKey);
731
+ return this.post("/api/v1/memory/supersede", { user_id: this.uid(userId), old_memory_id: oldMemoryId, new_content: newContent }, writeKey(opts));
717
732
  }
718
733
  async search(query, userId, limit = 10, opts = {}) {
719
734
  checkSearchOpts(opts);
@@ -721,7 +736,7 @@ export class Client {
721
736
  limit ??= 10;
722
737
  checkCount(limit, "limit");
723
738
  const { extra, ...known } = opts;
724
- const r = await this.post("/api/v1/memory/search", { ...extra, ...known, user_id: this.uid(userId), query, max_results: limit });
739
+ const r = await this.post("/api/v1/memory/search", { ...extra, ...givenOpts(known), user_id: this.uid(userId), query, max_results: limit });
725
740
  return mergeResults(r);
726
741
  }
727
742
  async searchSelf(query, userId, limit = 10, opts = {}) {
@@ -730,7 +745,7 @@ export class Client {
730
745
  limit ??= 10;
731
746
  checkCount(limit, "limit");
732
747
  const { extra, ...known } = opts;
733
- const r = await this.post("/api/v1/memory/search", { ...extra, ...known, user_id: this.uid(userId), query, max_results: limit });
748
+ const r = await this.post("/api/v1/memory/search", { ...extra, ...givenOpts(known), user_id: this.uid(userId), query, max_results: limit });
734
749
  return { memories: asRecords(r.memories), self_memories: asRecords(r.self_memories) };
735
750
  }
736
751
  async searchFull(query, userId, limit = 10, opts = {}) {
@@ -739,7 +754,7 @@ export class Client {
739
754
  limit ??= 10;
740
755
  checkCount(limit, "limit");
741
756
  const { extra, ...known } = opts;
742
- const r = await this.post("/api/v1/memory/search", { ...extra, ...known, user_id: this.uid(userId), query, max_results: limit });
757
+ const r = await this.post("/api/v1/memory/search", { ...extra, ...givenOpts(known), user_id: this.uid(userId), query, max_results: limit });
743
758
  return {
744
759
  ...r,
745
760
  memories: asRecords(r.memories),
@@ -874,9 +889,13 @@ export class Client {
874
889
  throw truncatedWalk(`stopped after ${MAX_PAGES} pages — the store did not end.`);
875
890
  }
876
891
  async revisions(userId, opts = {}) {
892
+ const inc = opts.include;
893
+ if (inc !== undefined && inc !== null && inc !== "revised" && inc !== "unrevised") {
894
+ throw new Error(`include must be "revised" or "unrevised", got ${JSON.stringify(inc)}.`);
895
+ }
877
896
  const limit = optRange(opts.limit, "limit", PAGE_LIMIT_MIN, PAGE_LIMIT_MAX);
878
897
  const body = {};
879
- if (opts.include !== undefined)
898
+ if (opts.include != null)
880
899
  body.include = opts.include;
881
900
  if (limit !== undefined)
882
901
  body.limit = limit;
@@ -1057,6 +1076,8 @@ export class Client {
1057
1076
  errorFromAnswer(res, body, retryAfter, mayBeDeleted = false, unread) {
1058
1077
  const e = parseErrorText(new TextDecoder().decode(body));
1059
1078
  let msg = cleanServerText(e.message) || `HTTP ${res.status}`;
1079
+ if (res.status === 410)
1080
+ msg += ` ${GONE_HINT}`;
1060
1081
  if (unread)
1061
1082
  msg += ` (the error body could not be read: ${cleanServerText(unread, 512)})`;
1062
1083
  const requestId = e.requestId === undefined ? undefined : cleanServerText(e.requestId, 256) || undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wontopos",
3
- "version": "2.2.43",
3
+ "version": "2.2.45",
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",