use car_ir::{ActionProposal, ToolSchema};
use serde_json::Value;
use std::collections::{HashMap, HashSet};
pub fn verify(
proposal_json: &str,
initial_state_json: Option<&str>,
tool_names: Option<Vec<String>>,
max_actions: usize,
tool_schemas_json: Option<&str>,
) -> Result<String, String> {
let proposal: ActionProposal =
serde_json::from_str(proposal_json).map_err(|e| format!("invalid proposal JSON: {}", e))?;
let initial_state: Option<HashMap<String, Value>> = initial_state_json
.map(|s| serde_json::from_str(s))
.transpose()
.map_err(|e| format!("invalid state JSON: {}", e))?;
let result = if let Some(schemas_json) = tool_schemas_json {
let schemas: Vec<ToolSchema> = serde_json::from_str(schemas_json)
.map_err(|e| format!("invalid tool schemas JSON: {}", e))?;
let map: HashMap<String, ToolSchema> =
schemas.into_iter().map(|s| (s.name.clone(), s)).collect();
car_verify::verify_with_schemas(&proposal, initial_state.as_ref(), Some(&map), max_actions)
} else {
let tools: Option<HashSet<String>> = tool_names.map(|v| v.into_iter().collect());
car_verify::verify(
&proposal,
initial_state.as_ref(),
tools.as_ref(),
max_actions,
)
};
serde_json::to_string(&serde_json::json!({
"valid": result.valid,
"issues": result.issues.iter().map(|i| serde_json::json!({
"action_id": i.action_id,
"severity": i.severity,
"message": i.message,
})).collect::<Vec<_>>(),
"simulated_state": result.simulated_state,
"execution_levels": result.execution_levels,
"conflicts": result.conflicts,
"evidence": result.evidence,
}))
.map_err(|e| e.to_string())
}
pub fn simulate(proposal_json: &str, initial_state_json: Option<&str>) -> Result<String, String> {
let proposal: ActionProposal =
serde_json::from_str(proposal_json).map_err(|e| format!("invalid proposal JSON: {}", e))?;
let initial_state: Option<HashMap<String, Value>> = initial_state_json
.map(|s| serde_json::from_str(s))
.transpose()
.map_err(|e| format!("invalid state JSON: {}", e))?;
let state = car_verify::simulate(&proposal, initial_state.as_ref());
serde_json::to_string(&state).map_err(|e| e.to_string())
}
pub fn optimize(proposal_json: &str) -> Result<String, String> {
let proposal: ActionProposal =
serde_json::from_str(proposal_json).map_err(|e| format!("invalid proposal JSON: {}", e))?;
let optimized = car_verify::optimize(&proposal);
serde_json::to_string(&optimized).map_err(|e| e.to_string())
}
pub fn transaction_check(
proposal_json: &str,
versions_json: Option<&str>,
state_json: Option<&str>,
) -> Result<String, String> {
let proposal: ActionProposal = crate::from_json("proposal", proposal_json)?;
let versions: HashMap<String, u64> =
crate::from_json_opt("versions", versions_json)?.unwrap_or_default();
let state: Option<HashMap<String, Value>> = crate::from_json_opt("state", state_json)?;
let report = car_verify::check_transaction(&proposal, &versions, state.as_ref());
crate::to_json(&report)
}
pub fn transaction_check_with_predictions(
proposal_json: &str,
versions_json: Option<&str>,
state_json: Option<&str>,
predictions_json: &str,
) -> Result<String, String> {
let proposal: ActionProposal = crate::from_json("proposal", proposal_json)?;
let versions: HashMap<String, u64> =
crate::from_json_opt("versions", versions_json)?.unwrap_or_default();
let state: Option<HashMap<String, Value>> = crate::from_json_opt("state", state_json)?;
let predicted: HashMap<String, Vec<String>> = crate::from_json("predictions", predictions_json)?;
let report = car_verify::check_transaction_with_predictions(
&proposal,
&versions,
state.as_ref(),
&predicted,
);
crate::to_json(&report)
}
pub fn check_information_flow(
proposal_json: &str,
labels_json: &str,
policy_json: Option<&str>,
) -> Result<String, String> {
let proposal: ActionProposal = crate::from_json("proposal", proposal_json)?;
let labels: HashMap<String, car_verify::ToolLabels> = crate::from_json("labels", labels_json)?;
let policy: car_verify::FlowPolicy =
crate::from_json_opt("policy", policy_json)?.unwrap_or_default();
let report = car_verify::check_information_flow(&proposal, &labels, &policy);
crate::to_json(&report)
}
pub fn gate_information_flow(
report_json: &str,
gate_policy_json: Option<&str>,
) -> Result<String, String> {
let report: car_verify::FlowReport = crate::from_json("report", report_json)?;
let policy: car_verify::FlowGatePolicy =
crate::from_json_opt("gate policy", gate_policy_json)?.unwrap_or_default();
let decision = car_verify::gate_flow(&report, &policy);
crate::to_json(&decision)
}
pub fn enforce_information_flow(
decision_json: &str,
approvals_json: Option<&str>,
) -> Result<String, String> {
let decision: car_verify::FlowGateDecision = crate::from_json("decision", decision_json)?;
let mut ledger = car_policy::permission::ApprovalLedger::new();
if let Some(aj) = approvals_json {
let records: Vec<car_policy::permission::ApprovalRecord> =
crate::from_json("approvals", aj)?;
for r in records {
ledger
.record(r)
.map_err(|e| format!("record approval: {e}"))?;
}
}
let enforcement = car_policy::enforce_flow(&decision, &ledger);
crate::to_json(&enforcement)
}
pub fn equivalent(p1_json: &str, p2_json: &str) -> Result<bool, String> {
let p1: ActionProposal =
serde_json::from_str(p1_json).map_err(|e| format!("invalid proposal1 JSON: {}", e))?;
let p2: ActionProposal =
serde_json::from_str(p2_json).map_err(|e| format!("invalid proposal2 JSON: {}", e))?;
Ok(car_verify::equivalent(&p1, &p2, None))
}
pub fn analyze_concurrency(ops_json: &str) -> Result<String, String> {
let ops: Vec<car_verify::AgentOp> = crate::from_json("ops", ops_json)?;
let report = car_verify::analyze_concurrency(&ops);
crate::to_json(&report)
}
pub fn gate_concurrency(report_json: &str, policy_json: Option<&str>) -> Result<String, String> {
let report: car_verify::ConcurrencyReport = crate::from_json("report", report_json)?;
let policy: car_verify::ConcurrencyGatePolicy = match policy_json {
Some(p) => crate::from_json("policy", p)?,
None => car_verify::ConcurrencyGatePolicy::default(),
};
let gate = car_verify::gate_concurrency(&report, &policy);
crate::to_json(&gate)
}
pub fn verify_workflow_graph(graph_json: &str) -> Result<String, String> {
let graph: car_verify::WorkflowGraph = crate::from_json("graph", graph_json)?;
let report = car_verify::verify_workflow_graph(&graph);
crate::to_json(&report)
}
pub fn check_workflow_policies(
graph_json: &str,
policies_json: &str,
) -> Result<String, String> {
let graph: car_verify::WorkflowGraph = crate::from_json("graph", graph_json)?;
let policies: Vec<car_verify::TemporalPolicy> = crate::from_json("policies", policies_json)?;
let report = car_verify::check_temporal_policies(&graph, &policies);
crate::to_json(&report)
}
pub fn check_plan(request_json: &str) -> Result<String, String> {
let req: car_verify::PlanCheckRequest = crate::from_json("request", request_json)?;
let report = car_verify::check_plan(&req);
crate::to_json(&report)
}
#[derive(serde::Deserialize)]
struct IntentCheckRequest {
#[serde(default)]
intent: car_verify::IntentSpec,
#[serde(default)]
actions: Vec<car_verify::IntentAction>,
}
pub fn check_intent(request_json: &str) -> Result<String, String> {
let req: IntentCheckRequest = crate::from_json("request", request_json)?;
let report = car_verify::check_intent(&req.intent, &req.actions);
crate::to_json(&report)
}
#[derive(serde::Deserialize)]
struct IntentPlanRequest {
#[serde(default)]
intent: car_verify::IntentSpec,
#[serde(default)]
actions: Vec<car_ir::Action>,
#[serde(default)]
untrusted_tools: Vec<String>,
#[serde(default)]
untrusted_ids: Vec<String>,
}
pub fn check_intent_plan(request_json: &str) -> Result<String, String> {
let req: IntentPlanRequest = crate::from_json("request", request_json)?;
let untrusted_tools: std::collections::HashSet<String> =
req.untrusted_tools.into_iter().collect();
let untrusted_ids: std::collections::HashSet<String> = req.untrusted_ids.into_iter().collect();
let actions = car_verify::intent_actions_from(&req.actions, &untrusted_tools, &untrusted_ids);
let report = car_verify::check_intent(&req.intent, &actions);
crate::to_json(&report)
}
pub fn gate_intent(report_json: &str, gate_policy_json: Option<&str>) -> Result<String, String> {
let report: car_verify::IntentReport = crate::from_json("report", report_json)?;
let policy: car_verify::IntentGatePolicy =
crate::from_json_opt("gate policy", gate_policy_json)?.unwrap_or_default();
let decision = car_verify::gate_intent(&report, &policy);
crate::to_json(&decision)
}
pub fn enforce_intent(
decision_json: &str,
approvals_json: Option<&str>,
) -> Result<String, String> {
let decision: car_verify::IntentGateDecision = crate::from_json("decision", decision_json)?;
let mut ledger = car_policy::permission::ApprovalLedger::new();
if let Some(aj) = approvals_json {
let records: Vec<car_policy::permission::ApprovalRecord> =
crate::from_json("approvals", aj)?;
for r in records {
ledger
.record(r)
.map_err(|e| format!("record approval: {e}"))?;
}
}
let enforcement = car_policy::enforce_intent(&decision, &ledger);
crate::to_json(&enforcement)
}