eval_magic/sandbox/
guard.rs1use std::path::Path;
11
12use serde_json::{Map, Value};
13
14use super::decide::GuardMarker;
15
16pub fn read_marker(path: &Path) -> Option<GuardMarker> {
19 let text = std::fs::read_to_string(path).ok()?;
20 serde_json::from_str(&text).ok()
21}
22
23pub(crate) fn parse_tool_call(payload: &str) -> Option<(String, Value)> {
27 let trimmed = payload.trim();
28 let parsed: Value =
29 serde_json::from_str(if trimmed.is_empty() { "{}" } else { trimmed }).ok()?;
30
31 let tool_name = parsed
32 .get("tool_name")
33 .and_then(Value::as_str)
34 .or_else(|| {
35 parsed
36 .get("tool")
37 .and_then(Value::as_object)
38 .and_then(|tool| tool.get("name"))
39 .and_then(Value::as_str)
40 })
41 .unwrap_or("")
42 .to_string();
43
44 let tool_input = merge_top_level_files(
45 parsed
46 .get("tool_input")
47 .or_else(|| parsed.get("input"))
48 .cloned()
49 .unwrap_or(Value::Null),
50 &parsed,
51 );
52
53 Some((tool_name, tool_input))
54}
55
56fn merge_top_level_files(input: Value, parsed: &Value) -> Value {
57 let Some(files) = parsed.get("files") else {
58 return input;
59 };
60
61 match input {
62 Value::Object(mut obj) => {
63 obj.entry("files").or_insert_with(|| files.clone());
64 Value::Object(obj)
65 }
66 Value::Null => {
67 let mut obj = Map::new();
68 obj.insert("files".to_string(), files.clone());
69 Value::Object(obj)
70 }
71 other => other,
72 }
73}