Skip to main content

loong_contracts/
contracts.rs

1use std::collections::BTreeSet;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6#[non_exhaustive]
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
8pub enum Capability {
9    InvokeTool,
10    InvokeConnector,
11    MemoryRead,
12    MemoryWrite,
13    FilesystemRead,
14    FilesystemWrite,
15    NetworkEgress,
16    ObserveTelemetry,
17    ControlRead,
18    ControlWrite,
19    ControlApprovals,
20    ControlPairing,
21    ControlAcp,
22}
23
24impl Capability {
25    pub const fn as_str(self) -> &'static str {
26        match self {
27            Self::InvokeTool => "invoke_tool",
28            Self::InvokeConnector => "invoke_connector",
29            Self::MemoryRead => "memory_read",
30            Self::MemoryWrite => "memory_write",
31            Self::FilesystemRead => "filesystem_read",
32            Self::FilesystemWrite => "filesystem_write",
33            Self::NetworkEgress => "network_egress",
34            Self::ObserveTelemetry => "observe_telemetry",
35            Self::ControlRead => "control_read",
36            Self::ControlWrite => "control_write",
37            Self::ControlApprovals => "control_approvals",
38            Self::ControlPairing => "control_pairing",
39            Self::ControlAcp => "control_acp",
40        }
41    }
42
43    pub fn parse(raw: &str) -> Option<Self> {
44        match raw.trim().to_ascii_lowercase().replace('-', "_").as_str() {
45            "invoke_tool" => Some(Self::InvokeTool),
46            "invoke_connector" => Some(Self::InvokeConnector),
47            "memory_read" => Some(Self::MemoryRead),
48            "memory_write" => Some(Self::MemoryWrite),
49            "filesystem_read" => Some(Self::FilesystemRead),
50            "filesystem_write" => Some(Self::FilesystemWrite),
51            "network_egress" => Some(Self::NetworkEgress),
52            "observe_telemetry" => Some(Self::ObserveTelemetry),
53            "control_read" => Some(Self::ControlRead),
54            "control_write" => Some(Self::ControlWrite),
55            "control_approvals" => Some(Self::ControlApprovals),
56            "control_pairing" => Some(Self::ControlPairing),
57            "control_acp" => Some(Self::ControlAcp),
58            _ => None,
59        }
60    }
61}
62
63#[non_exhaustive]
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
65pub enum HarnessKind {
66    EmbeddedPi,
67    Acp,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
71pub struct ExecutionRoute {
72    pub harness_kind: HarnessKind,
73    pub adapter: Option<String>,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
77pub struct CapabilityToken {
78    pub token_id: String,
79    pub pack_id: String,
80    pub agent_id: String,
81    pub allowed_capabilities: BTreeSet<Capability>,
82    pub issued_at_epoch_s: u64,
83    pub expires_at_epoch_s: u64,
84    pub generation: u64,
85}
86
87#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
88pub struct TaskIntent {
89    pub task_id: String,
90    pub objective: String,
91    pub required_capabilities: BTreeSet<Capability>,
92    pub payload: Value,
93}
94
95#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
96pub struct HarnessRequest {
97    pub token_id: String,
98    pub pack_id: String,
99    pub agent_id: String,
100    pub task_id: String,
101    pub objective: String,
102    pub payload: Value,
103}
104
105#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
106pub struct HarnessOutcome {
107    pub status: String,
108    pub output: Value,
109}
110
111#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
112pub struct ConnectorCommand {
113    pub connector_name: String,
114    pub operation: String,
115    pub required_capabilities: BTreeSet<Capability>,
116    pub payload: Value,
117}
118
119#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
120pub struct ConnectorOutcome {
121    pub status: String,
122    pub payload: Value,
123}
124
125#[cfg(test)]
126mod tests {
127    use super::Capability;
128
129    #[test]
130    fn capability_round_trips_through_canonical_names() {
131        let fixtures = [
132            (Capability::InvokeTool, "invoke_tool"),
133            (Capability::InvokeConnector, "invoke_connector"),
134            (Capability::MemoryRead, "memory_read"),
135            (Capability::MemoryWrite, "memory_write"),
136            (Capability::FilesystemRead, "filesystem_read"),
137            (Capability::FilesystemWrite, "filesystem_write"),
138            (Capability::NetworkEgress, "network_egress"),
139            (Capability::ObserveTelemetry, "observe_telemetry"),
140            (Capability::ControlRead, "control_read"),
141            (Capability::ControlWrite, "control_write"),
142            (Capability::ControlApprovals, "control_approvals"),
143            (Capability::ControlPairing, "control_pairing"),
144            (Capability::ControlAcp, "control_acp"),
145        ];
146
147        for (capability, expected_name) in fixtures {
148            assert_eq!(capability.as_str(), expected_name);
149            assert_eq!(Capability::parse(expected_name), Some(capability));
150            assert_eq!(
151                Capability::parse(&expected_name.to_ascii_uppercase()),
152                Some(capability)
153            );
154            assert_eq!(
155                Capability::parse(&expected_name.replace('_', "-")),
156                Some(capability)
157            );
158        }
159    }
160
161    #[test]
162    fn capability_parse_rejects_unknown_values() {
163        assert_eq!(Capability::parse("totally_unknown"), None);
164        assert_eq!(Capability::parse(""), None);
165        assert_eq!(Capability::parse("   "), None);
166        assert_eq!(Capability::parse("schedule_task"), None);
167    }
168}