@openclaw/comfy-provider 2026.9.2 → 2026.9.4

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.
@@ -6,8 +6,7 @@ import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
6
6
  import { resolvePositiveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
7
7
  import { isProviderApiKeyConfigured } from "openclaw/plugin-sdk/provider-auth";
8
8
  import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth-runtime";
9
- import { assertOkOrThrowHttpError, normalizeBaseUrl, readProviderJsonResponse, redactProviderResponseErrorText, resolveProviderHttpRequestConfig } from "openclaw/plugin-sdk/provider-http";
10
- import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
9
+ import { assertOkOrThrowHttpError, normalizeBaseUrl, readProviderBinaryResponse, readProviderJsonResponse, redactProviderResponseErrorText, resolveProviderHttpRequestConfig } from "openclaw/plugin-sdk/provider-http";
11
10
  import { normalizeSecretInputString, resolveConfiguredSecretInputString, resolveSecretInputString } from "openclaw/plugin-sdk/secret-input-runtime";
12
11
  import { canResolveEnvSecretRefInReadOnlyPath } from "openclaw/plugin-sdk/secret-ref-readonly";
13
12
  import { fetchWithSsrFGuard, isPrivateOrLoopbackHost, mergeSsrFPolicies, ssrfPolicyFromHttpBaseUrlAllowedOrigin } from "openclaw/plugin-sdk/ssrf-runtime";
@@ -218,49 +217,32 @@ function extractHistoryEntry(history, promptId) {
218
217
  if (isRecord(nested)) return nested;
219
218
  return null;
220
219
  }
221
- async function waitForLocalHistory(params) {
222
- const deadline = Date.now() + params.timeoutMs;
223
- for (;;) {
224
- const requestTimeoutMs = resolveComfyRemainingMs(deadline, params.timeoutMs);
225
- const entry = extractHistoryEntry(await readJsonResponse({
226
- url: `${params.baseUrl}/history/${params.promptId}`,
227
- init: {
228
- method: "GET",
229
- headers: params.headers
230
- },
231
- timeoutMs: requestTimeoutMs,
232
- policy: params.policy,
233
- dispatcherPolicy: params.dispatcherPolicy,
234
- auditContext: "comfy-history",
235
- errorPrefix: "Comfy history lookup failed"
236
- }), params.promptId);
237
- if (entry?.outputs && Object.keys(entry.outputs).length > 0) return entry;
238
- const pollDelayMs = resolveComfyRemainingMs(deadline, params.timeoutMs, params.pollIntervalMs);
239
- await new Promise((resolve) => {
240
- setTimeout(resolve, pollDelayMs);
241
- });
242
- }
243
- }
244
- async function waitForCloudCompletion(params) {
220
+ async function waitForComfyHistory(params) {
245
221
  const deadline = Date.now() + params.timeoutMs;
222
+ const read = (path, kind, timeoutMs) => readJsonResponse({
223
+ url: `${params.baseUrl}${path}`,
224
+ init: {
225
+ method: "GET",
226
+ headers: params.headers
227
+ },
228
+ timeoutMs,
229
+ policy: params.policy,
230
+ dispatcherPolicy: params.dispatcherPolicy,
231
+ auditContext: `comfy-${kind}`,
232
+ errorPrefix: `Comfy ${kind} lookup failed`
233
+ });
246
234
  for (;;) {
247
235
  const requestTimeoutMs = resolveComfyRemainingMs(deadline, params.timeoutMs);
248
- const status = await readJsonResponse({
249
- url: `${params.baseUrl}/api/job/${params.promptId}/status`,
250
- init: {
251
- method: "GET",
252
- headers: params.headers
253
- },
254
- timeoutMs: requestTimeoutMs,
255
- policy: params.policy,
256
- dispatcherPolicy: params.dispatcherPolicy,
257
- auditContext: "comfy-status",
258
- errorPrefix: "Comfy status lookup failed"
259
- });
260
- if (status.status === "completed") return;
261
- if (status.status === "failed" || status.status === "cancelled") {
262
- const detail = redactProviderResponseErrorText(status.error ?? status.message ?? params.promptId, params.headers);
263
- throw new Error(`Comfy workflow ${status.status}: ${detail}`);
236
+ if (params.mode === "cloud") {
237
+ const status = await read(`/api/job/${params.promptId}/status`, "status", requestTimeoutMs);
238
+ if (status.status === "completed") return await read(`/api/history_v2/${params.promptId}`, "history", params.timeoutMs);
239
+ if (status.status === "failed" || status.status === "cancelled") {
240
+ const detail = redactProviderResponseErrorText(status.error ?? status.message ?? params.promptId, params.headers);
241
+ throw new Error(`Comfy workflow ${status.status}: ${detail}`);
242
+ }
243
+ } else {
244
+ const entry = extractHistoryEntry(await read(`/history/${params.promptId}`, "history", requestTimeoutMs), params.promptId);
245
+ if (entry?.outputs && Object.keys(entry.outputs).length > 0) return entry;
264
246
  }
265
247
  const pollDelayMs = resolveComfyRemainingMs(deadline, params.timeoutMs, params.pollIntervalMs);
266
248
  await new Promise((resolve) => {
@@ -323,11 +305,13 @@ async function downloadOutputFile(params) {
323
305
  try {
324
306
  await assertOkOrThrowHttpError(firstResponse.response, "Comfy output download failed", { requestHeaders: params.headers });
325
307
  const mimeType = normalizeOptionalString(firstResponse.response.headers.get("content-type")) || "application/octet-stream";
308
+ const downloadLabel = `Comfy ${params.capability} output download`;
326
309
  return {
327
- buffer: await readResponseWithLimit(firstResponse.response, params.maxBytes, {
310
+ buffer: await readProviderBinaryResponse(firstResponse.response, downloadLabel, params.capability, {
311
+ maxBytes: params.maxBytes,
328
312
  chunkTimeoutMs: params.timeoutMs,
329
- onOverflow: ({ maxBytes }) => /* @__PURE__ */ new Error(`Comfy ${params.capability} output download exceeds ${maxBytes} bytes`),
330
- onIdleTimeout: ({ chunkTimeoutMs }) => /* @__PURE__ */ new Error(`Comfy ${params.capability} output download stalled after ${chunkTimeoutMs}ms`)
313
+ onOverflow: ({ maxBytes }) => /* @__PURE__ */ new Error(`${downloadLabel} exceeds ${maxBytes} bytes`),
314
+ onIdleTimeout: ({ chunkTimeoutMs }) => /* @__PURE__ */ new Error(`${downloadLabel} stalled after ${chunkTimeoutMs}ms`)
331
315
  }),
332
316
  mimeType
333
317
  };
@@ -465,36 +449,15 @@ async function runComfyWorkflow(params) {
465
449
  });
466
450
  const promptId = normalizeOptionalString(promptResponse.prompt_id);
467
451
  if (!promptId) throw new Error("Comfy workflow submit response missing prompt_id");
468
- const historyEntry = extractHistoryEntry(mode === "cloud" ? await (async () => {
469
- await waitForCloudCompletion({
470
- baseUrl: normalizedBaseUrl,
471
- promptId,
472
- headers: new Headers(headers),
473
- timeoutMs,
474
- pollIntervalMs,
475
- policy: networkPolicy.apiPolicy,
476
- dispatcherPolicy
477
- });
478
- return await readJsonResponse({
479
- url: `${normalizedBaseUrl}/api/history_v2/${promptId}`,
480
- init: {
481
- method: "GET",
482
- headers: new Headers(headers)
483
- },
484
- timeoutMs,
485
- policy: networkPolicy.apiPolicy,
486
- dispatcherPolicy,
487
- auditContext: "comfy-history",
488
- errorPrefix: "Comfy history lookup failed"
489
- });
490
- })() : await waitForLocalHistory({
452
+ const historyEntry = extractHistoryEntry(await waitForComfyHistory({
491
453
  baseUrl: normalizedBaseUrl,
492
454
  promptId,
493
455
  headers: new Headers(headers),
494
456
  timeoutMs,
495
457
  pollIntervalMs,
496
458
  policy: networkPolicy.apiPolicy,
497
- dispatcherPolicy
459
+ dispatcherPolicy,
460
+ mode
498
461
  }), promptId);
499
462
  if (!historyEntry) throw new Error(`Comfy history response missing outputs for prompt ${promptId}`);
500
463
  const outputFiles = collectOutputFiles({
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "id": "comfy",
3
+ "categories": ["models", "media"],
3
4
  "activation": {
4
5
  "onStartup": false
5
6
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/comfy-provider",
3
- "version": "2026.9.2",
3
+ "version": "2026.9.4",
4
4
  "description": "OpenClaw ComfyUI provider plugin.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,10 +18,10 @@
18
18
  "minHostVersion": ">=2026.7.2"
19
19
  },
20
20
  "compat": {
21
- "pluginApi": ">=2026.9.2"
21
+ "pluginApi": ">=2026.9.4"
22
22
  },
23
23
  "build": {
24
- "openclawVersion": "2026.9.2",
24
+ "openclawVersion": "2026.9.4",
25
25
  "bundledDist": false
26
26
  },
27
27
  "release": {
@@ -38,7 +38,7 @@
38
38
  "README.md"
39
39
  ],
40
40
  "peerDependencies": {
41
- "openclaw": ">=2026.9.2"
41
+ "openclaw": ">=2026.9.4"
42
42
  },
43
43
  "peerDependenciesMeta": {
44
44
  "openclaw": {