@pyxmate/memory 1.26.3 → 1.26.5
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/cli/pyx-mem.mjs +78 -8
- package/package.json +1 -1
package/dist/cli/pyx-mem.mjs
CHANGED
|
@@ -866,6 +866,19 @@ function mcpJson(payload) {
|
|
|
866
866
|
|
|
867
867
|
// src/mcp/http-client.ts
|
|
868
868
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
869
|
+
function parseRetryAfterSeconds(header) {
|
|
870
|
+
const value = header?.trim() ?? "";
|
|
871
|
+
return /^\d+$/.test(value) ? Number(value) : void 0;
|
|
872
|
+
}
|
|
873
|
+
var HTTP_DATE = /^(?:[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} GMT|[A-Z][a-z]{5,8}, \d{2}-[A-Z][a-z]{2}-\d{2} \d{2}:\d{2}:\d{2} GMT|[A-Z][a-z]{2} [A-Z][a-z]{2} [ \d]\d \d{2}:\d{2}:\d{2} \d{4})$/;
|
|
874
|
+
function parseRetryAfterMs(header) {
|
|
875
|
+
const seconds = parseRetryAfterSeconds(header);
|
|
876
|
+
if (seconds !== void 0) return seconds * 1e3;
|
|
877
|
+
const value = header?.trim() ?? "";
|
|
878
|
+
if (!HTTP_DATE.test(value)) return void 0;
|
|
879
|
+
const at = Date.parse(value.endsWith(" GMT") ? value : `${value} GMT`);
|
|
880
|
+
return Number.isNaN(at) ? void 0 : Math.max(0, at - Date.now());
|
|
881
|
+
}
|
|
869
882
|
function validateIdempotencyKey(key) {
|
|
870
883
|
if (key.length === 0 || !key.isWellFormed() || new TextEncoder().encode(key).byteLength > 256) {
|
|
871
884
|
throw new Error("idempotencyKey must be 1-256 well-formed UTF-8 bytes");
|
|
@@ -2126,6 +2139,7 @@ function createReadCredentials(providerFactory) {
|
|
|
2126
2139
|
import { createHash as createHash5, randomUUID as randomUUID5 } from "crypto";
|
|
2127
2140
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
2128
2141
|
import { basename as basename2, isAbsolute as isAbsolute2, resolve as resolve2 } from "path";
|
|
2142
|
+
import { setTimeout as delay2 } from "timers/promises";
|
|
2129
2143
|
import { Client as McpClient } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2130
2144
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
2131
2145
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -2317,8 +2331,7 @@ async function pause(ms, signal) {
|
|
|
2317
2331
|
});
|
|
2318
2332
|
}
|
|
2319
2333
|
function retryAfterMs(header) {
|
|
2320
|
-
const
|
|
2321
|
-
const seconds = /^\d+$/.test(value) ? Number(value) : DEFAULT_RETRY_AFTER_S;
|
|
2334
|
+
const seconds = parseRetryAfterSeconds(header) ?? DEFAULT_RETRY_AFTER_S;
|
|
2322
2335
|
return Math.min(seconds, MAX_RETRY_AFTER_S) * 1e3;
|
|
2323
2336
|
}
|
|
2324
2337
|
function formatCents(microcents, decimals) {
|
|
@@ -2736,6 +2749,67 @@ function createGuardedFetch(guard, fetchImpl = fetch) {
|
|
|
2736
2749
|
};
|
|
2737
2750
|
return Object.assign(wrapped, { preconnect: fetch.preconnect });
|
|
2738
2751
|
}
|
|
2752
|
+
var RETRYABLE_MCP_METHODS = /* @__PURE__ */ new Set([
|
|
2753
|
+
"initialize",
|
|
2754
|
+
"notifications/initialized",
|
|
2755
|
+
"tools/list",
|
|
2756
|
+
"prompts/list"
|
|
2757
|
+
]);
|
|
2758
|
+
var MCP_RETRY_BUDGET_MS = 2e4;
|
|
2759
|
+
var MIN_RESEND_SPACING_MS = 1e3;
|
|
2760
|
+
function isRetryableMcpMessage(input, init) {
|
|
2761
|
+
const method = init?.method ?? (input instanceof Request ? input.method : "GET");
|
|
2762
|
+
if (method.toUpperCase() !== "POST" || typeof init?.body !== "string") return false;
|
|
2763
|
+
let message;
|
|
2764
|
+
try {
|
|
2765
|
+
message = JSON.parse(init.body);
|
|
2766
|
+
} catch {
|
|
2767
|
+
return false;
|
|
2768
|
+
}
|
|
2769
|
+
if (typeof message !== "object" || message === null) return false;
|
|
2770
|
+
const { method: rpc } = message;
|
|
2771
|
+
return typeof rpc === "string" && RETRYABLE_MCP_METHODS.has(rpc);
|
|
2772
|
+
}
|
|
2773
|
+
function resendDelayMs(res, deadline) {
|
|
2774
|
+
if (res.status !== 429 && res.status !== 503) return void 0;
|
|
2775
|
+
const retryAfterMs2 = parseRetryAfterMs(res.headers.get("retry-after"));
|
|
2776
|
+
if (retryAfterMs2 === void 0) return void 0;
|
|
2777
|
+
const waitMs = Math.max(retryAfterMs2, MIN_RESEND_SPACING_MS);
|
|
2778
|
+
return Date.now() + waitMs > deadline ? void 0 : waitMs;
|
|
2779
|
+
}
|
|
2780
|
+
function createMcpRetryAfterFetch(fetchImpl = fetch, retryUntil = () => Date.now() + MCP_RETRY_BUDGET_MS) {
|
|
2781
|
+
const wrapped = async (input, init) => {
|
|
2782
|
+
if (!isRetryableMcpMessage(input, init)) return fetchImpl(input, init);
|
|
2783
|
+
const deadline = retryUntil();
|
|
2784
|
+
const signal = init?.signal ?? (input instanceof Request ? input.signal : void 0);
|
|
2785
|
+
for (; ; ) {
|
|
2786
|
+
const res = await fetchImpl(input, init);
|
|
2787
|
+
const waitMs = resendDelayMs(res, deadline);
|
|
2788
|
+
if (waitMs === void 0) return res;
|
|
2789
|
+
await res.body?.cancel();
|
|
2790
|
+
await delay2(waitMs, void 0, { signal });
|
|
2791
|
+
}
|
|
2792
|
+
};
|
|
2793
|
+
return Object.assign(wrapped, { preconnect: fetch.preconnect });
|
|
2794
|
+
}
|
|
2795
|
+
async function connectRemoteMcp(client, url, apiKey, fetchImpl, budgetMs = MCP_RETRY_BUDGET_MS) {
|
|
2796
|
+
const connectUntil = Date.now() + budgetMs;
|
|
2797
|
+
let connecting = true;
|
|
2798
|
+
const transport = new StreamableHTTPClientTransport(url, {
|
|
2799
|
+
requestInit: { headers: { Authorization: `Bearer ${apiKey}` } },
|
|
2800
|
+
fetch: createMcpIdempotentFetch(
|
|
2801
|
+
createMcpRetryAfterFetch(
|
|
2802
|
+
fetchImpl,
|
|
2803
|
+
() => connecting ? connectUntil : Date.now() + budgetMs
|
|
2804
|
+
)
|
|
2805
|
+
)
|
|
2806
|
+
});
|
|
2807
|
+
try {
|
|
2808
|
+
await client.connect(transport);
|
|
2809
|
+
} finally {
|
|
2810
|
+
connecting = false;
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2739
2813
|
function extractLocalUpload(meta) {
|
|
2740
2814
|
if (meta === null || typeof meta !== "object") return void 0;
|
|
2741
2815
|
const descriptor = meta[LOCAL_UPLOAD_META_KEY];
|
|
@@ -2877,7 +2951,7 @@ function createProxyServer(client, version, uploadLocalFile, hostedFileIngest) {
|
|
|
2877
2951
|
return server;
|
|
2878
2952
|
}
|
|
2879
2953
|
async function runMcpProxyServer(opts) {
|
|
2880
|
-
const version = opts.version ?? (true ? "1.26.
|
|
2954
|
+
const version = opts.version ?? (true ? "1.26.5" : "0.0.0-dev");
|
|
2881
2955
|
const read = await opts.readCredentials();
|
|
2882
2956
|
if (!read.ok) {
|
|
2883
2957
|
throw new Error(
|
|
@@ -2888,12 +2962,8 @@ async function runMcpProxyServer(opts) {
|
|
|
2888
2962
|
const url = new URL(`${endpoint.replace(/\/+$/, "")}${REMOTE_MCP_PATH}`);
|
|
2889
2963
|
const guard = createCredentialGuard(opts.readCredentials, read.credentials);
|
|
2890
2964
|
const client = new McpClient({ name: "pyx-mem-proxy", version }, { capabilities: {} });
|
|
2891
|
-
const clientTransport = new StreamableHTTPClientTransport(url, {
|
|
2892
|
-
requestInit: { headers: { Authorization: `Bearer ${apiKey}` } },
|
|
2893
|
-
fetch: createMcpIdempotentFetch(createGuardedFetch(guard))
|
|
2894
|
-
});
|
|
2895
2965
|
try {
|
|
2896
|
-
await client
|
|
2966
|
+
await connectRemoteMcp(client, url, apiKey, createGuardedFetch(guard));
|
|
2897
2967
|
} catch (err) {
|
|
2898
2968
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2899
2969
|
throw new Error(
|