MCP batch takes verbose: false for compact replies: feature steps leave out the full body list and sketch steps the ids they repeat outside created. Feature replies now also list changed_bodies and removed_bodies next to created_bodies, so a compact reply still shows every effect of a step. Un-ignores the #530 regression test. Fixes #530. Co-authored-by: jonaswre <jonas.wrede@beyondit.gmbh>
This commit is contained in:
1 parent
94ab54d1f5
commit
a4ca1b68db
5 files changed
+78
-6
No files matched your search
+25
-1
@@ -459,7 +459,6 @@ fn screenshot_renders_a_saved_named_view() {
|
||||
/// is mostly the same body list once per step. A compact batch reply names only what each step
|
||||
/// added or changed.
|
||||
#[test]
|
||||
#[ignore = "fails until #530 is fixed"]
|
||||
fn compact_batch_reply_does_not_repeat_the_body_list() {
|
||||
let mut s = server();
|
||||
let cube =
|
||||
@@ -480,6 +479,31 @@ fn compact_batch_reply_does_not_repeat_the_body_list() {
|
||||
}
|
||||
}
|
||||
|
||||
/// A compact batch reply keeps what each step did: the body a cut changed, and a sketch
|
||||
/// command's new ids once (under `created`); the default reply is unchanged.
|
||||
#[test]
|
||||
fn compact_batch_reply_keeps_changed_bodies_and_created_ids() {
|
||||
let mut s = server();
|
||||
let steps = json!([
|
||||
{"command": "solid.box", "params": {"length": 10, "width": 10, "height": 10, "body_name": "Base"}},
|
||||
{"command": "solid.box", "params": {"length": 4, "width": 4, "height": 10, "corner": [3, 3, 5], "operation": "cut", "targets": ["Base"]}},
|
||||
{"command": "sketch.create", "params": {"plane": "XY"}},
|
||||
{"command": "sketch.rectangle.two_point", "params": {"p0": [20, 0], "p1": [30, 10]}},
|
||||
]);
|
||||
let full = tool(&mut s, "batch", json!({"commands": steps}));
|
||||
assert_eq!(full["results"][1]["bodies"], json!(["Base"]), "{full}");
|
||||
assert_eq!(full["results"][3]["curves"], full["results"][3]["created"]["curves"], "{full}");
|
||||
tool(&mut s, "new_design", json!({}));
|
||||
let r = tool(&mut s, "batch", json!({"commands": steps, "verbose": false}));
|
||||
let cut = &r["results"][1];
|
||||
assert!(cut.get("bodies").is_none(), "{r}");
|
||||
assert_eq!(cut["changed_bodies"], json!(["Base"]), "{r}");
|
||||
let rect = &r["results"][3];
|
||||
assert!(rect.get("curves").is_none() && rect.get("constraints").is_none(), "{r}");
|
||||
assert_eq!(rect["created"]["curves"].as_array().map(Vec::len), Some(4), "{r}");
|
||||
assert!(rect["sides"].is_object(), "results that are not repeated stay: {r}");
|
||||
}
|
||||
|
||||
/// #531: a product model keeps an optional variant hidden in its default presentation. Hiding
|
||||
/// it must survive saving and reopening the design (suppressing it would change the design).
|
||||
#[test]
|
||||
|
||||
+22
-2
@@ -63,7 +63,7 @@ pub fn tool_definitions() -> Vec<Value> {
|
||||
created: {points, curves, constraints, dimensions}: the ids of what they added, stable and not reused \
|
||||
after a delete (undo rewinds the counters with the design), usable right away \
|
||||
in sketch.dimension, sketch.constraint.* and sketch.delete. Feature commands return the feature's id \
|
||||
and name, every body (bodies) and the bodies the feature created (created_bodies).",
|
||||
and name, every body (bodies) and the bodies the feature created, changed and removed (created_bodies, changed_bodies, removed_bodies).",
|
||||
obj(
|
||||
json!({
|
||||
"command": string("Command id (see list_commands)"),
|
||||
@@ -89,6 +89,7 @@ pub fn tool_definitions() -> Vec<Value> {
|
||||
"items": {"type": "object", "properties": {"command": {"type": "string"}, "params": {"type": "object"}}, "required": ["command"]},
|
||||
},
|
||||
"rollback": {"type": "boolean", "description": "Undo completed steps when one fails (default true)"},
|
||||
"verbose": {"type": "boolean", "description": "false: a compact reply. Feature steps leave out the full body list (created_bodies, changed_bodies and removed_bodies stay), sketch steps the ids they repeat outside `created` (default true)"},
|
||||
}),
|
||||
&["commands"],
|
||||
),
|
||||
@@ -449,6 +450,7 @@ fn batch(b: &mut dyn Backend, a: &Map<String, Value>) -> Value {
|
||||
return text_result(&json!(format!("batch too long ({} steps, at most {MAX_BATCH})", steps.len())), true);
|
||||
}
|
||||
let rollback = a.get("rollback").and_then(Value::as_bool).unwrap_or(true);
|
||||
let verbose = a.get("verbose").and_then(Value::as_bool).unwrap_or(true);
|
||||
let start = if rollback { Undo::begin(b) } else { Undo::None };
|
||||
let mut results = Vec::with_capacity(steps.len());
|
||||
for (i, step) in steps.iter().enumerate() {
|
||||
@@ -458,7 +460,7 @@ fn batch(b: &mut dyn Backend, a: &Map<String, Value>) -> Value {
|
||||
None => Err("missing `command`".to_string()),
|
||||
};
|
||||
match r {
|
||||
Ok(v) => results.push(v),
|
||||
Ok(v) => results.push(if verbose { v } else { compact(v) }),
|
||||
Err(e) => {
|
||||
let undone = start.rollback(b, i);
|
||||
return text_result(
|
||||
@@ -479,6 +481,24 @@ fn batch(b: &mut dyn Backend, a: &Map<String, Value>) -> Value {
|
||||
text_result(&json!({"ok": true, "completed": results.len(), "results": results}), false)
|
||||
}
|
||||
|
||||
/// A step's result without what the design already had (`batch` with `verbose: false`): a
|
||||
/// feature's full body list (its created, changed and removed bodies stay), and the sketch ids
|
||||
/// a sketch command repeats outside `created`.
|
||||
fn compact(mut v: Value) -> Value {
|
||||
let Some(o) = v.as_object_mut() else { return v };
|
||||
if o.contains_key("created_bodies") {
|
||||
o.remove("bodies");
|
||||
}
|
||||
if let Some(created) = o.get("created").cloned() {
|
||||
for k in ["points", "curves", "constraints", "dimensions"] {
|
||||
if o.get(k).is_some_and(|x| created.get(k) == Some(x)) {
|
||||
o.remove(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
static SHOT: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
/// `screenshot`: render or capture to a file, return it as an MCP image content block.
|
||||
|
||||
Reference in new issue
Block a user