comfyui-mcp 0.23.5 → 0.24.0
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/README.md +37 -4
- package/dist/index.js +55 -5
- package/dist/index.js.map +1 -1
- package/dist/orchestrator/agent-backend.js +18 -0
- package/dist/orchestrator/agent-backend.js.map +1 -1
- package/dist/orchestrator/backend-readiness.js +20 -0
- package/dist/orchestrator/backend-readiness.js.map +1 -1
- package/dist/orchestrator/index.js +44 -5
- package/dist/orchestrator/index.js.map +1 -1
- package/dist/orchestrator/ollama-backend.js +668 -0
- package/dist/orchestrator/ollama-backend.js.map +1 -0
- package/dist/services/agent-setup.js +122 -0
- package/dist/services/agent-setup.js.map +1 -0
- package/dist/tools/catalog.js +77 -0
- package/dist/tools/catalog.js.map +1 -0
- package/dist/tools/compact.js +174 -0
- package/dist/tools/compact.js.map +1 -0
- package/dist/tools/index.js +74 -47
- package/dist/tools/index.js.map +1 -1
- package/dist/transport/cli.js +45 -0
- package/dist/transport/cli.js.map +1 -1
- package/package.json +5 -2
- package/scripts/arena-bestof.mjs +88 -0
- package/scripts/arena-graphic.mjs +119 -0
- package/scripts/llm-arena.mjs +553 -0
- package/scripts/panel-smoke.mjs +217 -0
- package/scripts/test-local-llm.mjs +150 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# comfyui-mcp —
|
|
1
|
+
# comfyui-mcp — drive ComfyUI with ANY LLM
|
|
2
2
|
|
|
3
|
-
**The local-first, agent-native control plane for [ComfyUI](https://github.com/comfyanonymous/ComfyUI)** —
|
|
3
|
+
**The local-first, agent-native control plane for [ComfyUI](https://github.com/comfyanonymous/ComfyUI)** — an MCP server + live sidebar agent that generates images, video and audio, authors and runs workflows, manages models and custom nodes, and **edits your live ComfyUI graph in natural language**. Bring whatever model you have: **Claude or ChatGPT on your subscription, Gemini on your Google login, a free local model via Ollama (fully offline), or any hosted model over one API key** (DeepSeek, GLM, MiMo, Kimi, GPT, Claude via OpenRouter). Same tools, same panel, every tier — and the built-in [LLM Arena](https://comfyui-mcp.artokun.io/docs/arena) scores them all on real ComfyUI tasks so you know exactly what your model can do. One config targets local installs, LAN, VPS, or Comfy Cloud.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/comfyui-mcp)
|
|
6
6
|
[](https://nodejs.org)
|
|
@@ -19,7 +19,7 @@ Works on **macOS**, **Linux**, and **Windows**. Auto-detects your ComfyUI instal
|
|
|
19
19
|
The plugin ships **expert skills that grow with every release** — model-specific generation guides with curated download URLs, workflow recipes, troubleshooting, and custom-node authoring — so Claude knows the right sampler, CFG, resolution, and model files for each architecture without trial and error.
|
|
20
20
|
|
|
21
21
|
> ### ✅ Now available: the [ComfyUI Agent Panel](https://registry.comfy.org/nodes/comfyui-agent-panel) on ComfyUI-Manager & the Comfy Registry
|
|
22
|
-
> An autonomous AI agent in your ComfyUI sidebar — **
|
|
22
|
+
> An autonomous AI agent in your ComfyUI sidebar — **on Claude, ChatGPT, Gemini, or ANY local/hosted LLM** (Ollama and every OpenAI-compatible endpoint). Subscriptions work with no API key; local models work with no account at all. Pick a provider and it drives your live graph: edits, spatial layout, one-shot workflow/pack loads, rewind/rollback, a pending-message tray, activity cards, multi-tab — and it asks before spending paid API credits.
|
|
23
23
|
> Search **`comfyui-agent-panel`** in ComfyUI-Manager to install. [Read more →](https://comfyui-mcp.artokun.io/docs/panel)
|
|
24
24
|
|
|
25
25
|
📖 **Full documentation: [comfyui-mcp.artokun.io/docs](https://comfyui-mcp.artokun.io/docs)**
|
|
@@ -152,7 +152,7 @@ This package also ships as a **Claude Code plugin**, providing slash commands, s
|
|
|
152
152
|
|
|
153
153
|
---
|
|
154
154
|
|
|
155
|
-
## Panel agent (Claude
|
|
155
|
+
## Panel agent (Claude · ChatGPT · Gemini · any local/hosted LLM)
|
|
156
156
|
|
|
157
157
|
Beyond the headless MCP server, this package ships the **panel orchestrator** that
|
|
158
158
|
powers the **[ComfyUI Agent Panel](https://github.com/artokun/comfyui-mcp-panel)** —
|
|
@@ -599,6 +599,39 @@ npx -y comfyui-mcp@latest --http --host 0.0.0.0 --port 9100 # bind/port overri
|
|
|
599
599
|
| `--port <n>` | `MCP_PORT` | `9100` | HTTP port |
|
|
600
600
|
| `--comfyui-url <url>` | `COMFYUI_URL` | *(auto-detect)* | Target a specific (incl. remote) ComfyUI |
|
|
601
601
|
|
|
602
|
+
### Other agents & local LLMs (Hermes, OpenClaw, Copilot CLI, Ollama)
|
|
603
|
+
|
|
604
|
+
comfyui-mcp has **first-class support for non-Claude harnesses**. One command
|
|
605
|
+
writes the server entry into the harness's own config (merging, not
|
|
606
|
+
clobbering):
|
|
607
|
+
|
|
608
|
+
```bash
|
|
609
|
+
npx -y comfyui-mcp setup hermes # → ~/.hermes/config.yaml (compact by default)
|
|
610
|
+
npx -y comfyui-mcp setup openclaw # → ~/.openclaw/openclaw.json (compact by default)
|
|
611
|
+
npx -y comfyui-mcp setup copilot # → ~/.copilot/mcp-config.json (full by default)
|
|
612
|
+
# flags: --compact | --full, --comfyui-url <url>, --dry-run
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
**Model requirements**: tool calling is a hard requirement (no tool calling =
|
|
616
|
+
doesn't work). Thinking and vision are strongly recommended — without
|
|
617
|
+
thinking, multi-step tool chains degrade; without vision the agent can
|
|
618
|
+
generate but can't see its own outputs.
|
|
619
|
+
|
|
620
|
+
For small/local models, **compact tool mode** (`--compact` /
|
|
621
|
+
`COMFYUI_MCP_TOOL_MODE=compact`) registers 3 meta-tools
|
|
622
|
+
(`list_tools` → `describe_tool` → `call_tool`) instead of the full ~200-schema
|
|
623
|
+
surface, pulling schemas into context one tool at a time. Validated
|
|
624
|
+
end-to-end via Ollama with `gemma4:e4b`, `gemma4:e2b`, and `qwen3:4b`
|
|
625
|
+
(`npm run test:local-llm`); gemma3 has no native tool calling and is
|
|
626
|
+
unsupported. Full guide — hosted-model guidance (DeepSeek/MiMo/GLM class),
|
|
627
|
+
per-harness setup, troubleshooting:
|
|
628
|
+
**[Local LLMs & other agents](https://comfyui-mcp.artokun.io/docs/local-llms)**.
|
|
629
|
+
|
|
630
|
+
| Flag | Env | Default | Description |
|
|
631
|
+
|------|-----|---------|-------------|
|
|
632
|
+
| `setup <agent>` | | | Write the comfyui entry into hermes / openclaw / copilot config, then exit |
|
|
633
|
+
| `--compact` / `--tool-mode compact` | `COMFYUI_MCP_TOOL_MODE=compact` | `full` | Register 3 meta-tools instead of the full ~200-schema surface |
|
|
634
|
+
|
|
602
635
|
### Remote ComfyUI
|
|
603
636
|
|
|
604
637
|
Point the server at a ComfyUI running anywhere — no local install required:
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,8 @@ import { randomBytes } from "node:crypto";
|
|
|
3
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
5
|
import { ListPromptsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
-
import { registerAllTools } from "./tools/index.js";
|
|
6
|
+
import { registerAllTools, collectToolCatalog } from "./tools/index.js";
|
|
7
|
+
import { registerCompactTools } from "./tools/compact.js";
|
|
7
8
|
import { logger } from "./utils/logger.js";
|
|
8
9
|
import { JobWatcher } from "./services/job-watcher.js";
|
|
9
10
|
import { parseCliArgs, validateConnectUrl } from "./transport/cli.js";
|
|
@@ -73,7 +74,7 @@ function selfUpdateOnLoad() {
|
|
|
73
74
|
})
|
|
74
75
|
.catch(() => { });
|
|
75
76
|
}
|
|
76
|
-
async function createConfiguredServer() {
|
|
77
|
+
async function createConfiguredServer(toolMode = "full") {
|
|
77
78
|
const server = new McpServer({
|
|
78
79
|
name: "comfyui-mcp",
|
|
79
80
|
version: "0.1.0",
|
|
@@ -91,7 +92,18 @@ async function createConfiguredServer() {
|
|
|
91
92
|
prompts: {},
|
|
92
93
|
},
|
|
93
94
|
});
|
|
94
|
-
|
|
95
|
+
if (toolMode === "compact") {
|
|
96
|
+
// Compact tool mode for small/local LLMs (Hermes Agent, Ollama — issue #97):
|
|
97
|
+
// capture the whole tool surface into a catalog and expose only the
|
|
98
|
+
// list_tools/describe_tool/call_tool meta-tools, keeping the client's
|
|
99
|
+
// context cost near-zero until a tool is actually needed.
|
|
100
|
+
const catalog = await collectToolCatalog();
|
|
101
|
+
registerCompactTools(server, catalog);
|
|
102
|
+
logger.info(`Compact tool mode: ${catalog.tools.size} tools available via list_tools/describe_tool/call_tool`);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
await registerAllTools(server);
|
|
106
|
+
}
|
|
95
107
|
server.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
96
108
|
resources: [],
|
|
97
109
|
}));
|
|
@@ -171,6 +183,44 @@ function isRemoteHttpsPod(u) {
|
|
|
171
183
|
}
|
|
172
184
|
async function main() {
|
|
173
185
|
const cli = parseCliArgs(process.argv);
|
|
186
|
+
// `setup <agent>`: write the comfyui MCP entry into a non-Claude harness's
|
|
187
|
+
// config (Hermes Agent / OpenClaw / Copilot CLI — issue #97), print next
|
|
188
|
+
// steps, and exit. Never starts the MCP server.
|
|
189
|
+
if (cli.setupAgent !== undefined) {
|
|
190
|
+
const { setupAgent, AGENT_NAMES } = await import("./services/agent-setup.js");
|
|
191
|
+
const agent = cli.setupAgent;
|
|
192
|
+
if (!AGENT_NAMES.includes(agent)) {
|
|
193
|
+
process.stderr.write(`\nUsage: comfyui-mcp setup <${AGENT_NAMES.join("|")}> [--compact|--full] [--comfyui-url <url>] [--dry-run]\n` +
|
|
194
|
+
(cli.setupAgent ? `\nUnknown agent "${cli.setupAgent}".\n` : "") +
|
|
195
|
+
`\nWrites the comfyui MCP server entry into the agent's own config file.\n`);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const result = await setupAgent({
|
|
200
|
+
agent,
|
|
201
|
+
compact: cli.toolModeExplicit ? cli.toolMode === "compact" : undefined,
|
|
202
|
+
comfyuiUrl: cli.comfyuiUrl,
|
|
203
|
+
dryRun: cli.setupDryRun,
|
|
204
|
+
});
|
|
205
|
+
const lines = [
|
|
206
|
+
"",
|
|
207
|
+
result.wrote
|
|
208
|
+
? `✓ Added the "comfyui" MCP server to ${result.configPath}`
|
|
209
|
+
: `— dry run: would write ${result.configPath} as —`,
|
|
210
|
+
...(result.wrote ? [] : ["", result.content.trimEnd()]),
|
|
211
|
+
"",
|
|
212
|
+
"Next steps:",
|
|
213
|
+
...result.nextSteps.map((s) => ` • ${s}`),
|
|
214
|
+
"",
|
|
215
|
+
];
|
|
216
|
+
process.stdout.write(lines.join("\n"));
|
|
217
|
+
process.exit(0);
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
process.stderr.write(`\ncomfyui-mcp setup failed: ${err instanceof Error ? err.message : err}\n`);
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
174
224
|
// Standalone background orchestrator: owns the UI bridge and drives the panel
|
|
175
225
|
// with autonomous Agent SDK sessions. Not an MCP server — it never returns.
|
|
176
226
|
if (cli.panelOrchestrator) {
|
|
@@ -240,7 +290,7 @@ async function main() {
|
|
|
240
290
|
port: cli.port,
|
|
241
291
|
token,
|
|
242
292
|
allowUnauthenticated: cli.allowUnauthenticated,
|
|
243
|
-
createServer: () => createConfiguredServer(),
|
|
293
|
+
createServer: () => createConfiguredServer(cli.toolMode),
|
|
244
294
|
});
|
|
245
295
|
logger.info(`ComfyUI MCP server running on http://${cli.host}:${cli.port}/mcp`);
|
|
246
296
|
if (token) {
|
|
@@ -251,7 +301,7 @@ async function main() {
|
|
|
251
301
|
}
|
|
252
302
|
}
|
|
253
303
|
else {
|
|
254
|
-
const server = await createConfiguredServer();
|
|
304
|
+
const server = await createConfiguredServer(cli.toolMode);
|
|
255
305
|
const transport = new StdioServerTransport();
|
|
256
306
|
await server.connect(transport);
|
|
257
307
|
logger.info("ComfyUI MCP server running on stdio");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,kCAAkC,GACnC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,4 +46,22 @@ export const GEMINI_CAPABILITIES = {
|
|
|
46
46
|
hooks: false,
|
|
47
47
|
vision: true, // gemini-2.5 sees images; delivered as inline base64 image ContentBlocks
|
|
48
48
|
};
|
|
49
|
+
/** Capability descriptor for the Ollama local-LLM backend (issue #97's panel
|
|
50
|
+
* phase). Ollama is a stateless HTTP daemon, so the backend owns the whole
|
|
51
|
+
* agentic loop itself (stream /api/chat, dispatch tool calls, repeat) and
|
|
52
|
+
* keeps the conversation history in-memory — persistentChannel is true from
|
|
53
|
+
* the panel's perspective, but forkAtAnchor is out. Vision is false for now:
|
|
54
|
+
* most small tool-calling models are text-only, and a mixed field (gemma4 has
|
|
55
|
+
* vision, qwen3 doesn't) would fail unpredictably mid-conversation. */
|
|
56
|
+
export const OLLAMA_CAPABILITIES = {
|
|
57
|
+
persistentChannel: true, // in-memory history + repeated /api/chat
|
|
58
|
+
streamingDeltas: true, // NDJSON chunk stream
|
|
59
|
+
interruptMidTurn: true, // AbortController on the in-flight fetch
|
|
60
|
+
forkAtAnchor: false,
|
|
61
|
+
inProcessMcp: false, // MCP clients internally; the model sees the 6-tool router
|
|
62
|
+
modelEnumeration: true, // GET /api/tags (locally pulled models)
|
|
63
|
+
slashCommands: false,
|
|
64
|
+
hooks: false,
|
|
65
|
+
vision: false,
|
|
66
|
+
};
|
|
49
67
|
//# sourceMappingURL=agent-backend.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-backend.js","sourceRoot":"","sources":["../../src/orchestrator/agent-backend.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,mFAAmF;AACnF,oEAAoE;AACpE,EAAE;AACF,mFAAmF;AACnF,+EAA+E;AAC/E,+EAA+E;AAC/E,mFAAmF;AA8KnF,8DAA8D;AAC9D,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,iBAAiB,EAAE,IAAI;IACvB,eAAe,EAAE,IAAI;IACrB,gBAAgB,EAAE,IAAI;IACtB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,IAAI;IAClB,gBAAgB,EAAE,IAAI;IACtB,aAAa,EAAE,IAAI;IACnB,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI,EAAE,0DAA0D;CACzE,CAAC;AAEF,wEAAwE;AACxE,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,iBAAiB,EAAE,IAAI,EAAE,2CAA2C;IACpE,eAAe,EAAE,IAAI;IACrB,gBAAgB,EAAE,IAAI,EAAE,iBAAiB;IACzC,YAAY,EAAE,KAAK,EAAE,+CAA+C;IACpE,YAAY,EAAE,KAAK,EAAE,mCAAmC;IACxD,gBAAgB,EAAE,IAAI,EAAE,cAAc;IACtC,aAAa,EAAE,KAAK;IACpB,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,IAAI,EAAE,kEAAkE;CACjF,CAAC;AAEF;;;;gFAIgF;AAChF,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,iBAAiB,EAAE,IAAI,EAAE,wCAAwC;IACjE,eAAe,EAAE,IAAI,EAAE,2DAA2D;IAClF,gBAAgB,EAAE,IAAI,EAAE,iBAAiB;IACzC,YAAY,EAAE,KAAK,EAAE,sDAAsD;IAC3E,YAAY,EAAE,KAAK,EAAE,mDAAmD;IACxE,gBAAgB,EAAE,IAAI,EAAE,oEAAoE;IAC5F,aAAa,EAAE,KAAK;IACpB,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,IAAI,EAAE,yEAAyE;CACxF,CAAC"}
|
|
1
|
+
{"version":3,"file":"agent-backend.js","sourceRoot":"","sources":["../../src/orchestrator/agent-backend.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,mFAAmF;AACnF,oEAAoE;AACpE,EAAE;AACF,mFAAmF;AACnF,+EAA+E;AAC/E,+EAA+E;AAC/E,mFAAmF;AA8KnF,8DAA8D;AAC9D,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,iBAAiB,EAAE,IAAI;IACvB,eAAe,EAAE,IAAI;IACrB,gBAAgB,EAAE,IAAI;IACtB,YAAY,EAAE,IAAI;IAClB,YAAY,EAAE,IAAI;IAClB,gBAAgB,EAAE,IAAI;IACtB,aAAa,EAAE,IAAI;IACnB,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI,EAAE,0DAA0D;CACzE,CAAC;AAEF,wEAAwE;AACxE,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,iBAAiB,EAAE,IAAI,EAAE,2CAA2C;IACpE,eAAe,EAAE,IAAI;IACrB,gBAAgB,EAAE,IAAI,EAAE,iBAAiB;IACzC,YAAY,EAAE,KAAK,EAAE,+CAA+C;IACpE,YAAY,EAAE,KAAK,EAAE,mCAAmC;IACxD,gBAAgB,EAAE,IAAI,EAAE,cAAc;IACtC,aAAa,EAAE,KAAK;IACpB,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,IAAI,EAAE,kEAAkE;CACjF,CAAC;AAEF;;;;gFAIgF;AAChF,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,iBAAiB,EAAE,IAAI,EAAE,wCAAwC;IACjE,eAAe,EAAE,IAAI,EAAE,2DAA2D;IAClF,gBAAgB,EAAE,IAAI,EAAE,iBAAiB;IACzC,YAAY,EAAE,KAAK,EAAE,sDAAsD;IAC3E,YAAY,EAAE,KAAK,EAAE,mDAAmD;IACxE,gBAAgB,EAAE,IAAI,EAAE,oEAAoE;IAC5F,aAAa,EAAE,KAAK;IACpB,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,IAAI,EAAE,yEAAyE;CACxF,CAAC;AAEF;;;;;;wEAMwE;AACxE,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,iBAAiB,EAAE,IAAI,EAAE,yCAAyC;IAClE,eAAe,EAAE,IAAI,EAAE,sBAAsB;IAC7C,gBAAgB,EAAE,IAAI,EAAE,yCAAyC;IACjE,YAAY,EAAE,KAAK;IACnB,YAAY,EAAE,KAAK,EAAE,2DAA2D;IAChF,gBAAgB,EAAE,IAAI,EAAE,wCAAwC;IAChE,aAAa,EAAE,KAAK;IACpB,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,KAAK;CACd,CAAC"}
|
|
@@ -16,7 +16,20 @@ import { join } from "node:path";
|
|
|
16
16
|
const CLI_NAMES = {
|
|
17
17
|
codex: ["codex", "codex.cmd", "codex.exe"],
|
|
18
18
|
gemini: ["gemini", "gemini.cmd", "gemini.exe"],
|
|
19
|
+
ollama: ["ollama", "ollama.exe"],
|
|
19
20
|
};
|
|
21
|
+
/** Well-known Ollama install locations probed in addition to PATH (the Windows
|
|
22
|
+
* installer adds PATH for NEW shells only — an orchestrator started from an
|
|
23
|
+
* older shell would false-flag "not installed"). */
|
|
24
|
+
function ollamaInstalled(home) {
|
|
25
|
+
if (onPath(CLI_NAMES.ollama))
|
|
26
|
+
return true;
|
|
27
|
+
if (process.platform === "win32") {
|
|
28
|
+
const localAppData = process.env.LOCALAPPDATA || join(home, "AppData", "Local");
|
|
29
|
+
return fileExists(localAppData, "Programs", "Ollama", "ollama.exe");
|
|
30
|
+
}
|
|
31
|
+
return fileExists("/usr/local/bin/ollama") || fileExists("/opt/homebrew/bin/ollama");
|
|
32
|
+
}
|
|
20
33
|
/** True if any of `names` resolves on the local PATH. */
|
|
21
34
|
function onPath(names) {
|
|
22
35
|
const sep = process.platform === "win32" ? ";" : ":";
|
|
@@ -70,6 +83,13 @@ export function backendReadiness(backend, opts) {
|
|
|
70
83
|
const auth = fileExists(geminiHome, ".gemini", "oauth_creds.json");
|
|
71
84
|
return { backend: "gemini", cli, auth, ready: cli && auth };
|
|
72
85
|
}
|
|
86
|
+
if (b === "ollama") {
|
|
87
|
+
// No login concept — a local daemon. Binary presence is the readiness
|
|
88
|
+
// signal here (mirrors claude's posture); a stopped daemon still surfaces
|
|
89
|
+
// via the connect ack's model probe (GET /api/tags fails → degraded ack).
|
|
90
|
+
const cli = ollamaInstalled(home);
|
|
91
|
+
return { backend: "ollama", cli, auth: cli ? true : null, ready: cli };
|
|
92
|
+
}
|
|
73
93
|
return { backend: b, cli: false, auth: false, ready: false };
|
|
74
94
|
}
|
|
75
95
|
/** Readiness for every known backend, plus a rolled-up any_ready. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend-readiness.js","sourceRoot":"","sources":["../../src/orchestrator/backend-readiness.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,qEAAqE;AACrE,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAC/E,iFAAiF;AACjF,kFAAkF;AAClF,2EAA2E;AAC3E,mCAAmC;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAYjC,gFAAgF;AAChF,qEAAqE;AACrE,MAAM,SAAS,GAA6B;IAC1C,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,WAAW,CAAC;IAC1C,MAAM,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"backend-readiness.js","sourceRoot":"","sources":["../../src/orchestrator/backend-readiness.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,7 @@ import { readUserMcpServers } from "../services/user-mcp-config.js";
|
|
|
24
24
|
import { buildComfyuiMcpEnv, comfyuiSecretKeys, onComfyuiSecretsChanged, } from "../services/panel-secrets.js";
|
|
25
25
|
import { CodexBackend } from "./codex-backend.js";
|
|
26
26
|
import { GeminiBackend, GEMINI_DEFAULT_MODEL } from "./gemini-backend.js";
|
|
27
|
+
import { OllamaBackend } from "./ollama-backend.js";
|
|
27
28
|
import { allBackendReadiness } from "./backend-readiness.js";
|
|
28
29
|
import { startPanelMcpHttpServer } from "./panel-mcp-http.js";
|
|
29
30
|
import { readComfyuiCrashLog, formatCrashNote } from "../services/crash-log.js";
|
|
@@ -469,6 +470,23 @@ export async function runPanelOrchestrator() {
|
|
|
469
470
|
// COMFYUI_MCP_GEMINI_MODEL (default gemini-2.5-pro). The model is applied at spawn
|
|
470
471
|
// via the CLI `--model` flag (ACP exposes no per-session model setter).
|
|
471
472
|
const geminiModel = process.env.COMFYUI_MCP_GEMINI_MODEL ?? GEMINI_DEFAULT_MODEL;
|
|
473
|
+
// Ollama (local LLMs, issue #97): the model is a local tag (qwen3:4b, gemma4:e4b)
|
|
474
|
+
// applied PER REQUEST — switching live is free. Default = the LLM Arena's best
|
|
475
|
+
// performer (scripts/llm-arena.mjs): gemma4:e4b, 9/10 with the cleanest runs
|
|
476
|
+
// (first-try tool dispatch, no nudges) and multimodal headroom for vision.
|
|
477
|
+
const ollamaModel = process.env.COMFYUI_MCP_OLLAMA_MODEL ?? "gemma4:e4b";
|
|
478
|
+
// The same backend also speaks any OpenAI-compatible endpoint (OpenRouter,
|
|
479
|
+
// DeepSeek, vLLM, LM Studio): COMFYUI_MCP_OLLAMA_API=openai +
|
|
480
|
+
// COMFYUI_MCP_OLLAMA_BASE_URL (incl. /v1) + COMFYUI_MCP_OLLAMA_API_KEY
|
|
481
|
+
// (falls back to OPENROUTER_API_KEY). The chip stays "Ollama (local)".
|
|
482
|
+
const ollamaApi = process.env.COMFYUI_MCP_OLLAMA_API === "openai" ? "openai" : "ollama";
|
|
483
|
+
const ollamaBaseUrl = process.env.COMFYUI_MCP_OLLAMA_BASE_URL;
|
|
484
|
+
const ollamaApiKey = process.env.COMFYUI_MCP_OLLAMA_API_KEY || process.env.OPENROUTER_API_KEY;
|
|
485
|
+
const ollamaDeps = () => ({
|
|
486
|
+
api: ollamaApi,
|
|
487
|
+
...(ollamaBaseUrl ? { host: ollamaBaseUrl } : {}),
|
|
488
|
+
...(ollamaApi === "openai" && ollamaApiKey ? { apiKey: ollamaApiKey } : {}),
|
|
489
|
+
});
|
|
472
490
|
// ── Per-tab backend (single-port multi-provider) ──────────────────────────
|
|
473
491
|
// ONE orchestrator on ONE bridge port serves ALL providers; the panel picks a
|
|
474
492
|
// provider per tab via the `hello`/`set_backend` handshake, instead of the node
|
|
@@ -478,7 +496,7 @@ export async function runPanelOrchestrator() {
|
|
|
478
496
|
// provider (the panel replays the transcript to seed it) while a same-provider
|
|
479
497
|
// reconnect RESUMES. `backendId`/`codexModel`/`geminiModel` above are the
|
|
480
498
|
// DEFAULT + per-provider model config; the process is no longer pinned to one.
|
|
481
|
-
const KNOWN_BACKENDS = new Set(["claude", "codex", "gemini"]);
|
|
499
|
+
const KNOWN_BACKENDS = new Set(["claude", "codex", "gemini", "ollama"]);
|
|
482
500
|
const defaultBackend = KNOWN_BACKENDS.has(backendId) ? backendId : "claude";
|
|
483
501
|
const AGENT_KEY_SEP = "::";
|
|
484
502
|
const tabBackends = new Map(); // panel tabId -> selected backend
|
|
@@ -615,6 +633,16 @@ export async function runPanelOrchestrator() {
|
|
|
615
633
|
mcpServers: makeHttpBackendMcpServers(panelTabId),
|
|
616
634
|
});
|
|
617
635
|
}
|
|
636
|
+
if (backend === "ollama") {
|
|
637
|
+
return new OllamaBackend({
|
|
638
|
+
cwd: comfyuiPath ?? process.cwd(),
|
|
639
|
+
model: ollamaModel,
|
|
640
|
+
systemAppend: panelSystemAppend,
|
|
641
|
+
comfyuiUrl,
|
|
642
|
+
mcpServers: makeHttpBackendMcpServers(panelTabId),
|
|
643
|
+
...ollamaDeps(),
|
|
644
|
+
});
|
|
645
|
+
}
|
|
618
646
|
return undefined; // claude → built-in ClaudeBackend
|
|
619
647
|
};
|
|
620
648
|
logger.info(`[panel-orchestrator] single-port multi-provider: default backend=${defaultBackend}; ` +
|
|
@@ -633,7 +661,9 @@ export async function runPanelOrchestrator() {
|
|
|
633
661
|
pb =
|
|
634
662
|
backend === "codex"
|
|
635
663
|
? new CodexBackend({ cwd: comfyuiPath ?? process.cwd(), model: codexModel })
|
|
636
|
-
:
|
|
664
|
+
: backend === "ollama"
|
|
665
|
+
? new OllamaBackend({ cwd: comfyuiPath ?? process.cwd(), model: ollamaModel, ...ollamaDeps() })
|
|
666
|
+
: new GeminiBackend({ cwd: comfyuiPath ?? process.cwd(), model: geminiModel });
|
|
637
667
|
probeBackends.set(backend, pb);
|
|
638
668
|
}
|
|
639
669
|
return pb;
|
|
@@ -841,6 +871,8 @@ export async function runPanelOrchestrator() {
|
|
|
841
871
|
return codexModel;
|
|
842
872
|
if (backend === "gemini")
|
|
843
873
|
return geminiModel;
|
|
874
|
+
if (backend === "ollama")
|
|
875
|
+
return ollamaModel;
|
|
844
876
|
return model;
|
|
845
877
|
}
|
|
846
878
|
function pushModels(panelTabId) {
|
|
@@ -950,6 +982,7 @@ export async function runPanelOrchestrator() {
|
|
|
950
982
|
lastAckAt.set(panelTab, now);
|
|
951
983
|
const isCx = backend === "codex";
|
|
952
984
|
const isGm = backend === "gemini";
|
|
985
|
+
const isOl = backend === "ollama";
|
|
953
986
|
// TRUTHFUL "connected": only claim ready after PROVING the SELECTED backend
|
|
954
987
|
// can run, by probing its model list. If the probe fails — the "connected
|
|
955
988
|
// but dead" wedge — send a degraded ack so the panel shows the real state.
|
|
@@ -960,14 +993,18 @@ export async function runPanelOrchestrator() {
|
|
|
960
993
|
? (codexModel ?? models[0].value ?? "Codex")
|
|
961
994
|
: isGm
|
|
962
995
|
? (geminiModel ?? models[0].value ?? "Gemini")
|
|
963
|
-
:
|
|
996
|
+
: isOl
|
|
997
|
+
? (ollamaModel ?? models[0].value ?? "Ollama")
|
|
998
|
+
: model;
|
|
964
999
|
// Greet only on a FRESH session (a resume/reconnect already has the thread).
|
|
965
1000
|
if (!resume) {
|
|
966
1001
|
const readyText = isCx
|
|
967
1002
|
? `🟢 comfyui-mcp agent ready — ${agentLabel} on your Codex (ChatGPT) account. Ask away.`
|
|
968
1003
|
: isGm
|
|
969
1004
|
? `🟢 comfyui-mcp agent ready — ${agentLabel} on your Google account (Gemini Code Assist). Ask away.`
|
|
970
|
-
:
|
|
1005
|
+
: isOl
|
|
1006
|
+
? `🟢 comfyui-mcp agent ready — ${agentLabel} running locally via Ollama (no account, no API key). Small local models are slower and simpler than frontier ones — expect fewer frills. Ask away.`
|
|
1007
|
+
: `🟢 comfyui-mcp agent ready — ${agentLabel} on your Claude subscription. Ask away.`;
|
|
971
1008
|
bridge.push({ type: "say", text: readyText }, panelTab);
|
|
972
1009
|
}
|
|
973
1010
|
bridge.push({ type: "ack", ok: true, kind: "ready", agent: agentLabel, backend }, panelTab);
|
|
@@ -978,7 +1015,9 @@ export async function runPanelOrchestrator() {
|
|
|
978
1015
|
? "⚠️ The background agent isn't responding — the Codex app-server couldn't start. Make sure Codex is installed and signed in (run `codex login`), then Disconnect → Connect to retry."
|
|
979
1016
|
: isGm
|
|
980
1017
|
? "⚠️ The background agent isn't responding — the Gemini CLI couldn't start. Make sure the Gemini CLI is installed and signed in (run `gemini` once and complete the Google sign-in), then Disconnect → Connect to retry."
|
|
981
|
-
:
|
|
1018
|
+
: isOl
|
|
1019
|
+
? "⚠️ The background agent isn't responding — Ollama isn't reachable. Start it with `ollama serve` and pull a tool-calling model (e.g. `ollama pull gemma4:e4b`), then Disconnect → Connect to retry."
|
|
1020
|
+
: "⚠️ The background agent isn't responding — the Claude Agent SDK couldn't start. Make sure you're signed in (run `claude` once), then Disconnect → Connect to retry.";
|
|
982
1021
|
bridge.push({ type: "say", text: degradedText }, panelTab);
|
|
983
1022
|
bridge.push({ type: "ack", ok: false, kind: "degraded" }, panelTab);
|
|
984
1023
|
logger.warn(`[panel-orchestrator] tab ${panelTab.slice(0, 8)} connected (${backend}) but model probe empty — degraded ack`);
|