Skip to main content

vex_runtime/gate/
mod.rs

1use async_trait::async_trait;
2use sha2::Digest;
3use uuid::Uuid;
4use vex_core::audit::EvidenceCapsule;
5use vex_llm::Capability;
6
7/// Exogenous Gate Decision Boundary
8///
9/// A Gate acts as a continuation authority, deciding whether an agent's
10/// output is "Safe", "Valid", or "Audit-Compliant".
11#[async_trait]
12pub trait Gate: Send + Sync + std::fmt::Debug {
13    /// Evaluate the current execution state and return a signed Evidence Capsule.
14    async fn execute_gate(
15        &self,
16        agent_id: Uuid,
17        task_prompt: &str,
18        suggested_output: &str,
19        confidence: f64,
20        capabilities: Vec<Capability>,
21    ) -> EvidenceCapsule;
22}
23
24/// A mock implementation of the Generic Gate for testing and local development.
25#[derive(Debug, Default)]
26pub struct GenericGateMock;
27
28#[async_trait]
29impl Gate for GenericGateMock {
30    async fn execute_gate(
31        &self,
32        _agent_id: Uuid,
33        _task_prompt: &str,
34        suggested_output: &str,
35        confidence: f64,
36        capabilities: Vec<Capability>,
37    ) -> EvidenceCapsule {
38        // Simple logic for the mock:
39        // 1. If confidence is very low (< 0.3), HALT.
40        // 2. If the output contains common failure patterns, HALT.
41        // 3. Otherwise, ALLOW.
42
43        let (outcome, reason) = if confidence < 0.3 {
44            ("HALT", "LOW_CONFIDENCE")
45        } else if capabilities.contains(&Capability::Network)
46            && !suggested_output.to_lowercase().contains("http")
47        {
48            // Example policy: If you have network capability but don't explain the URL, caution.
49            ("ALLOW", "SENSORS_ORANGE_NETWORK_IDLE")
50        } else if suggested_output.to_lowercase().contains("i'm sorry")
51            || suggested_output.to_lowercase().contains("cannot fulfill")
52        {
53            ("HALT", "REFUSAL_FILTER")
54        } else {
55            ("ALLOW", "SENSORS_GREEN")
56        };
57
58        EvidenceCapsule {
59            capsule_id: format!("mock-{}", &Uuid::new_v4().to_string()[..8]),
60            outcome: outcome.to_string(),
61            reason_code: reason.to_string(),
62            witness_receipt: "mock-receipt-0xdeadbeef".to_string(),
63            nonce: 0,
64            magpie_source: None,
65            gate_sensors: serde_json::json!({
66                "confidence_sensor": if confidence > 0.5 { "GREEN" } else { "YELLOW" },
67                "content_length": suggested_output.len(),
68            }),
69            reproducibility_context: serde_json::json!({
70                "gate_provider": "ChoraGateMock",
71                "version": "0.1.0",
72            }),
73            vep_blob: None,
74        }
75    }
76}
77
78/// Networked Gate provider communicating over HTTP.
79/// Legacy wrapper: Now uses ChoraGate internally for unified handshake logic.
80#[derive(Debug, Clone)]
81pub struct HttpGate {
82    pub inner: std::sync::Arc<ChoraGate>,
83}
84
85impl HttpGate {
86    pub fn new(url: String, api_key: String) -> Self {
87        let client = vex_chora::client::make_authority_client(url, api_key);
88        let bridge = std::sync::Arc::new(vex_chora::AuthorityBridge::new(client));
89        Self {
90            inner: std::sync::Arc::new(ChoraGate { bridge }),
91        }
92    }
93
94    /// Attach a hardware identity to the underlying bridge.
95    pub fn with_identity(self, identity: std::sync::Arc<vex_hardware::api::AgentIdentity>) -> Self {
96        let bridge = (*self.inner.bridge).clone().with_identity(identity);
97        Self {
98            inner: std::sync::Arc::new(ChoraGate {
99                bridge: std::sync::Arc::new(bridge),
100            }),
101        }
102    }
103}
104
105#[async_trait]
106impl Gate for HttpGate {
107    async fn execute_gate(
108        &self,
109        agent_id: Uuid,
110        task_prompt: &str,
111        suggested_output: &str,
112        confidence: f64,
113        capabilities: Vec<Capability>,
114    ) -> EvidenceCapsule {
115        self.inner
116            .execute_gate(
117                agent_id,
118                task_prompt,
119                suggested_output,
120                confidence,
121                capabilities,
122            )
123            .await
124    }
125}
126
127/// The default CHORA Gate implementation using the unified AuthorityBridge.
128#[derive(Debug, Clone)]
129pub struct ChoraGate {
130    pub bridge: std::sync::Arc<vex_chora::AuthorityBridge>,
131}
132
133#[async_trait]
134impl Gate for ChoraGate {
135    async fn execute_gate(
136        &self,
137        _agent_id: Uuid,
138        _task_prompt: &str,
139        suggested_output: &str,
140        confidence: f64,
141        capabilities: Vec<Capability>,
142    ) -> EvidenceCapsule {
143        // 1. Build IntentData from execution context
144        let intent = vex_core::segment::IntentData {
145            request_sha256: hex::encode(sha2::Sha256::digest(suggested_output.as_bytes())),
146            confidence,
147            capabilities: capabilities.iter().map(|c| format!("{:?}", c)).collect(),
148            magpie_source: None,
149        };
150
151        // 2. Perform Handshake via Unified Bridge
152        match self.bridge.perform_handshake(intent).await {
153            Ok(capsule) => EvidenceCapsule {
154                capsule_id: capsule.capsule_id,
155                outcome: capsule.authority.outcome,
156                reason_code: capsule.authority.reason_code,
157                witness_receipt: capsule.witness.receipt_hash,
158                nonce: capsule.authority.nonce,
159                magpie_source: None,
160                gate_sensors: serde_json::json!({
161                    "trace_root": capsule.authority.trace_root,
162                    "identity_type": capsule.identity.identity_type,
163                }),
164                reproducibility_context: serde_json::json!({
165                    "gate_provider": "ChoraGate",
166                    "bridge_version": "v0.2.0",
167                }),
168                vep_blob: None,
169            },
170            Err(e) => EvidenceCapsule {
171                capsule_id: "error".to_string(),
172                outcome: "HALT".to_string(),
173                reason_code: format!("CHORA_BRIDGE_ERROR: {}", e),
174                witness_receipt: "error-none".to_string(),
175                nonce: 0,
176                magpie_source: None,
177                gate_sensors: serde_json::Value::Null,
178                reproducibility_context: serde_json::Value::Null,
179                vep_blob: None,
180            },
181        }
182    }
183}
184
185pub mod titan;
186pub use titan::TitanGate;