comfyui-mcp 0.52.192 → 0.52.193
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.
|
@@ -28,7 +28,7 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
28
28
|
import { resolveToolSurfacePolicy, toolActionPolicyError, toolAllowed, } from "../tools/tool-surface-filter.js";
|
|
29
29
|
import { logger as toolPolicyLogger } from "../utils/logger.js";
|
|
30
30
|
import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
31
|
-
import { forwardedByReferenceNote, oversizedInlineRefusal, resolveServableViewRef, stageFileIntoServedDir, stagedForDisplayNote, readShowMediaAck, unaccountedShowMediaNote, unverifiedViewRefNote, } from "../services/comfy-view-ref.js";
|
|
31
|
+
import { forwardedByReferenceNote, mediaKindFromMime, oversizedInlineRefusal, remoteViewRefInlineFailedNote, resolveServableViewRef, stageFileIntoServedDir, stagedForDisplayNote, readShowMediaAck, unaccountedShowMediaNote, unverifiedViewRefNote, viewRefTypeForFetch, } from "../services/comfy-view-ref.js";
|
|
32
32
|
import { extname, isAbsolute, join, resolve, sep } from "node:path";
|
|
33
33
|
import { fileURLToPath } from "node:url";
|
|
34
34
|
import { comfyuiFetch } from "../comfyui/fetch.js";
|
|
@@ -205,7 +205,7 @@ import { QueueMonitor, RUNNING_UNCONFIRMED_MS } from "../services/queue-monitor.
|
|
|
205
205
|
import { stallThresholdMs } from "../services/stall-threshold.js";
|
|
206
206
|
import { RunCompletions } from "./run-completion-journal.js";
|
|
207
207
|
import { AskAnswers, askFingerprint, PANEL_ASK_ID_PREFIX, } from "./ask-answer-journal.js";
|
|
208
|
-
import { getLogs, getQueueVerified, resetClient, resetObjectInfoCache, } from "../comfyui/client.js";
|
|
208
|
+
import { fetchImage, getLogs, getQueueVerified, resetClient, resetObjectInfoCache, } from "../comfyui/client.js";
|
|
209
209
|
import { convertUiToApi, collectNodeTypes } from "../services/workflow-converter.js";
|
|
210
210
|
import { outputNodeObjectInfoForPanel, recoverOutputNodeScopedRun, stampOutputNodeFlagsOnToolResult, } from "../services/output-node.js";
|
|
211
211
|
import { captureComfyUITargetFence, restartComfyUI, preflightLocalRestart, readServingArgv, resolveVerifiedProxyRestartTarget, describeArgvDrift, recordRestartDispatch, clearRestartDispatch, getRestartDispatchRecord, RESTART_DISPATCH_CAUSATION_WINDOW_MS, PROCESS_WIDE_RESTART_DISPATCH_TOKEN, __processControlTestHooks, targetFenceMatchesCurrent, targetFencesEqual, } from "../services/process-control.js";
|
|
@@ -23850,21 +23850,27 @@ CHECKED FOR YOU: the graph read this message prescribes was just run, and it ` +
|
|
|
23850
23850
|
resolved.push({ kind, dataUrl, filename, caption: item.caption });
|
|
23851
23851
|
}
|
|
23852
23852
|
else {
|
|
23853
|
-
// ComfyUI /view ref. A browser panel fetches it same-origin —
|
|
23854
|
-
// HEADLESS
|
|
23855
|
-
//
|
|
23856
|
-
// (
|
|
23857
|
-
// which the client renders as a caption card.
|
|
23853
|
+
// ComfyUI /view ref. A local browser panel fetches it same-origin —
|
|
23854
|
+
// but a HEADLESS client cannot, and a REMOTE/CLOUD browser panel's
|
|
23855
|
+
// /view is a different route from get_image's authenticated client
|
|
23856
|
+
// (the panel 404s while get_image succeeds — #2861).
|
|
23858
23857
|
//
|
|
23859
23858
|
// #2012 — judge the DESTINATION, not the address. `ctx.tabId` may be
|
|
23860
23859
|
// a scope / prefix / alias; `isHeadless` on the address is a lookup
|
|
23861
23860
|
// miss that answers false and a phone gets a /view URL it cannot
|
|
23862
|
-
// fetch. Positive requirement: inline
|
|
23863
|
-
// destination.
|
|
23861
|
+
// fetch. Positive requirement: inline a proven headless destination,
|
|
23862
|
+
// or a proven interactive destination whose ComfyUI is not local.
|
|
23863
|
+
//
|
|
23864
|
+
// #877/#899 — remote bytes come from fetchImage (the get_image
|
|
23865
|
+
// path), never a same-named file on the orchestrator disk. A remote
|
|
23866
|
+
// interactive tab that cannot be inlined is refused rather than
|
|
23867
|
+
// handed a viewRef the panel will drop (painted:0).
|
|
23864
23868
|
let inlined = false;
|
|
23865
|
-
|
|
23869
|
+
const dest = resolveClientKind(ctx);
|
|
23870
|
+
const remoteTarget = isRemoteMode() || isCloudMode();
|
|
23871
|
+
if (dest.kind === "headless") {
|
|
23866
23872
|
try {
|
|
23867
|
-
const base = (
|
|
23873
|
+
const base = getComfyUIBaseUrl().replace(/\/+$/, "");
|
|
23868
23874
|
const qs = new URLSearchParams({ filename: src.filename, type: src.type ?? "output" });
|
|
23869
23875
|
if (src.subfolder)
|
|
23870
23876
|
qs.set("subfolder", src.subfolder);
|
|
@@ -23872,9 +23878,10 @@ CHECKED FOR YOU: the graph read this message prescribes was just run, and it ` +
|
|
|
23872
23878
|
if (resp.ok) {
|
|
23873
23879
|
const mime = resp.headers.get("content-type") ?? "";
|
|
23874
23880
|
const buf = Buffer.from(await resp.arrayBuffer());
|
|
23875
|
-
|
|
23881
|
+
const kindFromMime = mediaKindFromMime(mime);
|
|
23882
|
+
if (kindFromMime && kindFromMime !== "audio" && buf.length <= MAX_BYTES) {
|
|
23876
23883
|
resolved.push({
|
|
23877
|
-
kind:
|
|
23884
|
+
kind: kindFromMime,
|
|
23878
23885
|
dataUrl: `data:${mime};base64,${buf.toString("base64")}`,
|
|
23879
23886
|
filename: src.filename,
|
|
23880
23887
|
caption: item.caption,
|
|
@@ -23887,6 +23894,41 @@ CHECKED FOR YOU: the graph read this message prescribes was just run, and it ` +
|
|
|
23887
23894
|
// fall through to the viewRef path
|
|
23888
23895
|
}
|
|
23889
23896
|
}
|
|
23897
|
+
else if (remoteTarget && dest.kind === "interactive") {
|
|
23898
|
+
try {
|
|
23899
|
+
const fetched = await fetchImage(src.filename, viewRefTypeForFetch(src.type), src.subfolder ?? "", { maxBytes: MAX_BYTES });
|
|
23900
|
+
const mime = fetched.mimeType.split(";")[0].trim();
|
|
23901
|
+
const buf = Buffer.from(fetched.base64, "base64");
|
|
23902
|
+
const kindFromMime = mediaKindFromMime(mime);
|
|
23903
|
+
if (kindFromMime && buf.length <= MAX_BYTES) {
|
|
23904
|
+
resolved.push({
|
|
23905
|
+
kind: kindFromMime,
|
|
23906
|
+
dataUrl: `data:${mime};base64,${fetched.base64}`,
|
|
23907
|
+
filename: src.filename,
|
|
23908
|
+
caption: item.caption,
|
|
23909
|
+
});
|
|
23910
|
+
inlined = true;
|
|
23911
|
+
}
|
|
23912
|
+
else {
|
|
23913
|
+
const detail = !kindFromMime
|
|
23914
|
+
? `The MCP client fetched it, but the body was not media (content-type "${mime || "unset"}").`
|
|
23915
|
+
: `The MCP client fetched it, but it is ${buf.length} bytes — over the ${MAX_BYTES} byte inline cap.`;
|
|
23916
|
+
return fail(remoteViewRefInlineFailedNote({
|
|
23917
|
+
filename: src.filename,
|
|
23918
|
+
detail,
|
|
23919
|
+
capBytes: MAX_BYTES,
|
|
23920
|
+
}));
|
|
23921
|
+
}
|
|
23922
|
+
}
|
|
23923
|
+
catch (err) {
|
|
23924
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
23925
|
+
return fail(remoteViewRefInlineFailedNote({
|
|
23926
|
+
filename: src.filename,
|
|
23927
|
+
detail,
|
|
23928
|
+
capBytes: MAX_BYTES,
|
|
23929
|
+
}));
|
|
23930
|
+
}
|
|
23931
|
+
}
|
|
23890
23932
|
if (!inlined) {
|
|
23891
23933
|
resolved.push({
|
|
23892
23934
|
kind: "viewRef",
|