Skip to main content

macp_modes/mode/
mod.rs

1pub mod decision;
2pub mod handoff;
3pub mod multi_round;
4pub mod passthrough;
5pub mod proposal;
6pub mod quorum;
7pub mod task;
8pub mod util;
9
10use macp_core::error::MacpError;
11use macp_core::session::Session;
12use macp_pb::pb::{Envelope, ModeDescriptor};
13use std::collections::HashMap;
14
15/// The canonical standards-track modes implemented by this runtime.
16pub const STANDARD_MODE_NAMES: &[&str] = &[
17    "macp.mode.decision.v1",
18    "macp.mode.proposal.v1",
19    "macp.mode.task.v1",
20    "macp.mode.handoff.v1",
21    "macp.mode.quorum.v1",
22];
23
24/// Built-in extension modes shipped with this runtime but not yet standards-track.
25pub const EXTENSION_MODE_NAMES: &[&str] = &["ext.multi_round.v1"];
26
27// `ModeResponse` (data) lives in `macp-core` so `Session::apply_mode_response`
28// can consume it without a core->modes cycle. The `Mode` trait (behavior) stays
29// here. Re-exported so `crate::mode::ModeResponse` keeps resolving.
30pub use macp_core::mode::ModeResponse;
31
32/// Trait that coordination modes implement.
33/// Modes receive immutable session references and return a ModeResponse.
34/// The runtime kernel is responsible for applying the response.
35pub trait Mode: Send + Sync {
36    fn on_session_start(
37        &self,
38        session: &Session,
39        env: &Envelope,
40    ) -> Result<ModeResponse, MacpError>;
41
42    fn on_message(&self, session: &Session, env: &Envelope) -> Result<ModeResponse, MacpError>;
43
44    /// Authorize the sender for this message. Modes can override to customize
45    /// authorization (e.g., allowing orchestrator bypass for Commitment messages).
46    fn authorize_sender(&self, session: &Session, env: &Envelope) -> Result<(), MacpError> {
47        if !session.participants.is_empty() && !session.participants.contains(&env.sender) {
48            return Err(MacpError::Forbidden);
49        }
50        Ok(())
51    }
52}
53
54pub fn standard_mode_names() -> &'static [&'static str] {
55    STANDARD_MODE_NAMES
56}
57
58pub fn extension_mode_names() -> &'static [&'static str] {
59    EXTENSION_MODE_NAMES
60}
61
62fn schema_map(path: &str) -> HashMap<String, String> {
63    HashMap::from([("protobuf".to_string(), path.to_string())])
64}
65
66pub fn standard_mode_descriptors() -> Vec<ModeDescriptor> {
67    vec![
68        ModeDescriptor {
69            mode: "macp.mode.decision.v1".into(),
70            mode_version: "1.0.0".into(),
71            title: "Decision Mode".into(),
72            description: "Structured decision making with proposals, evaluations, objections, votes, and a terminal Commitment.".into(),
73            determinism_class: "semantic-deterministic".into(),
74            participant_model: "declared".into(),
75            message_types: vec![
76                "SessionStart".into(),
77                "Proposal".into(),
78                "Evaluation".into(),
79                "Objection".into(),
80                "Vote".into(),
81                "Commitment".into(),
82            ],
83            terminal_message_types: vec!["Commitment".into()],
84            schema_uris: schema_map("buf.build/multiagentcoordinationprotocol/macp"),
85        },
86        ModeDescriptor {
87            mode: "macp.mode.proposal.v1".into(),
88            mode_version: "1.0.0".into(),
89            title: "Proposal Mode".into(),
90            description: "Negotiation with proposals, counterproposals, accepts, rejects, withdrawals, and a terminal Commitment.".into(),
91            determinism_class: "semantic-deterministic".into(),
92            participant_model: "peer".into(),
93            message_types: vec![
94                "SessionStart".into(),
95                "Proposal".into(),
96                "CounterProposal".into(),
97                "Accept".into(),
98                "Reject".into(),
99                "Withdraw".into(),
100                "Commitment".into(),
101            ],
102            terminal_message_types: vec!["Commitment".into()],
103            schema_uris: schema_map("buf.build/multiagentcoordinationprotocol/macp"),
104        },
105        ModeDescriptor {
106            mode: "macp.mode.task.v1".into(),
107            mode_version: "1.0.0".into(),
108            title: "Task Mode".into(),
109            description: "One bounded delegated task with assignee responses, progress, completion/failure reports, and a terminal Commitment.".into(),
110            determinism_class: "structural-only".into(),
111            participant_model: "orchestrated".into(),
112            message_types: vec![
113                "SessionStart".into(),
114                "TaskRequest".into(),
115                "TaskAccept".into(),
116                "TaskReject".into(),
117                "TaskUpdate".into(),
118                "TaskComplete".into(),
119                "TaskFail".into(),
120                "Commitment".into(),
121            ],
122            terminal_message_types: vec!["Commitment".into()],
123            schema_uris: schema_map("buf.build/multiagentcoordinationprotocol/macp"),
124        },
125        ModeDescriptor {
126            mode: "macp.mode.handoff.v1".into(),
127            mode_version: "1.0.0".into(),
128            title: "Handoff Mode".into(),
129            description: "Scoped responsibility transfer with handoff offers, context, target responses, and a terminal Commitment.".into(),
130            determinism_class: "context-frozen".into(),
131            participant_model: "delegated".into(),
132            message_types: vec![
133                "SessionStart".into(),
134                "HandoffOffer".into(),
135                "HandoffContext".into(),
136                "HandoffAccept".into(),
137                "HandoffDecline".into(),
138                "Commitment".into(),
139            ],
140            terminal_message_types: vec!["Commitment".into()],
141            schema_uris: schema_map("buf.build/multiagentcoordinationprotocol/macp"),
142        },
143        ModeDescriptor {
144            mode: "macp.mode.quorum.v1".into(),
145            mode_version: "1.0.0".into(),
146            title: "Quorum Mode".into(),
147            description: "Threshold approval with one approval request, participant ballots, and a terminal Commitment.".into(),
148            determinism_class: "semantic-deterministic".into(),
149            participant_model: "quorum".into(),
150            message_types: vec![
151                "SessionStart".into(),
152                "ApprovalRequest".into(),
153                "Approve".into(),
154                "Reject".into(),
155                "Abstain".into(),
156                "Commitment".into(),
157            ],
158            terminal_message_types: vec!["Commitment".into()],
159            schema_uris: schema_map("buf.build/multiagentcoordinationprotocol/macp"),
160        },
161    ]
162}
163
164pub fn extension_mode_descriptors() -> Vec<ModeDescriptor> {
165    vec![ModeDescriptor {
166        mode: "ext.multi_round.v1".into(),
167        mode_version: "1.0.0".into(),
168        title: "Multi-Round Mode".into(),
169        description: "Iterative convergence through multiple contribution rounds until all participants agree, with a terminal Commitment.".into(),
170        determinism_class: "semantic-deterministic".into(),
171        participant_model: "peer".into(),
172        message_types: vec![
173            "SessionStart".into(),
174            "Contribute".into(),
175            "Commitment".into(),
176        ],
177        terminal_message_types: vec!["Commitment".into()],
178        schema_uris: schema_map("buf.build/multiagentcoordinationprotocol/macp"),
179    }]
180}
181
182pub fn all_mode_descriptors() -> Vec<ModeDescriptor> {
183    let mut all = standard_mode_descriptors();
184    all.extend(extension_mode_descriptors());
185    all
186}