Nodes/rota_do_imperador-openrouter-single-node-public/Arrakis OpenRouter (Vision + Reasoning)
ComfyUI Node

Arrakis OpenRouter (Vision + Reasoning)

One node that sends your images to Grok, Claude, or any OpenRouter model

By adbrasi·Created 6 months ago·Updated 5 months ago· 0
Arrakis OpenRouter (Vision + Reasoning)
  • user_image
  • raw_response
  • json_response
  • value_1
  • value_2
  • value_3
  • value_4
  • value_5
  • value_6
  • value_7
  • status
api_key
system_promptYou are a structured output assistant. Return exactly one valid JSON object and nothing else. Do not wrap JSON in markdown fences.
user_prompt
reasoning_levellow
max_tokens0
modelx-ai/grok-4.1-fast
seed0
custom_parameters{}
timeout60
max_retries3
enforce_json_outputtrue
debugfalse
value_keys

Arrakis is one node, and it turns ComfyUI into something it stubbornly refuses to be on its own: a thing that can look at an image and tell you what's in it. Wire a Load Image into it, type a question, and a frontier LLM - by default Grok 4.1, but any model OpenRouter routes - reads your render and answers. No VAE, no CLIP, no local model download. Just your API key and the internet.

Why this instead of ComfyUI's built-in "API nodes"? Those route through Comfy Cloud credits and want you logged into a paid Comfy account. This is bring-your-own-key, exactly what the community keeps asking Comfy for. One OpenRouter key gets you Grok, Claude, GPT, Gemini, and a few hundred Llama variants - swap model and the same graph keeps working.

How it works

It's a plain HTTP client with good manners. It builds a chat request and POSTs it to https://openrouter.ai/api/v1/chat/completions, in the order OpenRouter's multimodal guidance wants: system message first, then your user text, then the image parts appended to the same user message - text before image, always.

The clever bit is the image handling. You feed it a real ComfyUI IMAGE tensor and it does the rest: converts to numpy, encodes as base64 JPEG data URLs, downscales anything over 1 megapixel, and if you feed a batch it samples at most three frames (first, middle, last) rather than torching your OpenRouter balance on every frame. Responses get a genuinely defensive JSON parser: direct decode, then markdown-fence stripping, then a hunt through the text for JSON fragments. Models wrap output in ```json fences constantly; this one doesn't care. It also retries on its own - 429s and other retryable errors get backoff (honoring Retry-After), up to max_retries.

Inputs and outputs that matter

For a beginner, only a few fields earn your attention:

  • api_key - paste the key, or reference an env var like $OPENROUTER_TOKEN and keep the secret out of your workflow file. Do that. Workflows get embedded in PNG metadata, and a literal key travels with every image you share.
  • model - any OpenRouter model id; default is x-ai/grok-4.1-fast.
  • reasoning_level - none through xhigh. The node sends "reasoning": {"effort": ...} for everything except none, which omits the field entirely.
  • user_image - the IMAGE tensor. Leave it disconnected and you've got a plain text LLM node.
  • value_keys - comma-separated JSON paths (name,stats.hp) to map the response into the numbered outputs. Nested keys with dots work.

Everything else is plumbing. custom_parameters is a raw JSON blob merged into the request body for things like temperature or response_format - note max_tokens inside it is ignored, use the dedicated input (0 = let the model decide). max_retries and timeout are what they sound like; enforce_json_output appends a strict "JSON only, no fences" suffix to the system prompt.

Outputs: raw_response (raw text), json_response (pretty-printed, parsed JSON), value_1 through value_7 (auto-extracted fields, or your value_keys picks), and status - a JSON object with status, model, tokens_used, request_id, and the error detail if it failed. Wire json_response or a value_N into anything that wants a STRING and data flows back into the graph.

Installing it

ComfyUI Manager, search the pack title, install, restart. Or by hand:

cd ComfyUI/custom_nodes
git clone https://github.com/adbrasi/rota_do_imperador-openrouter-single-node-public

Dependencies are just requests and json5 - nothing heavy, no model files, no separate runtime. One thing that trips people: the repo name says "node" and the README warns that this is not a Node.js app - it's a ComfyUI Python node. Running python __init__.py just prints a smoke-test status; it doesn't start a server.

Where people get burned

  • Empty raw_response but no error. Check the status output, not the console - the node logs a full JSON status with the error detail on every failure. Flip debug on for a payload dump too.
  • The seed input. The README claims it caches responses so unchanged inputs don't re-bill you. In the shipped code it's accepted and logged but not actually wired to a cache - don't count on it yet.
  • Silent image truncation. A 60-frame batch becomes three images. If you needed all frames analyzed, that's not what this does.
  • Key hygiene. The ComfyUI_LLMVISION incident - a vision/LLM node that shipped malware and stole keys - is the reason to be picky about which API nodes you install and never hardcode keys. This one's a thin, readable wrapper; that's the kind you want, but the lesson stands: review what you install, use env vars.

If the model ignores a parameter you passed, that's usually OpenRouter routing to a provider that doesn't support it, not the node eating it. And if you don't have an OpenRouter key yet, that's the actual prerequisite.

CategoryLLM/API

Inputs (14)

NameTypeDefaultDescription
api_keySTRING
system_promptSTRINGYou are a structured output assistant. Return exactly one valid JSON object and nothing else. Do not wrap JSON in markdown fences.
user_promptSTRING
reasoning_levelCOMBOlow6 options: none, low, minimal, medium, high, xhigh
max_tokensINT00–1280000 = sem limite (deixa o modelo decidir)
modelSTRINGx-ai/grok-4.1-fast
seedINT00–18446744073709550000
user_imageoptIMAGE
custom_parametersoptSTRING{}
timeoutoptINT6010–300
max_retriesoptINT31–10
enforce_json_outputoptBOOLEANtrue
debugoptBOOLEANfalse
value_keysoptSTRINGChaves JSON separadas por vírgula para mapear em value_1..value_7. Suporta acesso aninhado com ponto (ex: 'name,stats.hp,stats.mp'). Vazio = extração automática na ordem do JSON.

Outputs (10)

NameTypeDescription
raw_responseSTRING
json_responseSTRING
value_1STRING
value_2STRING
value_3STRING
value_4STRING
value_5STRING
value_6STRING
value_7STRING
statusSTRING