forked from 1b-agent/fieldcraft-upstream
MCP open: pass a design's model choice to geometry.open
The open tool's schema and description name the keep/new choice and the reply's related/stale report; docs/mcp.md says the same. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
4a60674530
commit
14e2d25e68
3 files changed
+22
-5
No files matched your search
@@ -163,6 +163,7 @@ fn hostile_tool_arguments_are_tool_errors() {
|
|||||||
("open", json!({"path": "/etc/passwd"})),
|
("open", json!({"path": "/etc/passwd"})),
|
||||||
("open", json!({"path": "/no/such/model.fieldcraft"})),
|
("open", json!({"path": "/no/such/model.fieldcraft"})),
|
||||||
("open", json!({"path": huge.clone() + ".solidcraft"})),
|
("open", json!({"path": huge.clone() + ".solidcraft"})),
|
||||||
|
("open", json!({"path": "/no/such/model.fieldcraft", "model": "new"})),
|
||||||
("save", json!({})),
|
("save", json!({})),
|
||||||
("write_deck", json!({"format": "abaqus", "path": "/no/such/dir/x.inp"})),
|
("write_deck", json!({"format": "abaqus", "path": "/no/such/dir/x.inp"})),
|
||||||
("mesh", json!({"method": "tet", "params": {"body": "Nope", "tolerance": 0.5}})),
|
("mesh", json!({"method": "tet", "params": {"body": "Nope", "tolerance": 0.5}})),
|
||||||
@@ -270,6 +271,7 @@ fn file_access_stays_inside_the_roots() {
|
|||||||
refused(&mut s, "open", json!({"path": input.join("link.solidcraft")}));
|
refused(&mut s, "open", json!({"path": input.join("link.solidcraft")}));
|
||||||
refused(&mut s, "execute", json!({"command": "geometry.open", "params": {"path": input.join("../outside/c.solidcraft")}}));
|
refused(&mut s, "execute", json!({"command": "geometry.open", "params": {"path": input.join("../outside/c.solidcraft")}}));
|
||||||
ok(&mut s, "open", json!({"path": input.join("c.solidcraft")}));
|
ok(&mut s, "open", json!({"path": input.join("c.solidcraft")}));
|
||||||
|
ok(&mut s, "open", json!({"path": input.join("c.solidcraft"), "model": "new"}));
|
||||||
refused(&mut s, "save", json!({"path": outside.join("m.fieldcraft")}));
|
refused(&mut s, "save", json!({"path": outside.join("m.fieldcraft")}));
|
||||||
refused(&mut s, "save", json!({"path": input.join("m.fieldcraft")}));
|
refused(&mut s, "save", json!({"path": input.join("m.fieldcraft")}));
|
||||||
refused(&mut s, "execute", json!({"command": "file.save_as", "params": {"path": outside.join("m.fieldcraft")}}));
|
refused(&mut s, "execute", json!({"command": "file.save_as", "params": {"path": outside.join("m.fieldcraft")}}));
|
||||||
|
|||||||
+19
-4
@@ -139,9 +139,17 @@ pub fn tool_definitions() -> Vec<Value> {
|
|||||||
"open",
|
"open",
|
||||||
"Open a file",
|
"Open a file",
|
||||||
"Open by extension: a .fieldcraft model (file.open: replaces the model; its design and meshes open again), a \
|
"Open by extension: a .fieldcraft model (file.open: replaces the model; its design and meshes open again), a \
|
||||||
SolidCraft design .solidcraft (geometry.open: its bodies become the geometry) or a face-tagged .3mf mesh \
|
SolidCraft design .solidcraft (geometry.open: its bodies become the geometry; `model` \"keep\", the default, \
|
||||||
(geometry.import.mesh: added as a surface).",
|
keeps the mesh and definitions for a reopen after an edit, \"new\" starts a new model; the reply's `related` \
|
||||||
obj(json!({"path": string("Path to a .fieldcraft, .solidcraft or .3mf file")}), &["path"]),
|
and `stale` say what no longer resolves on another part) or a face-tagged .3mf mesh (geometry.import.mesh: \
|
||||||
|
added as a surface).",
|
||||||
|
obj(
|
||||||
|
json!({
|
||||||
|
"path": string("Path to a .fieldcraft, .solidcraft or .3mf file"),
|
||||||
|
"model": {"type": "string", "enum": ["keep", "new"], "description": "For a .solidcraft design: keep the current model (default) or start a new one"},
|
||||||
|
}),
|
||||||
|
&["path"],
|
||||||
|
),
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
@@ -450,7 +458,14 @@ fn dispatch(b: &mut dyn Backend, name: &str, a: &Map<String, Value>) -> Result<V
|
|||||||
Some("3mf") => "geometry.import.mesh",
|
Some("3mf") => "geometry.import.mesh",
|
||||||
_ => return Err("open: a .fieldcraft model, a .solidcraft design or a .3mf mesh".into()),
|
_ => return Err("open: a .fieldcraft model, a .solidcraft design or a .3mf mesh".into()),
|
||||||
};
|
};
|
||||||
let r = b.execute(command, json!({"path": path}))?;
|
let mut params = json!({"path": path});
|
||||||
|
if let Some(model) = a.get("model").filter(|m| !m.is_null()) {
|
||||||
|
if command != "geometry.open" {
|
||||||
|
return Err("open: `model` applies to a .solidcraft design only".into());
|
||||||
|
}
|
||||||
|
params["model"] = model.clone();
|
||||||
|
}
|
||||||
|
let r = b.execute(command, params)?;
|
||||||
Ok(json!({"command": command, "result": r}))
|
Ok(json!({"command": command, "result": r}))
|
||||||
}
|
}
|
||||||
"save" => b.execute("file.save", pick(a, &["path"])),
|
"save" => b.execute("file.save", pick(a, &["path"])),
|
||||||
|
|||||||
+1
-1
@@ -96,7 +96,7 @@ software on the computer.
|
|||||||
| `batch` | `commands: [{command, params}]` | Run steps in order, stop at the first error; the reply has every result and the failing step (`failed.index`, `failed.command`, `failed.error`). Steps before it stay applied (`undo` takes them back). |
|
| `batch` | `commands: [{command, params}]` | Run steps in order, stop at the first error; the reply has every result and the failing step (`failed.index`, `failed.command`, `failed.error`). Steps before it stay applied (`undo` takes them back). |
|
||||||
| `inspect_model` | — | `model.info` (counts, units, definitions), `model.activity` (the step table) and `geometry.bodies` (bodies with measures and persistent face names, which sets name as `{body, face}`). |
|
| `inspect_model` | — | `model.info` (counts, units, definitions), `model.activity` (the step table) and `geometry.bodies` (bodies with measures and persistent face names, which sets name as `{body, face}`). |
|
||||||
| `check_model` | — | `model.check`: errors and warnings, each naming its item. |
|
| `check_model` | — | `model.check`: errors and warnings, each naming its item. |
|
||||||
| `open` | `path` | By extension: `.fieldcraft` (`file.open`), `.solidcraft` (`geometry.open`), `.3mf` (`geometry.import.mesh`). |
|
| `open` | `path`, `model?` | By extension: `.fieldcraft` (`file.open`), `.solidcraft` (`geometry.open`), `.3mf` (`geometry.import.mesh`). For a design, `model` is `keep` (default: the mesh and definitions stay, as a reopen after an edit wants) or `new` (a new model with the design); the reply's `related` is false when the design has none of the bodies the model refers to, and `stale` lists the mesh bodies and sets that no longer resolve. |
|
||||||
| `save` | `path?` | `file.save`: to `path` or the model's own file. |
|
| `save` | `path?` | `file.save`: to `path` or the model's own file. |
|
||||||
| `write_deck` | `format` (abaqus, nastran, lsdyna), `path`, `steps?` | `deck.write`. |
|
| `write_deck` | `format` (abaqus, nastran, lsdyna), `path`, `steps?` | `deck.write`. |
|
||||||
| `mesh` | `method`, `params?` | Runs the mesher (`tet`: `mesh.tet.generate`; `planar`: `mesh.planar`; the hex and block meshers as they land) and replies with its result, `model.info` and `mesh.quality`. |
|
| `mesh` | `method`, `params?` | Runs the mesher (`tet`: `mesh.tet.generate`; `planar`: `mesh.planar`; the hex and block meshers as they land) and replies with its result, `model.info` and `mesh.quality`. |
|
||||||
|
|||||||
Reference in new issue
Block a user