wontopos-mcp 1.0.19 → 1.0.20
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 +9 -0
- package/index.mjs +24 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -224,6 +224,15 @@ advertise different limits.
|
|
|
224
224
|
|
|
225
225
|
## Changelog
|
|
226
226
|
|
|
227
|
+
- **1.0.20** - a trimmed reply no longer misreports its own size. When a result is
|
|
228
|
+
larger than the 128KB cap the server cuts the arrays inside it, and the sibling
|
|
229
|
+
`count` field kept the number from before the cut: a model was handed 100 memories
|
|
230
|
+
beside `"count": 200` and reasonably read that as JSON truncated mid-structure. The
|
|
231
|
+
count now says what is actually there. The advice that follows it - "ask for this
|
|
232
|
+
page again with limit=N" - took N from the longest array anywhere in the reply, so
|
|
233
|
+
it could name a nested list that had nothing to do with the page; it reads the page's
|
|
234
|
+
own list now. Underneath, the `wontopos` SDK pin moves to **2.2.38**.
|
|
235
|
+
|
|
227
236
|
- **1.0.19** - out of beta, and the release that made `recall` keep the other half of
|
|
228
237
|
its promise. It opens by offering "recent turns", and nothing in this server could
|
|
229
238
|
ever write one: turns go through their own API route, every tool here wrote
|
package/index.mjs
CHANGED
|
@@ -214,22 +214,33 @@ const RECALL_TURNS = 20;
|
|
|
214
214
|
|
|
215
215
|
function droppableLists(root) {
|
|
216
216
|
const out = [];
|
|
217
|
-
const stack = [["", root]];
|
|
217
|
+
const stack = [["", root, null]];
|
|
218
218
|
let budget = 20000;
|
|
219
219
|
while (stack.length && budget-- > 0) {
|
|
220
|
-
const [name, node] = stack.pop();
|
|
220
|
+
const [name, node, owner] = stack.pop();
|
|
221
221
|
if (Array.isArray(node)) {
|
|
222
|
-
|
|
223
|
-
|
|
222
|
+
// `owner` is the object holding this array, so a sibling `count` can be corrected
|
|
223
|
+
// when the array is cut. Without it the trimmer handed a model 100 memories beside
|
|
224
|
+
// "count": 200 — and the schemas call that field authoritative, so the model reads
|
|
225
|
+
// the JSON as truncated mid-structure and either retries or reports the store wrong.
|
|
226
|
+
if (node.length > 1 && node.some((e) => e && typeof e === "object")) out.push([name || "items", node, owner]);
|
|
227
|
+
for (const v of node) if (v && typeof v === "object") stack.push([name, v, null]);
|
|
224
228
|
continue;
|
|
225
229
|
}
|
|
226
230
|
for (const [k, v] of Object.entries(node)) {
|
|
227
|
-
if (v && typeof v === "object") stack.push([Array.isArray(v) ? k : name, v]);
|
|
231
|
+
if (v && typeof v === "object") stack.push([Array.isArray(v) ? k : name, v, Array.isArray(v) ? node : null]);
|
|
228
232
|
}
|
|
229
233
|
}
|
|
230
234
|
return out;
|
|
231
235
|
}
|
|
232
236
|
|
|
237
|
+
/** After an array is cut, make its sibling `count` say what is actually there. Only the
|
|
238
|
+
* field literally named `count`, and only when it already matched the old length —
|
|
239
|
+
* `total_found` and friends mean something else and are left alone. */
|
|
240
|
+
function syncCount(owner, arr, before) {
|
|
241
|
+
if (owner && typeof owner.count === "number" && owner.count === before) owner.count = arr.length;
|
|
242
|
+
}
|
|
243
|
+
|
|
233
244
|
function truncationKey(obj) {
|
|
234
245
|
let k = "_truncated";
|
|
235
246
|
while (Object.prototype.hasOwnProperty.call(obj, k)) k = `_${k}`;
|
|
@@ -285,12 +296,14 @@ function fitToCap(result) {
|
|
|
285
296
|
let guard = 64;
|
|
286
297
|
while (byteLen(text) > MAX_RESULT_BYTES && guard-- > 0) {
|
|
287
298
|
let cutAny = false;
|
|
288
|
-
for (const [name, arr] of lists) {
|
|
299
|
+
for (const [name, arr, owner] of lists) {
|
|
289
300
|
if (arr.length <= 1) continue;
|
|
301
|
+
const before = arr.length;
|
|
290
302
|
const keep = Math.max(1, Math.floor(arr.length / 2));
|
|
291
303
|
dropped[name || "items"] = (dropped[name || "items"] ?? 0) + (arr.length - keep);
|
|
292
304
|
if (KEEP_TAIL.has(name)) arr.splice(0, arr.length - keep);
|
|
293
305
|
else arr.length = keep;
|
|
306
|
+
syncCount(owner, arr, before);
|
|
294
307
|
cutAny = true;
|
|
295
308
|
}
|
|
296
309
|
if (!cutAny) break;
|
|
@@ -300,7 +313,11 @@ function fitToCap(result) {
|
|
|
300
313
|
const paged = ["next_cursor", "next_before", "next_skip_ids"].some(
|
|
301
314
|
(k) => !Array.isArray(clone) && clone[k] != null
|
|
302
315
|
);
|
|
303
|
-
|
|
316
|
+
// The page's own list, not the longest array anywhere in the reply: `kept` used
|
|
317
|
+
// to be a Math.max over every list, so the advice could name the length of a
|
|
318
|
+
// nested array and send the model back for a page that overflows again.
|
|
319
|
+
const pageList = lists.find(([name]) => !KEEP_TAIL.has(name) && dropped[name || "items"]);
|
|
320
|
+
const kept = pageList ? pageList[1].length : 0;
|
|
304
321
|
const note =
|
|
305
322
|
`dropped ${Object.entries(dropped).map(([k, n]) => `${n} ${k}`).join(", ")} to fit the ` +
|
|
306
323
|
(paged
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wontopos-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"mcpName": "com.wontopos/mcp",
|
|
5
5
|
"description": "Wontopos (WOS) long-term memory as an MCP server — one memory across Claude Code, Claude Desktop, Cursor, ChatGPT, and your own agents.",
|
|
6
6
|
"keywords": [
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
37
|
-
"wontopos": "2.2.
|
|
37
|
+
"wontopos": "2.2.38",
|
|
38
38
|
"zod": "^3.23.0"
|
|
39
39
|
},
|
|
40
40
|
"overrides": {
|