comfyui-mcp 0.50.69 → 0.50.71

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.
@@ -5290,11 +5290,26 @@ function recoveredAskResult(entry) {
5290
5290
  * the question at hand, which is the misattribution this whole path exists to
5291
5291
  * prevent. Reporting them beats swallowing them — the user did answer something.
5292
5292
  */
5293
- function askTimeoutResult(tabId, fingerprint, recovery) {
5294
- let text = "The question card was not answered in time (or no interactive panel surface " +
5295
- "rendered ite.g. an exec/headless run), so nothing was selected. If you " +
5296
- "still need the decision, ask the user directly in plain chat text, or " +
5297
- "re-invoke panel_ask from an interactive ComfyUI tab.";
5293
+ export function askTimeoutResult(tabId, fingerprint, recovery,
5294
+ /**
5295
+ * #1243 did a reachability check actually run before the wait? When it did, the
5296
+ * "maybe nothing rendered the card" alternative has ALREADY been ruled out, and
5297
+ * offering it anyway sends the agent to re-invoke from "an interactive tab" it was
5298
+ * demonstrably already on. `ctx.ensureReachable` is optional-chained at the call
5299
+ * site, so this is threaded rather than assumed — an absent check means the
5300
+ * alternative is still live and is still named.
5301
+ */
5302
+ surfaceConfirmed) {
5303
+ const waited = `${Math.round(ASK_TOTAL_BUDGET_CAP_MS / 1000)}s`;
5304
+ let text = surfaceConfirmed
5305
+ ? `The question card was delivered to the panel and went unanswered for ${waited}, ` +
5306
+ "so nothing was selected — this is a timeout, not a delivery failure. The user " +
5307
+ "may simply not have been at the screen. If you still need the decision, ask them " +
5308
+ "directly in plain chat text, or re-invoke panel_ask when they are present."
5309
+ : `The question card was not answered within ${waited} — either it went unanswered, ` +
5310
+ "or no interactive panel surface rendered it (e.g. an exec/headless run), and this " +
5311
+ "call could not establish which. If you still need the decision, ask the user " +
5312
+ "directly in plain chat text, or re-invoke panel_ask from an interactive ComfyUI tab.";
5298
5313
  // What is surfaced, and why each:
5299
5314
  // • an answer that reached NO tool call — nobody has it, so it must be told;
5300
5315
  // • an answer to THIS EXACT question that DID reach a tool call but could not
@@ -5454,7 +5469,13 @@ async function askUserWithGrace(ctx, ask) {
5454
5469
  // a conversation replaced mid-ask would let the live turn's ack settle a
5455
5470
  // warning that conversation never saw — the debt path reaching a live turn
5456
5471
  // through a helper, which is how it slipped the gate before.
5457
- const body = askTimeoutResult(tabId, fingerprint, outcome.recovery);
5472
+ // #1243 derive this rather than hardcoding `true`. The reachability call above
5473
+ // is optional-chained (`ctx.ensureReachable?.()`), so on a ctx that does not
5474
+ // provide it NO check ran and the no-surface alternative is still live. Passing a
5475
+ // literal would have made the false branch unreachable in production — dead code
5476
+ // justified by a hypothetical, and a test exercising a path nothing takes.
5477
+ const surfaceConfirmed = typeof ctx.ensureReachable === "function";
5478
+ const body = askTimeoutResult(tabId, fingerprint, outcome.recovery, surfaceConfirmed);
5458
5479
  return AskAnswers.askBelongsToLiveConversation(askId)
5459
5480
  ? withDroppedAnswerWarning(tabId, body)
5460
5481
  : body;
@@ -7469,7 +7490,7 @@ export function buildPanelToolDefs() {
7469
7490
  .min(1)
7470
7491
  .describe("Wizard step/field refs to glow green (as the wizard labels them). Pass several to highlight a set."),
7471
7492
  }, async (args, ctx) => ctx.call({ cmd: "training_highlight", refs: args.refs }, 10000)),
7472
- def("panel_ask", "Ask the user to choose between options — renders an interactive question card in the panel chat and BLOCKS until they pick, returning their choice as text. Use this (NOT the AskUserQuestion tool, which never renders here) whenever you need the user to decide between options. Each option may carry a short description. The card always includes an 'Other…' free-text field, so the returned string may be a listed label or whatever the user typed (comma-joined for multi_select). Ask only when the answer genuinely changes what you do.", {
7493
+ def("panel_ask", "Ask the user to choose between options — renders an interactive question card in the panel chat and BLOCKS until they pick, returning their choice as text. It does NOT block forever: if nobody answers within ~285s the call returns an error saying so, and you must then ask in plain chat text or re-invoke when the user is present. Budget for that — a question asked while the user is away costs the better part of five minutes before you learn anything. Use this (NOT the AskUserQuestion tool, which never renders here) whenever you need the user to decide between options. Each option may carry a short description. The card always includes an 'Other…' free-text field, so the returned string may be a listed label or whatever the user typed (comma-joined for multi_select). Ask only when the answer genuinely changes what you do.", {
7473
7494
  question: z.string().describe("The question to ask, e.g. 'Which sampler should I use?'"),
7474
7495
  options: z
7475
7496
  .array(z.object({