@prom.codes/memory-mcp 0.9.1 → 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 +190 -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
|
});
|
|
@@ -2107,9 +2262,25 @@ function discoverMemoryEmbedder(env) {
|
|
|
2107
2262
|
return { id: "none", embedder: void 0 };
|
|
2108
2263
|
}
|
|
2109
2264
|
function discoverMemoryReranker(env) {
|
|
2110
|
-
const
|
|
2111
|
-
|
|
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")
|
|
2112
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
|
+
}
|
|
2113
2284
|
if (forced === "voyage") {
|
|
2114
2285
|
const apiKey = env.VOYAGE_API_KEY;
|
|
2115
2286
|
if (apiKey === void 0 || apiKey === "") {
|
|
@@ -2146,7 +2317,7 @@ function discoverMemoryReranker(env) {
|
|
|
2146
2317
|
});
|
|
2147
2318
|
return { id: "bge", provider };
|
|
2148
2319
|
}
|
|
2149
|
-
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")`);
|
|
2150
2321
|
}
|
|
2151
2322
|
function discoverMemoryExtractor(env) {
|
|
2152
2323
|
const forced = (env.PROMETHEUS_MEMORY_EXTRACT_PROVIDER ?? "none").toLowerCase();
|