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