wire.rsannotatedwire.rssource106 lines · 3.9 KB · raw

What the tablet and the service say to each other on the Jev-backed routes (/check, /embed, /rerank). It lives in the core, not in the guard, because both ends need it and the service must be able to build for a Worker, which the guard's HTTP client cannot.

5use serde::{Deserialize, Serialize};
7use crate::profile::Age;
8use crate::types::{Direction, Verdict};

What the tablet sends the guard service: one message, which way it is going, and the age of the child it is judged for. There is no name on the wire: the service does not need one.

12#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
13pub struct CheckRequest {
14    pub direction: Direction,

Optional; absent, the service judges for the youngest supported age, the strictest. An age outside the supported range does not parse, and so is refused.

16    #[serde(default)]
17    pub age: Option<Age>,
18    pub text: String,
19}
21impl CheckRequest {
22    pub fn age(&self) -> Age {
23        self.age.unwrap_or(Age::YOUNGEST)
24    }
25}

The service answers a verdict, or says it could not decide. "Could not decide" is not an Allow: the client turns it into a GuardError.

29#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
30pub enum CheckReply {
31    Verdict(Verdict),
32    Unavailable(String),
33}

Texts to embed.

36#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
37pub struct EmbedRequest {
38    pub texts: Vec<String>,
39}
41#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
42pub enum EmbedReply {
43    Vectors(Vec<Vec<f32>>),
44    Unavailable(String),
45}

A message and the shortlist of memories to order for it.

48#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
49pub struct RankRequest {
50    pub query: String,
51    pub candidates: Vec<String>,
52}
54#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
55pub enum RankReply {
56    Probabilities(Vec<f32>),
57    Unavailable(String),
58}

The text of one fact, to be given a picture. A fact is what Whiskers remembers about the child, so the request carries no age and no name: the picture is chosen for the words alone.

62#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
63pub struct IconRequest {
64    pub text: String,
65}

The picture chosen for a fact, or that none of the admitted ones fits, or that it could not be decided. "Could not decide" is not "none fits": the first is tried again later, the second is an answer.

69#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
70pub enum IconReply {
71    Icon(whiskers_icons::IconId),
72    NoneFits,
73    Unavailable(String),
74}
76#[cfg(test)]
77mod tests {
78    use super::*;
79
80    #[test]
81    fn an_icon_reply_names_an_admitted_icon_or_it_does_not_parse() {
82        let r: IconReply = serde_json::from_str(r#"{"Icon":"cat"}"#).unwrap();
83        assert_eq!(r, IconReply::Icon(whiskers_icons::IconId::new("cat").unwrap()));
84        assert_eq!(serde_json::from_str::<IconReply>(r#""NoneFits""#).unwrap(), IconReply::NoneFits);
85        assert!(serde_json::from_str::<IconReply>(r#"{"Icon":"beer"}"#).is_err());
86        assert_eq!(serde_json::to_string(&IconRequest { text: "x".into() }).unwrap(), r#"{"text":"x"}"#);
87    }
88
89    #[test]
90    fn a_request_without_an_age_is_judged_for_the_youngest() {
91        let r: CheckRequest = serde_json::from_str(r#"{"direction":"FromChild","text":"hi"}"#).unwrap();
92        assert_eq!(r.age(), Age::YOUNGEST);
93    }
94
95    #[test]
96    fn an_age_outside_the_range_does_not_parse() {
97        assert!(serde_json::from_str::<CheckRequest>(r#"{"direction":"FromChild","age":2,"text":"hi"}"#).is_err());
98        assert!(serde_json::from_str::<CheckRequest>(r#"{"direction":"FromChild","age":200,"text":"hi"}"#).is_err());
99    }
100
101    #[test]
102    fn the_request_carries_the_age_and_nothing_that_could_be_a_name() {
103        let r = CheckRequest { direction: Direction::ToChild, age: Some(Age::new(6).unwrap()), text: "hi".into() };
104        assert_eq!(serde_json::to_string(&r).unwrap(), r#"{"direction":"ToChild","age":6,"text":"hi"}"#);
105    }
106}