comfyui-mcp 0.52.83 → 0.52.84
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.
|
@@ -5693,10 +5693,22 @@ function isRetryableRunToNodeStampRace(res, rejection) {
|
|
|
5693
5693
|
return (/workflow graph CHANGED after the run was queued/i.test(text) &&
|
|
5694
5694
|
/Nothing was queued/i.test(text));
|
|
5695
5695
|
}
|
|
5696
|
+
/**
|
|
5697
|
+
* #2120 — an older panel can decorate a fixed seed while it builds the deferred
|
|
5698
|
+
* run prompt. That can make the same scoped run hit the certified stamp race more
|
|
5699
|
+
* than once. The panel still has to identify the changed entry as a seed; this is
|
|
5700
|
+
* deliberately narrower than allowing an arbitrary third dispatch.
|
|
5701
|
+
*/
|
|
5702
|
+
const MAX_SCOPED_STAMP_RACE_RETRIES = 2;
|
|
5703
|
+
function isSeedRunToNodeStampRace(res, rejection) {
|
|
5704
|
+
return (isRetryableRunToNodeStampRace(res, rejection) &&
|
|
5705
|
+
/\bdiffering\b[\s\S]{0,160}\bseed\b/i.test(toolResultText(rejection)));
|
|
5706
|
+
}
|
|
5696
5707
|
export const __panelRunTestHooks = {
|
|
5697
5708
|
detectRunRejection,
|
|
5698
5709
|
formatRunRejection,
|
|
5699
5710
|
isRetryableRunToNodeStampRace,
|
|
5711
|
+
isSeedRunToNodeStampRace,
|
|
5700
5712
|
describeDroppedOutputs,
|
|
5701
5713
|
};
|
|
5702
5714
|
/** Drop a trailing .json (case-insensitive) so filename/path forms compare equal. */
|
|
@@ -13276,15 +13288,25 @@ export function buildPanelToolDefs() {
|
|
|
13276
13288
|
// "you'll be notified automatically" guidance. Only a genuine queue
|
|
13277
13289
|
// gets the anti-poll note below.
|
|
13278
13290
|
let rejection = detectRunRejection(res);
|
|
13279
|
-
// #772 —
|
|
13280
|
-
//
|
|
13281
|
-
//
|
|
13282
|
-
//
|
|
13291
|
+
// #772/#2120 — re-issue only the scoped-run stamp race the panel explicitly
|
|
13292
|
+
// certifies as not-queued. Gated on OUR OWN args (this really was a scoped run)
|
|
13293
|
+
// and on the panel having ANSWERED, so an unknown outcome is never retried.
|
|
13294
|
+
// The ordinary race gets one re-issue. A repeated race gets ONE additional
|
|
13295
|
+
// chance only when the panel names a differing seed entry — the fixed-seed
|
|
13296
|
+
// decoration race reported in #2120. Every attempt still passes the panel's
|
|
13297
|
+
// graph-stamp check independently; this is not a bypass or a blind mutation
|
|
13298
|
+
// retry.
|
|
13283
13299
|
let scopeRebuilt = false;
|
|
13284
|
-
|
|
13300
|
+
let scopeRetryCount = 0;
|
|
13301
|
+
while (rejection &&
|
|
13285
13302
|
typeof args.to_node_id === "number" &&
|
|
13286
|
-
isRetryableRunToNodeStampRace(res, rejection)
|
|
13303
|
+
isRetryableRunToNodeStampRace(res, rejection) &&
|
|
13304
|
+
(scopeRetryCount === 0 ||
|
|
13305
|
+
(scopeRetryCount < MAX_SCOPED_STAMP_RACE_RETRIES &&
|
|
13306
|
+
isSeedRunToNodeStampRace(res, rejection)))) {
|
|
13287
13307
|
scopeRebuilt = true;
|
|
13308
|
+
scopeRetryCount += 1;
|
|
13309
|
+
let retryResultReceived = false;
|
|
13288
13310
|
try {
|
|
13289
13311
|
// #1050 — SETTLE before re-issuing. The panel refuses this race when the
|
|
13290
13312
|
// graph changed between dispatch and apply, and re-dispatching in the
|
|
@@ -13306,6 +13328,7 @@ export function buildPanelToolDefs() {
|
|
|
13306
13328
|
// prompt id rather than allowing that stale arm to be synthesized (#2021).
|
|
13307
13329
|
runDispatchedAt = Date.now();
|
|
13308
13330
|
res = await ctx.call(runCmd, 20000, observeRunRid);
|
|
13331
|
+
retryResultReceived = true;
|
|
13309
13332
|
// #1175 — the re-issue can miss its window exactly as the first
|
|
13310
13333
|
// dispatch can, and this is the one whose outcome is genuinely open
|
|
13311
13334
|
// (the first was CERTIFIED to have queued nothing). Reconcile it on
|
|
@@ -13314,17 +13337,37 @@ export function buildPanelToolDefs() {
|
|
|
13314
13337
|
rejection = detectRunRejection(res);
|
|
13315
13338
|
}
|
|
13316
13339
|
catch (err) {
|
|
13340
|
+
// A bridge/late-receipt failure after ctx.call already returned must not
|
|
13341
|
+
// erase the retry's own result (notably its retry_of token). Preserve it
|
|
13342
|
+
// verbatim and stop: no further dispatch is justified by a failed local
|
|
13343
|
+
// reconciliation step.
|
|
13344
|
+
if (retryResultReceived) {
|
|
13345
|
+
return appendToolResultText(res, `\n\n(Dispatch history: the retry dispatch returned the result above, but local ` +
|
|
13346
|
+
`late-ack reconciliation failed before this handler could finish ` +
|
|
13347
|
+
`interpreting it. That result is preserved and no further dispatch was ` +
|
|
13348
|
+
`made. Do not infer an additional queue entry from the reconciliation ` +
|
|
13349
|
+
`failure alone. (${err instanceof Error ? err.message : String(err)})`);
|
|
13350
|
+
}
|
|
13317
13351
|
// ctx.call settles every panel/transport failure into a ToolResult and does
|
|
13318
13352
|
// not throw today — but this await is the one point where a throw would
|
|
13319
|
-
// DESTROY evidence we already hold: that
|
|
13320
|
-
// not-queued, and that
|
|
13321
|
-
// unknown. Propagating the raw throw would lose both and invite a
|
|
13322
|
-
// dispatch. Report what we observed, claim nothing we did not.
|
|
13323
|
-
|
|
13324
|
-
`
|
|
13325
|
-
|
|
13326
|
-
|
|
13327
|
-
|
|
13353
|
+
// DESTROY evidence we already hold: that every prior dispatch was
|
|
13354
|
+
// certified not-queued, and that this dispatch went out whose outcome is
|
|
13355
|
+
// now unknown. Propagating the raw throw would lose both and invite a
|
|
13356
|
+
// blind dispatch. Report what we observed, claim nothing we did not.
|
|
13357
|
+
if (scopeRetryCount === 1) {
|
|
13358
|
+
return fail(`panel_run re-issued the scoped run after the panel's certified run-to-node ` +
|
|
13359
|
+
`stamp race, and that SECOND dispatch failed before any reply could be read — ` +
|
|
13360
|
+
`its outcome is UNKNOWN and it may have queued a render. The FIRST dispatch was ` +
|
|
13361
|
+
`certified by the panel to have queued nothing. Do NOT re-run blindly: check the ` +
|
|
13362
|
+
`queue (action:"list") or get_history before deciding. (${err instanceof Error ? err.message : String(err)})`);
|
|
13363
|
+
}
|
|
13364
|
+
return fail(`panel_run re-issued the scoped run ${scopeRetryCount} times after the panel ` +
|
|
13365
|
+
`certified each prior run-to-node stamp race as not-queued, and the ` +
|
|
13366
|
+
`dispatch ${scopeRetryCount + 1} failed before any reply could be read — ` +
|
|
13367
|
+
`its outcome is UNKNOWN and it may have queued a render. The first ` +
|
|
13368
|
+
`${scopeRetryCount} dispatches were certified by the panel to have queued ` +
|
|
13369
|
+
`nothing. Do NOT re-run blindly: check the queue (action:"list") or ` +
|
|
13370
|
+
`get_history before deciding. (${err instanceof Error ? err.message : String(err)})`);
|
|
13328
13371
|
}
|
|
13329
13372
|
}
|
|
13330
13373
|
if (rejection) {
|
|
@@ -13341,14 +13384,24 @@ export function buildPanelToolDefs() {
|
|
|
13341
13384
|
// cannot tell whether these are one event or two.
|
|
13342
13385
|
if (!scopeRebuilt)
|
|
13343
13386
|
return lateAckNote ? appendToolResultText(rejection, lateAckNote) : rejection;
|
|
13344
|
-
return appendToolResultText(rejection,
|
|
13345
|
-
|
|
13346
|
-
|
|
13347
|
-
|
|
13348
|
-
|
|
13349
|
-
|
|
13350
|
-
|
|
13351
|
-
|
|
13387
|
+
return appendToolResultText(rejection, scopeRetryCount === 1
|
|
13388
|
+
? `\n\n(Dispatch history: the first graph_run was refused by the panel's run-to-node ` +
|
|
13389
|
+
`graph-stamp race, which CERTIFIED that nothing was queued, so the scoped run was ` +
|
|
13390
|
+
`re-issued exactly once — after a short pause to let pending graph edits land ` +
|
|
13391
|
+
`(#1050). The failure above is that SECOND dispatch; it was not retried again. ` +
|
|
13392
|
+
`Judge whether anything was queued from that message alone — the first dispatch ` +
|
|
13393
|
+
`definitely queued nothing. Racing AGAIN after the pause means the graph is still ` +
|
|
13394
|
+
`changing under the run: let the canvas settle, then re-run.)` +
|
|
13395
|
+
lateAckNote
|
|
13396
|
+
: `\n\n(Dispatch history: the first ${scopeRetryCount} graph_run dispatches were each ` +
|
|
13397
|
+
`refused by the panel's run-to-node graph-stamp race, and each CERTIFIED ` +
|
|
13398
|
+
`that nothing was queued. The scoped run was re-issued ${scopeRetryCount} ` +
|
|
13399
|
+
`times after short pauses to let pending graph edits land (#1050). The ` +
|
|
13400
|
+
`failure above is dispatch ${scopeRetryCount + 1}; it was not retried again. ` +
|
|
13401
|
+
`Judge whether anything was queued from that message alone — the first ` +
|
|
13402
|
+
`${scopeRetryCount} dispatches definitely queued nothing. Let the canvas ` +
|
|
13403
|
+
`settle, then re-run.)` +
|
|
13404
|
+
lateAckNote);
|
|
13352
13405
|
}
|
|
13353
13406
|
// Attribute this genuine queue to ourselves so a later panel_run in the
|
|
13354
13407
|
// same batch recognizes the in-flight job as our own and doesn't false-warn
|
|
@@ -13479,22 +13532,28 @@ export function buildPanelToolDefs() {
|
|
|
13479
13532
|
// clear_pending remedy that would wipe the user's whole batch (#559). A
|
|
13480
13533
|
// genuinely stalled render is caught by the turn-start stall notice, which
|
|
13481
13534
|
// does the staleness gating and keeps the interrupt guidance.
|
|
13482
|
-
// #772 — never report a dispatch history the caller did not see.
|
|
13483
|
-
//
|
|
13484
|
-
//
|
|
13535
|
+
// #772/#2120 — never report a dispatch history the caller did not see. Say
|
|
13536
|
+
// exactly which earlier dispatches were certified clean, so the agent does
|
|
13537
|
+
// not read a refusal (if it surfaces in a log) as a separate queued job.
|
|
13485
13538
|
//
|
|
13486
13539
|
// It says only what was OBSERVED (codex gate). An earlier draft said "exactly one
|
|
13487
13540
|
// render was queued" — but `batch_count` is "times to queue", so a successful
|
|
13488
13541
|
// dispatch can enqueue several, and the panel reports one prompt id, not a count.
|
|
13489
|
-
// The certified fact is about DISPATCHES, not renders: the
|
|
13490
|
-
// so everything in the queue came from the
|
|
13491
|
-
const retryNote =
|
|
13492
|
-
? "
|
|
13493
|
-
|
|
13494
|
-
"
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13542
|
+
// The certified fact is about DISPATCHES, not renders: the prior dispatches
|
|
13543
|
+
// queued nothing, so everything in the queue came from the final dispatch.
|
|
13544
|
+
const retryNote = scopeRetryCount === 0
|
|
13545
|
+
? ""
|
|
13546
|
+
: scopeRetryCount === 1
|
|
13547
|
+
? "\n\n[NOTE] The first dispatch of this scoped run was refused by the panel's run-to-node " +
|
|
13548
|
+
"graph-stamp race (the graph changed between dispatch and apply); the panel certified that " +
|
|
13549
|
+
"nothing was queued, so the scope was rebuilt and re-issued once, and THAT is the run above. " +
|
|
13550
|
+
"The first dispatch contributed NOTHING to the queue, so whatever this run queued was " +
|
|
13551
|
+
"queued once, not twice."
|
|
13552
|
+
: `\n\n[NOTE] The first ${scopeRetryCount} dispatches of this scoped run were refused by the ` +
|
|
13553
|
+
`panel's run-to-node graph-stamp race (the graph changed between dispatch and apply), ` +
|
|
13554
|
+
`and each was certified to have queued NOTHING. The scope was rebuilt and re-issued ` +
|
|
13555
|
+
`${scopeRetryCount} times, and THAT is the run above. Whatever this run queued came ` +
|
|
13556
|
+
`from the final dispatch; the earlier dispatches contributed NOTHING to the queue.`;
|
|
13498
13557
|
let warn = "";
|
|
13499
13558
|
if (pre.connected && pre.running) {
|
|
13500
13559
|
const pending = Math.max(0, pre.queueDepth - 1);
|