@memfork/cli 0.1.32 → 0.1.33
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/commands/ui-server.js +39 -13
- package/package.json +1 -1
|
@@ -58,18 +58,39 @@ async function handleApiConfig(res) {
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
61
|
-
*
|
|
61
|
+
* Per-namespace cache + global rate-limit backoff. The relayer caps usage at
|
|
62
|
+
* 500 weighted-requests/hour, so we must avoid redundant calls:
|
|
62
63
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
* • Cache each namespace's recall result for CACHE_TTL_MS — the /api/facts
|
|
65
|
+
* and /api/history endpoints both recall the same namespace, and the UI
|
|
66
|
+
* polls on a timer, so most requests are served from cache for free.
|
|
67
|
+
* • On a 429, parse retry_after_seconds and refuse ALL relayer calls until
|
|
68
|
+
* it elapses, serving stale cache instead. This stops the polling loop
|
|
69
|
+
* from continually re-arming the ban.
|
|
70
|
+
*/
|
|
71
|
+
const CACHE_TTL_MS = 60_000;
|
|
72
|
+
const recallCache = new Map();
|
|
73
|
+
let rateLimitedUntil = 0;
|
|
74
|
+
function parseRetryAfterMs(err) {
|
|
75
|
+
const m = err.match(/retry_after_seconds"?\s*:\s*(\d+)/);
|
|
76
|
+
const secs = m ? Number(m[1]) : 300;
|
|
77
|
+
return secs * 1_000;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Recall entries from a MemWal namespace using the SDK (signed requests),
|
|
81
|
+
* with caching and 429 backoff. A single broad query at a high limit returns
|
|
82
|
+
* the whole namespace, since recall returns the top-`limit` nearest entries
|
|
83
|
+
* and namespaces typically hold fewer than `limit` commits.
|
|
71
84
|
*/
|
|
72
85
|
async function memwalRecall(relayer, key, accountId, namespace, limit = 200) {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
const cached = recallCache.get(namespace);
|
|
88
|
+
// Fresh cache hit — no relayer call needed.
|
|
89
|
+
if (cached && now - cached.ts < CACHE_TTL_MS)
|
|
90
|
+
return cached.data;
|
|
91
|
+
// In a rate-limit backoff window — serve stale cache (or empty), don't call.
|
|
92
|
+
if (now < rateLimitedUntil)
|
|
93
|
+
return cached?.data ?? [];
|
|
73
94
|
const mw = MemWal.create({ key, accountId, serverUrl: relayer, namespace });
|
|
74
95
|
const seen = new Set();
|
|
75
96
|
const out = [];
|
|
@@ -85,14 +106,19 @@ async function memwalRecall(relayer, key, accountId, namespace, limit = 200) {
|
|
|
85
106
|
out.push({ blob_id: blobId, text: String(r.text ?? ""), distance: r.distance });
|
|
86
107
|
}
|
|
87
108
|
}
|
|
109
|
+
recallCache.set(namespace, { ts: now, data: out });
|
|
110
|
+
return out;
|
|
88
111
|
}
|
|
89
112
|
catch (e) {
|
|
90
|
-
|
|
91
|
-
if (
|
|
92
|
-
|
|
113
|
+
const msg = String(e);
|
|
114
|
+
if (msg.includes("429")) {
|
|
115
|
+
const backoff = parseRetryAfterMs(msg);
|
|
116
|
+
rateLimitedUntil = Date.now() + backoff;
|
|
117
|
+
console.warn(`[memforks] MemWal rate limit hit — pausing relayer calls for ${Math.round(backoff / 1000)}s, serving cached data.`);
|
|
93
118
|
}
|
|
119
|
+
// Serve stale cache if we have it; otherwise empty.
|
|
120
|
+
return cached?.data ?? [];
|
|
94
121
|
}
|
|
95
|
-
return out;
|
|
96
122
|
}
|
|
97
123
|
async function handleApiFacts(res, url) {
|
|
98
124
|
const branch = url.searchParams.get("branch") ?? "main";
|