diff --git a/crates/automation/src/tests.rs b/crates/automation/src/tests.rs index 5853f6b9..44a61cc1 100644 --- a/crates/automation/src/tests.rs +++ b/crates/automation/src/tests.rs @@ -1053,3 +1053,14 @@ fn panicked_render_worker_finishes_with_an_error() { let reply: Value = serde_json::from_slice(&out).unwrap(); assert_eq!(reply["result"]["isError"], true, "{reply}"); } + +/// `id` is an accepted alias of `command` (#365 made unknown keys an error). +#[test] +fn command_tools_accept_id_as_an_alias() { + let mut s = server(); + let d = call_json(&mut s, "describe_command", json!({"id": "comp.new"})); + assert_eq!(d["id"], "comp.new", "{d}"); + call_json(&mut s, "execute_command", json!({"id": "comp.new", "params": {"name": "Alias", "width": 64, "height": 36}})); + let (_, err) = call(&mut s, "execute_command", json!({})); + assert!(err, "neither key is an error"); +} diff --git a/crates/automation/src/tools.rs b/crates/automation/src/tools.rs index 89b8b7b8..3e30895b 100644 --- a/crates/automation/src/tools.rs +++ b/crates/automation/src/tools.rs @@ -537,7 +537,12 @@ static TOOLS: &[ToolDef] = &[ name: "describe_command", description: "One command in full: id, label, menu path, shortcut, the `params` doc, a JSON Schema of its parameters (`schema`: properties, required, additionalProperties) and whether it can run now (`why` if not). Use before execute_command when unsure of the parameters; execute_command rejects unknown keys.", bridge_only: false, - schema: || schema(json!({"command": {"type": "string", "description": "Command id, e.g. `layer.newText`."}}), &["command"]), + schema: || { + schema( + json!({"command": {"type": "string", "description": "Command id, e.g. `layer.newText`."}, "id": {"type": "string", "description": "Alias of `command`."}}), + &[], + ) + }, run: describe_command, }, ToolDef { @@ -548,9 +553,10 @@ static TOOLS: &[ToolDef] = &[ schema( json!({ "command": {"type": "string", "description": "Command id, e.g. `comp.new`, `layer.newText`, `effect.apply` (see list_commands)."}, + "id": {"type": "string", "description": "Alias of `command`."}, "params": {"type": "object", "description": "Command parameters as documented by list_commands.", "additionalProperties": true} }), - &["command"], + &[], ) }, run: execute_command, diff --git a/docs/agents.md b/docs/agents.md index fb6b6f5d..85189343 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -80,8 +80,8 @@ See [MCP conventions](mcp.md) for core tools, resources, strict arguments, and r | Tool | What it does | |---|---| | `list_commands {filter?, enabled_only?, schemas?}` | Discover command ids, their param docs (and, with `schemas`, a JSON Schema each), and whether each can run now. | -| `describe_command {command}` | One command in full: label, menu, shortcut, params doc, JSON `schema`, enabled / `why`. | -| `execute_command {command, params?}` | Run any command (undoable). Unknown parameter keys are rejected with the accepted list. | +| `describe_command {command \| id}` | One command in full: label, menu, shortcut, params doc, JSON `schema`, enabled / `why`. | +| `execute_command {command \| id, params?}` | Run any command (undoable). Unknown parameter keys are rejected with the accepted list. | | `get_state` | Editor state (active comp, time, selections, tool) plus `app`: version, command and effect counts, export formats, parity summary. | | `run_script {code, name?}` | Run JavaScript with the After Effects-style scripting object model (`app.project`, `comp.layers.addText(…)`, `layer.property("ADBE Transform Group").property("ADBE Position").setValueAtTime(…)`…). Returns `{ok, result, output, error: {message, line, column}}`; edits are undoable. | | `get_project` / `get_comp {comp?}` | Project items, comp settings and layers. |