use async_trait::async_trait;
use echo_core::tools::permission::PermissionDecision;
use std::sync::Arc;
use super::permission::{
PermissionRequest, PermissionRequestHandler, PermissionResponse, PermissionResponseDecision,
};
use super::service::PermissionService;
use echo_core::error::Result;
pub struct PermissionPolicyAdapter {
policy: Arc<dyn echo_core::tools::permission::PermissionPolicy>,
}
impl PermissionPolicyAdapter {
pub fn new(policy: Arc<dyn echo_core::tools::permission::PermissionPolicy>) -> Self {
Self { policy }
}
pub fn into_service(self) -> PermissionService {
let handler: Arc<dyn PermissionRequestHandler> = Arc::new(PolicyBridgeHandler {
policy: self.policy.clone(),
});
PermissionService::new().with_request_handler(handler)
}
}
struct PolicyBridgeHandler {
policy: Arc<dyn echo_core::tools::permission::PermissionPolicy>,
}
#[async_trait]
impl PermissionRequestHandler for PolicyBridgeHandler {
async fn handle(&self, request: PermissionRequest) -> Result<PermissionResponse> {
let decision = self
.policy
.check(&request.tool_name, &request.required_permissions)
.await;
Ok(match decision {
PermissionDecision::Allow => PermissionResponse::allowed(),
PermissionDecision::Deny { reason } => PermissionResponse::denied(Some(reason)),
PermissionDecision::RequireApproval => {
PermissionResponse::denied(Some("需要人工审批".to_string()))
}
PermissionDecision::Ask { suggestions } => PermissionResponse {
decision: PermissionResponseDecision::NeedMoreInfo {
question: suggestions.join(", "),
},
rule_updates: Vec::new(),
feedback: None,
updated_input: None,
},
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use echo_core::tools::permission::{PermissionDecision, ToolPermission};
use futures::future::BoxFuture;
struct MockPolicy;
impl echo_core::tools::permission::PermissionPolicy for MockPolicy {
fn check<'a>(
&'a self,
_tool_name: &'a str,
permissions: &'a [ToolPermission],
) -> BoxFuture<'a, PermissionDecision> {
Box::pin(async move {
if permissions.contains(&ToolPermission::Execute) {
PermissionDecision::RequireApproval
} else {
PermissionDecision::Allow
}
})
}
}
#[tokio::test]
async fn test_policy_adapter_into_service() {
let policy = Arc::new(MockPolicy);
let adapter = PermissionPolicyAdapter::new(policy);
let _service = adapter.into_service();
}
}