1use async_trait::async_trait;
10use chrono::Utc;
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
20pub enum EvidenceType {
21 ToolOutput,
22 ExternalApi,
23 HumanInput,
24 DocumentReference,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
29pub enum UaicpState {
30 Intake,
31 Planning,
32 Executing,
33 Verification,
34 Delivery,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
39pub enum RollbackActionType {
40 CompensatingToolCall,
41 RevertApi,
42 ManualIntervention,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46#[serde(rename_all = "snake_case")]
47pub enum PolicyOutcomeStatus {
48 Allow,
49 Deny,
50 NeedsReview,
51 FailSafe,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct EvidenceObject {
60 pub evidence_id: String,
61 pub evidence_type: EvidenceType,
62 pub source: String,
63 pub collected_at: String, #[serde(skip_serializing_if = "Option::is_none")]
65 pub hash: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
67 pub parent_trace_id: Option<String>, pub payload: HashMap<String, serde_json::Value>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct UaicpRollbackAction {
73 pub action_type: RollbackActionType,
74 pub payload: HashMap<String, serde_json::Value>,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct UaicpStreaming {
79 pub chunk_id: String,
80 pub is_final: bool,
81 pub content: String,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct AgentIdentity {
86 pub agent_id: String,
87 pub agent_type: String,
88 pub framework: String,
89 pub version: String,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct PolicyOutcome {
94 pub status: PolicyOutcomeStatus,
95 pub reason_code: String,
96 pub resolution: Option<String>,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct MessageEnvelope {
101 pub uaicp_version: String,
102 pub trace_id: String,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 pub parent_trace_id: Option<String>, pub state: UaicpState,
106 pub identity: AgentIdentity,
107 pub evidence: Vec<EvidenceObject>,
108 #[serde(skip_serializing_if = "Option::is_none")]
109 pub outcome: Option<PolicyOutcome>,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub streaming: Option<UaicpStreaming>, #[serde(skip_serializing_if = "Option::is_none")]
113 pub rollback_action: Option<UaicpRollbackAction>, }
115
116#[derive(Debug, Clone)]
121pub struct PolicyResult {
122 pub allowed: bool,
123 pub reason: String,
124 pub requires_review: bool,
125}
126
127#[async_trait]
132pub trait UaicpAdapter: Send + Sync {
133 type FrameworkState;
134 type FrameworkToolCall;
135
136 fn map_to_envelope(&self, state: &Self::FrameworkState) -> MessageEnvelope;
138
139 fn normalize_evidence(&self, tool_call: &Self::FrameworkToolCall) -> EvidenceObject;
141
142 async fn verify_gates(&self, envelope: &MessageEnvelope) -> bool;
144
145 async fn enforce_policy(&self, envelope: &MessageEnvelope) -> PolicyResult;
147
148 fn stream_partial(&self, chunk: &serde_json::Value) -> Option<UaicpStreaming> {
150 let _ = chunk;
151 None
152 }
153
154 fn rollback_payload(&self, envelope: &MessageEnvelope) -> Option<UaicpRollbackAction> {
156 let _ = envelope;
157 None
158 }
159}
160
161pub fn now_iso() -> String {
163 Utc::now().to_rfc3339()
164}