Nodes/comfyui-nodes-agents/Agent Receive (← agent)
ComfyUI Node

Agent Receive (← agent)

Wait for an agent's reply, then feed it back into the graph

By ethanfel·Created 2 months ago·Updated 2 months ago· 1
Agent Receive (← agent)
  • signal
  • text
  • image
  • seed
channelmain
wait_seconds30
keep_lasttrue
stop_on_timeouttrue

Agent Receive (← agent) is the node that makes a ComfyUI workflow stop and listen. It's the inbound half of the Agent Bridge: it blocks - up to wait_seconds - until an external agent pushes a text, image, or seed onto the named channel, then hands those to whatever's downstream. Pair it with its sibling Agent Emit and you've got a real agentic loop: the graph emits a prompt and a starting image, the agent thinks and edits, and Receive hands the result to a KSampler or a preview node without you touching anything.

The mental model is a mailbox with a turn counter, not a shared variable. Per channel there's an outbox (agent → graph), and each pushed message is consumed once. Receive blocks until the outbox turn count moves past what it last read, grabs the new value, and marks it consumed - so a second Receive on the same channel won't replay it, and re-running the workflow with no new push gives you nothing. That consume-once rule is also why the pack insists on one Receive per channel: two of them compete for pushes and one silently starves.

The blocking behavior is the thing to respect. wait_seconds ties up a ComfyUI execution worker for its whole duration, so keep it in seconds for interactive use, not hours. And because the agent can push at any time, independent of your graph's inputs, the node cheats ComfyUI's cache by returning float("NaN") from IS_CHANGED - the classic "always dirty" idiom from the node-plumbing playbook, so it re-runs on every queue instead of serving a stale cached output.

The inputs, in order of how often you'll touch them:

  • channel (STRING, default main) - must match the channel the agent pushes to via comfy_push.
  • wait_seconds (FLOAT, default 30.0, max 86400) - how long to block for a new push.
  • keep_last (BOOLEAN, default true) - on timeout, re-output the last message instead of blanking. Leave it on for Auto Queue so your preview holds steady between evals. Off, you get "" plus a 64×64 black placeholder.
  • stop_on_timeout (BOOLEAN, default true) - on timeout, tells the ComfyUI frontend to flip Auto Queue off, so the loop halts when the message stream goes quiet instead of spinning forever.
  • signal (ANY) - the one beginners miss. Its value is ignored; it's purely an order-only dependency. Wire your upstream Agent Emit into it so Emit fires before Receive starts waiting. Without it, Receive can block while the agent has nothing to work on yet.

Outputs are (text, image, seed) - the seed being whatever the agent passed to comfy_push(seed=...), or 0 if it passed none. Wire that seed straight into a KSampler and the agent effectively controls the next roll. The image comes back as a normal IMAGE tensor (loaded from the path the agent pushed), so it plugs into Preview, Save, img2img, anything.

Install is the pack-level story: clone https://github.com/ethanfel/ComfyUI-Agent-Bridge into custom_nodes, pip install -r requirements.txt (mcp>=1.2.0), restart. The bridge auto-starts and logs its URL, which you register with the agent via claude mcp add --transport http comfy http://127.0.0.1:9188/mcp (or Codex's plugin / codex mcp add).

Troubleshooting the silent failures. If Receive returns blank text and a black image, look for SENDER PROBLEM in the ComfyUI log - it's the node telling you the pushed image_path doesn't exist on this host, which is the shared-mount / Docker problem (fix with COMFY_BRIDGE_TMP_PUBLIC). If it timeouts every time with nothing arriving, check three things in order: channel names match, the Emit is wired into signal so it runs first, and wait_seconds is longer than the agent actually takes to respond.

Categoryagents/bridge

Inputs (5)

NameTypeDefaultDescription
channelSTRINGmain
wait_secondsFLOAT300–86400
keep_lastBOOLEANtrue
stop_on_timeoutBOOLEANtrue
signalopt*

Outputs (3)

NameTypeDescription
textSTRING
imageIMAGE
seedINT