Let the agent use the graph, scene and project commands (#429)
feuerwerk / gate (push) Successful in 5m10s
feuerwerk / suite (push) Failing after 18m49s

The agent knew 23 of the editor's commands. It could not point a
Variables node at a variable, group nodes, edit ports, transitions,
containers, colliders or the project settings. Stage 5a brings the
catalog to 85 commands in five areas and keeps every answer short.

- The catalog lists names and descriptions only. With a query (an
  area or command names) it adds the arguments. All schemas at once
  would pass the 60 000 character limit of one answer.
- add_port points a Variables node at a variable. The port takes the
  variable's kind, and an unknown name is refused with the list of
  the ones that exist.
- add_group and add_comment take nodes instead of coordinates. They
  follow the nodes after the arrange step, in the same undo step.
- The rule for which list a port picks from moved into portChoices.ts.
  Inspector and agent now share it.
- The frame of a group around nodes moved into annotationDrag.ts, so
  the button and the agent get the same frame.
- list_assets returns the project settings. get_asset shows the
  content of placed containers with the ids overrides need. get_graph
  shows declared ports and frame colors.
- A new node is placed at the height of its port, in the free spot
  whose links cross the fewest others. A source goes left of the node
  it feeds. Before, new nodes always went right of the rest.
- Arrange breaks a tie in crossings by putting the flow on top, and
  exec links pull harder when a column is sorted.
- A comment over a group keeps clear of the group's title bar.
- The agent's instructions and lint_graph ask to look at crossings
  too and to call arrange_graph when there are more than needed.

Left out on purpose: file assets (no upload), paste from the
clipboard, internal wrapper commands and switching plugins on.

Found on the way:
- Variable commands on a Struct asset did not run through
  WithStructTypes. New fields did not reach variables of that type.
- A query "variables" also matched set_variables_scope. A word that
  names an area now means only that area.

Tests:
- agent-catalog (new, 10), agent-edit, graph-arrange (3 new) and
  relay green. 11 bends of the code, all red.
- e2e 71 on atx: 22/22, the new check sees port speed and a group
  around all 4 drawn nodes.
- Live on a test project: a speed variable of 300 moved the player
  to x 150.03 in 0.5 s. A re-placed Variables node landed below Axis
  input with 4 crossings instead of 7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-18 16:01:15 +02:00
1 parent 1943539a7a
commit 0d8fd6ff52
26 files changed
+2585 -672

No files matched your search

+39
View File
@@ -346,6 +346,45 @@ export async function mcp(t) {
JSON.stringify({ zoomBefore, ...farView }),
);
// 71g5. Past nodes and edges (#429 stage 5a): a Variables node reads a variable once add_port names it,
// and a group made in the same call frames every node as drawn, the one the call arranged among them.
const gathered = await callTool('run_commands', {
label: 'speed in a group',
steps: [
{ command: 'add_variable', args: { asset: walkId, key: 'speed', kind: 'number' } },
{ command: 'add_node', args: { asset: walkId, node: 'Variables' }, as: 'vars' },
{ command: 'add_port', args: { asset: walkId, node: '$vars', key: 'speed' } },
{
command: 'add_group',
args: { asset: walkId, nodes: [...graph.nodes.map((node) => node.id), '$vars'], title: 'Walk' },
},
],
});
await settle();
const groupId = gathered?.structuredContent?.made?.find((entry) => entry.step === 4)?.id;
const varsId = gathered?.structuredContent?.made?.find((entry) => entry.step === 2)?.id;
const framing = await json(`(() => {
const box = __gm.graph.annotationRect(${JSON.stringify(groupId)});
const ids = ${JSON.stringify([...graph.nodes.map((node) => node.id), varsId])};
const nodes = ids.map((id) => __gm.graph.nodeRect(id));
const inside = Boolean(box) && nodes.every((n) => n && n.x > box.x && n.y > box.y &&
n.x + n.w < box.x + box.w && n.y + n.h < box.y + box.h);
return { box, nodes, inside };
})()`);
const readVars = (await callTool('get_graph', { asset: walkId }))?.structuredContent?.nodes?.find(
(node) => node.id === varsId,
);
const gatheredLint = (await callTool('lint_graph', { asset: walkId }))?.structuredContent;
await callTool('undo');
check(
'add_port names a variable on a Variables node, and add_group frames every drawn node of the call',
gathered?.isError === false &&
framing.inside &&
readVars?.outputs?.some((port) => port.key === 'speed' && port.type === 'number') &&
gatheredLint?.overlaps === 0,
JSON.stringify({ text: gathered?.content?.[0]?.text?.slice(0, 300), framing, readVars, gatheredLint }),
);
// 71h. Played by the agent, the object walks left while the user holds the arrow.
const started = await callTool('play', { action: 'play' });
await waitUntil('__gm.state.mode === "play"', { timeout: 10000, label: 'the game runs' });
+8 -4
View File
@@ -35,12 +35,16 @@ const INSTRUCTIONS = [
'live: the user sees every change you make and can take it back with Ctrl+Z.',
'Start with get_view to learn what the user is looking at; screenshot shows it as a picture.',
'Read the project with list_assets, get_asset and get_graph. Change it with run_commands: its steps',
'are commands from catalog topic "commands", run as one undo step, and a step can name what an',
'earlier one made ("as": "x", then "$x"). Nodes for a graph come from catalog topic "nodes".',
'A behavior acts on the object it is placed under: place it with parent set to that object.',
'are commands from catalog topic "commands" (by area; ask with query for their arguments), run as',
'one undo step, and a step can name what an earlier one made ("as": "x", then "$x"). Nodes for a',
'graph come from catalog topic "nodes". A Variables node reads or writes a variable once add_port',
'names it. A behavior acts on the object it is placed under: place it with parent set to that object.',
'Give new nodes no x and y: the editor arranges them when the call ends, and leaves the nodes',
'already there where they are. Keep a graph readable: a value needed far away comes from a second',
'Get or Owner node next to its user, not over a long link; check with lint_graph.',
'Get or Owner node next to its user, not over a long link. Check with lint_graph, the crossings',
'too: when there are more than the links need, arrange_graph orders the whole graph for the',
'fewest. Put nodes that belong together into a group with add_group, and say what they do with',
'add_comment.',
'The editor follows your edits: after run_commands the user sees the graph, scene or asset it worked',
'on, with what it touched selected. Use open and select to show anything else.',
'Test what you built yourself: play, then play_input sends keys and mouse clicks into the game,',