Let an AI agent read and edit the open project through MCP (#429)
Stage 2 of #429. Until now an agent could only look at the editor. Now it reads the project and changes it through the same commands the user's own edits run, so every change shows up live and one Ctrl+Z takes back a whole agent call. - Read tools: list_assets, get_asset, get_graph and catalog. The catalog lists the commands with their arguments, the nodes of a graph from the same palette the user sees, asset types and variable kinds. - run_commands runs its steps as one undo step named "Agent: ...". A failing step rolls back the steps before it. The answer names the step and the reason the editor gave. - A step can name what it made ("as") and later steps use "$name". Each step is built after the one before has run, so one call can make a behavior and fill it. - 23 commands cover assets, variables, scene objects and graphs. Textures, fonts, sounds and videos need a file and are left out. - open, select, play and undo/redo drive the editor. - Deleting asks the user with the same text as their own delete. The tab sends "wait", and the relay then gives the call 2 minutes instead of 30 seconds. - tools.json is the only source of the argument schemas. argCheck checks every call against them before anything runs. - An open menu now names its first entries in get_view, instead of an empty title. - The new host functions live in editorToolHost.ts, so Editor.ts does not grow further. Found while testing: e2e 71 hung for 30 s in Page.navigate after a failure. The beforeunload guard of an unsaved project held the page and hid the real error. The module now reports the error first and waits for the save before it navigates. Tests: - Gate on melektaus-atx: CHECK EXIT 0, 317 files, 4903 tests. - agent-edit 14/14, agent-view 10/10, relay 24/24. - e2e 71 16/16 on atx and against the live site. One call builds a sprite with an arrow-key behavior, play moves it from x 0 to -125, and one undo restores the assets exactly. - Counter-checks turned red: no rollback, a partial undo, no delete question, a relay that ignores "wait". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
48ec722660
commit
25af064249
19 files changed
+1913
-60
No files matched your search
+168
-1
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"name": "get_view",
|
||||
"title": "What the user sees",
|
||||
"description": "What the user is looking at in the editor right now: the project, the open tab and document, the selection (asset, scene objects, graph nodes, keys, ...), the camera of the view showing, whether the game is playing or paused, and an open dialog. Call it first, and again whenever you were told the view changed.",
|
||||
"description": "What the user is looking at in the editor right now: the project, the open tab and document, the selection (asset, scene objects, graph nodes, keys, ...), the camera of the view showing, whether the game is playing or paused, and an open menu or dialog. Call it first, and again whenever you were told the view changed.",
|
||||
"inputSchema": { "type": "object", "properties": {}, "additionalProperties": false },
|
||||
"annotations": { "readOnlyHint": true, "openWorldHint": false }
|
||||
},
|
||||
@@ -23,5 +23,172 @@
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": { "readOnlyHint": true, "openWorldHint": false }
|
||||
},
|
||||
{
|
||||
"name": "list_assets",
|
||||
"title": "List the assets",
|
||||
"description": "The project's assets with their ids, names and types, and how many objects or nodes each holds. Filter by type and by a part of the name.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Only assets of this type (scene, sprite, behavior, ...)."
|
||||
},
|
||||
"query": { "type": "string", "description": "Only assets whose name contains this." }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": { "readOnlyHint": true, "openWorldHint": false }
|
||||
},
|
||||
{
|
||||
"name": "get_asset",
|
||||
"title": "Read an asset",
|
||||
"description": "One asset as stored: its property values, the rows of its properties (key, kind, default), the objects of a scene or container with their names and positions. A graph is only counted here; read it with get_graph.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": { "asset": { "type": "string", "description": "Id of the asset." } },
|
||||
"required": ["asset"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": { "readOnlyHint": true, "openWorldHint": false }
|
||||
},
|
||||
{
|
||||
"name": "get_graph",
|
||||
"title": "Read a graph",
|
||||
"description": "The graph of a behavior, state machine, shader, particles, sound FX or instrument: each node with its settings and its input and output ports as they are now, the edges between ports, and the groups and notes.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": { "asset": { "type": "string", "description": "Id of the asset holding the graph." } },
|
||||
"required": ["asset"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": { "readOnlyHint": true, "openWorldHint": false }
|
||||
},
|
||||
{
|
||||
"name": "catalog",
|
||||
"title": "What can be made",
|
||||
"description": "Looks things up before an edit. topic \"commands\": every command run_commands knows, with its arguments. topic \"nodes\" with asset: the nodes that graph can hold; with query, the best matches in full (ports, settings). topic \"asset_types\": the kinds of asset; with type, that kind's properties. topic \"variable_kinds\": what a variable can hold.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"topic": { "type": "string", "enum": ["commands", "nodes", "asset_types", "variable_kinds"] },
|
||||
"asset": { "type": "string", "description": "For nodes: id of the graph asset." },
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "For nodes: words to search for, like \"key held\" or \"move\"."
|
||||
},
|
||||
"type": { "type": "string", "description": "For asset_types: one type to describe in full." }
|
||||
},
|
||||
"required": ["topic"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": { "readOnlyHint": true, "openWorldHint": false }
|
||||
},
|
||||
{
|
||||
"name": "run_commands",
|
||||
"title": "Change the project",
|
||||
"description": "Runs commands (catalog topic \"commands\") in order as ONE undo step: if one fails, none of them stays, and the answer names the step. A step with \"as\": \"name\" lets later steps use what it made: \"$name\" is its id, \"$name.closing\" another id it names. Each step is built after the one before has run, so a step can add nodes to a behavior made in the same call. Deleting an asset asks the user first.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"steps": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": { "type": "string", "minLength": 1, "description": "Name of the command." },
|
||||
"args": { "type": "object", "description": "Its arguments, as the catalog lists them." },
|
||||
"as": { "type": "string", "minLength": 1, "description": "A name for what this step makes." }
|
||||
},
|
||||
"required": ["command"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "What the edit does, in a few words: the user sees it as the undo step."
|
||||
}
|
||||
},
|
||||
"required": ["steps"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": {
|
||||
"readOnlyHint": false,
|
||||
"destructiveHint": true,
|
||||
"idempotentHint": false,
|
||||
"openWorldHint": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "open",
|
||||
"title": "Show something",
|
||||
"description": "Brings up an asset's tab (a scene becomes the scene being edited), or the scene or game tab.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"asset": { "type": "string", "description": "Id of the asset to open." },
|
||||
"tab": { "type": "string", "enum": ["scene", "game"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": { "readOnlyHint": false, "destructiveHint": false, "openWorldHint": false }
|
||||
},
|
||||
{
|
||||
"name": "select",
|
||||
"title": "Select",
|
||||
"description": "Selects an asset, placed objects of a scene or container, or nodes of a graph – what the inspector then shows. kind \"none\" clears the selection.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"kind": { "type": "string", "enum": ["none", "asset", "objects", "nodes"] },
|
||||
"asset": {
|
||||
"type": "string",
|
||||
"description": "The asset (kind asset), or the graph asset (kind nodes)."
|
||||
},
|
||||
"in": { "type": "string", "description": "Kind objects: the scene or container." },
|
||||
"objects": { "type": "array", "items": { "type": "string" } },
|
||||
"nodes": { "type": "array", "items": { "type": "string" } }
|
||||
},
|
||||
"required": ["kind"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": { "readOnlyHint": false, "destructiveHint": false, "openWorldHint": false }
|
||||
},
|
||||
{
|
||||
"name": "play",
|
||||
"title": "Play the game",
|
||||
"description": "Plays the game in the editor, pauses, resumes or stops it. Edits made while it runs change the running copy only and are gone when it stops.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": { "action": { "type": "string", "enum": ["play", "pause", "resume", "stop"] } },
|
||||
"required": ["action"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": { "readOnlyHint": false, "destructiveHint": false, "openWorldHint": false }
|
||||
},
|
||||
{
|
||||
"name": "undo",
|
||||
"title": "Undo",
|
||||
"description": "Takes back the last edits, the user's as well as yours, like Ctrl+Z; one run_commands call is one step.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": { "steps": { "type": "integer", "minimum": 1, "maximum": 20 } },
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": { "readOnlyHint": false, "destructiveHint": false, "openWorldHint": false }
|
||||
},
|
||||
{
|
||||
"name": "redo",
|
||||
"title": "Redo",
|
||||
"description": "Does the edits again that undo took back, like Ctrl+Y.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": { "steps": { "type": "integer", "minimum": 1, "maximum": 20 } },
|
||||
"additionalProperties": false
|
||||
},
|
||||
"annotations": { "readOnlyHint": false, "destructiveHint": false, "openWorldHint": false }
|
||||
}
|
||||
]
|
||||
Reference in new issue
Block a user