diff --git a/src/config/clientFeatureFlags.json b/src/config/clientFeatureFlags.json index e3fae66286..4b82140400 100644 --- a/src/config/clientFeatureFlags.json +++ b/src/config/clientFeatureFlags.json @@ -1,4 +1,5 @@ { "supports_preview_metadata": true, - "supports_manager_v4_ui": true + "supports_manager_v4_ui": true, + "supports_progress_text_metadata": true } diff --git a/src/schemas/apiSchema.ts b/src/schemas/apiSchema.ts index 2d22423d08..6e4b58ea97 100644 --- a/src/schemas/apiSchema.ts +++ b/src/schemas/apiSchema.ts @@ -112,7 +112,8 @@ const zExecutionErrorWsMessage = zExecutionWsMessageBase.extend({ const zProgressTextWsMessage = z.object({ nodeId: zNodeId, - text: z.string() + text: z.string(), + prompt_id: z.string().optional() }) const zNotificationWsMessage = z.object({ diff --git a/src/scripts/api.ts b/src/scripts/api.ts index 35938a2430..993d40b88b 100644 --- a/src/scripts/api.ts +++ b/src/scripts/api.ts @@ -623,15 +623,44 @@ export class ComfyApi extends EventTarget { let imageMime switch (eventType) { - case 3: - const decoder = new TextDecoder() - const data = event.data.slice(4) - const nodeIdLength = view.getUint32(4) - this.dispatchCustomEvent('progress_text', { - nodeId: decoder.decode(data.slice(4, 4 + nodeIdLength)), - text: decoder.decode(data.slice(4 + nodeIdLength)) - }) + case 3: { + try { + const decoder3 = new TextDecoder() + const rawData = event.data.slice(4) + const rawView = new DataView(rawData) + + let offset = 0 + let promptId: string | undefined + + if ( + this.getClientFeatureFlags()?.supports_progress_text_metadata + ) { + const promptIdLength = rawView.getUint32(offset) + offset += 4 + promptId = decoder3.decode( + rawData.slice(offset, offset + promptIdLength) + ) + offset += promptIdLength + } + + const nodeIdLength = rawView.getUint32(offset) + offset += 4 + const nodeId = decoder3.decode( + rawData.slice(offset, offset + nodeIdLength) + ) + offset += nodeIdLength + const text = decoder3.decode(rawData.slice(offset)) + + this.dispatchCustomEvent('progress_text', { + nodeId, + text, + ...(promptId !== undefined && { prompt_id: promptId }) + }) + } catch (e) { + console.warn('Failed to parse progress_text binary message', e) + } break + } case 1: const imageType = view.getUint32(4) const imageData = event.data.slice(8) diff --git a/src/stores/executionStore.ts b/src/stores/executionStore.ts index 41b8158353..bbe42f227a 100644 --- a/src/stores/executionStore.ts +++ b/src/stores/executionStore.ts @@ -517,11 +517,16 @@ export const useExecutionStore = defineStore('execution', () => { } function handleProgressText(e: CustomEvent) { - const { nodeId, text } = e.detail + const { nodeId, text, prompt_id } = e.detail if (!text || !nodeId) return + // Filter: only accept progress for the active prompt + if (prompt_id && activeJobId.value && prompt_id !== activeJobId.value) + return + // Handle execution node IDs for subgraphs const currentId = getNodeIdIfExecuting(nodeId) + if (!currentId) return const node = canvasStore.getCanvas().graph?.getNodeById(currentId) if (!node) return