comfyui-mcp 0.51.28 → 0.51.29

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.
@@ -3726,6 +3726,7 @@ panelGapNote = "") {
3726
3726
  if (fenceStillMatches) {
3727
3727
  return {
3728
3728
  binding: "not_recovered",
3729
+ settleByRead: true,
3729
3730
  note: `${lead}. This session's fence was NOT re-derived, and whether that reply describes ` +
3730
3731
  `the LIVE canvas is exactly what could not be confirmed — a stale or background ` +
3731
3732
  `record can carry the right uuid and still not be the canvas in front of the user, ` +
@@ -9197,10 +9198,95 @@ export function buildPanelToolDefs() {
9197
9198
  const fence = fenceRebind
9198
9199
  ? describeFenceRebind(fenceRebind, canMutateNow, refusalCause)
9199
9200
  : undefined;
9201
+ // #1473 — TAKE THE ADVICE THIS MESSAGE GIVES, instead of assigning it as homework.
9202
+ //
9203
+ // The reporter restarted ComfyUI, called this, was told the binding was NOT
9204
+ // restored — and their very next `panel_graph_outline` succeeded with the expected
9205
+ // graph. #1401 already made the message right for this shape: when the panel's
9206
+ // reported identity MATCHES the fence this session already holds, it says so, says
9207
+ // it is NOT a claim that graph tools work, and prescribes a cheap graph read to
9208
+ // settle it. All true. It just left the caller to run that read themselves.
9209
+ //
9210
+ // So the read is taken here, on the matching-uuid path ONLY, and its ANSWER is put
9211
+ // in the message.
9212
+ //
9213
+ // THE RESULT STILL REPORTS FAILURE, deliberately, and that is #1401's call not
9214
+ // mine: "softening the DIAGNOSIS must not soften the RESULT — the rebind genuinely
9215
+ // did not happen". It did not. What changes is that the caller no longer has to
9216
+ // discover, one call later, that nothing was wrong: the answer arrives with the
9217
+ // refusal instead of after it. Whether this should become a SUCCESS is a real
9218
+ // product question and a reversal of a reasoned decision, so it is raised on the
9219
+ // issue rather than decided here.
9220
+ let settledNote = "";
9221
+ if (fence && fence.binding === "not_recovered" && fence.settleByRead) {
9222
+ // WHAT THE PROBE PROVES, AND ONLY THAT (codex).
9223
+ //
9224
+ // Two ways to overclaim here, and the first version did both:
9225
+ //
9226
+ // • EVERY error read as "refused". `ctx.call` turns a transport failure into an
9227
+ // error result too, so a `graph_query` that merely TIMED OUT on a backgrounded
9228
+ // tab would have been reported as a confirmed fence refusal — inventing a wedge
9229
+ // out of a slow tab, and contradicting this block's own "unknown says nothing"
9230
+ // rule. Only an actual instance-mismatch refusal proves the fence rejected it.
9231
+ // • A passing READ read as "graph tools work". The write fence is a SEPARATE
9232
+ // capability: a panel can serve reads while refusing every mutation, and the
9233
+ // capability probe above already knows. So the claim is scoped to reads, and the
9234
+ // known-negative write case is stated rather than papered over.
9235
+ let probeRefused;
9236
+ let probeOk = false;
9237
+ try {
9238
+ // The cheapest fenced read there is: ids only, one row. It is refused by the
9239
+ // same instance fence every graph command carries, which is exactly the
9240
+ // question — a full outline would answer it no better and would cost the caller
9241
+ // a page of graph on a recovery path.
9242
+ const probe = await ctx.call({ cmd: "graph_query", fields: "ids", limit: 1 }, 8000);
9243
+ if (!probe.isError)
9244
+ probeOk = true;
9245
+ else
9246
+ probeRefused = isWorkflowInstanceMismatch(toolResultText(probe));
9247
+ }
9248
+ catch (err) {
9249
+ probeRefused = isWorkflowInstanceMismatch(err);
9250
+ }
9251
+ if (probeOk) {
9252
+ settledNote =
9253
+ // ONE OBSERVATION, STATED AS ONE (codex r2). A passing graph_query proves that
9254
+ // read passed this fence just now — not that every command will, and not that
9255
+ // the cause "was" a race. The earlier wording generalised to "READS work" and
9256
+ // asserted the cause outright, which is the same overclaim this reply exists to
9257
+ // stop making.
9258
+ `
9259
+
9260
+ CHECKED FOR YOU: the graph read this message prescribes was just run — a ` +
9261
+ `graph_query against this fence — and it SUCCEEDED. So the fence did not reject ` +
9262
+ `THAT command a moment ago, which is the single fact this settles: it is evidence ` +
9263
+ `of a reconciliation race after the reconnect rather than a broken binding, not a ` +
9264
+ `guarantee about the next command.` +
9265
+ (canMutateNow === false
9266
+ ? ` MUTATIONS are a separate matter and remain refused on this tab — that is the ` +
9267
+ `write-fence capability above, not the binding, and re-running this will not ` +
9268
+ `change it.`
9269
+ : ` Nothing suggests a recovery step is needed for the binding; the next graph ` +
9270
+ `command is still the authority.`) +
9271
+ ` (The rebind itself still did not happen, which is why this is reported as a ` +
9272
+ `failure.)`;
9273
+ }
9274
+ else if (probeRefused === true) {
9275
+ settledNote =
9276
+ `
9277
+
9278
+ CHECKED FOR YOU: the graph read this message prescribes was just run, and it ` +
9279
+ `was REFUSED by the instance fence — so the reply was stale after all and graph ` +
9280
+ `commands really are being rejected. The remedy above applies.`;
9281
+ }
9282
+ // Anything else — a timeout, a dropped tab, an error that is not a fence refusal —
9283
+ // settles NOTHING and says nothing. An inconclusive probe must not become evidence
9284
+ // in either direction.
9285
+ }
9200
9286
  if (fence && fence.binding === "not_recovered") {
9201
9287
  return fail(`panel_set_workflow_target({mode:"current"}) did NOT restore this session's graph ` +
9202
9288
  `binding.\n\nAPPLIED (do not repeat this part): the workflow target is now ` +
9203
- `mode:"current"${rebindNote ? `.${rebindNote}` : "."}\n\nNOT APPLIED:${fence.note}`);
9289
+ `mode:"current"${rebindNote ? `.${rebindNote}` : "."}\n\nNOT APPLIED:${fence.note}${settledNote}`);
9204
9290
  }
9205
9291
  // #888 — SAY what the scope repin did. A silent success is as unhelpful
9206
9292
  // here as the silent refusal #1077 fixed: the whole complaint is that