Merge pull request #1177 from storytold/fix/1163-preview-artboard
#1163: MCP render_preview takes an artboard index
This commit is contained in:
commit
433c8d5aa7
File diff suppressed because one or more lines are too long
|
|
@ -65,6 +65,17 @@ fn conventions_commands_batch_and_bounded_preview() {
|
|||
for max in [json!(0), json!(4097), json!("64")] {
|
||||
assert_eq!(call(&mut s, "render_preview", json!({"max_side":max}))["isError"], true);
|
||||
}
|
||||
// Another artboard, three times wider than tall, previews by its index (#1163).
|
||||
let r = call(&mut s, "run_command", json!({"command":"artboard.new","params":{"x":2000,"y":0,"width":300,"height":100}}));
|
||||
assert_eq!(r["isError"], false, "{r}");
|
||||
let r = call(&mut s, "render_preview", json!({"max_side":60,"artboard":1}));
|
||||
assert_eq!(r["isError"], false, "{r}");
|
||||
let png = vectorcraft_format::base64_decode(r["content"][0]["data"].as_str().unwrap()).unwrap();
|
||||
let img = image::load_from_memory(&png).unwrap();
|
||||
assert_eq!((img.width(), img.height()), (60, 20));
|
||||
for board in [json!(2), json!(-1), json!("1")] {
|
||||
assert_eq!(call(&mut s, "render_preview", json!({"artboard":board}))["isError"], true, "{board}");
|
||||
}
|
||||
for name in ["ui_inspect", "ui_screenshot"] {
|
||||
assert_eq!(call(&mut s, name, json!({}))["isError"], true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,8 +113,11 @@ pub fn tool_definitions() -> Vec<Value> {
|
|||
tool(
|
||||
"render_preview",
|
||||
"Render a preview",
|
||||
"Render the first artboard as inline PNG without changing the document. max_side defaults to 1024, limited to 1..4096.",
|
||||
obj(json!({"max_side":{"type":"integer","minimum":1,"maximum":4096}}), &[]),
|
||||
"Render an artboard (default the first) as inline PNG without changing the document. max_side defaults to 1024, limited to 1..4096.",
|
||||
obj(
|
||||
json!({"max_side":{"type":"integer","minimum":1,"maximum":4096},"artboard":{"type":"integer","minimum":0,"description":"0-based artboard (default 0)"}}),
|
||||
&[],
|
||||
),
|
||||
true,
|
||||
),
|
||||
tool("ui_inspect", "Inspect the interface", "Inspect the connected desktop interface; returns a tool error in headless mode.", empty(), true),
|
||||
|
|
@ -946,8 +949,13 @@ fn render_preview(b: &mut dyn Backend, a: &Args) -> Result<ToolResult, String> {
|
|||
None => 1024,
|
||||
Some(v) => v.as_u64().filter(|v| (1..=4096).contains(v)).ok_or("`max_side` must be an integer in 1..4096")?,
|
||||
};
|
||||
let index = match a.get("artboard") {
|
||||
None => 0,
|
||||
Some(v) => v.as_u64().ok_or("`artboard` must be a 0-based artboard index")?,
|
||||
};
|
||||
let doc = b.call("document.inspect", json!({"depth":0}))?;
|
||||
let board = doc.get("artboards").and_then(Value::as_array).and_then(|v| v.first()).ok_or("no such artboard")?;
|
||||
let board =
|
||||
doc.get("artboards").and_then(Value::as_array).and_then(|v| v.get(usize::try_from(index).ok()?)).ok_or(format!("no artboard {index}"))?;
|
||||
let width = board.get("width").and_then(Value::as_f64).ok_or("artboard has no width")?;
|
||||
let height = board.get("height").and_then(Value::as_f64).ok_or("artboard has no height")?;
|
||||
if !width.is_finite() || !height.is_finite() || width <= 0.0 || height <= 0.0 {
|
||||
|
|
@ -959,7 +967,7 @@ fn render_preview(b: &mut dyn Backend, a: &Args) -> Result<ToolResult, String> {
|
|||
if width.max(height) * scale > 4096.0 {
|
||||
return Err("artboard is too large for a bounded preview".into());
|
||||
}
|
||||
let r = b.call("ui.render", json!({"scale":scale}))?;
|
||||
let r = b.call("ui.render", json!({"scale":scale, "artboard": index}))?;
|
||||
let encoded = r.get("pngBase64").and_then(Value::as_str).ok_or("renderer returned no image")?;
|
||||
let png = vectorcraft_format::base64_decode(encoded).ok_or("renderer returned bad base64")?;
|
||||
let img = image::load_from_memory_with_format(&png, image::ImageFormat::Png).map_err(|e| format!("read preview: {e}"))?;
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ The older names below remain listed because existing workflows use them.
|
|||
| `command_run` | `id`, optional `params`; runs the command through the existing backend |
|
||||
| `command_batch` | `steps: [{id, params?}]`, optional `stop_on_error` (default true); returns `completed`, `failed`, `results: [{ok, result\|error}]`. Each edit has its own undo step; failures set `isError`. A param string `"$N.path"` or `"$last.path"` takes a value from an earlier step's result (see `run` below) |
|
||||
| `doc_inspect` | Optional `depth`, `childLimit`; same summary as `inspect_document` |
|
||||
| `render_preview` | Optional `max_side` (1–4096, default 1024); inline PNG of the first artboard without editing it. Artboards too large to render within the allocation bound return a tool error |
|
||||
| `render_preview` | Optional `max_side` (1–4096, default 1024) and `artboard` (0-based, default 0); inline PNG of that artboard without editing it. Artboards too large to render within the allocation bound return a tool error |
|
||||
| `ui_inspect`, `ui_screenshot` | Connected desktop state/window capture; tool errors in headless mode |
|
||||
|
||||
Every tool declares read-only, destructive, idempotent and open-world hints. File-writing
|
||||
|
|
|
|||
Loading…
Reference in New Issue