comfyui-mcp 0.52.37 → 0.52.39
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/dist/orchestrator/panel-tools.js +39 -147
- package/dist/orchestrator/panel-tools.js.map +1 -1
- package/dist/services/node-management.js +75 -1
- package/dist/services/node-management.js.map +1 -1
- package/dist/services/panel-graph-cmd-tools.js +183 -0
- package/dist/services/panel-graph-cmd-tools.js.map +1 -0
- package/dist/services/ui-bridge.js +31 -6
- package/dist/services/ui-bridge.js.map +1 -1
- package/dist/services/workspace-env.js +144 -1
- package/dist/services/workspace-env.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool ↔ bridge-command correspondence used by agent-facing refusals.
|
|
3
|
+
*
|
|
4
|
+
* Two maps, one reverse index. The forward maps are NOT injective (graph_load
|
|
5
|
+
* is dispatched by two tools), so the reverse index omits ambiguous commands
|
|
6
|
+
* rather than guessing — a confidently wrong tool name is the defect this
|
|
7
|
+
* module exists to prevent (#1933, #1935).
|
|
8
|
+
*
|
|
9
|
+
* Lives here, not in panel-tools.ts, so ui-bridge can name tools in its own
|
|
10
|
+
* refusals without a circular import (panel-tools already imports ui-bridge).
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* #694 — the MUTATING panel tools that accept retry_of, keyed to the bridge
|
|
14
|
+
* command each dispatches. Covers every command the bridge fences to a workflow
|
|
15
|
+
* (GRAPH_CMD_EFFECT "targeted" — see requiresWorkflowStampEnforcement) plus the
|
|
16
|
+
* four workflow mutators (workflow_save / workflow_save_as / workflow_rename /
|
|
17
|
+
* workflow_close). Navigation/creation (workflow_open / workflow_new) and the
|
|
18
|
+
* tools whose descriptions declare them view/read-only (panel_find_nodes,
|
|
19
|
+
* panel_canvas, panel_screenshot, panel_list_subgraphs) are excluded: a read must
|
|
20
|
+
* never mint or carry a retry token — its retry could be answered from the ledger
|
|
21
|
+
* with a STALE outcome (codex gate).
|
|
22
|
+
*
|
|
23
|
+
* Four UI-STATE commands are admitted on purpose (graph_select_nodes,
|
|
24
|
+
* graph_enter/exit_subgraph, graph_copy_nodes): they change selection, subgraph
|
|
25
|
+
* scope or clipboard idempotently, so a deduped retry is a no-op. THIS MAP — not
|
|
26
|
+
* the workflow fence — is what decides whether a token is minted and whether a
|
|
27
|
+
* caller-supplied one reaches the wire, so those four keep behaving exactly as
|
|
28
|
+
* they did before #778 reclassified them as `inert` for the fence. The two
|
|
29
|
+
* questions are related but not the same, and answering one with the other is
|
|
30
|
+
* the defect #778 is about.
|
|
31
|
+
*
|
|
32
|
+
* EXPLICIT MAP, mirroring the RETRY_SAFE_CMDS / MUTATING_GRAPH_EDIT_CMDS
|
|
33
|
+
* maintenance model — keep in sync when mutating tools are added. Exported for
|
|
34
|
+
* the #694 surface-integrity test.
|
|
35
|
+
*/
|
|
36
|
+
export const RETRY_TOKEN_CMD_BY_TOOL = {
|
|
37
|
+
panel_add_node: "graph_add_node",
|
|
38
|
+
panel_edit_node: "graph_edit_node",
|
|
39
|
+
panel_remove_node: "graph_remove_node",
|
|
40
|
+
panel_clear: "graph_clear",
|
|
41
|
+
panel_flatten_workflow: "graph_load",
|
|
42
|
+
panel_load_workflow: "graph_load",
|
|
43
|
+
panel_connect: "graph_connect",
|
|
44
|
+
panel_disconnect: "graph_disconnect",
|
|
45
|
+
// Idempotent: inputs/outputs/default_mode are absolute values, so a deduped
|
|
46
|
+
// retry writes the same metadata again rather than doubling anything.
|
|
47
|
+
panel_configure_app_mode: "graph_configure_app_mode",
|
|
48
|
+
panel_set_widget: "graph_set_widget",
|
|
49
|
+
panel_remove_widget: "graph_remove_widget",
|
|
50
|
+
panel_set_property: "graph_set_node_property",
|
|
51
|
+
panel_move_node: "graph_move_node",
|
|
52
|
+
panel_resize_node: "graph_resize_node",
|
|
53
|
+
panel_auto_layout: "graph_auto_layout",
|
|
54
|
+
panel_run: "graph_run",
|
|
55
|
+
panel_save_workflow: "workflow_save", // workflow_save_as when `name` is given
|
|
56
|
+
panel_rename_workflow: "workflow_rename",
|
|
57
|
+
panel_close_workflow: "workflow_close",
|
|
58
|
+
panel_select_nodes: "graph_select_nodes",
|
|
59
|
+
panel_create_subgraph: "graph_create_subgraph",
|
|
60
|
+
panel_subgraph_group: "graph_subgraph_group",
|
|
61
|
+
panel_copy_nodes: "graph_copy_nodes",
|
|
62
|
+
panel_paste_nodes: "graph_paste_nodes",
|
|
63
|
+
panel_save_subgraph: "graph_save_subgraph",
|
|
64
|
+
panel_add_subgraph: "graph_add_subgraph",
|
|
65
|
+
panel_create_group: "graph_create_group",
|
|
66
|
+
panel_move_group: "graph_move_group",
|
|
67
|
+
panel_edit_group: "graph_edit_group",
|
|
68
|
+
panel_remove_group: "graph_remove_group",
|
|
69
|
+
panel_set_node_title: "graph_set_title",
|
|
70
|
+
panel_set_node_collapsed: "graph_set_node_collapsed",
|
|
71
|
+
panel_set_node_mode: "graph_set_node_mode",
|
|
72
|
+
panel_set_node_color: "graph_set_node_color",
|
|
73
|
+
panel_enter_subgraph: "graph_enter_subgraph",
|
|
74
|
+
panel_exit_subgraph: "graph_exit_subgraph",
|
|
75
|
+
panel_move_rail: "graph_move_rail",
|
|
76
|
+
panel_promote_widget: "graph_promote_widget",
|
|
77
|
+
panel_expose_subgraph_output: "graph_expose_subgraph_output",
|
|
78
|
+
panel_expose_subgraph_input: "graph_expose_subgraph_input",
|
|
79
|
+
panel_unexpose_subgraph_output: "graph_unexpose_subgraph_output",
|
|
80
|
+
panel_unexpose_subgraph_input: "graph_unexpose_subgraph_input",
|
|
81
|
+
panel_unpack_subgraph: "graph_unpack_subgraph",
|
|
82
|
+
panel_update_node: "graph_update_node",
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* #1935 — the READ / view-only tools that agent-facing refusals may advertise,
|
|
86
|
+
* keyed to the bridge command each dispatches.
|
|
87
|
+
*
|
|
88
|
+
* Separate from RETRY_TOKEN_CMD_BY_TOOL on purpose: a read must never mint a
|
|
89
|
+
* retry token (that map's own doc). The instance-mismatch refusal in ui-bridge
|
|
90
|
+
* still has to NAME these, and the mapping is NOT the `panel_` prefix
|
|
91
|
+
* mechanically applied — `graph_query`'s tool is `panel_query_graph`, not
|
|
92
|
+
* `panel_graph_query`.
|
|
93
|
+
*
|
|
94
|
+
* `graph_get_state` is omitted: it is an internal pre-0.8.2 fallback
|
|
95
|
+
* (panel_strip_workflow reconstruction), not a registered tool. Naming it would
|
|
96
|
+
* send the agent to an "unknown tool" the same way the bare bridge commands did.
|
|
97
|
+
*/
|
|
98
|
+
export const GRAPH_READ_CMD_BY_TOOL = {
|
|
99
|
+
panel_graph_outline: "graph_outline",
|
|
100
|
+
panel_query_graph: "graph_query",
|
|
101
|
+
panel_get_errors: "graph_get_errors",
|
|
102
|
+
panel_find_nodes: "graph_find_nodes",
|
|
103
|
+
panel_list_subgraphs: "graph_list_subgraphs",
|
|
104
|
+
panel_screenshot: "graph_screenshot",
|
|
105
|
+
panel_canvas: "graph_canvas",
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* #1933 — the READ TOOLS the QUEUE BUSY refusal advertises, by their REGISTERED
|
|
109
|
+
* tool name.
|
|
110
|
+
*
|
|
111
|
+
* They must be tool names, not the `graph_outline` / `graph_query` /
|
|
112
|
+
* `graph_get_errors` bridge commands they dispatch: this string is the whole
|
|
113
|
+
* recovery contract for a fenced write, and an agent that follows it calls what
|
|
114
|
+
* it is told to call. A bridge command is not callable, so the advice returned
|
|
115
|
+
* "unknown tool" — a hard failure mid-degraded-state that the agent cannot
|
|
116
|
+
* diagnose, and from which it can only conclude that reads are unavailable
|
|
117
|
+
* during a render, which is precisely the state panel#1489 fixed and this
|
|
118
|
+
* sentence exists to advertise (reported from the field in
|
|
119
|
+
* artokun/comfyui-mcp-panel#1549).
|
|
120
|
+
*
|
|
121
|
+
* Written out (not derived by prefixing `panel_`) because `graph_query`'s tool
|
|
122
|
+
* is `panel_query_graph`. `graph-read-during-render.test.ts` asserts every one
|
|
123
|
+
* of them is in `buildPanelToolDefs()` — the registry the caller actually
|
|
124
|
+
* dispatches against. That test is what stops this list from drifting again:
|
|
125
|
+
* the old literal was green for the whole of its life with all three names
|
|
126
|
+
* wrong, because the assertion matched `/graph_outline/`, which a wrong name
|
|
127
|
+
* and a right one both satisfy.
|
|
128
|
+
*
|
|
129
|
+
* #1935 reuses this same list in the workflow-instance-stamp refusal's
|
|
130
|
+
* refused/unknown branches, rather than a third hand-written name list.
|
|
131
|
+
*/
|
|
132
|
+
export const QUEUE_BUSY_READ_TOOLS = [
|
|
133
|
+
"panel_graph_outline",
|
|
134
|
+
"panel_query_graph",
|
|
135
|
+
"panel_get_errors",
|
|
136
|
+
];
|
|
137
|
+
/**
|
|
138
|
+
* #1933/#1935 — the reverse of RETRY_TOKEN_CMD_BY_TOOL ∪ GRAPH_READ_CMD_BY_TOOL:
|
|
139
|
+
* which TOOL does a caller reach this bridge command through?
|
|
140
|
+
*
|
|
141
|
+
* An agent-facing message written below the tool layer can only see `cmd.cmd`;
|
|
142
|
+
* `PanelToolCtx.call` takes a command object and no tool identity, so by the
|
|
143
|
+
* time a pre-dispatch refusal is worded the tool name is genuinely gone. This
|
|
144
|
+
* recovers it from the maps that already maintain the correspondence, rather
|
|
145
|
+
* than adding another hand-written list that can drift out of step with the
|
|
146
|
+
* first.
|
|
147
|
+
*
|
|
148
|
+
* IT REFUSES TO GUESS. The forward maps are not injective — `graph_load` is
|
|
149
|
+
* dispatched by both `panel_load_workflow` and `panel_flatten_workflow` — and
|
|
150
|
+
* naming one of two possible tools is a confidently wrong answer, which is worse
|
|
151
|
+
* than declining to name one. Ambiguous commands are therefore OMITTED, and
|
|
152
|
+
* callers must handle `undefined`.
|
|
153
|
+
*
|
|
154
|
+
* Coverage of mutations is not assumed either: every `targeted` GRAPH_CMD_EFFECT
|
|
155
|
+
* command except `graph_run` is a value of the retry map, so the queue-busy
|
|
156
|
+
* fence resolves a tool for everything it can refuse except `graph_load`.
|
|
157
|
+
* `graph-read-during-render.test.ts` pins both halves — the resolution and the
|
|
158
|
+
* refusal to guess. Reads resolve through GRAPH_READ_CMD_BY_TOOL; `graph_get_state`
|
|
159
|
+
* is intentionally absent (no callable tool).
|
|
160
|
+
*/
|
|
161
|
+
export const PANEL_TOOL_BY_GRAPH_CMD = (() => {
|
|
162
|
+
const claims = new Map();
|
|
163
|
+
for (const map of [RETRY_TOKEN_CMD_BY_TOOL, GRAPH_READ_CMD_BY_TOOL]) {
|
|
164
|
+
for (const [tool, cmd] of Object.entries(map)) {
|
|
165
|
+
const prior = claims.get(cmd);
|
|
166
|
+
if (prior)
|
|
167
|
+
prior.push(tool);
|
|
168
|
+
else
|
|
169
|
+
claims.set(cmd, [tool]);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const unique = new Map();
|
|
173
|
+
for (const [cmd, tools] of claims)
|
|
174
|
+
if (tools.length === 1)
|
|
175
|
+
unique.set(cmd, tools[0]);
|
|
176
|
+
return unique;
|
|
177
|
+
})();
|
|
178
|
+
/** #1933/#1935 — the registered tool a bridge command is reached through, or
|
|
179
|
+
* `undefined` when no tool, or more than one tool, claims it. */
|
|
180
|
+
export function panelToolForGraphCmd(cmd) {
|
|
181
|
+
return PANEL_TOOL_BY_GRAPH_CMD.get(cmd);
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=panel-graph-cmd-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel-graph-cmd-tools.js","sourceRoot":"","sources":["../../src/services/panel-graph-cmd-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,6 +25,7 @@ import { describePanelUpdateRecovery, } from "./panel-recovery.js";
|
|
|
25
25
|
import { primePanelBase, verifiedPanelDiskVersion } from "./panel-workspace.js";
|
|
26
26
|
import { compareSemver, detectInstallMode } from "./self-update.js";
|
|
27
27
|
import { SHARED_SESSION_SCOPE, isScopeAddress } from "./session-scope.js";
|
|
28
|
+
import { QUEUE_BUSY_READ_TOOLS, panelToolForGraphCmd, } from "./panel-graph-cmd-tools.js";
|
|
28
29
|
export const DEFAULT_BRIDGE_PORT = 9101;
|
|
29
30
|
/** Panel build that first implements the full graph_* / ui_* bridge command set.
|
|
30
31
|
* Used as the DEFAULT minimum for any bridge command not listed in
|
|
@@ -4160,22 +4161,46 @@ export class UiBridge {
|
|
|
4160
4161
|
const PROBE = `Try panel_list_workflows — the panel exempts that read from this fence (it is the ` +
|
|
4161
4162
|
`recovery probe), though a build predating the exemption fences it too. Non-graph ` +
|
|
4162
4163
|
`tools are unaffected.`;
|
|
4164
|
+
// #1935 — name TOOLS, not the bridge commands they dispatch. An agent
|
|
4165
|
+
// that follows this recovery advice calls what it is told to call, and
|
|
4166
|
+
// none of graph_outline / graph_query / graph_get_state is registered.
|
|
4167
|
+
// The mapping is not a mechanical `panel_` prefix (graph_query →
|
|
4168
|
+
// panel_query_graph), so names come from panelToolForGraphCmd /
|
|
4169
|
+
// QUEUE_BUSY_READ_TOOLS rather than a third hand-written list.
|
|
4170
|
+
// graph_get_state is an internal pre-0.8.2 fallback with no callable
|
|
4171
|
+
// tool — the reverse index omits it, so it drops out of the execute
|
|
4172
|
+
// list rather than being advertised.
|
|
4173
|
+
const readTools = QUEUE_BUSY_READ_TOOLS.join(" / ");
|
|
4174
|
+
const viewTools = [
|
|
4175
|
+
"graph_outline",
|
|
4176
|
+
"graph_query",
|
|
4177
|
+
"graph_get_state",
|
|
4178
|
+
"graph_find_nodes",
|
|
4179
|
+
"graph_list_subgraphs",
|
|
4180
|
+
"graph_screenshot",
|
|
4181
|
+
"graph_canvas",
|
|
4182
|
+
]
|
|
4183
|
+
.map((c) => panelToolForGraphCmd(c))
|
|
4184
|
+
.filter((n) => n !== undefined)
|
|
4185
|
+
.join(", ");
|
|
4163
4186
|
const readsNote = readsVerdict === "refused"
|
|
4164
4187
|
? `GRAPH READS ARE REFUSED TOO, for this same missing stamp: this tab's panel ` +
|
|
4165
4188
|
`enforces the per-command fence and refuses an UNSTAMPED command rather than ` +
|
|
4166
|
-
`fail open, so
|
|
4189
|
+
`fail open, so ${readTools} answer "workflow instance mismatch: ` +
|
|
4167
4190
|
`this command carries no workflow-instance stamp" as well. ${PROBE}`
|
|
4168
4191
|
: readsVerdict === "unknown"
|
|
4169
4192
|
? `WHETHER GRAPH READS STILL WORK IS NOT KNOWN FROM HERE, and is not claimed: a ` +
|
|
4170
4193
|
`read carries this session's stamp (${trustedStamp}), and this tab's panel runs ` +
|
|
4171
4194
|
`it only while that stamp still names the ACTIVE canvas — a comparison only the ` +
|
|
4172
4195
|
`panel can make. If the workflow was switched or replaced after this session ` +
|
|
4173
|
-
`bound to it,
|
|
4196
|
+
`bound to it, ${readTools} are refused with "workflow instance ` +
|
|
4174
4197
|
`mismatch" as well; if it was not, they work. ${PROBE}`
|
|
4175
|
-
: `Reads and view-only commands still work (
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4198
|
+
: `Reads and view-only commands still work (${viewTools}).`;
|
|
4199
|
+
// Same defect on the SUBJECT: `cmd.cmd` is the bridge command the tool
|
|
4200
|
+
// dispatched (observed: panel_add_node arrives here as graph_add_node).
|
|
4201
|
+
// Ambiguous commands fall back to a subject naming no tool at all.
|
|
4202
|
+
const subject = panelToolForGraphCmd(typeof cmd.cmd === "string" ? cmd.cmd : "") ?? "This command";
|
|
4203
|
+
const refusal = markDispatched(new Error(`"${subject}" cannot be safely targeted to the active workflow: ${why}. ${readsNote}`), false);
|
|
4179
4204
|
return Promise.reject(capabilityMissing ? markCapabilityRefusal(refusal) : refusal);
|
|
4180
4205
|
}
|
|
4181
4206
|
}
|