@prom.codes/memory-mcp 0.9.0 → 0.10.0
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/bin.js +195 -19
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -871,11 +871,166 @@ var VoyageRerankProvider = class {
|
|
|
871
871
|
}
|
|
872
872
|
};
|
|
873
873
|
|
|
874
|
-
// ../rerank-
|
|
875
|
-
var
|
|
874
|
+
// ../rerank-prometheus/dist/index.js
|
|
875
|
+
var DEFAULT_BASE2 = "https://api.prom.codes";
|
|
876
|
+
var DEFAULT_NAME = "prometheus";
|
|
877
|
+
var DEFAULT_MODEL2 = "prometheus";
|
|
876
878
|
var DEFAULT_BATCH4 = 100;
|
|
877
|
-
var DEFAULT_RETRIES4 =
|
|
878
|
-
var DEFAULT_BACKOFF4 =
|
|
879
|
+
var DEFAULT_RETRIES4 = 4;
|
|
880
|
+
var DEFAULT_BACKOFF4 = 250;
|
|
881
|
+
function sleep4(ms, signal) {
|
|
882
|
+
return new Promise((resolve3, reject) => {
|
|
883
|
+
if (signal?.aborted === true) {
|
|
884
|
+
reject(new Error("aborted"));
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const timer = setTimeout(() => {
|
|
888
|
+
signal?.removeEventListener("abort", onAbort);
|
|
889
|
+
resolve3();
|
|
890
|
+
}, ms);
|
|
891
|
+
const onAbort = () => {
|
|
892
|
+
clearTimeout(timer);
|
|
893
|
+
reject(new Error("aborted"));
|
|
894
|
+
};
|
|
895
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
function nonRetryable4(message) {
|
|
899
|
+
const err = new Error(message);
|
|
900
|
+
err.nonRetryable = true;
|
|
901
|
+
return err;
|
|
902
|
+
}
|
|
903
|
+
var PrometheusRerankProvider = class {
|
|
904
|
+
name;
|
|
905
|
+
model;
|
|
906
|
+
region;
|
|
907
|
+
#apiKey;
|
|
908
|
+
#url;
|
|
909
|
+
#batchSize;
|
|
910
|
+
#maxRetries;
|
|
911
|
+
#retryBaseMs;
|
|
912
|
+
#fetch;
|
|
913
|
+
#creditsUsed = 0;
|
|
914
|
+
constructor(opts) {
|
|
915
|
+
if (typeof opts.apiKey !== "string" || opts.apiKey === "") {
|
|
916
|
+
throw new Error("PrometheusRerankProvider: apiKey is required");
|
|
917
|
+
}
|
|
918
|
+
if (opts.batchSize !== void 0 && (!Number.isInteger(opts.batchSize) || opts.batchSize <= 0 || opts.batchSize > 1e3)) {
|
|
919
|
+
throw new Error(`PrometheusRerankProvider: batchSize must be an integer in 1..1000, got ${opts.batchSize}`);
|
|
920
|
+
}
|
|
921
|
+
this.name = opts.name ?? DEFAULT_NAME;
|
|
922
|
+
this.model = opts.model ?? DEFAULT_MODEL2;
|
|
923
|
+
this.region = opts.region ?? "eu";
|
|
924
|
+
this.#apiKey = opts.apiKey;
|
|
925
|
+
this.#url = `${(opts.baseUrl ?? DEFAULT_BASE2).replace(/\/+$/, "")}/rerank`;
|
|
926
|
+
this.#batchSize = opts.batchSize ?? DEFAULT_BATCH4;
|
|
927
|
+
this.#maxRetries = opts.maxRetries ?? DEFAULT_RETRIES4;
|
|
928
|
+
this.#retryBaseMs = opts.retryBaseMs ?? DEFAULT_BACKOFF4;
|
|
929
|
+
this.#fetch = opts.fetch ?? fetch;
|
|
930
|
+
}
|
|
931
|
+
/** Cumulative credits charged across all rerank calls of this instance. */
|
|
932
|
+
get creditsUsed() {
|
|
933
|
+
return this.#creditsUsed;
|
|
934
|
+
}
|
|
935
|
+
async rerank(query, candidates, opts) {
|
|
936
|
+
if (candidates.length === 0)
|
|
937
|
+
return [];
|
|
938
|
+
const all = new Array(candidates.length);
|
|
939
|
+
let cursor = 0;
|
|
940
|
+
for (let start = 0; start < candidates.length; start += this.#batchSize) {
|
|
941
|
+
const slice = candidates.slice(start, start + this.#batchSize);
|
|
942
|
+
const scored = await this.#rerankBatch(query, slice, opts?.signal);
|
|
943
|
+
for (const hit of scored) {
|
|
944
|
+
const globalIndex = start + hit.localIndex;
|
|
945
|
+
const cand = candidates[globalIndex];
|
|
946
|
+
all[cursor++] = { id: cand.id, index: globalIndex, score: hit.score };
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
all.sort((a, b) => b.score - a.score);
|
|
950
|
+
if (opts?.topK !== void 0 && opts.topK >= 0 && opts.topK < all.length) {
|
|
951
|
+
return all.slice(0, opts.topK);
|
|
952
|
+
}
|
|
953
|
+
return all;
|
|
954
|
+
}
|
|
955
|
+
async #rerankBatch(query, batch, signal) {
|
|
956
|
+
const init = {
|
|
957
|
+
method: "POST",
|
|
958
|
+
headers: {
|
|
959
|
+
"content-type": "application/json",
|
|
960
|
+
authorization: `Bearer ${this.#apiKey}`
|
|
961
|
+
},
|
|
962
|
+
body: JSON.stringify({ query, documents: batch.map((c) => c.text) })
|
|
963
|
+
};
|
|
964
|
+
if (signal !== void 0)
|
|
965
|
+
init.signal = signal;
|
|
966
|
+
const payload = await this.#requestJson(init, signal);
|
|
967
|
+
if (payload?.ok !== true || !Array.isArray(payload.results)) {
|
|
968
|
+
throw nonRetryable4("prometheus-rerank: malformed rerank response");
|
|
969
|
+
}
|
|
970
|
+
if (payload.results.length !== batch.length) {
|
|
971
|
+
throw nonRetryable4(`prometheus-rerank: expected ${batch.length} rerank rows, got ${payload.results.length}`);
|
|
972
|
+
}
|
|
973
|
+
const credits = payload.usage?.credits;
|
|
974
|
+
if (typeof credits === "number" && Number.isFinite(credits)) {
|
|
975
|
+
this.#creditsUsed += credits;
|
|
976
|
+
}
|
|
977
|
+
return payload.results.map((row) => {
|
|
978
|
+
if (!Number.isInteger(row.index) || row.index < 0 || row.index >= batch.length) {
|
|
979
|
+
throw nonRetryable4(`prometheus-rerank: invalid index ${row.index} in rerank response`);
|
|
980
|
+
}
|
|
981
|
+
if (typeof row.relevanceScore !== "number" || !Number.isFinite(row.relevanceScore)) {
|
|
982
|
+
throw nonRetryable4(`prometheus-rerank: invalid relevanceScore ${row.relevanceScore} at index ${row.index}`);
|
|
983
|
+
}
|
|
984
|
+
return { localIndex: row.index, score: row.relevanceScore };
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Fetch with retry. 5xx and network errors back off exponentially;
|
|
989
|
+
* everything else (401 invalid key, 413 oversized input, 429 monthly
|
|
990
|
+
* quota exhausted) fails fast with the proxy's error code in the
|
|
991
|
+
* message.
|
|
992
|
+
*/
|
|
993
|
+
async #requestJson(init, signal) {
|
|
994
|
+
let attempt = 0;
|
|
995
|
+
let lastError = null;
|
|
996
|
+
while (attempt <= this.#maxRetries) {
|
|
997
|
+
try {
|
|
998
|
+
const res = await this.#fetch(this.#url, init);
|
|
999
|
+
if (res.status >= 500 && res.status < 600) {
|
|
1000
|
+
lastError = new Error(`prometheus-rerank: HTTP ${res.status}`);
|
|
1001
|
+
attempt += 1;
|
|
1002
|
+
if (attempt > this.#maxRetries)
|
|
1003
|
+
break;
|
|
1004
|
+
await sleep4(this.#retryBaseMs * 2 ** (attempt - 1), signal);
|
|
1005
|
+
continue;
|
|
1006
|
+
}
|
|
1007
|
+
if (!res.ok) {
|
|
1008
|
+
const body = await res.json().catch(() => null);
|
|
1009
|
+
const detail = typeof body?.code === "string" ? `${body.code}${typeof body.error === "string" ? ` \u2014 ${body.error}` : ""}` : res.statusText;
|
|
1010
|
+
throw nonRetryable4(`prometheus-rerank: HTTP ${res.status} ${detail}`);
|
|
1011
|
+
}
|
|
1012
|
+
return await res.json();
|
|
1013
|
+
} catch (err) {
|
|
1014
|
+
if (err?.name === "AbortError")
|
|
1015
|
+
throw err;
|
|
1016
|
+
if (err?.nonRetryable === true)
|
|
1017
|
+
throw err;
|
|
1018
|
+
if (attempt >= this.#maxRetries)
|
|
1019
|
+
throw err;
|
|
1020
|
+
lastError = err;
|
|
1021
|
+
attempt += 1;
|
|
1022
|
+
await sleep4(this.#retryBaseMs * 2 ** (attempt - 1), signal);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
throw lastError instanceof Error ? lastError : new Error(`prometheus-rerank: exhausted ${this.#maxRetries} retries`);
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
// ../rerank-openai-compat/dist/index.js
|
|
1030
|
+
var DEFAULT_MODEL3 = "bge-reranker-base";
|
|
1031
|
+
var DEFAULT_BATCH5 = 100;
|
|
1032
|
+
var DEFAULT_RETRIES5 = 6;
|
|
1033
|
+
var DEFAULT_BACKOFF5 = 2e3;
|
|
879
1034
|
var DEFAULT_RETRY_MAX3 = 6e4;
|
|
880
1035
|
var DEFAULT_TIMEOUT = 18e4;
|
|
881
1036
|
function parseRetryAfterMs3(value, now = Date.now()) {
|
|
@@ -898,7 +1053,7 @@ function parseRetryAfterMs3(value, now = Date.now()) {
|
|
|
898
1053
|
const delta = ts - now;
|
|
899
1054
|
return delta > 0 ? delta : 0;
|
|
900
1055
|
}
|
|
901
|
-
function
|
|
1056
|
+
function sleep5(ms, signal) {
|
|
902
1057
|
return new Promise((resolve3, reject) => {
|
|
903
1058
|
if (signal?.aborted === true) {
|
|
904
1059
|
reject(new Error("aborted"));
|
|
@@ -915,7 +1070,7 @@ function sleep4(ms, signal) {
|
|
|
915
1070
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
916
1071
|
});
|
|
917
1072
|
}
|
|
918
|
-
function
|
|
1073
|
+
function nonRetryable5(message) {
|
|
919
1074
|
const err = new Error(message);
|
|
920
1075
|
err.nonRetryable = true;
|
|
921
1076
|
return err;
|
|
@@ -942,14 +1097,14 @@ var OpenAICompatRerankProvider = class {
|
|
|
942
1097
|
if (opts.timeoutMs !== void 0 && (!Number.isInteger(opts.timeoutMs) || opts.timeoutMs < 0)) {
|
|
943
1098
|
throw new Error(`OpenAICompatRerankProvider: timeoutMs must be a non-negative integer (0 disables), got ${opts.timeoutMs}`);
|
|
944
1099
|
}
|
|
945
|
-
this.model = opts.model ??
|
|
1100
|
+
this.model = opts.model ?? DEFAULT_MODEL3;
|
|
946
1101
|
this.name = opts.name ?? `openai-compat:${this.model}`;
|
|
947
1102
|
this.region = opts.region ?? "self-hosted";
|
|
948
1103
|
this.#baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
949
1104
|
this.#apiKey = opts.apiKey === void 0 || opts.apiKey === "" ? void 0 : opts.apiKey;
|
|
950
|
-
this.#batchSize = opts.batchSize ??
|
|
951
|
-
this.#maxRetries = opts.maxRetries ??
|
|
952
|
-
this.#retryBaseMs = opts.retryBaseMs ??
|
|
1105
|
+
this.#batchSize = opts.batchSize ?? DEFAULT_BATCH5;
|
|
1106
|
+
this.#maxRetries = opts.maxRetries ?? DEFAULT_RETRIES5;
|
|
1107
|
+
this.#retryBaseMs = opts.retryBaseMs ?? DEFAULT_BACKOFF5;
|
|
953
1108
|
this.#retryMaxMs = opts.retryMaxMs ?? DEFAULT_RETRY_MAX3;
|
|
954
1109
|
this.#timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT;
|
|
955
1110
|
this.#fetch = opts.fetch ?? fetch;
|
|
@@ -1018,12 +1173,12 @@ var OpenAICompatRerankProvider = class {
|
|
|
1018
1173
|
if (attempt > this.#maxRetries)
|
|
1019
1174
|
break;
|
|
1020
1175
|
const backoff = this.#computeBackoff(attempt, res.headers.get("retry-after"));
|
|
1021
|
-
await
|
|
1176
|
+
await sleep5(backoff, signal);
|
|
1022
1177
|
continue;
|
|
1023
1178
|
}
|
|
1024
1179
|
if (!res.ok) {
|
|
1025
1180
|
const text = await res.text().catch(() => "");
|
|
1026
|
-
throw
|
|
1181
|
+
throw nonRetryable5(`${this.name}: HTTP ${res.status} ${res.statusText}${text === "" ? "" : ` \u2014 ${text}`}`);
|
|
1027
1182
|
}
|
|
1028
1183
|
const payload = await res.json();
|
|
1029
1184
|
return this.#decode(payload, batch.length);
|
|
@@ -1038,7 +1193,7 @@ var OpenAICompatRerankProvider = class {
|
|
|
1038
1193
|
throw normalized;
|
|
1039
1194
|
lastError = normalized;
|
|
1040
1195
|
attempt += 1;
|
|
1041
|
-
await
|
|
1196
|
+
await sleep5(this.#computeBackoff(attempt, null), signal);
|
|
1042
1197
|
} finally {
|
|
1043
1198
|
if (timer !== void 0)
|
|
1044
1199
|
clearTimeout(timer);
|
|
@@ -1056,14 +1211,14 @@ var OpenAICompatRerankProvider = class {
|
|
|
1056
1211
|
}
|
|
1057
1212
|
#decode(payload, expected) {
|
|
1058
1213
|
if (!Array.isArray(payload.results) || payload.results.length !== expected) {
|
|
1059
|
-
throw
|
|
1214
|
+
throw nonRetryable5(`${this.name}: expected ${expected} rerank rows, got ${payload.results?.length ?? 0}`);
|
|
1060
1215
|
}
|
|
1061
1216
|
return payload.results.map((row) => {
|
|
1062
1217
|
if (!Number.isInteger(row.index) || row.index < 0 || row.index >= expected) {
|
|
1063
|
-
throw
|
|
1218
|
+
throw nonRetryable5(`${this.name}: invalid index ${row.index} in rerank response`);
|
|
1064
1219
|
}
|
|
1065
1220
|
if (typeof row.relevance_score !== "number" || !Number.isFinite(row.relevance_score)) {
|
|
1066
|
-
throw
|
|
1221
|
+
throw nonRetryable5(`${this.name}: invalid relevance_score ${row.relevance_score} at index ${row.index}`);
|
|
1067
1222
|
}
|
|
1068
1223
|
return { localIndex: row.index, score: row.relevance_score };
|
|
1069
1224
|
});
|
|
@@ -1599,6 +1754,7 @@ var SqliteMemoryBackend = class {
|
|
|
1599
1754
|
}
|
|
1600
1755
|
this.db = new Database(dbPath);
|
|
1601
1756
|
this.db.pragma("journal_mode = WAL");
|
|
1757
|
+
this.db.pragma("synchronous = NORMAL");
|
|
1602
1758
|
this.db.exec(SCHEMA);
|
|
1603
1759
|
this.db.exec(FTS_SCHEMA);
|
|
1604
1760
|
this.db.exec(VEC_SCHEMA);
|
|
@@ -2033,6 +2189,10 @@ ${h.record.value}`
|
|
|
2033
2189
|
if (this.closed)
|
|
2034
2190
|
return;
|
|
2035
2191
|
this.closed = true;
|
|
2192
|
+
try {
|
|
2193
|
+
this.db.pragma("wal_checkpoint(TRUNCATE)");
|
|
2194
|
+
} catch {
|
|
2195
|
+
}
|
|
2036
2196
|
this.db.close();
|
|
2037
2197
|
}
|
|
2038
2198
|
};
|
|
@@ -2102,9 +2262,25 @@ function discoverMemoryEmbedder(env) {
|
|
|
2102
2262
|
return { id: "none", embedder: void 0 };
|
|
2103
2263
|
}
|
|
2104
2264
|
function discoverMemoryReranker(env) {
|
|
2105
|
-
const
|
|
2106
|
-
|
|
2265
|
+
const explicit = env.PROMETHEUS_MEMORY_RERANK_PROVIDER?.toLowerCase();
|
|
2266
|
+
const hasKey = (env[API_KEY_ENV] ?? "").trim() !== "";
|
|
2267
|
+
const forced = explicit === void 0 || explicit === "" ? hasKey ? "prometheus" : "none" : explicit;
|
|
2268
|
+
if (forced === "none")
|
|
2107
2269
|
return { id: "none", provider: null };
|
|
2270
|
+
if (forced === "prometheus") {
|
|
2271
|
+
const apiKey = requireApiKey(env);
|
|
2272
|
+
const baseUrl = env.PROMETHEUS_API_URL;
|
|
2273
|
+
const provider = new PrometheusRerankProvider({
|
|
2274
|
+
name: "prometheus-rerank",
|
|
2275
|
+
apiKey,
|
|
2276
|
+
region: "eu",
|
|
2277
|
+
...baseUrl !== void 0 && baseUrl !== "" ? { baseUrl } : {},
|
|
2278
|
+
maxRetries: intEnv(env, "PROMETHEUS_MEMORY_RERANK_MAX_RETRIES", 4),
|
|
2279
|
+
retryBaseMs: intEnv(env, "PROMETHEUS_MEMORY_RERANK_RETRY_BASE_MS", 250),
|
|
2280
|
+
batchSize: intEnv(env, "PROMETHEUS_MEMORY_RERANK_BATCH", 100)
|
|
2281
|
+
});
|
|
2282
|
+
return { id: "prometheus", provider };
|
|
2283
|
+
}
|
|
2108
2284
|
if (forced === "voyage") {
|
|
2109
2285
|
const apiKey = env.VOYAGE_API_KEY;
|
|
2110
2286
|
if (apiKey === void 0 || apiKey === "") {
|
|
@@ -2141,7 +2317,7 @@ function discoverMemoryReranker(env) {
|
|
|
2141
2317
|
});
|
|
2142
2318
|
return { id: "bge", provider };
|
|
2143
2319
|
}
|
|
2144
|
-
throw new Error(`unknown PROMETHEUS_MEMORY_RERANK_PROVIDER="${forced}" (expected "none", "voyage", or "bge")`);
|
|
2320
|
+
throw new Error(`unknown PROMETHEUS_MEMORY_RERANK_PROVIDER="${forced}" (expected "none", "prometheus", "voyage", or "bge")`);
|
|
2145
2321
|
}
|
|
2146
2322
|
function discoverMemoryExtractor(env) {
|
|
2147
2323
|
const forced = (env.PROMETHEUS_MEMORY_EXTRACT_PROVIDER ?? "none").toLowerCase();
|