1use async_trait::async_trait;
2use sha2::Digest;
3use uuid::Uuid;
4use vex_core::audit::EvidenceCapsule;
5use vex_llm::Capability;
6
7#[async_trait]
12pub trait Gate: Send + Sync + std::fmt::Debug {
13 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#[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 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 ("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#[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 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#[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 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 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;