Skip to main content

agent_types/
approval.rs

1//! Approval-related pure types: RiskLevel, ApprovalDecision, ApprovalRequest.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
7pub enum RiskLevel {
8    Safe,
9    Sensitive,
10    Destructive,
11}
12
13#[derive(Clone, Debug, Deserialize, Serialize)]
14pub struct ApprovalRequest {
15    pub title: String,
16    pub message: String,
17    pub action_key: Option<String>,
18    pub risk_level: RiskLevel,
19    pub raw: Option<Value>,
20    /// 发起方标识(子 agent 的 agent_path,如 "root/coder-1")。
21    /// 主 agent 发起时为 None(serde default 保证旧 JSON 可反序列化)。
22    #[serde(default)]
23    pub source: Option<String>,
24}
25
26#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
27pub enum ApprovalDecision {
28    AllowOnce,
29    AllowAlways,
30    Deny,
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    /// 旧 JSON(无 source 字段)必须照常反序列化(serde default 向后兼容,
38    /// 设计文档 D4)。旧日志 / 旧调用方不受影响。
39    #[test]
40    fn deserializes_legacy_json_without_source() {
41        let old = r#"{"title":"t","message":"m","action_key":null,"risk_level":"Safe","raw":null}"#;
42        let req: ApprovalRequest = serde_json::from_str(old).unwrap();
43        assert_eq!(req.source, None);
44    }
45
46    /// 新 JSON 带 source 时正常携带。
47    #[test]
48    fn roundtrips_source_field() {
49        let req = ApprovalRequest {
50            title: "write_file".into(),
51            message: "Write file: src/x.rs".into(),
52            action_key: Some("write_file:src/x.rs".into()),
53            risk_level: RiskLevel::Sensitive,
54            raw: None,
55            source: Some("root/coder-1".into()),
56        };
57        let json = serde_json::to_string(&req).unwrap();
58        let back: ApprovalRequest = serde_json::from_str(&json).unwrap();
59        assert_eq!(back.source.as_deref(), Some("root/coder-1"));
60    }
61}