comfyui-mcp 0.52.59 → 0.52.61
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.
|
@@ -41,7 +41,7 @@ import { isPanelAnsweredError } from "../services/panel-answered.js";
|
|
|
41
41
|
import { isPreExecutorRefusal } from "../services/panel-refusal.js";
|
|
42
42
|
import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
|
|
43
43
|
import { parse as parseYaml } from "yaml";
|
|
44
|
-
import { requiredPanelVersion, SEMVER_RE, LATE_ASK_TTL_MS, tabIncarnationSlot, } from "../services/ui-bridge.js";
|
|
44
|
+
import { requiredPanelVersion, SEMVER_RE, LATE_ASK_TTL_MS, tabIncarnationSlot, SHOW_MEDIA_KIND_MIN_PANEL_VERSION, showMediaItemsPanelCannotPaint, } from "../services/ui-bridge.js";
|
|
45
45
|
import { compareSemver } from "../services/self-update.js";
|
|
46
46
|
import { describeInstallPanelAction } from "../services/panel-recovery.js";
|
|
47
47
|
import { peekResolvedPanelBase, primePanelBase, verifiedPanelDiskVersion, } from "../services/panel-workspace.js";
|
|
@@ -3770,6 +3770,56 @@ function tabAdvertisedPanelVersion(ctx) {
|
|
|
3770
3770
|
const v = reading?.version;
|
|
3771
3771
|
return typeof v === "string" && SEMVER_RE.test(v.trim()) ? v.trim() : undefined;
|
|
3772
3772
|
}
|
|
3773
|
+
function tabPanelVersionReading(ctx) {
|
|
3774
|
+
const fn = ctx.bridge.advertisedPanelVersion;
|
|
3775
|
+
if (typeof fn !== "function")
|
|
3776
|
+
return {};
|
|
3777
|
+
try {
|
|
3778
|
+
return fn.call(ctx.bridge, ctx.tabId) ?? {};
|
|
3779
|
+
}
|
|
3780
|
+
catch {
|
|
3781
|
+
return {};
|
|
3782
|
+
}
|
|
3783
|
+
}
|
|
3784
|
+
function tabAdvertisedShowMediaKinds(ctx) {
|
|
3785
|
+
const fn = ctx.bridge.tabShowMediaKinds;
|
|
3786
|
+
if (typeof fn !== "function")
|
|
3787
|
+
return undefined;
|
|
3788
|
+
try {
|
|
3789
|
+
return fn.call(ctx.bridge, ctx.tabId);
|
|
3790
|
+
}
|
|
3791
|
+
catch {
|
|
3792
|
+
return undefined;
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
/**
|
|
3796
|
+
* #2017 — refuse a kind this panel is proven unable to paint, rather than send
|
|
3797
|
+
* an item that becomes a broken-image card and reports success.
|
|
3798
|
+
*
|
|
3799
|
+
* Names the advertised version (when we have one) and the upgrade; a restart
|
|
3800
|
+
* alone leaves cached JS running, so the hard-refresh is part of the remedy.
|
|
3801
|
+
*/
|
|
3802
|
+
function formatShowMediaKindUnsupported(blocked) {
|
|
3803
|
+
const kinds = [...new Set(blocked.map((b) => b.kind))];
|
|
3804
|
+
const kindList = kinds.map((k) => `"${k}"`).join(", ");
|
|
3805
|
+
const needed = blocked.find((b) => b.needed)?.needed ??
|
|
3806
|
+
kinds.map((k) => SHOW_MEDIA_KIND_MIN_PANEL_VERSION[k]).find((v) => typeof v === "string");
|
|
3807
|
+
const version = blocked.find((b) => b.version)?.version;
|
|
3808
|
+
const items = blocked.map((b) => ` - ${b.filename} (${b.kind})`).join("\n");
|
|
3809
|
+
const update = describeInstallPanelAction("update", "update the ComfyUI-MCP panel via ComfyUI Manager");
|
|
3810
|
+
const floor = needed ? ` to ≥${needed}` : " to a build that can paint it";
|
|
3811
|
+
const detected = version ? ` This tab announced panel ${version}.` : "";
|
|
3812
|
+
const why = blocked.some((b) => b.reason === "not_in_hello")
|
|
3813
|
+
? `The panel advertised the kinds it can paint and ${kindList} ${kinds.length === 1 ? "is" : "are"} not among them.`
|
|
3814
|
+
: `kind ${kindList} ${kinds.length === 1 ? "is" : "are"} only understood by panels from #710 onward` +
|
|
3815
|
+
(needed ? ` (first shipped in ${needed})` : "") +
|
|
3816
|
+
".";
|
|
3817
|
+
return (`This panel cannot paint ${kindList}.${detected} ${why} ` +
|
|
3818
|
+
`Sending ${blocked.length === 1 ? "it" : "them"} would show a broken-image card and report success.\n` +
|
|
3819
|
+
`Items not sent:\n${items}\n` +
|
|
3820
|
+
`${update}${floor}, then HARD-REFRESH the browser tab (Ctrl+Shift+R, or Cmd+Shift+R on macOS); ` +
|
|
3821
|
+
`a restart alone leaves the tab running cached old JS.`);
|
|
3822
|
+
}
|
|
3773
3823
|
/**
|
|
3774
3824
|
* #1828 — an allowlisted frontend-only type refused as "backend does not
|
|
3775
3825
|
* provide it" is version skew when the tab's advertised panel is below this
|
|
@@ -3939,6 +3989,46 @@ function rewriteToolResultJson(res, payload) {
|
|
|
3939
3989
|
content: res.content.map((c, i) => i === idx && c.type === "text" ? { ...c, text: JSON.stringify(payload, null, 2) } : c),
|
|
3940
3990
|
};
|
|
3941
3991
|
}
|
|
3992
|
+
/**
|
|
3993
|
+
* #2075 — a verified widget write that fell back to last-observed schema still
|
|
3994
|
+
* succeeded. The panel's `schema_note` (#1223) tells the agent the live probes
|
|
3995
|
+
* went silent and to re-read "once ComfyUI is responding again", which makes a
|
|
3996
|
+
* routine canvas edit look degraded while ComfyUI and the panel bridge are
|
|
3997
|
+
* healthy.
|
|
3998
|
+
*
|
|
3999
|
+
* Sibling panel#1582 skips re-waiting on later writes once silence is known.
|
|
4000
|
+
* This report is the write immediately after adding a node: that add records a
|
|
4001
|
+
* live map and unlatches the skip, so the next set_widget re-probes, times out
|
|
4002
|
+
* inside the 2000 ms snapshot budget, and re-emits the note. Matched on the
|
|
4003
|
+
* panel's own snapshotAuthorizationNote wording. Used ONLY to drop the note
|
|
4004
|
+
* from a write the panel already verified against an unchanged backend —
|
|
4005
|
+
* never to authorize anything, never on a refusal, never when `set` is missing.
|
|
4006
|
+
*/
|
|
4007
|
+
function stripVerifiedLastObservedSchemaNote(res) {
|
|
4008
|
+
if (res.isError)
|
|
4009
|
+
return res;
|
|
4010
|
+
const payload = parseToolResultJson(res);
|
|
4011
|
+
if (!payload)
|
|
4012
|
+
return res;
|
|
4013
|
+
if (payload.schema_source !== "last-observed")
|
|
4014
|
+
return res;
|
|
4015
|
+
if (typeof payload.schema_note !== "string")
|
|
4016
|
+
return res;
|
|
4017
|
+
const note = payload.schema_note;
|
|
4018
|
+
if (!/write SUCCEEDED and was verified/i.test(note))
|
|
4019
|
+
return res;
|
|
4020
|
+
if (!/last whole \/?object_info observed/i.test(note))
|
|
4021
|
+
return res;
|
|
4022
|
+
if (!/backend has not reconnected/i.test(note))
|
|
4023
|
+
return res;
|
|
4024
|
+
const set = payload.set;
|
|
4025
|
+
if (!set || typeof set !== "object" || Array.isArray(set))
|
|
4026
|
+
return res;
|
|
4027
|
+
const next = { ...payload };
|
|
4028
|
+
delete next.schema_note;
|
|
4029
|
+
delete next.schema_source;
|
|
4030
|
+
return rewriteToolResultJson(res, next);
|
|
4031
|
+
}
|
|
3942
4032
|
async function exitSubgraphLevels(ctx, count) {
|
|
3943
4033
|
const failures = [];
|
|
3944
4034
|
for (let i = 0; i < count; i++) {
|
|
@@ -12114,7 +12204,7 @@ export function buildPanelToolDefs() {
|
|
|
12114
12204
|
// to the raw success reply so a later appendToolResultText disclosure
|
|
12115
12205
|
// (which makes the text no longer parse as JSON) cannot dodge it.
|
|
12116
12206
|
const echoFull = args.echo === "full";
|
|
12117
|
-
const write = async (nodeId, widget) => summarizeSetWidgetEcho(await ctx.call({ cmd: "graph_set_widget", node_id: nodeId, widget, value }, OBJECT_INFO_REFRESH_ACK_TIMEOUT_MS), echoFull);
|
|
12207
|
+
const write = async (nodeId, widget) => stripVerifiedLastObservedSchemaNote(summarizeSetWidgetEcho(await ctx.call({ cmd: "graph_set_widget", node_id: nodeId, widget, value }, OBJECT_INFO_REFRESH_ACK_TIMEOUT_MS), echoFull));
|
|
12118
12208
|
let first = await write(args.node_id, args.widget);
|
|
12119
12209
|
if (!first.isError) {
|
|
12120
12210
|
markPanelSchemaReady(panelSchemaKey(ctx));
|
|
@@ -16525,6 +16615,20 @@ CHECKED FOR YOU: the graph read this message prescribes was just run, and it ` +
|
|
|
16525
16615
|
}
|
|
16526
16616
|
}
|
|
16527
16617
|
}
|
|
16618
|
+
// #2017 — do not send a painter kind this panel is proven unable to
|
|
16619
|
+
// render. A pre-#710 panel paints `audio` as `<img>` and reports
|
|
16620
|
+
// success; refusing with the version and the upgrade is strictly better
|
|
16621
|
+
// than a broken-image card. Fail-OPEN when the version is unknown or
|
|
16622
|
+
// inherited (same tri-state as the #392 command gate) so a current
|
|
16623
|
+
// panel that omitted the field is never told to update. Image/video
|
|
16624
|
+
// skip the check entirely.
|
|
16625
|
+
const blocked = showMediaItemsPanelCannotPaint(resolved, {
|
|
16626
|
+
reading: tabPanelVersionReading(ctx),
|
|
16627
|
+
advertisedKinds: tabAdvertisedShowMediaKinds(ctx),
|
|
16628
|
+
});
|
|
16629
|
+
if (blocked.length > 0) {
|
|
16630
|
+
return fail(formatShowMediaKindUnsupported(blocked));
|
|
16631
|
+
}
|
|
16528
16632
|
// #2010 — the reply below is the CLIENT's, and one of the two clients
|
|
16529
16633
|
// that answer show_media says `{shown:true}` without reading the items.
|
|
16530
16634
|
// Correct the claim against what the reply actually accounted for BEFORE
|