tap_msg/message/
agent_management.rs

1//! Agent management message types for the Transaction Authorization Protocol.
2//!
3//! This module defines the message types for managing agents in the TAP protocol,
4//! including adding, replacing, and removing agents from transactions.
5
6use serde::{Deserialize, Serialize};
7
8use crate::error::{Error, Result};
9use crate::message::agent::TapParticipant;
10use crate::message::Agent;
11use crate::TapMessage;
12
13/// Add agents message body (TAIP-5).
14#[derive(Debug, Clone, Serialize, Deserialize, TapMessage)]
15#[tap(
16    message_type = "https://tap.rsvp/schema/1.0#AddAgents",
17    custom_validation
18)]
19pub struct AddAgents {
20    /// ID of the transaction to add agents to.
21    #[tap(thread_id)]
22    pub transaction_id: String,
23
24    /// Agents to add.
25    #[tap(participant_list)]
26    pub agents: Vec<Agent>,
27}
28
29impl AddAgents {
30    /// Create a new AddAgents message
31    pub fn new(transaction_id: &str, agents: Vec<Agent>) -> Self {
32        Self {
33            transaction_id: transaction_id.to_string(),
34            agents,
35        }
36    }
37
38    /// Add a single agent to this message
39    pub fn add_agent(mut self, agent: Agent) -> Self {
40        self.agents.push(agent);
41        self
42    }
43}
44
45impl AddAgents {
46    /// Custom validation for AddAgents messages
47    pub fn validate_addagents(&self) -> Result<()> {
48        if self.transaction_id.is_empty() {
49            return Err(Error::Validation(
50                "Transaction ID is required in AddAgents".to_string(),
51            ));
52        }
53
54        if self.agents.is_empty() {
55            return Err(Error::Validation(
56                "At least one agent must be specified in AddAgents".to_string(),
57            ));
58        }
59
60        // Validate each agent
61        for agent in &self.agents {
62            if agent.id().is_empty() {
63                return Err(Error::Validation("Agent ID cannot be empty".to_string()));
64            }
65        }
66
67        Ok(())
68    }
69}
70
71/// Replace agent message body (TAIP-5).
72///
73/// This message type allows replacing an agent with another agent in a transaction.
74#[derive(Debug, Clone, Serialize, Deserialize, TapMessage)]
75#[tap(
76    message_type = "https://tap.rsvp/schema/1.0#ReplaceAgent",
77    custom_validation
78)]
79pub struct ReplaceAgent {
80    /// ID of the transaction to replace agent in.
81    #[tap(thread_id)]
82    pub transaction_id: String,
83
84    /// DID of the original agent to replace.
85    pub original: String,
86
87    /// Replacement agent.
88    #[tap(participant)]
89    pub replacement: Agent,
90}
91
92impl ReplaceAgent {
93    /// Create a new ReplaceAgent message
94    pub fn new(transaction_id: &str, original: &str, replacement: Agent) -> Self {
95        Self {
96            transaction_id: transaction_id.to_string(),
97            original: original.to_string(),
98            replacement,
99        }
100    }
101}
102
103impl ReplaceAgent {
104    /// Custom validation for ReplaceAgent messages
105    pub fn validate_replaceagent(&self) -> Result<()> {
106        if self.transaction_id.is_empty() {
107            return Err(Error::Validation(
108                "Transaction ID is required in ReplaceAgent".to_string(),
109            ));
110        }
111
112        if self.original.is_empty() {
113            return Err(Error::Validation(
114                "Original agent ID is required in ReplaceAgent".to_string(),
115            ));
116        }
117
118        if self.replacement.id().is_empty() {
119            return Err(Error::Validation(
120                "Replacement agent ID is required in ReplaceAgent".to_string(),
121            ));
122        }
123
124        Ok(())
125    }
126}
127
128/// Remove agent message body (TAIP-5).
129///
130/// This message type allows removing an agent from a transaction.
131#[derive(Debug, Clone, Serialize, Deserialize, TapMessage)]
132#[tap(
133    message_type = "https://tap.rsvp/schema/1.0#RemoveAgent",
134    custom_validation
135)]
136pub struct RemoveAgent {
137    /// ID of the transaction to remove agent from.
138    #[tap(thread_id)]
139    pub transaction_id: String,
140
141    /// DID of the agent to remove.
142    pub agent: String,
143}
144
145impl RemoveAgent {
146    /// Create a new RemoveAgent message
147    pub fn new(transaction_id: &str, agent: &str) -> Self {
148        Self {
149            transaction_id: transaction_id.to_string(),
150            agent: agent.to_string(),
151        }
152    }
153}
154
155impl RemoveAgent {
156    /// Custom validation for RemoveAgent messages
157    pub fn validate_removeagent(&self) -> Result<()> {
158        if self.transaction_id.is_empty() {
159            return Err(Error::Validation(
160                "Transaction ID is required in RemoveAgent".to_string(),
161            ));
162        }
163
164        if self.agent.is_empty() {
165            return Err(Error::Validation(
166                "Agent ID is required in RemoveAgent".to_string(),
167            ));
168        }
169
170        Ok(())
171    }
172}