comfyui-mcp 0.50.18 → 0.50.20

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.
@@ -5349,11 +5349,45 @@ export function buildPanelToolDefs() {
5349
5349
  text: (p) => fixedCapHint("selected node(s)", replyCount(p, "nodes"), p.selected_count, "Ask the user to select fewer nodes, or read the ones you need by id with panel_query_graph {ids:[…], fields:'detail'}, which DOES take limit and max_chars."),
5350
5350
  },
5351
5351
  ])),
5352
- def("panel_view_nodes_in_viewport", "ONLY the nodes inside the current VIEWPORT (pan+zoom) — a screen-region subset, NOT the whole open graph (that is panel_graph_outline, which is what 'show me what's on the canvas' means). Use this to SCOPE your work to what's on their screen: when they say \"these nodes\", \"the ones here\", \"what am I looking at right now\", or when a graph is large and you only need the region in front of them. Returns the viewport rect in graph coordinates (x, y, width, height, zoom), `node_count` (whole graph) vs `in_view_count`, and the detail summary of each visible node. A node counts as visible if any part of it overlaps the viewport. On a big canvas this is dramatically cheaper than reading everything. Read-only.", {}, async (_args, ctx) => withTruncationHints(await ctx.call({ cmd: "graph_view_nodes_in_viewport" }), [
5352
+ def("panel_view_nodes_in_viewport", "ONLY the nodes inside the current VIEWPORT (pan+zoom) — a screen-region subset, NOT the whole open graph (that is panel_graph_outline, which is what 'show me what's on the canvas' means). Use this to SCOPE your work to what's on their screen: when they say \"these nodes\", \"the ones here\", \"what am I looking at right now\", or when a graph is large and you only need the region in front of them. Returns the viewport rect in graph coordinates (x, y, width, height, zoom), `node_count` (whole graph) vs `in_view_count`, and the detail summary of each visible node. A node counts as visible if any part of it overlaps the viewport. On a big canvas this is dramatically cheaper than reading everything. This tool does NOT filter to specific nodes — to read one node's exact slot/widget detail use panel_query_graph {ids:[…], fields:'detail'}. Read-only.", {
5353
+ // #845/#754 — the panel has enforced a CHARACTER budget here since the
5354
+ // 135k-character reply that motivated it, but the budget was unreachable:
5355
+ // this schema was `{}` and the call below passed no arguments, so the
5356
+ // default applied and no caller could raise or lower it. Its sibling
5357
+ // panel_query_graph has always exposed the lever. An enforced-but-hidden
5358
+ // knob is the worst of both — callers hit a cap they cannot see or move.
5359
+ //
5360
+ // The range described here is the PANEL's own clamp (viewport-char-bound.js),
5361
+ // not panel_graph_outline's 500–60000. Two different clamps already exist;
5362
+ // describing the one that is not enforced would make this text false, and a
5363
+ // schema that lies about its bounds is worse than one that omits them.
5364
+ max_chars: z
5365
+ .number()
5366
+ .int()
5367
+ .positive()
5368
+ // Declared so the #809 gate can check the ceiling this tool STATES
5369
+ // against the one it enforces. Only the ceiling: the floor stays
5370
+ // undeclared so a small value clamps up panel-side rather than being
5371
+ // refused — a caller asking for 1000 wants less, not an error.
5372
+ .max(200000)
5373
+ .optional()
5374
+ .describe("Character budget for the whole reply (default 24000, clamped 2000–200000). Nodes are taken in view order until it is spent, never partially serialized. `in_view_count` keeps describing the SCREEN, so compare it to nodes.length to see what was withheld."),
5375
+ }, async (args, ctx) => withTruncationHints(await ctx.call({
5376
+ cmd: "graph_view_nodes_in_viewport",
5377
+ // Forwarded only when supplied: an explicit `undefined` on the wire
5378
+ // would reach the panel's normalizer as a nonsense value, and it
5379
+ // deliberately falls back to the default rather than to zero — but
5380
+ // sending it at all would misreport this caller as having asked.
5381
+ ...(args.max_chars === undefined ? {} : { max_chars: args.max_chars }),
5382
+ }), [
5353
5383
  {
5354
5384
  flag: "truncated",
5355
5385
  key: "truncation_hint",
5356
- text: (p) => fixedCapHint("visible node(s)", replyCount(p, "nodes"), p.in_view_count, "Ask the user to zoom in so fewer nodes are on screen, or read the region with panel_query_graph (which DOES take limit and max_chars) / panel_graph_outline for the whole graph."),
5386
+ text: (p) => fixedCapHint("visible node(s)", replyCount(p, "nodes"), p.in_view_count,
5387
+ // #754 — this remedy used to send the caller to panel_query_graph
5388
+ // "which DOES take limit and max_chars", because this tool did not.
5389
+ // It does now, so the first move is the lever in your own hand.
5390
+ "Raise `max_chars` up to 200000 to see more of the same screen, or ask the user to zoom in so fewer nodes are on it. To read SPECIFIC nodes instead, panel_query_graph {ids:[…], fields:'detail'}; for the whole graph, panel_graph_outline."),
5357
5391
  },
5358
5392
  ])),
5359
5393
  def("panel_audit_prompt_director", "Audit Prompt Director on the LIVE canvas without changing it. Correlates Prompt Director/Producer/Auto/Context/Reference/Critic widget values and wiring with detected model-loader filenames, every LoRA loader's actual model/CLIP strengths, and Prompt Director's latest sanitized runtime edit plan, resolved Model Explorer metadata, warnings, exact final prompt, and critic verdict. Returns observations plus proposed panel_set_widget changes with requires_confirmation=true. Call this when Prompt Director nodes are present, before saying the model/LoRA setup is correct, or when an edit prompt is ignored. READ-ONLY: present useful findings to the user and ask before applying any recommendation unless they already explicitly asked you to fix it.", {}, async (_args, ctx) => ctx.call({ cmd: "graph_prompt_director_audit" })),
@@ -5972,6 +6006,20 @@ export function buildPanelToolDefs() {
5972
6006
  isRetryableRunToNodeStampRace(res, rejection)) {
5973
6007
  scopeRebuilt = true;
5974
6008
  try {
6009
+ // #1050 — SETTLE before re-issuing. The panel refuses this race when the
6010
+ // graph changed between dispatch and apply, and re-dispatching in the
6011
+ // same tick lands in the SAME window: a reporter's retry raced
6012
+ // identically and instantly, so the one re-issue was spent for nothing
6013
+ // and the run was refused twice with nothing queued.
6014
+ //
6015
+ // This is a SETTLE PAUSE, not the mutation-quiescence barrier the report
6016
+ // asked for. The panel exposes no such signal, and inventing a
6017
+ // graph-is-quiet reading from out here would be guessing at the
6018
+ // frontend's state. It buys pending edits a moment to land — exactly
6019
+ // what the reconnect retry already does for a dropped socket — and
6020
+ // nothing more. A graph still moving after it (a user actively editing)
6021
+ // races again and is SURFACED, never re-raced.
6022
+ await sleep(retrySettleMs());
5975
6023
  res = await ctx.call(runCmd, 20000);
5976
6024
  rejection = detectRunRejection(res);
5977
6025
  }
@@ -5999,9 +6047,11 @@ export function buildPanelToolDefs() {
5999
6047
  return rejection;
6000
6048
  return appendToolResultText(rejection, `\n\n(Dispatch history: the first graph_run was refused by the panel's run-to-node ` +
6001
6049
  `graph-stamp race, which CERTIFIED that nothing was queued, so the scoped run was ` +
6002
- `re-issued exactly once. The failure above is that SECOND dispatch; it was not ` +
6003
- `retried again. Judge whether anything was queued from that message alone the ` +
6004
- `first dispatch definitely queued nothing.)`);
6050
+ `re-issued exactly once after a short pause to let pending graph edits land ` +
6051
+ `(#1050). The failure above is that SECOND dispatch; it was not retried again. ` +
6052
+ `Judge whether anything was queued from that message alone — the first dispatch ` +
6053
+ `definitely queued nothing. Racing AGAIN after the pause means the graph is still ` +
6054
+ `changing under the run: let the canvas settle, then re-run.)`);
6005
6055
  }
6006
6056
  // Attribute this genuine queue to ourselves so a later panel_run in the
6007
6057
  // same batch recognizes the in-flight job as our own and doesn't false-warn