1use chio_core::capability::governance::{
2 GovernedApprovalToken, GovernedTransactionIntent, GovernedTransactionIntentBody,
3 ThresholdApprovalProposal, VerifiedApprovalSetBody, ACTIVE_RESPONSE_PLAN_TOOL_NAME,
4 ACTIVE_RESPONSE_SERVER_ID,
5};
6use chio_core::capability::threshold_approval::ThresholdApprovalRequirement;
7use chio_core::capability::token::CapabilityToken;
8use chio_core::PublicKey;
9
10use crate::admission_operation::{AdmissionOperationState, AdmissionOperationV1};
11use crate::kernel::{
12 current_unix_timestamp, current_unix_timestamp_ms, ChioKernel, DurableToolAdmission,
13 VerifiedApprovalReservation,
14};
15use crate::{KernelError, ToolCallRequest};
16
17#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
18#[serde(deny_unknown_fields)]
19pub struct GovernedActiveResponseRequest {
20 pub request_id: String,
21 pub operator_capability: CapabilityToken,
22 pub governed_intent: GovernedTransactionIntent,
23 pub approval_tokens: Vec<GovernedApprovalToken>,
24 pub threshold_approval_proposal: ThresholdApprovalProposal,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub federated_origin_kernel_id: Option<String>,
27}
28
29pub struct GovernedActiveResponseAdmission {
30 admission: DurableToolAdmission,
31 governed_intent_hash: String,
32 operator_capability: VerifiedActiveResponseOperatorCapability,
33 requirement: ThresholdApprovalRequirement,
34 approval_set: VerifiedApprovalSetBody,
35 approval_set_hash: String,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct VerifiedActiveResponseOperatorCapability {
40 pub capability_id: String,
41 pub capability_digest: String,
42 pub expires_at: u64,
43 pub executor_subject: PublicKey,
44}
45
46impl core::fmt::Debug for GovernedActiveResponseAdmission {
47 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 formatter
49 .debug_struct("GovernedActiveResponseAdmission")
50 .field("operation_id", &self.operation_id())
51 .field("state", &self.state())
52 .field("governed_intent_hash", &self.governed_intent_hash)
53 .field("operator_capability", &self.operator_capability)
54 .field("requirement", &self.requirement)
55 .field("approval_set", &self.approval_set)
56 .field("approval_set_hash", &self.approval_set_hash)
57 .finish()
58 }
59}
60
61impl GovernedActiveResponseAdmission {
62 #[must_use]
63 pub fn operation_id(&self) -> &str {
64 self.admission.operation_id()
65 }
66
67 #[must_use]
68 pub fn state(&self) -> AdmissionOperationState {
69 self.admission.state()
70 }
71
72 #[must_use]
73 pub fn operation(&self) -> &AdmissionOperationV1 {
74 self.admission.operation()
75 }
76
77 #[must_use]
78 pub fn governed_intent_hash(&self) -> &str {
79 &self.governed_intent_hash
80 }
81
82 #[must_use]
83 pub fn approval_set_hash(&self) -> &str {
84 &self.approval_set_hash
85 }
86
87 #[must_use]
88 pub const fn operator_capability(&self) -> &VerifiedActiveResponseOperatorCapability {
89 &self.operator_capability
90 }
91
92 #[must_use]
93 pub const fn requirement(&self) -> &ThresholdApprovalRequirement {
94 &self.requirement
95 }
96
97 #[must_use]
98 pub const fn approval_set(&self) -> &VerifiedApprovalSetBody {
99 &self.approval_set
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
104pub enum GovernedActiveResponseDispatchCommit {
105 Committed,
106 AlreadyCommitted,
107}
108
109impl ChioKernel {
110 pub fn admit_governed_active_response(
111 &self,
112 request: &GovernedActiveResponseRequest,
113 ) -> Result<GovernedActiveResponseAdmission, KernelError> {
114 self.admit_governed_active_response_at(
115 request,
116 current_unix_timestamp(),
117 current_unix_timestamp_ms(),
118 )
119 }
120
121 pub(crate) fn admit_governed_active_response_at(
122 &self,
123 request: &GovernedActiveResponseRequest,
124 now_unix_seconds: u64,
125 trusted_now_unix_ms: u64,
126 ) -> Result<GovernedActiveResponseAdmission, KernelError> {
127 let GovernedTransactionIntentBody::ActiveResponsePlan(plan) = &request.governed_intent.body
128 else {
129 return Err(KernelError::GovernedTransactionDenied(
130 "governed active-response admission requires an active-response intent body"
131 .to_owned(),
132 ));
133 };
134 self.verify_capability_full_pre_admit(
135 &request.operator_capability,
136 request.federated_origin_kernel_id.as_deref(),
137 now_unix_seconds,
138 )
139 .map_err(KernelError::GovernedTransactionDenied)?;
140 self.check_revocation(&request.operator_capability)?;
141 self.validate_delegation_admission(&request.operator_capability)?;
142
143 let tool_request = ToolCallRequest {
144 request_id: request.request_id.clone(),
145 capability: request.operator_capability.clone(),
146 tool_name: ACTIVE_RESPONSE_PLAN_TOOL_NAME.to_owned(),
147 server_id: ACTIVE_RESPONSE_SERVER_ID.to_owned(),
148 agent_id: request.operator_capability.subject.to_hex(),
149 arguments: plan.canonical_plan_body.clone(),
150 dpop_proof: None,
151 execution_nonce: None,
152 governed_intent: Some(request.governed_intent.clone()),
153 approval_token: None,
154 approval_tokens: request.approval_tokens.clone(),
155 threshold_approval_proposal: Some(request.threshold_approval_proposal.clone()),
156 supplemental_authorization: None,
157 model_metadata: None,
158 federated_origin_kernel_id: request.federated_origin_kernel_id.clone(),
159 };
160 self.validate_active_response_intent(
161 &tool_request,
162 &request.operator_capability,
163 &request.governed_intent,
164 now_unix_seconds,
165 )?;
166 let governed_intent_hash = request.governed_intent.binding_hash().map_err(|error| {
167 KernelError::GovernedTransactionDenied(format!(
168 "failed to hash governed active-response intent: {error}"
169 ))
170 })?;
171 let verified = self.validate_threshold_approval_set(
172 &tool_request,
173 &request.operator_capability,
174 &governed_intent_hash,
175 now_unix_seconds,
176 )?;
177 let approval_set_hash = verified
178 .body
179 .approval_set_hash()
180 .map_err(|error| KernelError::GovernedTransactionDenied(error.to_string()))?;
181 let requirement = verified.requirement.clone();
182 let approval_set = verified.body.clone();
183 let reservation = VerifiedApprovalReservation {
184 threshold_proposal_hash: verified.body.threshold_proposal_hash.clone(),
185 approval_set_hash: approval_set_hash.clone(),
186 threshold_replay: Some(verified.replay),
187 };
188 let (mut admission, created_by_this_attempt) = self
189 .begin_durable_active_response_admission(
190 request,
191 &governed_intent_hash,
192 trusted_now_unix_ms,
193 )?;
194 if let Err(error) =
195 self.reserve_durable_approval_set(&mut admission, &reservation, trusted_now_unix_ms)
196 {
197 if created_by_this_attempt {
198 let _ = self.compensate_durable_admission_before_dispatch(
199 admission.operation(),
200 serde_json::json!({"cause": "active-response-approval-reservation-failed"}),
201 trusted_now_unix_ms,
202 );
203 }
204 return Err(error);
205 }
206 Ok(GovernedActiveResponseAdmission {
207 admission,
208 governed_intent_hash,
209 operator_capability: VerifiedActiveResponseOperatorCapability {
210 capability_id: plan.operator_capability_id.clone(),
211 capability_digest: plan.operator_capability_hash.clone(),
212 expires_at: plan.operator_capability_expires_at,
213 executor_subject: plan.executor_subject.clone(),
214 },
215 requirement,
216 approval_set,
217 approval_set_hash,
218 })
219 }
220
221 pub fn commit_governed_active_response_dispatch(
222 &self,
223 admission: &mut GovernedActiveResponseAdmission,
224 ) -> Result<GovernedActiveResponseDispatchCommit, KernelError> {
225 self.commit_governed_active_response_dispatch_at(admission, current_unix_timestamp_ms())
226 }
227
228 pub(crate) fn commit_governed_active_response_dispatch_at(
229 &self,
230 admission: &mut GovernedActiveResponseAdmission,
231 trusted_now_unix_ms: u64,
232 ) -> Result<GovernedActiveResponseDispatchCommit, KernelError> {
233 if admission.admission.state() == AdmissionOperationState::DispatchCommitted {
234 return Ok(GovernedActiveResponseDispatchCommit::AlreadyCommitted);
235 }
236 self.commit_durable_dispatch(&mut admission.admission, trusted_now_unix_ms)?;
237 Ok(GovernedActiveResponseDispatchCommit::Committed)
238 }
239
240 pub fn cancel_governed_active_response(
241 &self,
242 admission: &GovernedActiveResponseAdmission,
243 ) -> Result<(), KernelError> {
244 self.compensate_durable_admission_before_dispatch(
245 admission.admission.operation(),
246 serde_json::json!({"cause": "active-response-cancelled"}),
247 current_unix_timestamp_ms(),
248 )
249 }
250}