wontopos 2.2.20 → 2.2.22
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/dist/wontopos.d.ts +0 -2
- package/dist/wontopos.js +36 -8
- package/package.json +1 -1
package/dist/wontopos.d.ts
CHANGED
|
@@ -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;
|
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.
|
|
40
|
+
const VERSION = "2.2.22";
|
|
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). */
|
|
@@ -129,8 +129,35 @@ function parseRateLimit(h) {
|
|
|
129
129
|
// that isn't actually an array/object to the empty value.
|
|
130
130
|
const asList = (x) => (Array.isArray(x) ? x : []);
|
|
131
131
|
const asObj = (x) => (x != null && typeof x === "object" && !Array.isArray(x) ? x : {});
|
|
132
|
+
// A list of API records (memories, turns, models...) — every element is an object
|
|
133
|
+
// by contract. `asList` only fixes the CONTAINER: a hostile/broken server sending
|
|
134
|
+
// `{"memories": [null, 1, "x", {...}]}` still handed the caller those non-objects,
|
|
135
|
+
// typed as Memory[], and the first `m.content` threw a raw TypeError from inside
|
|
136
|
+
// user code. Drop elements that aren't objects and keep the valid records, so one
|
|
137
|
+
// bad element never poisons the batch (and never destroys it).
|
|
138
|
+
const asRecords = (x) => asList(x).filter((m) => m != null && typeof m === "object" && !Array.isArray(m));
|
|
132
139
|
// Attach a delivery-form override (memoir/archive) + tz to a body, the way search
|
|
133
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
|
+
}
|
|
134
161
|
function withForm(body, form, tz) {
|
|
135
162
|
if (form !== undefined)
|
|
136
163
|
body.form = form;
|
|
@@ -188,7 +215,8 @@ const STATUS_ERRORS = {
|
|
|
188
215
|
429: RateLimitError,
|
|
189
216
|
};
|
|
190
217
|
/** Build the most specific WosError subclass for an HTTP status. */
|
|
191
|
-
|
|
218
|
+
// Internal factory — the typed error CLASSES are the public surface.
|
|
219
|
+
function errorFor(status, message, requestId) {
|
|
192
220
|
const Cls = status === 0
|
|
193
221
|
? APIConnectionError
|
|
194
222
|
: STATUS_ERRORS[status] ?? (status >= 500 && status < 600 ? ServerError : WosError);
|
|
@@ -343,7 +371,7 @@ export class Client {
|
|
|
343
371
|
// Reserved fields win over ...opts: an app that forwards untrusted input as
|
|
344
372
|
// opts must not be able to override the store (user_id), query, or limit.
|
|
345
373
|
const r = await this.post("/api/v1/memory/search", { ...opts, user_id: this.uid(userId), query, max_results: limit });
|
|
346
|
-
return
|
|
374
|
+
return mergeLanes(r);
|
|
347
375
|
}
|
|
348
376
|
/** Search a self-memory model (Scroll 1.2+): both lanes from ONE call. Returns
|
|
349
377
|
* `{ memories, self_memories }` — `memories` is the main lane (what others said /
|
|
@@ -352,7 +380,7 @@ export class Client {
|
|
|
352
380
|
* without a self lane, `self_memories` is `[]`. `userId` optional (default store). */
|
|
353
381
|
async searchSelf(query, userId, limit = 10, opts = {}) {
|
|
354
382
|
const r = await this.post("/api/v1/memory/search", { ...opts, user_id: this.uid(userId), query, max_results: limit });
|
|
355
|
-
return { memories:
|
|
383
|
+
return { memories: asRecords(r.memories), self_memories: asRecords(r.self_memories) };
|
|
356
384
|
}
|
|
357
385
|
/** One-call LLM context: short-term turns + long-term matches + surrounding context.
|
|
358
386
|
* `form` ("memoir"/"archive", Scroll 1.2+) renders each long-term memory's time in
|
|
@@ -368,7 +396,7 @@ export class Client {
|
|
|
368
396
|
/** Recent conversation turns (short-term memory). */
|
|
369
397
|
async history(userId) {
|
|
370
398
|
const r = await this.post("/api/v1/memory/history", { user_id: this.uid(userId) });
|
|
371
|
-
return
|
|
399
|
+
return asRecords(r.turns);
|
|
372
400
|
}
|
|
373
401
|
/** Memory counts for a store: { total_memories, short_term_turns }. */
|
|
374
402
|
stats(userId) {
|
|
@@ -416,7 +444,7 @@ export class Client {
|
|
|
416
444
|
// server that mints a FRESH cursor every page forever — bound the walk.
|
|
417
445
|
for (let page = 0; page < MAX_PAGES; page++) {
|
|
418
446
|
const p = await this.listMemories(userId, { limit: opts.pageSize ?? 100, cursor });
|
|
419
|
-
for (const m of
|
|
447
|
+
for (const m of asRecords(p.memories))
|
|
420
448
|
yield m;
|
|
421
449
|
const next = p.next_cursor ?? undefined;
|
|
422
450
|
if (!next || seen.has(next))
|
|
@@ -443,7 +471,7 @@ export class Client {
|
|
|
443
471
|
/** Available models: `[{ id, name, available, memory }, ...]`. Needs no API key. */
|
|
444
472
|
async listModels() {
|
|
445
473
|
const data = await this.request("GET", "/api/v1/models");
|
|
446
|
-
return
|
|
474
|
+
return asRecords(data.models);
|
|
447
475
|
}
|
|
448
476
|
// ----- stores -----
|
|
449
477
|
/** Create a store — the `userId` you read and write under. Stores are explicit:
|
|
@@ -456,7 +484,7 @@ export class Client {
|
|
|
456
484
|
/** List your stores: `[{ user_id, created_at }, ...]` (`default` first). */
|
|
457
485
|
async listStores() {
|
|
458
486
|
const r = await this.request("GET", "/api/v1/memory/collections");
|
|
459
|
-
return
|
|
487
|
+
return asRecords(r.collections);
|
|
460
488
|
}
|
|
461
489
|
/** Delete a store and ALL its memories. Returns `{ user_id, status }`. */
|
|
462
490
|
deleteStore(userId) {
|
package/package.json
CHANGED