comfyui-mcp 0.50.21 → 0.50.23
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.
- package/dist/comfyui/cloud-client.js +97 -8
- package/dist/comfyui/cloud-client.js.map +1 -1
- package/dist/comfyui/fetch.js +71 -7
- package/dist/comfyui/fetch.js.map +1 -1
- package/dist/orchestrator/panel-tools.js +69 -10
- package/dist/orchestrator/panel-tools.js.map +1 -1
- package/dist/services/secure-bridge.js +11 -0
- package/dist/services/secure-bridge.js.map +1 -1
- package/dist/services/ui-bridge.js +35 -2
- package/dist/services/ui-bridge.js.map +1 -1
- package/package.json +1 -1
- package/scripts/export-vocabulary.mts +12 -4
- package/scripts/smoke-install.mjs +134 -3
- package/scripts/tools-dump.mts +48 -2
|
@@ -11,7 +11,12 @@
|
|
|
11
11
|
// with `fetchImage` / `uploadImageHttp` added so our existing image tools
|
|
12
12
|
// keep working in cloud mode.
|
|
13
13
|
import { getApiKey, getCloudUrl } from "../config.js";
|
|
14
|
-
|
|
14
|
+
// Shared with the headless client on purpose: one ceiling, one delivery-doubt
|
|
15
|
+
// rule. The cloud client is a parallel implementation, and the last two rounds of
|
|
16
|
+
// hardening (the 0.50.11 timeout ceiling, the delivery-doubt disclosure) reached
|
|
17
|
+
// only its twin — which is exactly how a parallel implementation rots.
|
|
18
|
+
import { comfyHttpTimeoutSeconds, defaultComfyTimeoutSignal, deliveryDoubt, isTimeoutAbort, } from "./fetch.js";
|
|
19
|
+
import { ComfyUIError, ConnectionError, describeFetchFailure } from "../utils/errors.js";
|
|
15
20
|
import { logger } from "../utils/logger.js";
|
|
16
21
|
function cloudUrl(path) {
|
|
17
22
|
const base = getCloudUrl().replace(/\/+$/, "");
|
|
@@ -30,8 +35,14 @@ async function cloudFetch(path, init) {
|
|
|
30
35
|
...authHeaders(baseHeaders),
|
|
31
36
|
...(init?.headers ?? {}),
|
|
32
37
|
};
|
|
38
|
+
const method = String(init?.method ?? "GET").toUpperCase();
|
|
39
|
+
// A CEILING, not a policy — the same one comfyuiFetch got in 0.50.11, which this
|
|
40
|
+
// client never inherited. Without it a cloud request that never answers hangs the
|
|
41
|
+
// tool call forever: no timeout, no error, nothing for the caller to act on. A
|
|
42
|
+
// caller's own signal always wins.
|
|
43
|
+
const signal = init?.signal ?? defaultComfyTimeoutSignal();
|
|
33
44
|
try {
|
|
34
|
-
const res = await fetch(url, { ...init, headers });
|
|
45
|
+
const res = await fetch(url, { ...init, headers, signal });
|
|
35
46
|
if (!res.ok) {
|
|
36
47
|
const body = await res.text().catch(() => "");
|
|
37
48
|
throw new ComfyUIError(`Cloud API error: ${res.status} ${res.statusText} — ${body.slice(0, 500)}`, "CLOUD_API_ERROR", { url, status: res.status });
|
|
@@ -41,7 +52,24 @@ async function cloudFetch(path, init) {
|
|
|
41
52
|
catch (err) {
|
|
42
53
|
if (err instanceof ComfyUIError)
|
|
43
54
|
throw err;
|
|
44
|
-
|
|
55
|
+
// Our own ceiling firing is not the same event as a caller's abort, and must
|
|
56
|
+
// not be reported as one. Only rewrite when WE supplied the signal.
|
|
57
|
+
if (init?.signal === undefined && isTimeoutAbort(err)) {
|
|
58
|
+
throw new ConnectionError(`No reply from Comfy Cloud within ${comfyHttpTimeoutSeconds()}s — while requesting ` +
|
|
59
|
+
`${url} (${method}).` +
|
|
60
|
+
deliveryDoubt(undefined, method) +
|
|
61
|
+
` Raise COMFYUI_MCP_HTTP_TIMEOUT_S if the cloud is simply slow.`);
|
|
62
|
+
}
|
|
63
|
+
// "Failed to reach" was a claim, not an observation. A transport error on a
|
|
64
|
+
// POST to /api/prompt does not establish that the submission never landed —
|
|
65
|
+
// and a blind retry there bills a SECOND cloud render. Same three states as
|
|
66
|
+
// the headless client: delivered, definitely not delivered, unknown.
|
|
67
|
+
const { message, code } = describeFetchFailure(err);
|
|
68
|
+
const wrapped = new ConnectionError(`Could not complete the ${method} to Comfy Cloud at ${url}: ${message}.` +
|
|
69
|
+
deliveryDoubt(code, method));
|
|
70
|
+
if (code)
|
|
71
|
+
wrapped.code = code;
|
|
72
|
+
throw wrapped;
|
|
45
73
|
}
|
|
46
74
|
}
|
|
47
75
|
export async function enqueuePrompt(workflow, extraData) {
|
|
@@ -73,13 +101,47 @@ export async function getHistory(promptId) {
|
|
|
73
101
|
}
|
|
74
102
|
return {};
|
|
75
103
|
}
|
|
104
|
+
/** HTTP statuses that mean "this cloud has no such endpoint" rather than "the
|
|
105
|
+
* request failed". Only these may fall back to the placeholder. */
|
|
106
|
+
const ENDPOINT_ABSENT_STATUSES = new Set([404, 405, 501]);
|
|
107
|
+
/**
|
|
108
|
+
* #1070 — the catch here used to swallow EVERYTHING and return an invented
|
|
109
|
+
* device, so an expired API key, a 402, a DNS failure, a timeout and a network
|
|
110
|
+
* partition all came back looking like a successful health check.
|
|
111
|
+
*
|
|
112
|
+
* That mattered more than a mislabelled outcome usually does, for two reasons.
|
|
113
|
+
* `get_system_stats (action:"health")` is the remedy our own error messages send
|
|
114
|
+
* people to — it is named in describeComfyFetchFailure, in the timeout text, and
|
|
115
|
+
* in this file's messages — so in cloud mode the remedy could not return a
|
|
116
|
+
* negative result. And health-check.ts / local-models-fallback.ts both call this
|
|
117
|
+
* as a REACHABILITY PROBE, which the placeholder answered "yes" to unconditionally.
|
|
118
|
+
*
|
|
119
|
+
* It also fabricated data rather than merely mislabelling it: `vram_total: 0` is
|
|
120
|
+
* not a reading, and a caller sizing a job against it is reading an invention.
|
|
121
|
+
*
|
|
122
|
+
* Three states now, not two:
|
|
123
|
+
* - answered → return what the endpoint said
|
|
124
|
+
* - endpoint ABSENT (404) → the placeholder, which is the case this was written
|
|
125
|
+
* for, but named so a reader can see it is not a reading
|
|
126
|
+
* - could not ask → propagate, because that is a real failure
|
|
127
|
+
*/
|
|
76
128
|
export async function getSystemStats() {
|
|
77
129
|
try {
|
|
78
130
|
const res = await cloudFetch("/system_stats");
|
|
79
131
|
return (await res.json());
|
|
80
132
|
}
|
|
81
|
-
catch {
|
|
82
|
-
|
|
133
|
+
catch (err) {
|
|
134
|
+
const status = err instanceof ComfyUIError && err.details && typeof err.details === "object"
|
|
135
|
+
? err.details.status
|
|
136
|
+
: undefined;
|
|
137
|
+
if (typeof status !== "number" || !ENDPOINT_ABSENT_STATUSES.has(status)) {
|
|
138
|
+
// Auth, billing, transport, timeout — a real failure. The caller asked
|
|
139
|
+
// whether the cloud is reachable; inventing a GPU is not an answer.
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
logger.info("Cloud: /system_stats not implemented by this cloud, returning placeholder", {
|
|
143
|
+
status,
|
|
144
|
+
});
|
|
83
145
|
return {
|
|
84
146
|
system: {
|
|
85
147
|
os: "cloud",
|
|
@@ -89,7 +151,9 @@ export async function getSystemStats() {
|
|
|
89
151
|
},
|
|
90
152
|
devices: [
|
|
91
153
|
{
|
|
92
|
-
|
|
154
|
+
// Named, not silent: these are placeholders, not measurements. The
|
|
155
|
+
// "Comfy Cloud GPU" prefix is kept so anything matching on it still does.
|
|
156
|
+
name: "Comfy Cloud GPU (no stats endpoint — values below are placeholders, not readings)",
|
|
93
157
|
type: "cloud",
|
|
94
158
|
index: 0,
|
|
95
159
|
vram_total: 0,
|
|
@@ -159,8 +223,33 @@ export async function getLogs() {
|
|
|
159
223
|
export async function fetchImage(filename, type = "output", subfolder = "") {
|
|
160
224
|
const params = new URLSearchParams({ filename, type, subfolder });
|
|
161
225
|
const url = cloudUrl(`/api/view?${params.toString()}`);
|
|
162
|
-
// /api/view returns either bytes or a 302 to a signed URL
|
|
163
|
-
|
|
226
|
+
// /api/view returns either bytes or a 302 to a signed URL, which is why this
|
|
227
|
+
// does NOT go through cloudFetch: it needs redirect-following and raw bytes
|
|
228
|
+
// rather than the JSON envelope. That exemption is also how it kept the bare,
|
|
229
|
+
// signal-less `fetch` that #1069 removed from cloudFetch one call over — a
|
|
230
|
+
// download from a wedged cloud hung the tool call with nothing to act on.
|
|
231
|
+
let res;
|
|
232
|
+
try {
|
|
233
|
+
res = await fetch(url, {
|
|
234
|
+
headers: authHeaders(),
|
|
235
|
+
redirect: "follow",
|
|
236
|
+
signal: defaultComfyTimeoutSignal(),
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
if (isTimeoutAbort(err)) {
|
|
241
|
+
throw new ConnectionError(`No reply from Comfy Cloud within ${comfyHttpTimeoutSeconds()}s while downloading ` +
|
|
242
|
+
`"${filename}" — ${url} (GET). Nothing was learned about the image from this: a ` +
|
|
243
|
+
`timeout is not a "not found". Raise COMFYUI_MCP_HTTP_TIMEOUT_S if the cloud is ` +
|
|
244
|
+
`simply slow.`);
|
|
245
|
+
}
|
|
246
|
+
// A read, so no delivery doubt applies — re-requesting an image is safe.
|
|
247
|
+
const { message, code } = describeFetchFailure(err);
|
|
248
|
+
const wrapped = new ConnectionError(`Could not download "${filename}" from Comfy Cloud at ${url}: ${message}.`);
|
|
249
|
+
if (code)
|
|
250
|
+
wrapped.code = code;
|
|
251
|
+
throw wrapped;
|
|
252
|
+
}
|
|
164
253
|
if (!res.ok) {
|
|
165
254
|
throw new ComfyUIError(`Cloud /api/view ${res.status} for "${filename}"`, "CLOUD_API_ERROR", { status: res.status });
|
|
166
255
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-client.js","sourceRoot":"","sources":["../../src/comfyui/cloud-client.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,wEAAwE;AACxE,2EAA2E;AAC3E,iEAAiE;AACjE,6EAA6E;AAC7E,qCAAqC;AACrC,EAAE;AACF,uEAAuE;AACvE,2EAA2E;AAC3E,4EAA4E;AAC5E,0EAA0E;AAC1E,8BAA8B;AAE9B,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"cloud-client.js","sourceRoot":"","sources":["../../src/comfyui/cloud-client.ts"],"names":[],"mappings":"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"}
|
package/dist/comfyui/fetch.js
CHANGED
|
@@ -13,6 +13,11 @@ function targetOf(input) {
|
|
|
13
13
|
return String(input);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
/** The request's HTTP method, uppercased. `init.method` wins over a Request's own,
|
|
17
|
+
* matching what fetch itself does when both are supplied. */
|
|
18
|
+
function methodOf(input, init) {
|
|
19
|
+
return String(init.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
20
|
+
}
|
|
16
21
|
/**
|
|
17
22
|
* What the CONNECTED panels front, for the drift comparison below (#952).
|
|
18
23
|
*
|
|
@@ -96,10 +101,69 @@ function describeTargetDrift(target) {
|
|
|
96
101
|
* the browser is on, while these calls go to the configured COMFYUI_URL. That is
|
|
97
102
|
* not a bug, but it is invisible unless the failure names the address — and,
|
|
98
103
|
* where the bridge can tell us, says whether the two actually differ.
|
|
104
|
+
*
|
|
105
|
+
* Header for the three pieces below: the never-delivered code set, the delivery
|
|
106
|
+
* doubt it gates, and describeComfyFetchFailure itself.
|
|
99
107
|
*/
|
|
100
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Failure codes that prove the request was NEVER DELIVERED.
|
|
110
|
+
*
|
|
111
|
+
* Each one fires before any byte of the request could reach the application: the
|
|
112
|
+
* connection was refused, the name never resolved, the TLS handshake failed, or
|
|
113
|
+
* the URL was rejected locally. On these the server cannot have acted, so saying
|
|
114
|
+
* so is accurate and a retry is safe.
|
|
115
|
+
*
|
|
116
|
+
* Everything else is deliberately NOT listed. ECONNRESET, EPIPE, "socket hang up"
|
|
117
|
+
* and UND_ERR_SOCKET all fire on an ESTABLISHED connection, which is precisely the
|
|
118
|
+
* case where ComfyUI may have received and acted on the request before the socket
|
|
119
|
+
* died. The default for an unrecognised code is therefore "may have been
|
|
120
|
+
* delivered": a spurious "verify first" costs one extra read, while a spurious
|
|
121
|
+
* "it never arrived" costs a duplicate render.
|
|
122
|
+
*/
|
|
123
|
+
const NEVER_DELIVERED_CODES = new Set([
|
|
124
|
+
"ECONNREFUSED",
|
|
125
|
+
"ENOTFOUND",
|
|
126
|
+
"EAI_AGAIN",
|
|
127
|
+
"ERR_INVALID_URL",
|
|
128
|
+
"ERR_UNSUPPORTED_PROTOCOL",
|
|
129
|
+
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
130
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
131
|
+
"SELF_SIGNED_CERT_IN_CHAIN",
|
|
132
|
+
"CERT_HAS_EXPIRED",
|
|
133
|
+
"ERR_TLS_CERT_ALTNAME_INVALID",
|
|
134
|
+
]);
|
|
135
|
+
/**
|
|
136
|
+
* The transport-failure twin of describeComfyTimeout's OUTCOME UNKNOWN.
|
|
137
|
+
*
|
|
138
|
+
* A timeout on a POST already warned that /prompt may have queued the render
|
|
139
|
+
* before the reply was lost. A CONNECTION ERROR on that same POST carries the
|
|
140
|
+
* identical risk — an ECONNRESET after the server accepted and enqueued the
|
|
141
|
+
* prompt is indistinguishable, at this layer, from one before it — yet the
|
|
142
|
+
* message said only "confirm the server is up", which reads as "it never got
|
|
143
|
+
* there". The caller retries and the render is queued twice, on the single most
|
|
144
|
+
* expensive operation this client makes.
|
|
145
|
+
*
|
|
146
|
+
* Only suppressed when the code POSITIVELY proves non-delivery, or the method is
|
|
147
|
+
* a read. See NEVER_DELIVERED_CODES for why the default runs the other way.
|
|
148
|
+
*/
|
|
149
|
+
export function deliveryDoubt(code, method) {
|
|
150
|
+
if (method === "GET" || method === "HEAD")
|
|
151
|
+
return "";
|
|
152
|
+
if (code !== undefined && NEVER_DELIVERED_CODES.has(code))
|
|
153
|
+
return "";
|
|
154
|
+
// Says only what is known. Claiming "the connection was established" would be an
|
|
155
|
+
// overclaim for an unrecognised code — the same folding this function exists to
|
|
156
|
+
// undo, merely pointed the other way.
|
|
157
|
+
return (` This ${method} may already have been received and acted on: a transport failure ` +
|
|
158
|
+
`does not establish that the request never arrived. Do NOT blindly re-issue it; ` +
|
|
159
|
+
`check the server's state first (for a queued prompt, queue (action:"list") and ` +
|
|
160
|
+
`get_history (action:"list")).`);
|
|
161
|
+
}
|
|
162
|
+
function describeComfyFetchFailure(err, target, method) {
|
|
101
163
|
const { message, code } = describeFetchFailure(err);
|
|
102
|
-
const wrapped = new Error(`${message} — while requesting ${target}
|
|
164
|
+
const wrapped = new Error(`${message} — while requesting ${target} (${method}).` +
|
|
165
|
+
deliveryDoubt(code, method) +
|
|
166
|
+
` ` +
|
|
103
167
|
`That is the headless ComfyUI target (COMFYUI_URL); a CONNECTED sidebar panel does not imply this address is reachable, ` +
|
|
104
168
|
`because the panel talks to whichever ComfyUI its browser tab is on.` +
|
|
105
169
|
describeTargetDrift(target) +
|
|
@@ -132,15 +196,15 @@ function describeComfyFetchFailure(err, target) {
|
|
|
132
196
|
* request.
|
|
133
197
|
*/
|
|
134
198
|
const DEFAULT_COMFY_HTTP_TIMEOUT_S = 120;
|
|
135
|
-
function comfyHttpTimeoutSeconds() {
|
|
199
|
+
export function comfyHttpTimeoutSeconds() {
|
|
136
200
|
const raw = Number(process.env.COMFYUI_MCP_HTTP_TIMEOUT_S);
|
|
137
201
|
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_COMFY_HTTP_TIMEOUT_S;
|
|
138
202
|
}
|
|
139
|
-
function defaultComfyTimeoutSignal() {
|
|
203
|
+
export function defaultComfyTimeoutSignal() {
|
|
140
204
|
return AbortSignal.timeout(Math.round(comfyHttpTimeoutSeconds() * 1000));
|
|
141
205
|
}
|
|
142
206
|
/** True for an abort raised by AbortSignal.timeout (not a caller's own abort). */
|
|
143
|
-
function isTimeoutAbort(err) {
|
|
207
|
+
export function isTimeoutAbort(err) {
|
|
144
208
|
return err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError");
|
|
145
209
|
}
|
|
146
210
|
/**
|
|
@@ -154,7 +218,7 @@ function isTimeoutAbort(err) {
|
|
|
154
218
|
*/
|
|
155
219
|
function describeComfyTimeout(input, init) {
|
|
156
220
|
const target = targetOf(input);
|
|
157
|
-
const method =
|
|
221
|
+
const method = methodOf(input, init);
|
|
158
222
|
const seconds = comfyHttpTimeoutSeconds();
|
|
159
223
|
const mutating = method !== "GET" && method !== "HEAD";
|
|
160
224
|
const err = new Error(`No reply from ComfyUI within ${seconds}s — while requesting ${target} (${method}). ` +
|
|
@@ -213,7 +277,7 @@ export async function comfyuiFetch(input, init = {}) {
|
|
|
213
277
|
// replacing that text would be a downgrade.
|
|
214
278
|
if (!isBareFetchFailure(err))
|
|
215
279
|
throw err;
|
|
216
|
-
throw describeComfyFetchFailure(err, targetOf(input));
|
|
280
|
+
throw describeComfyFetchFailure(err, targetOf(input), methodOf(input, init));
|
|
217
281
|
}
|
|
218
282
|
}
|
|
219
283
|
//# sourceMappingURL=fetch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/comfyui/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE9E,4EAA4E;AAC5E,SAAS,QAAQ,CAAC,KAA6B;IAC7C,IAAI,CAAC;QACH,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC5C,IAAI,KAAK,YAAY,GAAG;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC;QAC5C,OAAQ,KAAiB,CAAC,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,IAAI,qBAAqB,GAA4B,IAAI,CAAC;AAE1D,6EAA6E;AAC7E,MAAM,UAAU,wBAAwB,CAAC,EAA2B;IAClE,qBAAqB,GAAG,EAAE,CAAC;AAC7B,CAAC;AAED,mFAAmF;AACnF,SAAS,QAAQ,CAAC,MAAc;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAS,mBAAmB,CAAC,MAAc;IACzC,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE;QACpB,IAAI,CAAC;YACH,OAAO,qBAAqB,EAAE,EAAE,IAAI,EAAE,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC,CAAC,4DAA4D;QACzE,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IACL,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACvC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,CACL,qFAAqF;YACrF,yBAAyB,IAAI,oDAAoD;YACjF,gDAAgD,CACjD,CAAC;IACJ,CAAC;IACD,OAAO,CACL,4BAA4B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,uCAAuC;QACtF,0FAA0F;QAC1F,mBAAmB,CACpB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,yBAAyB,CAAC,GAAY,EAAE,MAAc;
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/comfyui/fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -2520,8 +2520,33 @@ refusalCause) {
|
|
|
2520
2520
|
: ` It has no graph command fence; whether graph reads work is unknown, because the ` +
|
|
2521
2521
|
`read that would have told us is the one that failed.`) +
|
|
2522
2522
|
` This is not a rebind — it is an unknown.` +
|
|
2523
|
-
|
|
2524
|
-
|
|
2523
|
+
// #1071 — WHY the read failed decides the remedy, exactly as the
|
|
2524
|
+
// no_identity case below already does. Bucketing them would hand half the
|
|
2525
|
+
// callers an instruction they cannot act on.
|
|
2526
|
+
//
|
|
2527
|
+
// - REFUSED BY THE FENCE: retrying is provably useless. This rebind reads
|
|
2528
|
+
// workflow_list, which the panel fences, so the fence being wrong is
|
|
2529
|
+
// precisely what makes the read fail — every time, forever. A reporter
|
|
2530
|
+
// called this five times over twenty minutes on "retry in a moment" and
|
|
2531
|
+
// lost the canvas for the rest of the task. workflow_open is the one
|
|
2532
|
+
// command the fence EXEMPTS, so it still runs while everything else is
|
|
2533
|
+
// refused, and it now re-derives the fence from its own reply.
|
|
2534
|
+
// - ANY OTHER CAUSE (a dead tab, a transport drop, a busy panel): the
|
|
2535
|
+
// panel is not answering at all, so reopening would fail too and
|
|
2536
|
+
// retrying really is the reachable move.
|
|
2537
|
+
(/workflow instance mismatch/i.test(r.detail)
|
|
2538
|
+
? `\n\nWHAT TO DO: reopen the workflow you want with panel_open_workflow(<path>). ` +
|
|
2539
|
+
`The panel refused the read because of the FENCE itself, so retrying this call ` +
|
|
2540
|
+
`cannot work — it needs the very read the fence blocks. The panel's fence EXEMPTS ` +
|
|
2541
|
+
`workflow_open, so it still runs while everything else is refused, and it ` +
|
|
2542
|
+
`re-derives this session's fence from its own reply. Note panel_list_workflows is ` +
|
|
2543
|
+
`fenced too, so if you do not already know the path, ask the user rather than ` +
|
|
2544
|
+
`guessing. If the canvas you want is an UNSAVED one (a blank workflow you just ` +
|
|
2545
|
+
`created), there is no path to reopen and opening anything else would abandon it — ` +
|
|
2546
|
+
`that case needs the tab refresh below, not a reopen. If reopening also fails: ` +
|
|
2547
|
+
`${RELOAD_TAB_REMEDY}`
|
|
2548
|
+
: `\n\nWHAT TO DO: retry in a moment — a busy or mid-reconnect panel often answers ` +
|
|
2549
|
+
`on the next attempt. If it keeps failing: ${RELOAD_TAB_REMEDY}`) +
|
|
2525
2550
|
`\n\nUNDERLYING CAUSE (quoted verbatim — disregard any rebind advice inside it; ` +
|
|
2526
2551
|
`rebinding is what just failed): ${r.detail}`,
|
|
2527
2552
|
};
|
|
@@ -2621,18 +2646,52 @@ async function refreshOpenWorkflowUuid(ctx, requestedPath, openResult) {
|
|
|
2621
2646
|
: null;
|
|
2622
2647
|
if (!requestedIdentity || requestedIdentity !== openedIdentity)
|
|
2623
2648
|
return;
|
|
2649
|
+
// THREE outcomes for this corroborating read, not two — and conflating the last
|
|
2650
|
+
// two is #1071 (also #932/#1043).
|
|
2651
|
+
//
|
|
2652
|
+
// `workflow_list` is NOT exempt from the panel's fence (activeWorkflowFenceApplies
|
|
2653
|
+
// exempts only canvas-independent ops, workflow_open/new, and non-active-targeted
|
|
2654
|
+
// rename/close). So in exactly the state this refresh exists to repair — a session
|
|
2655
|
+
// fenced to a workflow instance that is no longer active — the read is REFUSED by
|
|
2656
|
+
// the stale fence, the old code took the `return` / `catch`, and the fence was
|
|
2657
|
+
// never refreshed. The recovery was gated behind the one call the wedge blocks.
|
|
2658
|
+
//
|
|
2659
|
+
// The open reply already carries what is needed. The panel publishes
|
|
2660
|
+
// `workflow_uuid` there only after a FINAL SYNCHRONOUS check that `target` is
|
|
2661
|
+
// still the active workflow (#716, activeWorkflowUuidForOpenReply) — omitting it
|
|
2662
|
+
// otherwise, expressly so "the MCP keeps its existing fence fail-closed". It is a
|
|
2663
|
+
// fence-quality value the panel went out of its way to prove; using it when the
|
|
2664
|
+
// read cannot be made is what it is for.
|
|
2665
|
+
let list = null;
|
|
2666
|
+
let readable = false;
|
|
2624
2667
|
try {
|
|
2625
|
-
const
|
|
2626
|
-
if (!
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
refreshWorkflowUuid(ctx, list.active) || refreshWorkflowUuid(ctx, parseToolResultJson(openResult));
|
|
2668
|
+
const res = await ctx.call({ cmd: "workflow_list" }, 6000);
|
|
2669
|
+
if (!res?.isError) {
|
|
2670
|
+
list = parseToolResultJson(res);
|
|
2671
|
+
readable = list !== null;
|
|
2672
|
+
}
|
|
2631
2673
|
}
|
|
2632
2674
|
catch {
|
|
2633
|
-
|
|
2634
|
-
|
|
2675
|
+
readable = false;
|
|
2676
|
+
}
|
|
2677
|
+
if (readable) {
|
|
2678
|
+
// ANSWERED. It either confirms our target is active — prefer the just-read
|
|
2679
|
+
// value, which is fresher than the reply — or it names a DIFFERENT active
|
|
2680
|
+
// workflow, in which case another tab won the slot and adopting our target's
|
|
2681
|
+
// uuid would fence this session to a canvas that is not mounted. Adopt nothing.
|
|
2682
|
+
if (!activeMatchesOpenRefreshTarget(list.active, requestedPath))
|
|
2683
|
+
return;
|
|
2684
|
+
refreshWorkflowUuid(ctx, list.active) || refreshWorkflowUuid(ctx, parsedOpen);
|
|
2685
|
+
return;
|
|
2635
2686
|
}
|
|
2687
|
+
// COULD NOT ASK — the wedged case. Fall back to the reply's proven uuid rather
|
|
2688
|
+
// than leaving the session fenced to a dead instance forever. This is strictly
|
|
2689
|
+
// safer than the alternative it replaces: a stamp the panel proved against its
|
|
2690
|
+
// own active workflow can only authorize commands naming the canvas that is
|
|
2691
|
+
// actually mounted, whereas doing nothing here guarantees every subsequent
|
|
2692
|
+
// command is refused. A reply that carries no uuid (the panel could not prove
|
|
2693
|
+
// it) still refreshes nothing, so fail-closed is preserved.
|
|
2694
|
+
refreshWorkflowUuid(ctx, parsedOpen);
|
|
2636
2695
|
}
|
|
2637
2696
|
/** Exact resolved-path check for an open receipt. A filename/basename is not a
|
|
2638
2697
|
* workflow identity: `other/foo.json` must never confirm `wanted/foo.json`. */
|