1use kernel::IdemKey;
27
28use super::kind::Command;
29use super::no_secret::NoSecret;
30use super::step::{
31 AgentAdding, AgentLoginStart, CityClosing, CitySettings, DeviceForgetting, DoorAnswer,
32 DoorOpening, DoorStep, PolicyChange, ProposalDecisions, RangeWrite, RulesWrite,
33 SecretForgetting, SessionNaming,
34};
35
36pub type WireCommand = Command<NoSecret>;
39
40impl<Secret> Command<Secret> {
41 pub fn idem(&self) -> Option<&IdemKey> {
45 match *self {
46 Self::Dispatch { ref idem, .. }
47 | Self::Wake { ref idem, .. }
48 | Self::OpenSession { ref idem, .. }
49 | Self::ProbeEndpoint { ref idem, .. }
50 | Self::ConfigureBuilding { ref idem, .. }
51 | Self::CreateBuilding { ref idem, .. }
52 | Self::RemoveBuilding { ref idem, .. }
53 | Self::Steer { ref idem, .. }
54 | Self::Cancel { ref idem, .. }
55 | Self::Halt { ref idem, .. }
56 | Self::Release { ref idem, .. }
57 | Self::BatchByBuilding { ref idem, .. }
58 | Self::Approve { ref idem, .. }
59 | Self::HandOff { ref idem, .. }
60 | Self::SetAutonomy { ref idem, .. }
61 | Self::Pursue { ref idem, .. }
62 | Self::PutDocument { ref idem, .. }
63 | Self::PutIdentity { ref idem, .. }
64 | Self::PutRules(RulesWrite { ref idem, .. })
65 | Self::ConfigureCity(CitySettings { ref idem, .. })
66 | Self::RestoreFile { ref idem, .. }
67 | Self::PutGuide { ref idem, .. }
68 | Self::PutSpine { ref idem, .. }
69 | Self::PutRange(RangeWrite { ref idem, .. })
70 | Self::DecideProposals(ProposalDecisions { ref idem, .. })
71 | Self::PutPreferences { ref idem, .. }
72 | Self::PutShelved { ref idem, .. }
73 | Self::AttachEndpoint { ref idem, .. }
74 | Self::SelectModel { ref idem, .. }
75 | Self::Reveal { ref idem, .. }
76 | Self::RestoreDiscard { ref idem, .. }
77 | Self::DoctorInstall { ref idem, .. }
78 | Self::DoctorRefresh { ref idem, .. }
79 | Self::ConnectToolkit { ref idem, .. }
80 | Self::NameSession(SessionNaming { ref idem, .. })
81 | Self::ChangeRunPolicy(PolicyChange { ref idem, .. })
82 | Self::OpenRemoteDoor(DoorOpening { ref idem, .. })
83 | Self::ConfirmRemoteDoor(DoorAnswer { ref idem, .. })
84 | Self::ReplaceCityKey(DoorStep { ref idem })
85 | Self::CloseRemoteDoor(DoorStep { ref idem })
86 | Self::PrivacyOperation(crate::PrivacyRequest { ref idem, .. })
87 | Self::ForgetSecret(SecretForgetting { ref idem, .. })
88 | Self::CloseCity(CityClosing { ref idem, .. })
89 | Self::AddAgent(AgentAdding { ref idem, .. })
90 | Self::AgentLogin(AgentLoginStart { ref idem, .. })
91 | Self::ForgetDevice(DeviceForgetting { ref idem, .. }) => Some(idem),
92 Self::PutSecret { .. } | Self::Auth { .. } => None,
93 }
94 }
95}
96
97impl From<WireCommand> for Command {
98 fn from(wire: WireCommand) -> Self {
101 match wire {
102 #[rustfmt::skip]
104 Command::Wake { source, subject, body, idem } => Self::Wake { source, subject, body, idem },
105 Command::Dispatch {
106 addr,
107 task,
108 goal,
109 policy,
110 idem,
111 session,
112 effort,
113 model,
114 } => Self::Dispatch {
115 addr,
116 task,
117 goal,
118 policy,
119 idem,
120 session,
121 effort,
122 model,
123 },
124 Command::ConfigureBuilding {
125 addr,
126 sandbox,
127 mcp,
128 desktop,
129 context_second_threshold,
130 idem,
131 } => Self::ConfigureBuilding {
132 addr,
133 sandbox,
134 mcp,
135 desktop,
136 context_second_threshold,
137 idem,
138 },
139 Command::ProbeEndpoint {
140 name,
141 base_url,
142 dialect,
143 secret,
144 auth_header,
145 tuning,
146 idem,
147 } => Self::ProbeEndpoint {
148 name,
149 base_url,
150 dialect,
151 secret,
152 auth_header,
153 tuning,
154 idem,
155 },
156 Command::AttachEndpoint {
157 name,
158 base_url,
159 dialect,
160 secret,
161 auth_header,
162 admit,
163 named,
164 tuning,
165 idem,
166 } => Self::AttachEndpoint {
167 name,
168 base_url,
169 dialect,
170 secret,
171 auth_header,
172 admit,
173 named,
174 tuning,
175 idem,
176 },
177 Command::SelectModel {
178 endpoint,
179 model,
180 tag,
181 context_tokens,
182 max_output_tokens,
183 input,
184 idem,
185 } => Self::SelectModel {
186 endpoint,
187 model,
188 tag,
189 context_tokens,
190 max_output_tokens,
191 input,
192 idem,
193 },
194 Command::OpenSession {
195 addr,
196 carry,
197 from,
198 idem,
199 } => Self::OpenSession {
200 addr,
201 carry,
202 from,
203 idem,
204 },
205 #[rustfmt::skip]
207 Command::CreateBuilding { addr, template, idem } =>
208 Self::CreateBuilding { addr, template, idem },
209 Command::PutSecret { value, .. } => match value {},
210 Command::Steer { run, text, idem } => Self::Steer { run, text, idem },
211 Command::Cancel { run, idem } => Self::Cancel { run, idem },
212 Command::Halt { scope, idem } => Self::Halt { scope, idem },
213 Command::Reveal { at, idem } => Self::Reveal { at, idem },
214 Command::RestoreDiscard { restoration, idem } => {
215 Self::RestoreDiscard { restoration, idem }
216 }
217 Command::RemoveBuilding { addr, idem } => Self::RemoveBuilding { addr, idem },
218 Command::DoctorInstall { item, idem } => Self::DoctorInstall { item, idem },
219 Command::DoctorRefresh { idem } => Self::DoctorRefresh { idem },
220 Command::ConnectToolkit { toolkit, idem } => Self::ConnectToolkit { toolkit, idem },
221 Command::Release { scope, idem } => Self::Release { scope, idem },
222 Command::BatchByBuilding { addr, idem } => Self::BatchByBuilding { addr, idem },
223 Command::Approve {
224 item,
225 verdict,
226 idem,
227 } => Self::Approve {
228 item,
229 verdict,
230 idem,
231 },
232 Command::HandOff { item, to, idem } => Self::HandOff { item, to, idem },
233 Command::Pursue { addr, step, idem } => Self::Pursue { addr, step, idem },
234 Command::SetAutonomy {
235 scope,
236 autonomy,
237 idem,
238 } => Self::SetAutonomy {
239 scope,
240 autonomy,
241 idem,
242 },
243 Command::PutDocument {
244 which,
245 base,
246 body,
247 idem,
248 } => Self::PutDocument {
249 which,
250 base,
251 body,
252 idem,
253 },
254 Command::PutIdentity { card, base, idem } => Self::PutIdentity { card, base, idem },
255 Command::PutRules(write) => Self::PutRules(write),
256 Command::RestoreFile { at, point, idem } => Self::RestoreFile { at, point, idem },
257 Command::PutGuide { progress, idem } => Self::PutGuide { progress, idem },
258 Command::ConfigureCity(settings) => Self::ConfigureCity(settings),
259 Command::PutRange(write) => Self::PutRange(write),
260 Command::DecideProposals(decisions) => Self::DecideProposals(decisions),
261 Command::PutSpine {
262 building,
263 which,
264 base,
265 body,
266 idem,
267 } => Self::PutSpine {
268 building,
269 which,
270 base,
271 body,
272 idem,
273 },
274 Command::PutPreferences { patch, idem } => Self::PutPreferences { patch, idem },
275 Command::NameSession(naming) => Self::NameSession(naming),
276 Command::ChangeRunPolicy(change) => Self::ChangeRunPolicy(change),
277 Command::OpenRemoteDoor(opening) => Self::OpenRemoteDoor(opening),
278 Command::ReplaceCityKey(step) => Self::ReplaceCityKey(step),
279 Command::ConfirmRemoteDoor(answer) => Self::ConfirmRemoteDoor(answer),
280 Command::CloseRemoteDoor(step) => Self::CloseRemoteDoor(step),
281 Command::PrivacyOperation(request) => Self::PrivacyOperation(request),
282 Command::ForgetSecret(forgetting) => Self::ForgetSecret(forgetting),
283 Command::CloseCity(closing) => Self::CloseCity(closing),
284 Command::AddAgent(adding) => Self::AddAgent(adding),
285 Command::AgentLogin(login) => Self::AgentLogin(login),
286 Command::ForgetDevice(forgetting) => Self::ForgetDevice(forgetting),
287 #[rustfmt::skip]
288 Command::PutShelved { shelf, name, text, idem } => Self::PutShelved { shelf, name, text, idem },
289 Command::Auth { token } => Self::Auth { token },
290 }
291 }
292}
293
294#[cfg(test)]
295#[allow(
296 clippy::float_arithmetic,
297 clippy::unwrap_used,
298 clippy::expect_used,
299 clippy::panic,
300 clippy::indexing_slicing,
301 clippy::string_slice,
302 clippy::arithmetic_side_effects,
303 reason = "test code"
304)]
305mod tests {
306 use super::*;
307 #[test]
311 fn a_wire_frame_carrying_put_secret_fails_to_decode() {
312 let json = r#"{"put_secret":{"realm":"anthropic","name":"api","value":"sk-nope"}}"#;
313 let decoded: Result<WireCommand, _> = serde_json::from_str(json);
314 let err = decoded.expect_err("PutSecret has no wire form");
315 assert!(
316 !err.to_string().contains("sk-nope"),
317 "the refusal must not echo the bytes it protects"
318 );
319 }
320}