starweaver_context/
config.rs1mod model;
4mod tool;
5
6use serde::{Deserialize, Serialize};
7
8pub use model::{ModelCapability, ModelConfig};
9pub use tool::{ToolAvailabilityPolicy, ToolConfig};
10
11#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
13pub struct PerThousandRatio {
14 #[serde(alias = "parts_per_thousand")]
15 per_thousand: u16,
16}
17
18impl PerThousandRatio {
19 #[must_use]
21 pub const fn from_per_thousand(per_thousand: u16) -> Self {
22 Self { per_thousand }
23 }
24
25 #[must_use]
27 pub const fn per_thousand(self) -> u16 {
28 self.per_thousand
29 }
30
31 #[must_use]
33 pub fn as_fraction(self) -> f64 {
34 f64::from(self.per_thousand) / 1000.0
35 }
36}
37
38impl Default for PerThousandRatio {
39 fn default() -> Self {
40 Self::from_per_thousand(1000)
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::PerThousandRatio;
47
48 #[test]
49 fn legacy_parts_per_thousand_deserializes_to_the_canonical_ratio()
50 -> Result<(), serde_json::Error> {
51 let ratio = serde_json::from_str::<PerThousandRatio>(r#"{"parts_per_thousand": 900}"#)?;
52
53 assert_eq!(ratio.per_thousand(), 900);
54 assert_eq!(
55 serde_json::to_value(ratio)?["per_thousand"],
56 serde_json::json!(900)
57 );
58 Ok(())
59 }
60}
61
62#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
64#[serde(rename_all = "snake_case")]
65pub enum ShellReviewAction {
66 #[default]
68 Defer,
69 Deny,
71}
72
73#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
75#[serde(rename_all = "snake_case")]
76pub enum ShellReviewRiskLevel {
77 Low,
79 Medium,
81 #[default]
83 High,
84 ExtraHigh,
86}
87
88#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
90pub struct ShellReviewConfig {
91 #[serde(default)]
93 pub enabled: bool,
94 #[serde(default, skip_serializing_if = "Option::is_none")]
96 pub model: Option<String>,
97 #[serde(default)]
99 pub on_needs_approval: ShellReviewAction,
100 #[serde(default)]
102 pub risk_threshold: ShellReviewRiskLevel,
103 #[serde(default, skip_serializing_if = "Option::is_none")]
105 pub system_prompt: Option<String>,
106}
107
108#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
110pub struct SecurityConfig {
111 #[serde(default, skip_serializing_if = "Option::is_none")]
113 pub shell_review: Option<ShellReviewConfig>,
114}
115
116impl SecurityConfig {
117 #[must_use]
119 pub fn is_default(&self) -> bool {
120 self == &Self::default()
121 }
122}