1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//! **What one workspace's roles are set to** — the read half of the tuning
//! family (yog's `docs/REMOTE.md` §3; PROTOCOL 6).
//!
//! One row per role the workspace's config declares. It is the same
//! `providers.yaml` assignment [`crate::verbs::tuning`]'s three writes land in,
//! read back from where they wrote it — which is what lets a control open
//! showing what is in force instead of blank.
//!
//! # `effort` is an OPTION and not a closed set, on purpose
//!
//! The gesture that sets it takes one of four things and the boundary refuses a
//! fifth by name. This does not, and upstream states why: *a gesture asserts a
//! level out of a closed set, while this reports what the file holds.* A config
//! written by a hand, or by a yog that knows a word this seat does not, holds
//! whatever it holds — so the reading is [`super`]'s rung 3 and the word is
//! carried **verbatim**, for a pane to paint as itself rather than as a
//! neighbour it is not.
//!
//! `None` is the absence, and the absence is a reading rather than a gap:
//! nothing was requested and the provider's own default governs. There is no
//! word for it on the wire, which is why there is none in the type.
//!
//! # `priority` is a required bool
//!
//! `false` and absent are one fact upstream — off is the provider's own default
//! lane — so the field is always written and a reader must not be made to tell
//! them apart. It is [`super::fields::flag`] and not an option.
use serde_json::{Map, Value};
use super::fields;
/// The kind token this reading answers to.
pub(crate) const KIND: &str = "roles";
/// One role, and the tuning in force on it.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RoleRow {
/// The role's name, as this workspace's config declares it. It is the
/// address every write in the family takes.
pub role: String,
/// The provider row its model calls go down.
pub provider: String,
/// The model id bound to it.
pub model: String,
/// Whether it asks for the provider's priority lane.
pub priority: bool,
/// How much reasoning it asks for, or `None` where it asks for none.
pub effort: Option<String>,
}
/// One row, strictly. Every field is required except the effort, and each
/// refusal names the field it refused on ([`super::fields`]).
pub(crate) fn row(value: &Value) -> Result<RoleRow, String> {
let obj: &Map<String, Value> = value.as_object().ok_or("role row: not an object")?;
Ok(RoleRow {
role: fields::text(obj, "role")?,
provider: fields::text(obj, "provider")?,
model: fields::text(obj, "model")?,
priority: fields::flag(obj, "priority")?,
effort: fields::opt_text(obj, "effort")?,
})
}
impl RoleRow {
/// **What this role runs on**, as one line: the provider row and the model
/// id, in the spelling `model` takes them back in.
///
/// A method rather than a format string at the one call site, because the
/// pane that paints it and the editor that pre-fills from it are two
/// places, and a second spelling of *what a role runs on* would drift the
/// first time either was reworded.
pub fn runs_on(&self) -> String {
format!("{} {}", self.provider, self.model)
}
}
#[cfg(test)]
mod tests;